DNA SVN: r996 - in trunk/docs/reference/src/main/docbook/en-US: content/jcr and 1 other directory.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-06-08 11:21:29 -0400 (Mon, 08 Jun 2009)
New Revision: 996
Added:
trunk/docs/reference/src/main/docbook/en-US/content/jcr/deploying_dna_jcr.xml
Modified:
trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml
trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml
trunk/docs/reference/src/main/docbook/en-US/master.xml
Log:
Added changes for the extra JCR chapter, moved JCR WIP docs into new directory structure
Added: trunk/docs/reference/src/main/docbook/en-US/content/jcr/deploying_dna_jcr.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/jcr/deploying_dna_jcr.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/jcr/deploying_dna_jcr.xml 2009-06-08 15:21:29 UTC (rev 996)
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="deploying_dna_jcr">
+ <title>Deploying the JBoss DNA JCR Implementation</title>
+ <para>
+ Placeholder for the JBoss DNA REST Server documentation
+ </para>
+ <sect1 id="jcr_deployment_models">
+ <title>JBoss DNA JCR Deployment Models</title>
+ <para>
+ One of the objects that must be supplied to many JBoss DNA components is an &ExecutionContext;. Some components
+ require this context to be passed into individual methods, allowing the context to vary with each method invocation.
+ Other components require the context to be provided before it's used, and will use that context for all its operations
+ (until it is given a different one).
+ </para>
+ </sect1>
+ <sect1 id="jcr_security">
+ <title>Understanding JCR Security in JBoss DNA</title>
+ <para>
+ One of the objects that must be supplied to many JBoss DNA components is an &ExecutionContext;. Some components
+ require this context to be passed into individual methods, allowing the context to vary with each method invocation.
+ Other components require the context to be provided before it's used, and will use that context for all its operations
+ (until it is given a different one).
+ </para>
+ </sect1>
+ <sect1 id="jcr_configuring_security">
+ <title>Configuring Security</title>
+ <para>
+ One of the objects that must be supplied to many JBoss DNA components is an &ExecutionContext;. Some components
+ require this context to be passed into individual methods, allowing the context to vary with each method invocation.
+ Other components require the context to be provided before it's used, and will use that context for all its operations
+ (until it is given a different one).
+ </para>
+ </sect1>
+ <sect1 id="jcr_repository_configuration">
+ <title>Configuring the Repositories</title>
+ <para>
+ One of the objects that must be supplied to many JBoss DNA components is an &ExecutionContext;. Some components
+ require this context to be passed into individual methods, allowing the context to vary with each method invocation.
+ Other components require the context to be provided before it's used, and will use that context for all its operations
+ (until it is given a different one).
+ </para>
+ <sect2 id="jcr_choosing_connectors">
+ <title>Choosing the Correct Connectors</title>
+ <para>
+ One of the objects that must be supplied to many JBoss DNA components is an &ExecutionContext;. Some components
+ require this context to be passed into individual methods, allowing the context to vary with each method invocation.
+ Other components require the context to be provided before it's used, and will use that context for all its operations
+ (until it is given a different one).
+ </para>
+ </sect2>
+ </sect1>
+ <sect1 id="jcr_dna_core_configuration">
+ <title>Configuring JBoss DNA Core</title>
+ <para>
+ One of the objects that must be supplied to many JBoss DNA components is an &ExecutionContext;. Some components
+ require this context to be passed into individual methods, allowing the context to vary with each method invocation.
+ Other components require the context to be provided before it's used, and will use that context for all its operations
+ (until it is given a different one).
+ </para>
+ </sect1>
+ <sect1 id="jcr_smoke_test">
+ <title>Smoke Testing the Installation</title>
+ <para>
+ One such implementation is the &JaasSecurityContext;, which delegates any authentication or authorization requests to a
+ <ulink url="http://java.sun.com/javase/technologies/security/">Java Authentication and Authorization Service (JAAS)</ulink>
+ provider. This is the standard approach for authenticating and authorizing in Java, and is the default mechanism
+ used by the &JcrEngine;.
+ </para>
+ </sect1>
+</chapter>
+
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/jcr/deploying_dna_jcr.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml 2009-06-08 14:57:17 UTC (rev 995)
+++ trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml 2009-06-08 15:21:29 UTC (rev 996)
@@ -29,7 +29,7 @@
%CustomDTD;
]>
<chapter id="jcr">
- <title>Content Repositories for Java (JCR)</title>
+ <title>The JBoss DNA Content Repository for Java (JCR) Implementation</title>
<para>
The
<ulink url="&JSR170;">Content Repository for Java technology API</ulink>
@@ -108,6 +108,15 @@
So while the current implementation provides 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.
</para>
+ <sect2>
+ <title>Optional Features</title>
+ </sect2>
+ <sect2>
+ <title>JCR Security</title>
+ </sect2>
+ <sect2>
+ <title>Node Type Registration</title>
+ </sect2>
</sect1>
<sect1>
<title>Summary</title>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml 2009-06-08 14:57:17 UTC (rev 995)
+++ trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml 2009-06-08 15:21:29 UTC (rev 996)
@@ -28,16 +28,46 @@
<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
%CustomDTD;
]>
-<chapter id="rest-service">
- <title>RESTful Web Service</title>
+<chapter id="rest_service">
+ <title>The JBoss DNA REST Server</title>
<para>
- blah blah
+ Placeholder for the JBoss DNA REST Server documentation
</para>
- <sect1>
- <title>Summary</title>
+ <sect1 id="supported_rest_resources">
+ <title>Supported Resources and URIs</title>
<para>
- In this chapter, we covered .... something .... FIX ME.
+ One of the objects that must be supplied to many JBoss DNA components is an &ExecutionContext;. Some components
+ require this context to be passed into individual methods, allowing the context to vary with each method invocation.
+ Other components require the context to be provided before it's used, and will use that context for all its operations
+ (until it is given a different one).
</para>
</sect1>
+ <sect1 id="jcr_rest_spi">
+ <title>Repository Providers</title>
+ <para>
+ One of the objects that must be supplied to many JBoss DNA components is an &ExecutionContext;. Some components
+ require this context to be passed into individual methods, allowing the context to vary with each method invocation.
+ Other components require the context to be provided before it's used, and will use that context for all its operations
+ (until it is given a different one).
+ </para>
+ </sect1>
+ <sect1 id="dna_rest_server_configuration">
+ <title>Configuring the DNA REST Server</title>
+ <para>
+ One of the objects that must be supplied to many JBoss DNA components is an &ExecutionContext;. Some components
+ require this context to be passed into individual methods, allowing the context to vary with each method invocation.
+ Other components require the context to be provided before it's used, and will use that context for all its operations
+ (until it is given a different one).
+ </para>
+ </sect1>
+ <sect1 id="dna_rest_server_deployment">
+ <title>Deploying the DNA REST Server</title>
+ <para>
+ One such implementation is the &JaasSecurityContext;, which delegates any authentication or authorization requests to a
+ <ulink url="http://java.sun.com/javase/technologies/security/">Java Authentication and Authorization Service (JAAS)</ulink>
+ provider. This is the standard approach for authenticating and authorizing in Java, and is the default mechanism
+ used by the &JcrEngine;.
+ </para>
+ </sect1>
</chapter>
Modified: trunk/docs/reference/src/main/docbook/en-US/master.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/master.xml 2009-06-08 14:57:17 UTC (rev 995)
+++ trunk/docs/reference/src/main/docbook/en-US/master.xml 2009-06-08 15:21:29 UTC (rev 996)
@@ -69,6 +69,7 @@
<part>
<title>JBoss DNA JCR</title>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/jcr/jcr.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/jcr/deploying_dna_jcr.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/jcr/rest_service.xml"/>
</part>
<part>
16 years, 6 months
DNA SVN: r995 - in trunk/docs/reference/src/main/docbook/en-US: content and 5 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-06-08 10:57:17 -0400 (Mon, 08 Jun 2009)
New Revision: 995
Added:
trunk/docs/reference/src/main/docbook/en-US/content/connectors/
trunk/docs/reference/src/main/docbook/en-US/content/connectors/in_memory.xml
trunk/docs/reference/src/main/docbook/en-US/content/core/
trunk/docs/reference/src/main/docbook/en-US/content/core/classloaders.xml
trunk/docs/reference/src/main/docbook/en-US/content/core/configuration.xml
trunk/docs/reference/src/main/docbook/en-US/content/core/environment.xml
trunk/docs/reference/src/main/docbook/en-US/content/core/mimetypes.xml
trunk/docs/reference/src/main/docbook/en-US/content/core/repositories.xml
trunk/docs/reference/src/main/docbook/en-US/content/core/sequencing.xml
trunk/docs/reference/src/main/docbook/en-US/content/developers/
trunk/docs/reference/src/main/docbook/en-US/content/developers/testing.xml
trunk/docs/reference/src/main/docbook/en-US/content/developers/tools.xml
trunk/docs/reference/src/main/docbook/en-US/content/jcr/
trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml
trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml
trunk/docs/reference/src/main/docbook/en-US/content/sequencers/
trunk/docs/reference/src/main/docbook/en-US/content/sequencers/zip.xml
Removed:
trunk/docs/reference/src/main/docbook/en-US/content/classloaders.xml
trunk/docs/reference/src/main/docbook/en-US/content/configuration.xml
trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml
trunk/docs/reference/src/main/docbook/en-US/content/environment.xml
trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml
trunk/docs/reference/src/main/docbook/en-US/content/mimetypes.xml
trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml
trunk/docs/reference/src/main/docbook/en-US/content/sequencing.xml
trunk/docs/reference/src/main/docbook/en-US/content/testing.xml
Modified:
trunk/docs/reference/src/main/docbook/en-US/master.xml
Log:
Reorganized the Reference Guide into parts.
Deleted: trunk/docs/reference/src/main/docbook/en-US/content/classloaders.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/classloaders.xml 2009-06-08 00:52:09 UTC (rev 994)
+++ trunk/docs/reference/src/main/docbook/en-US/content/classloaders.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -1,121 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
-%CustomDTD;
-]>
-<chapter id="classloaders">
- <title>Class loaders</title>
- <para>
- JBoss DNA is designed around extensions: sequencers, connectors, MIME type detectors, and class loader factories.
- The core part of JBoss DNA is relatively small and has few dependencies, while all of the "interesting" components
- are extensions that plug into and are used by different parts of the core. The core doesn't really care what
- the extensions do or what external libraries they require, as long as the extension fulfills its end of the
- extension contract.
- </para>
- <para>
- This means that you only need the core modules of JBoss DNA on the application classpath, while the extensions
- do not have to be on the application classpath. And because the core modules of JBoss DNA have few dependencies,
- the risk of JBoss DNA libraries conflicting with the application's are lower. Extensions, on the other hand,
- will likely have a lot of unique dependencies. By separating the core of JBoss DNA from the class loaders used
- to load the extensions, your application is isolated from the extensions and their dependencies. Of course,
- you can put all the JARs on the application classpath, too. (This is what the examples in the &GettingStarted; document do.)
- </para>
- <para>
- This design also allows you to select only those extensions that are interesting and useful for your application.
- Not every application needs all of the JBoss DNA functionality.
- Some applications may only need JBoss DNA sequencing, and specifically just a few types of sequencers.
- Other applications may not need sequencing but do want to use JBoss DNA federation capabilities.
- </para>
- <para>
- Finally, the use of these formal extensions also makes it easier for you to write your own customized extensions.
- You may have proprietary file formats that you want to sequence. Or, you may have a non-JCR repository system that you
- want to access via JCR and maybe even federate with information from other sources. Since extensions do
- only one thing (e.g., be a sequencer, or a connector, etc.), its easier to develop those customizations.
- </para>
- <sect1 id="dna-classloader-factory">
- <title>Class loader factory</title>
- <para>
- JBoss DNA loads all of the extension classes using class loaders returned by a <emphasis>class loader factory</emphasis>.
- Each time JBoss DNA wants to load a class, it needs the name of the class and an optional "class loader name".
- The meaning of the names is dependent upon the implementation of the class loader factory. For example, the
- <link linkend="dna-maven-classloader">Maven class loader factory</link> expects the names to be
- <ulink url="http://maven.apache.org/pom.html#Maven_Coordinates">Maven coordinates</ulink>. Either way,
- the class loader factory implementation uses the name to create and return a &ClassLoader;
- instance that can be used to load the class. Of course, if no name is provided, then a JBoss DNA service
- just uses its class loader to load the class. (This is why putting all the extension jars on the classpath works.)
- </para>
- <para>
- The class loader factory interface is pretty simple:
- </para>
- <programlisting>
-public interface &ClassLoaderFactory; {
-
- /**
- * Get a class loader given the supplied classpath. The meaning of the classpath is implementation-dependent.
- * @param classpath the classpath to use
- * @return the class loader; may not be null
- */
- &ClassLoader; getClassLoader( String... classpath );
-}
-</programlisting>
- <para>In the <link linkend="environment">next chapter</link> we'll describe an &ExecutionContext; interface that is
- supplied to each of the JBoss DNA core services. This context interface actually extends the &ClassLoaderFactory;
- interface, so setting up an &ExecutionContext; implicitly sets up the class loader factory.</para>
- </sect1>
- <sect1 id="dna-standard-classloader">
- <title>Standard class loader factory</title>
- <para>JBoss DNA includes and uses as a default a standard class loader factory that just loads the classes using the Thread's current context
- class loader (if there is one), or a delegate class loader that defaults to the class loader that loaded
- the &StandardClassLoaderFactory; class. The class ignores any class loader names that are supplied.
- </para>
- </sect1>
- <sect1 id="dna-maven-classloader">
- <title>Maven Repository class loader factory</title>
- <para>
- The <code>dna-classloader-maven</code> project has a class loader factory implementation that parses the names into
- <ulink url="http://maven.apache.org/pom.html#Maven_Coordinates">Maven coordinates</ulink>, then uses those coordinates
- to look up artifacts in a Maven 2 repository. The artifact's POM file is used to determine the dependencies,
- which is done transitively to obtain the complete dependency graph. The resulting class loader has access
- to these artifacts in dependency order.
- </para>
- <para>
- This class loader is also able to use a JCR repository that contains the equivalent contents of a Maven repository.
- However, JBoss DNA doesn't currently have any tooling to help populate that repository, so this component may be
- of limited use right now.
- </para>
- </sect1>
- <sect1>
- <title>Summary</title>
- <para>
- In this chapter, we described the framework used by JBoss DNA to load extension classes, like implementations
- of repositories, sequencers, MIME type detectors, and other components.
- <link linkend="environment">Next</link>, we cover how JBoss security works and how the various components
- of JBoss DNA can access this security information as well as information about the environment in which the component is running.
- </para>
- </sect1>
-</chapter>
Deleted: trunk/docs/reference/src/main/docbook/en-US/content/configuration.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/configuration.xml 2009-06-08 00:52:09 UTC (rev 994)
+++ trunk/docs/reference/src/main/docbook/en-US/content/configuration.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -1,371 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
-%CustomDTD;
-]>
-<chapter id="configuration">
- <title>Configuring and Using JBoss DNA</title>
- <para>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 <code>JcrEngine</code>. After that, you obtain the
- <code>javax.jcr.Repository</code> instance for a named repository and just use the standard JCR API throughout your
- application.
- </para>
- <sect1 id="jcr_engine">
- <title>JBoss DNA's JcrEngine</title>
- <para>
- JBoss DNA encapsulates everything necessary to run one or more JCR repositories into a single &JcrEngine; instance.
- This includes all underlying repository sources, the pools of connections to the sources, the sequencers,
- the MIME type detector(s), and the &Repository; implementations.
- </para>
- <para>
- Obtaining a &JcrEngine; instance is very easy - assuming that you have a valid &JcrConfiguration; instance. We'll see
- how to get one of those in a little bit, but if you have one then all you have to do is build and start the engine:
- </para>
- <programlisting role="JAVA"><![CDATA[
-JcrConfiguration config = ...
-JcrEngine engine = config.build();
-engine.start();
- ]]></programlisting>
- <para>
- Obtaining a JCR &Repository; instance is a matter of simply asking the engine for it by the name defined in the configuration:
- </para>
- <programlisting role="JAVA"><![CDATA[
-javax.jcr.Repository repository = engine.getRepository("Name of repository");
- ]]></programlisting>
- <para>
- At this point, your application can proceed by working with the JCR API.
- </para>
- <para>
- And, once you're finished with the &JcrEngine;, you should shut it down:
- </para>
- <programlisting role="JAVA"><![CDATA[
-engine.shutdown();
-engine.awaitTermination(3,TimeUnit.SECONDS); // optional
- ]]></programlisting>
- <para>
- When the <code>shutdown()</code> method is called, the &Repository; instances managed by the engine are marked as being shut down,
- and they will not be able to create new &Session;s. However, any existing &Session;s or ongoing operations (e.g., event notifications)
- present at the time of the <code>shutdown()</code> call will be allowed to finish.
- In essence, <code>shutdown()</code> is a <emphasis>graceful</emphasis> request, and since it may take some time to complete,
- you can wait until the shutdown has completed by simply calling <code>awaitTermination(...)</code> as shown above.
- This method will block until the engine has indeed shutdown or until the supplied time duration has passed (whichever comes first).
- And, yes, you can call the <code>awaitTermination(...)</code> method repeatedly if needed.
- </para>
- </sect1>
- <sect1 id="jcr_configuration">
- <title>JcrConfiguration</title>
- <para>
- The previous section assumed the existence of a &JcrConfiguration;. It's not really that creating an instance is all that difficult.
- In fact, there's only one no-argument constructor, so actually creating the instance is a piece of cake. What can be a little more challenging,
- though, is setting up the &JcrConfiguration; instance, which must define the following components:
- <itemizedlist>
- <listitem>
- <para><emphasis role="strong"><code>Repository sources</code></emphasis> are the POJO objects that each describe a particular
- location where content is stored. Each repository source object is an instance of a JBoss DNA connector, and is configured
- with the properties that particular source. JBoss DNA'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. </para>
- </listitem>
- <listitem>
- <para><emphasis role="strong"><code>Repositories</code></emphasis> define the JCR repositories that are available. Each
- repository has a unique name that is used to obtain the &Repository; instance from the &JcrEngine;'s <code>getRepository(String)</code>
- method, but each repository definition also can include the predefined namespaces (other than those automatically defined by
- JBoss DNA), various options, and the node types that are to be available in the repository without explicit registration
- through the JCR API.</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong"><code>Sequencers</code></emphasis> 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.</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong"><code>MIME type detectors</code></emphasis> 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. JBoss DNA 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.</para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- There really are three options:
- <itemizedlist>
- <listitem>
- <para><emphasis role="strong"><code>Load from a file</code></emphasis> is conceptually the easiest and requires the least amount
- of Java code, but it now requires a configuration file.</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong"><code>Load from a configuration repository</code></emphasis> is not much more complicated than loading
- from a file, but it does allow multiple &JcrEngine; instances (usually in different processes perhaps on different machines)
- to easily access their (shared) configuration. And technically, loading the configuration from a file really just creates an
- &InMemoryRepositorySource;, imports the configuration file into that source, and then proceeds with this approach.</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong"><code>Programmatic configuration</code></emphasis> is always possible, even if the configuration is loaded
- from a file or repository. Using the &JcrConfiguration;'s API, you can define (or update or remove) all of the definitions that make
- up a configuration.</para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- Each of these approaches has their obvious advantages, so the choice of which one to use is entirely up to you.
- </para>
- <sect2 id="loading_from_file">
- <title>Loading from a configuration file</title>
- <para>
- Loading the JBoss DNA configuration from a file is actually very simple:
- </para>
- <programlisting role="JAVA"><![CDATA[
-JcrConfiguration config = new JcrConfiguration();
-configuration.loadFrom(file);
- ]]></programlisting>
- <para>
- where the <code>file</code> parameter can actually be a &File; instance, a &URL; to the file, an &InputStream;
- containing the contents of the file, or even a &String; containing the contents of the file.
- </para>
- <note>
- <para>The <code>loadFrom(...)</code> method can be called any number of times, but each time it is called it completely wipes
- out any current notion of the configuration and replaces it with the configuration found in the file.
- </para>
- </note>
- <para>
- There is an optional second parameter that defines the &Path; within the configuration file identifying the parent node of the various
- configuration nodes. If not specified, it assumes "/". This makes it possible for the configuration content to be
- located at a different location in the hierarchical structure. (This is not often required, but when it is required
- this second parameter is very useful.)
- </para>
- <para>
- 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):
- </para>
- <programlisting role="JAVA"><![CDATA[
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration xmlns="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
- <!--
- Define the JCR repositories
- -->
- <dna:repositories>
- <!--
- Define a JCR repository that accesses the 'Cars' source directly.
- This of course is optional, since we could access the same content through 'vehicles'.
- -->
- <dna:repository jcr:name="car repository" dna:source="Cars">
- <options jcr:primaryType="dna:options"/>
- <jaasLoginConfigName jcr:primaryType="dna:option" dna:value="dna-jcr"/>
- </options>
- </dna:repository>
- </dna:repositories>
- <!--
- Define the sources for the content. These sources are directly accessible using the DNA-specific Graph API.
- -->
- <dna:sources jcr:primaryType="nt:unstructured">
- <dna:source jcr:name="Cars" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" dna:retryLimit="3" dna:defaultWorkspaceName="workspace1"/>
- <dna:source jcr:name="Aircraft" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource">
- <!-- Define the name of the workspace used by default. Optional, but convenient. -->
- <defaultWorkspaceName>workspace2</defaultWorkspaceName>
- </dna:source>
- </dna:sources>
- <!--
- Define the sequencers. This is an optional section. For this example, we're not using any sequencers.
- -->
- <dna:sequencers>
- <!--dna:sequencer jcr:name="Image Sequencer" dna:classname="org.jboss.dna.sequencer.image.ImageMetadataSequencer">
- <dna:description>Image metadata sequencer</dna:description>
- <dna:pathExpression>/foo/source => /foo/target</dna:pathExpression>
- <dna:pathExpression>/bar/source => /bar/target</dna:pathExpression>
- </dna:sequencer-->
- </dna:sequencers>
- <dna:mimeTypeDetectors>
- <dna:mimeTypeDetector jcr:name="Detector" dna:description="Standard extension-based MIME type detector"/>
- </dna:mimeTypeDetectors>
-</configuration>
- ]]></programlisting>
- </sect2>
- <sect2 id="loading_from_repository">
- <title>Loading from a configuration repository</title>
- <para>
- Loading the JBoss DNA configuration from an existing repository is also pretty straightforward. Simply create and configure the
- &RepositorySource; instance to point to the desired repository, and then call the <code>loadFrom(&RepositorySource; source)</code>
- method:
- </para>
- <programlisting role="JAVA"><![CDATA[
-RepositorySource configSource = ...
-JcrConfiguration config = new JcrConfiguration();
-configuration.loadFrom(configSource);
- ]]></programlisting>
- <para>
- This really is a more advanced way to define your configuration, so we won't go into how you configure a &RepositorySource;.
- For more information, consult the &ReferenceGuide;.
- </para>
- <note>
- <para>The <code>loadFrom(...)</code> method can be called any number of times, but each time it is called it completely wipes
- out any current notion of the configuration and replaces it with the configuration found in the file.
- </para>
- </note>
- <para>
- There is an optional second parameter that defines the name of the workspace in the supplied source where the configuration content
- can be found. It is not needed if the workspace is the source's default workspace.
- There is an optional third parameter that defines the &Path; within the configuration repository identifying the parent node of the various
- configuration nodes. If not specified, it assumes "/". This makes it possible for the configuration content to be
- located at a different location in the hierarchical structure. (This is not often required, but when it is required
- this second parameter is very useful.)
- </para>
- </sect2>
- <sect2 id="programmatic_configuration">
- <title>Programmatic configuration</title>
- <para>
- Defining the configuration programmatically is not terribly complicated, and it for obvious reasons results in more verbose Java code.
- But this approach is very useful and often the easiest approach when the configuration must change or is a reflection of other
- dynamic information.
- </para>
- <para>
- The &JcrConfiguration; class was designed to have an easy-to-use API that makes it easy to configure each of the different kinds of
- components, especially when using an IDE with code completion. Here are several examples:
- </para>
- <sect3 id="programmatically_configuring_sources">
- <title>Repository sources</title>
- <para>Each repository source definition must include the name of the &RepositorySource; class as well as each bean property
- that should be set on the object:
- </para>
- <programlisting role="JAVA"><![CDATA[
-JcrConfiguration config = ...
-config.repositorySource("source A")
- .usingClass(InMemoryRepositorySource.class)
- .setDescription("The repository for our content")
- .setProperty("defaultWorkspaceName", workspaceName);
- ]]></programlisting>
- <para>
- This example defines an in-memory source with the name "source A", a description, and a single "defaultWorkspaceName" bean property.
- Different &RepositorySource; implementations will the bean properties that are required and optional.
- Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
- the classpath or from a specific classpath).
- </para>
- <note>
- <para>Each time <code>repositorySource(String)</code> is called, it will either load the existing definition with the supplied
- name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
- on the result of <code>repositorySource(String)</code>.
- The set of existing definitions can be accessed with the <code>repositorySources()</code> method.
- </para>
- </note>
- </sect3>
- <sect3 id="programmatically_configuring_repositories">
- <title>Repositories</title>
- <para>Each repository must be defined to use a named repository source, but all other aspects (e.g., namespaces, node types, options)
- are optional.</para>
- <programlisting role="JAVA"><![CDATA[
-JcrConfiguration config = ...
-config.repository("repository A")
- .addNodeTypes("myCustomNodeTypes.cnd")
- .setSource("source 1")
- .registerNamespace("acme","http://www.example.com/acme")
- .setOption(JcrRepository.Option.JAAS_LOGIN_CONFIG_NAME, "dna-jcr");
- ]]></programlisting>
- <para>
- This example defines a repository that uses the "source 1" repository source (which could be a federated source, an in-memory source,
- a database store, or any other source). Additionally, this example adds the node types in the "myCustomNodeTypes.cnd" file as those
- that will be made available when the repository is accessed. It also defines the "http://www.example.com/acme" namespace,
- and finally sets the "JAAS_LOGIN_CONFIG_NAME" option to define the name of the JAAS login configuration that should be used by
- the JBoss DNA repository.
- </para>
- <note>
- <para>Each time <code>repository(String)</code> is called, it will either load the existing definition with the supplied
- name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
- on the result of <code>repository(String)</code>.
- The set of existing definitions can be accessed with the <code>repositories()</code> method.
- </para>
- </note>
- </sect3>
- <sect3 id="programmatically_configuring_sequencers">
- <title>Sequencers</title>
- <para>Each defined sequencer must specify the name of the &StreamSequencer; implementation class as well as the path expressions
- defining which nodes should be sequenced and the output paths defining where the sequencer output should be placed (often as a function
- of the input path expression).</para>
- <programlisting role="JAVA"><![CDATA[
-JcrConfiguration config = ...
-config.sequencer("Image Sequencer")
- .usingClass("org.jboss.dna.sequencer.image.ImageMetadataSequencer")
- .loadedFromClasspath()
- .setDescription("Sequences image files to extract the characteristics of the image")
- .sequencingFrom("//(*.(jpg|jpeg|gif|bmp|pcx|png|iff|ras|pbm|pgm|ppm|psd)[*])/jcr:content[@jcr:data]")
- .andOutputtingTo("/images/$1");
- ]]></programlisting>
- <para>
- This shows an example of a sequencer definition named "Image Sequencer" that uses the &ImageMetadataSequencer; class
- (loaded from the classpath), that is to sequence the "jcr:data" property on any new or changed nodes that are named
- "jcr:content" below a parent node with a name ending in ".jpg", ".jpeg", ".gif", ".bmp", ".pcx", ".iff", ".ras",
- ".pbm", ".pgm", ".ppm" or ".psd". The output of the sequencing operation should be placed at the "/images/$1" node,
- where the "$1" value is captured as the name of the parent node. (The capture groups work the same was as regular expressions;
- see the &ReferenceGuide; for more details.)
- Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
- the classpath or from a specific classpath).
- </para>
- <note>
- <para>Each time <code>sequencer(String)</code> is called, it will either load the existing definition with the supplied
- name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
- on the result of <code>sequencer(String)</code>.
- The set of existing definitions can be accessed with the <code>sequencers()</code> method.
- </para>
- </note>
- </sect3>
- <sect3 id="programmatically_configuring_mime_type_detectors">
- <title>MIME type detectors</title>
- <para>Each defined MIME type detector must specify the name of the &MimeTypeDetector; implementation class as well as any
- other bean properties required by the implementation.</para>
- <programlisting role="JAVA"><![CDATA[
-JcrConfiguration config = ...
-config.mimeTypeDetector("Extension Detector")
- .usingClass(org.jboss.dna.graph.mimetype.ExtensionBasedMimeTypeDetector.class);
- ]]></programlisting>
- <para>
- Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
- the classpath or from a specific classpath).
- </para>
- <note>
- <para>Each time <code>mimeTypeDetector(String)</code> is called, it will either load the existing definition with the supplied
- name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
- on the result of <code>mimeTypeDetector(String)</code>.
- The set of existing definitions can be accessed with the <code>mimeTypeDetectors()</code> method.
- </para>
- </note>
- </sect3>
- </sect2>
- </sect1>
- <sect1 id="using_dna_whats_next">
- <title>What's next</title>
- <para>
- This chapter outline how you configure JBoss DNA, how you then access a <code>javax.jcr.Repository</code> instance,
- and use the standard JCR API to interact with the repository. The
- <link linkend="downloading_and_running">next chapter </link> walks you through downloading
- and running the JBoss DNA examples.
- </para>
- </sect1>
-</chapter>
Added: trunk/docs/reference/src/main/docbook/en-US/content/connectors/in_memory.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/in_memory.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/in_memory.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="in-memory-connector">
+ <title>In-Memory Connector</title>
+ <para>
+ blah blah
+ </para>
+</chapter>
+
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/connectors/in_memory.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Copied: trunk/docs/reference/src/main/docbook/en-US/content/core/classloaders.xml (from rev 994, trunk/docs/reference/src/main/docbook/en-US/content/classloaders.xml)
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/core/classloaders.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/core/classloaders.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="classloaders">
+ <title>Class loaders</title>
+ <para>
+ JBoss DNA is designed around extensions: sequencers, connectors, MIME type detectors, and class loader factories.
+ The core part of JBoss DNA is relatively small and has few dependencies, while all of the "interesting" components
+ are extensions that plug into and are used by different parts of the core. The core doesn't really care what
+ the extensions do or what external libraries they require, as long as the extension fulfills its end of the
+ extension contract.
+ </para>
+ <para>
+ This means that you only need the core modules of JBoss DNA on the application classpath, while the extensions
+ do not have to be on the application classpath. And because the core modules of JBoss DNA have few dependencies,
+ the risk of JBoss DNA libraries conflicting with the application's are lower. Extensions, on the other hand,
+ will likely have a lot of unique dependencies. By separating the core of JBoss DNA from the class loaders used
+ to load the extensions, your application is isolated from the extensions and their dependencies. Of course,
+ you can put all the JARs on the application classpath, too. (This is what the examples in the &GettingStarted; document do.)
+ </para>
+ <para>
+ This design also allows you to select only those extensions that are interesting and useful for your application.
+ Not every application needs all of the JBoss DNA functionality.
+ Some applications may only need JBoss DNA sequencing, and specifically just a few types of sequencers.
+ Other applications may not need sequencing but do want to use JBoss DNA federation capabilities.
+ </para>
+ <para>
+ Finally, the use of these formal extensions also makes it easier for you to write your own customized extensions.
+ You may have proprietary file formats that you want to sequence. Or, you may have a non-JCR repository system that you
+ want to access via JCR and maybe even federate with information from other sources. Since extensions do
+ only one thing (e.g., be a sequencer, or a connector, etc.), its easier to develop those customizations.
+ </para>
+ <sect1 id="dna-classloader-factory">
+ <title>Class loader factory</title>
+ <para>
+ JBoss DNA loads all of the extension classes using class loaders returned by a <emphasis>class loader factory</emphasis>.
+ Each time JBoss DNA wants to load a class, it needs the name of the class and an optional "class loader name".
+ The meaning of the names is dependent upon the implementation of the class loader factory. For example, the
+ <link linkend="dna-maven-classloader">Maven class loader factory</link> expects the names to be
+ <ulink url="http://maven.apache.org/pom.html#Maven_Coordinates">Maven coordinates</ulink>. Either way,
+ the class loader factory implementation uses the name to create and return a &ClassLoader;
+ instance that can be used to load the class. Of course, if no name is provided, then a JBoss DNA service
+ just uses its class loader to load the class. (This is why putting all the extension jars on the classpath works.)
+ </para>
+ <para>
+ The class loader factory interface is pretty simple:
+ </para>
+ <programlisting>
+public interface &ClassLoaderFactory; {
+ /**
+ * Get a class loader given the supplied classpath. The meaning of the classpath
+ * is implementation-dependent.
+ * @param classpath the classpath to use
+ * @return the class loader; may not be null
+ */
+ &ClassLoader; getClassLoader( &String;... classpath );
+}
+</programlisting>
+ <para>In the <link linkend="environment">next chapter</link> we'll describe an &ExecutionContext; interface that is
+ supplied to each of the JBoss DNA core services. This context interface actually extends the &ClassLoaderFactory;
+ interface, so setting up an &ExecutionContext; implicitly sets up the class loader factory.</para>
+ </sect1>
+ <sect1 id="dna-standard-classloader">
+ <title>Standard class loader factory</title>
+ <para>JBoss DNA includes and uses as a default a standard class loader factory that just loads the classes using the Thread's current context
+ class loader (if there is one), or a delegate class loader that defaults to the class loader that loaded
+ the &StandardClassLoaderFactory; class. The class ignores any class loader names that are supplied.
+ </para>
+ </sect1>
+ <sect1 id="dna-maven-classloader">
+ <title>Maven Repository class loader factory</title>
+ <para>
+ The <code>dna-classloader-maven</code> project has a class loader factory implementation that parses the names into
+ <ulink url="http://maven.apache.org/pom.html#Maven_Coordinates">Maven coordinates</ulink>, then uses those coordinates
+ to look up artifacts in a Maven 2 repository. The artifact's POM file is used to determine the dependencies,
+ which is done transitively to obtain the complete dependency graph. The resulting class loader has access
+ to these artifacts in dependency order.
+ </para>
+ <para>
+ This class loader is also able to use a JCR repository that contains the equivalent contents of a Maven repository.
+ However, JBoss DNA doesn't currently have any tooling to help populate that repository, so this component may be
+ of limited use right now.
+ </para>
+ </sect1>
+ <sect1>
+ <title>Summary</title>
+ <para>
+ In this chapter, we described the framework used by JBoss DNA to load extension classes, like implementations
+ of repositories, sequencers, MIME type detectors, and other components.
+ <link linkend="environment">Next</link>, we cover how JBoss security works and how the various components
+ of JBoss DNA can access this security information as well as information about the environment in which the component is running.
+ </para>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/core/classloaders.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Copied: trunk/docs/reference/src/main/docbook/en-US/content/core/configuration.xml (from rev 994, trunk/docs/reference/src/main/docbook/en-US/content/configuration.xml)
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/core/configuration.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/core/configuration.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -0,0 +1,371 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="configuration">
+ <title>Configuring and Using JBoss DNA</title>
+ <para>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 <code>JcrEngine</code>. After that, you obtain the
+ <code>javax.jcr.Repository</code> instance for a named repository and just use the standard JCR API throughout your
+ application.
+ </para>
+ <sect1 id="jcr_engine">
+ <title>JBoss DNA's JcrEngine</title>
+ <para>
+ JBoss DNA encapsulates everything necessary to run one or more JCR repositories into a single &JcrEngine; instance.
+ This includes all underlying repository sources, the pools of connections to the sources, the sequencers,
+ the MIME type detector(s), and the &Repository; implementations.
+ </para>
+ <para>
+ Obtaining a &JcrEngine; instance is very easy - assuming that you have a valid &JcrConfiguration; instance. We'll see
+ how to get one of those in a little bit, but if you have one then all you have to do is build and start the engine:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+JcrEngine engine = config.build();
+engine.start();
+ ]]></programlisting>
+ <para>
+ Obtaining a JCR &Repository; instance is a matter of simply asking the engine for it by the name defined in the configuration:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+javax.jcr.Repository repository = engine.getRepository("Name of repository");
+ ]]></programlisting>
+ <para>
+ At this point, your application can proceed by working with the JCR API.
+ </para>
+ <para>
+ And, once you're finished with the &JcrEngine;, you should shut it down:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+engine.shutdown();
+engine.awaitTermination(3,TimeUnit.SECONDS); // optional
+ ]]></programlisting>
+ <para>
+ When the <code>shutdown()</code> method is called, the &Repository; instances managed by the engine are marked as being shut down,
+ and they will not be able to create new &Session;s. However, any existing &Session;s or ongoing operations (e.g., event notifications)
+ present at the time of the <code>shutdown()</code> call will be allowed to finish.
+ In essence, <code>shutdown()</code> is a <emphasis>graceful</emphasis> request, and since it may take some time to complete,
+ you can wait until the shutdown has completed by simply calling <code>awaitTermination(...)</code> as shown above.
+ This method will block until the engine has indeed shutdown or until the supplied time duration has passed (whichever comes first).
+ And, yes, you can call the <code>awaitTermination(...)</code> method repeatedly if needed.
+ </para>
+ </sect1>
+ <sect1 id="jcr_configuration">
+ <title>JcrConfiguration</title>
+ <para>
+ The previous section assumed the existence of a &JcrConfiguration;. It's not really that creating an instance is all that difficult.
+ In fact, there's only one no-argument constructor, so actually creating the instance is a piece of cake. What can be a little more challenging,
+ though, is setting up the &JcrConfiguration; instance, which must define the following components:
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="strong"><code>Repository sources</code></emphasis> are the POJO objects that each describe a particular
+ location where content is stored. Each repository source object is an instance of a JBoss DNA connector, and is configured
+ with the properties that particular source. JBoss DNA'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. </para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>Repositories</code></emphasis> define the JCR repositories that are available. Each
+ repository has a unique name that is used to obtain the &Repository; instance from the &JcrEngine;'s <code>getRepository(String)</code>
+ method, but each repository definition also can include the predefined namespaces (other than those automatically defined by
+ JBoss DNA), various options, and the node types that are to be available in the repository without explicit registration
+ through the JCR API.</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>Sequencers</code></emphasis> 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.</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>MIME type detectors</code></emphasis> 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. JBoss DNA 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.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ There really are three options:
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="strong"><code>Load from a file</code></emphasis> is conceptually the easiest and requires the least amount
+ of Java code, but it now requires a configuration file.</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>Load from a configuration repository</code></emphasis> is not much more complicated than loading
+ from a file, but it does allow multiple &JcrEngine; instances (usually in different processes perhaps on different machines)
+ to easily access their (shared) configuration. And technically, loading the configuration from a file really just creates an
+ &InMemoryRepositorySource;, imports the configuration file into that source, and then proceeds with this approach.</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>Programmatic configuration</code></emphasis> is always possible, even if the configuration is loaded
+ from a file or repository. Using the &JcrConfiguration;'s API, you can define (or update or remove) all of the definitions that make
+ up a configuration.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Each of these approaches has their obvious advantages, so the choice of which one to use is entirely up to you.
+ </para>
+ <sect2 id="loading_from_file">
+ <title>Loading from a configuration file</title>
+ <para>
+ Loading the JBoss DNA configuration from a file is actually very simple:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = new JcrConfiguration();
+configuration.loadFrom(file);
+ ]]></programlisting>
+ <para>
+ where the <code>file</code> parameter can actually be a &File; instance, a &URL; to the file, an &InputStream;
+ containing the contents of the file, or even a &String; containing the contents of the file.
+ </para>
+ <note>
+ <para>The <code>loadFrom(...)</code> method can be called any number of times, but each time it is called it completely wipes
+ out any current notion of the configuration and replaces it with the configuration found in the file.
+ </para>
+ </note>
+ <para>
+ There is an optional second parameter that defines the &Path; within the configuration file identifying the parent node of the various
+ configuration nodes. If not specified, it assumes "/". This makes it possible for the configuration content to be
+ located at a different location in the hierarchical structure. (This is not often required, but when it is required
+ this second parameter is very useful.)
+ </para>
+ <para>
+ 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):
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration xmlns="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <!--
+ Define the JCR repositories
+ -->
+ <dna:repositories>
+ <!--
+ Define a JCR repository that accesses the 'Cars' source directly.
+ This of course is optional, since we could access the same content through 'vehicles'.
+ -->
+ <dna:repository jcr:name="car repository" dna:source="Cars">
+ <options jcr:primaryType="dna:options"/>
+ <jaasLoginConfigName jcr:primaryType="dna:option" dna:value="dna-jcr"/>
+ </options>
+ </dna:repository>
+ </dna:repositories>
+ <!--
+ Define the sources for the content. These sources are directly accessible using the DNA-specific Graph API.
+ -->
+ <dna:sources jcr:primaryType="nt:unstructured">
+ <dna:source jcr:name="Cars" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" dna:retryLimit="3" dna:defaultWorkspaceName="workspace1"/>
+ <dna:source jcr:name="Aircraft" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource">
+ <!-- Define the name of the workspace used by default. Optional, but convenient. -->
+ <defaultWorkspaceName>workspace2</defaultWorkspaceName>
+ </dna:source>
+ </dna:sources>
+ <!--
+ Define the sequencers. This is an optional section. For this example, we're not using any sequencers.
+ -->
+ <dna:sequencers>
+ <!--dna:sequencer jcr:name="Image Sequencer" dna:classname="org.jboss.dna.sequencer.image.ImageMetadataSequencer">
+ <dna:description>Image metadata sequencer</dna:description>
+ <dna:pathExpression>/foo/source => /foo/target</dna:pathExpression>
+ <dna:pathExpression>/bar/source => /bar/target</dna:pathExpression>
+ </dna:sequencer-->
+ </dna:sequencers>
+ <dna:mimeTypeDetectors>
+ <dna:mimeTypeDetector jcr:name="Detector" dna:description="Standard extension-based MIME type detector"/>
+ </dna:mimeTypeDetectors>
+</configuration>
+ ]]></programlisting>
+ </sect2>
+ <sect2 id="loading_from_repository">
+ <title>Loading from a configuration repository</title>
+ <para>
+ Loading the JBoss DNA configuration from an existing repository is also pretty straightforward. Simply create and configure the
+ &RepositorySource; instance to point to the desired repository, and then call the <code>loadFrom(&RepositorySource; source)</code>
+ method:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+RepositorySource configSource = ...
+JcrConfiguration config = new JcrConfiguration();
+configuration.loadFrom(configSource);
+ ]]></programlisting>
+ <para>
+ This really is a more advanced way to define your configuration, so we won't go into how you configure a &RepositorySource;.
+ For more information, consult the &ReferenceGuide;.
+ </para>
+ <note>
+ <para>The <code>loadFrom(...)</code> method can be called any number of times, but each time it is called it completely wipes
+ out any current notion of the configuration and replaces it with the configuration found in the file.
+ </para>
+ </note>
+ <para>
+ There is an optional second parameter that defines the name of the workspace in the supplied source where the configuration content
+ can be found. It is not needed if the workspace is the source's default workspace.
+ There is an optional third parameter that defines the &Path; within the configuration repository identifying the parent node of the various
+ configuration nodes. If not specified, it assumes "/". This makes it possible for the configuration content to be
+ located at a different location in the hierarchical structure. (This is not often required, but when it is required
+ this second parameter is very useful.)
+ </para>
+ </sect2>
+ <sect2 id="programmatic_configuration">
+ <title>Programmatic configuration</title>
+ <para>
+ Defining the configuration programmatically is not terribly complicated, and it for obvious reasons results in more verbose Java code.
+ But this approach is very useful and often the easiest approach when the configuration must change or is a reflection of other
+ dynamic information.
+ </para>
+ <para>
+ The &JcrConfiguration; class was designed to have an easy-to-use API that makes it easy to configure each of the different kinds of
+ components, especially when using an IDE with code completion. Here are several examples:
+ </para>
+ <sect3 id="programmatically_configuring_sources">
+ <title>Repository sources</title>
+ <para>Each repository source definition must include the name of the &RepositorySource; class as well as each bean property
+ that should be set on the object:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+config.repositorySource("source A")
+ .usingClass(InMemoryRepositorySource.class)
+ .setDescription("The repository for our content")
+ .setProperty("defaultWorkspaceName", workspaceName);
+ ]]></programlisting>
+ <para>
+ This example defines an in-memory source with the name "source A", a description, and a single "defaultWorkspaceName" bean property.
+ Different &RepositorySource; implementations will the bean properties that are required and optional.
+ Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
+ the classpath or from a specific classpath).
+ </para>
+ <note>
+ <para>Each time <code>repositorySource(String)</code> is called, it will either load the existing definition with the supplied
+ name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
+ on the result of <code>repositorySource(String)</code>.
+ The set of existing definitions can be accessed with the <code>repositorySources()</code> method.
+ </para>
+ </note>
+ </sect3>
+ <sect3 id="programmatically_configuring_repositories">
+ <title>Repositories</title>
+ <para>Each repository must be defined to use a named repository source, but all other aspects (e.g., namespaces, node types, options)
+ are optional.</para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+config.repository("repository A")
+ .addNodeTypes("myCustomNodeTypes.cnd")
+ .setSource("source 1")
+ .registerNamespace("acme","http://www.example.com/acme")
+ .setOption(JcrRepository.Option.JAAS_LOGIN_CONFIG_NAME, "dna-jcr");
+ ]]></programlisting>
+ <para>
+ This example defines a repository that uses the "source 1" repository source (which could be a federated source, an in-memory source,
+ a database store, or any other source). Additionally, this example adds the node types in the "myCustomNodeTypes.cnd" file as those
+ that will be made available when the repository is accessed. It also defines the "http://www.example.com/acme" namespace,
+ and finally sets the "JAAS_LOGIN_CONFIG_NAME" option to define the name of the JAAS login configuration that should be used by
+ the JBoss DNA repository.
+ </para>
+ <note>
+ <para>Each time <code>repository(String)</code> is called, it will either load the existing definition with the supplied
+ name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
+ on the result of <code>repository(String)</code>.
+ The set of existing definitions can be accessed with the <code>repositories()</code> method.
+ </para>
+ </note>
+ </sect3>
+ <sect3 id="programmatically_configuring_sequencers">
+ <title>Sequencers</title>
+ <para>Each defined sequencer must specify the name of the &StreamSequencer; implementation class as well as the path expressions
+ defining which nodes should be sequenced and the output paths defining where the sequencer output should be placed (often as a function
+ of the input path expression).</para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+config.sequencer("Image Sequencer")
+ .usingClass("org.jboss.dna.sequencer.image.ImageMetadataSequencer")
+ .loadedFromClasspath()
+ .setDescription("Sequences image files to extract the characteristics of the image")
+ .sequencingFrom("//(*.(jpg|jpeg|gif|bmp|pcx|png|iff|ras|pbm|pgm|ppm|psd)[*])/jcr:content[@jcr:data]")
+ .andOutputtingTo("/images/$1");
+ ]]></programlisting>
+ <para>
+ This shows an example of a sequencer definition named "Image Sequencer" that uses the &ImageMetadataSequencer; class
+ (loaded from the classpath), that is to sequence the "jcr:data" property on any new or changed nodes that are named
+ "jcr:content" below a parent node with a name ending in ".jpg", ".jpeg", ".gif", ".bmp", ".pcx", ".iff", ".ras",
+ ".pbm", ".pgm", ".ppm" or ".psd". The output of the sequencing operation should be placed at the "/images/$1" node,
+ where the "$1" value is captured as the name of the parent node. (The capture groups work the same was as regular expressions;
+ see the &ReferenceGuide; for more details.)
+ Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
+ the classpath or from a specific classpath).
+ </para>
+ <note>
+ <para>Each time <code>sequencer(String)</code> is called, it will either load the existing definition with the supplied
+ name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
+ on the result of <code>sequencer(String)</code>.
+ The set of existing definitions can be accessed with the <code>sequencers()</code> method.
+ </para>
+ </note>
+ </sect3>
+ <sect3 id="programmatically_configuring_mime_type_detectors">
+ <title>MIME type detectors</title>
+ <para>Each defined MIME type detector must specify the name of the &MimeTypeDetector; implementation class as well as any
+ other bean properties required by the implementation.</para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+config.mimeTypeDetector("Extension Detector")
+ .usingClass(org.jboss.dna.graph.mimetype.ExtensionBasedMimeTypeDetector.class);
+ ]]></programlisting>
+ <para>
+ Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
+ the classpath or from a specific classpath).
+ </para>
+ <note>
+ <para>Each time <code>mimeTypeDetector(String)</code> is called, it will either load the existing definition with the supplied
+ name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
+ on the result of <code>mimeTypeDetector(String)</code>.
+ The set of existing definitions can be accessed with the <code>mimeTypeDetectors()</code> method.
+ </para>
+ </note>
+ </sect3>
+ </sect2>
+ </sect1>
+ <sect1 id="using_dna_whats_next">
+ <title>What's next</title>
+ <para>
+ This chapter outline how you configure JBoss DNA, how you then access a <code>javax.jcr.Repository</code> instance,
+ and use the standard JCR API to interact with the repository. The
+ <link linkend="downloading_and_running">next chapter </link> walks you through downloading
+ and running the JBoss DNA examples.
+ </para>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/core/configuration.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Copied: trunk/docs/reference/src/main/docbook/en-US/content/core/environment.xml (from rev 994, trunk/docs/reference/src/main/docbook/en-US/content/environment.xml)
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/core/environment.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/core/environment.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -0,0 +1,310 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="environment">
+ <title>Environment</title>
+ <para>
+ The various components of JBoss DNA are designed as plain old Java objects, or POJOs. And rather than making assumptions
+ about their environment, each component instead requires that any external dependencies necessary for it to operate
+ must be supplied to it. This pattern is known as Dependency Injection, and it allows the components to be simpler
+ and allows for a great deal of flexibility and customization in how the components are configured.
+ And, JBoss DNA will soon provide a higher-level component that leverages the
+ <ulink url="http://www.jboss.org/jbossmc">JBoss Microcontainer</ulink> to automatically assemble and wire together
+ all the lower-level components.
+ </para>
+ <sect1 id="execution-context">
+ <title>Execution contexts</title>
+ <para>
+ One of the objects that must be supplied to many JBoss DNA components is an &ExecutionContext;. Some components
+ require this context to be passed into individual methods, allowing the context to vary with each method invocation.
+ Other components require the context to be provided before it's used, and will use that context for all its operations
+ (until it is given a different one).
+ </para>
+ <para>
+ What does an &ExecutionContext; represent? Quite simply, it's the set of objects that define the environment
+ or context in which the method or component is currently operating. It includes a way for recording and reporting
+ errors and problems. It includes the ability to <link linkend="classloaders">create class loaders</link>
+ given a classpath of class loader names. It also includes information about the current <link linkend="security">user</link>.
+ It includes access to factories that can be used to create and convert property values. And it includes factories
+ for working with namespaces and fully-qualified names. In fact, as JBoss DNA evolves, more things may need to be
+ added. Here is what the &ExecutionContext; interface looks like:
+ </para>
+ <programlisting>
+public class &ExecutionContext; implements &ClassLoaderFactory; {
+
+ /**
+ * Get the factories that should be used to create values for {@link Property properties}.
+ * @return the property value factory; never null
+ */
+ public &ValueFactories; getValueFactories() {...}
+
+ /**
+ * Get the namespace registry for this context.
+ * @return the namespace registry; never null
+ */
+ public &NamespaceRegistry; getNamespaceRegistry() {...}
+
+ /**
+ * Get the factory for creating {@link Property} objects.
+ * @return the property factory; never null
+ */
+ public &PropertyFactory; getPropertyFactory() {...}
+
+ /**
+ * Get the security context for this environment.
+ * @return the security context; never <code>null</code>
+ */
+ public &SecurityContext; getSecurityContext() {...}
+
+ /**
+ * Return a logger associated with this context. This logger records only those activities within the
+ * context and provide a way to capture the context-specific activities. All log messages are also
+ * sent to the system logger, so classes that log via this mechanism should <i>not</i> also
+ * {@link Logger#getLogger(Class) obtain a system logger}.
+ * @param clazz the class that is doing the logging
+ * @return the logger, named after <code>clazz</code>; never null
+ */
+ public &Logger; getLogger( Class<?> clazz ) {...}
+
+ /**
+ * Return a logger associated with this context. This logger records only those activities within the
+ * context and provide a way to capture the context-specific activities. All log messages are also
+ * sent to the system logger, so classes that log via this mechanism should <i>not</i> also
+ * {@link Logger#getLogger(Class) obtain a system logger}.
+ * @param name the name for the logger
+ * @return the logger, named after <code>clazz</code>; never null
+ */
+ public &Logger; getLogger( String name ) {...}
+
+ ...
+}
+</programlisting>
+ <para>
+ Notice that &ExecutionContext; implements the &ClassLoaderFactory; interface described in the
+ <link linkend="classloaders">previous chapter</link>, meaning it can be used to create other contexts. These other methods are not shown,
+ but can be used to create create subcontexts with different <link linkend="security">security contexts</link>,
+ with different namespace registry, or with different combinations of components.
+ </para>
+ <para>
+ The fact that so many of the JBoss DNA components take &ExecutionContext; instances gives us some interesting possibilities.
+ For example, one execution context instance can be used as the highest-level (or "application-level") context for all of the services
+ (e.g., &RepositoryService;, &SequencingService;, etc.).
+ Then, an execution context could be created for each user that will be performing operations, and that user's context can
+ be passed around to not only provide security information about the user but also to allow the activities being performed
+ to be recorded for user feedback, monitoring and/or auditing purposes.
+ </para>
+ <para>
+ The following code fragment shows how easy it is to create various execution contexts:
+ </para>
+ <programlisting>
+&ExecutionContext; context1 = new &ExecutionContext;();
+String jaasRealm = ...;
+
+// Create a context for a user, authenticating using a JAAS LoginContext...
+char[] password = "password".toCharArray();
+&SecurityContext; securityContext = new JaasSecurityContext(jaasRealm, "username", password);
+&ExecutionContext; context2 = context1.with(securityContext);
+
+// Create a context for the same user, authenticating using JAAS, and using a different callback handler ...
+&CallbackHandler; callbackHandler = ...
+&ExecutionContext; context3 = context1.with(new JaasSecurityContext(jaasRealm, callbackHandler);
+
+// Create a context that uses a provided &SecurityContext; (see the <link linkend="security">next section</link>)...
+&SecurityContext; mySecurityContext = ...
+&ExecutionContext; context4 = context1.with(mySecurityContext);
+</programlisting>
+ <para>
+ These contexts can then be passed to the various components as needed.
+ </para>
+ </sect1>
+ <sect1 id="security">
+ <title>Security</title>
+ <para>
+ JBoss DNA uses a simple abstraction layer to isolate it from the security infrastructure used within an application.
+ The &SecurityContext; interface is defined as follows:
+ </para>
+ <programlisting>
+public interface &SecurityContext; {
+
+ /**
+ * Get the name of the authenticated user.
+ * @return the authenticated user's name
+ */
+ &String; getUserName();
+
+ /**
+ * Determine whether the authenticated user has the given role.
+ * @param roleName the name of the role to check
+ * @return true if the user has the role and is logged in; false otherwise
+ */
+ boolean hasRole( String roleName );
+
+ /**
+ * Logs the user out of the authentication mechanism.
+ * For some authentication mechanisms, this will be implemented as a no-op.
+ */
+ void logout();
+}
+</programlisting>
+ <para>
+ As noted below, this security context is made available through the &ExecutionContext; described above.
+ </para>
+ <sect2 id="jaas_security">
+ <title>JAAS</title>
+ <para>
+ One such implementation is the &JaasSecurityContext;, which delegates any authentication or authorization requests to a
+ <ulink url="http://java.sun.com/javase/technologies/security/">Java Authentication and Authorization Service (JAAS)</ulink>
+ provider. This is the standard approach for authenticating and authorizing in Java, and is the default mechanism
+ used by the &JcrEngine;.
+ </para>
+ <para>
+ There are quite a few JAAS providers available, but one of the best and most powerful providers is
+ <ulink url="http://www.jboss.org/jbosssecurity/">JBoss Security</ulink>, the open source
+ security framework used by JBoss. JBoss Security offers a number of JAAS login modules, including:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis role="strong">User-Roles Login Module</emphasis>
+ is a simple
+ <code>javax.security.auth.login.LoginContext</code>
+ implementation that uses usernames and passwords stored in a properties file.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Client Login Module</emphasis>
+ prompts the user for their username and password.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Database Server Login Module</emphasis>
+ uses a JDBC database to authenticate principals and associate them with roles.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">LDAP Login Module</emphasis>
+ uses an LDAP directory to authenticate principals. Two implementations are available.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Certificate Login Module</emphasis>
+ authenticates using X509 certificates, obtaining roles from either property files or a JDBC database.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Operating System Login Module</emphasis>
+ authenticates using the operating system's mechanism.
+ </para>
+ </listitem>
+ </itemizedlist>
+ and many others. Plus, JBoss Security also provides other capabilities, such as using XACML policies or using federated single sign-on.
+ For more detail, see the <ulink url="http://www.jboss.org/jbosssecurity/">JBoss Security</ulink> project.
+ </para>
+ </sect2>
+ <sect2 id="web_security">
+ <title>Web application security</title>
+ <para>
+ If JBoss DNA is being used within a web application, then it is probably desirable to reuse the security infrastructure
+ of the application server. This can be accomplished by implementing the &SecurityContext; interface with an implementation
+ that delegates to the <interface>HttpServletRequest</interface>. Then, for each request, create a &SecurityContextCredentials;
+ instance around your &SecurityContext;, and use that credentials to obtain a JCR &Session;.
+ </para>
+ <para>
+ Here is an example of the &SecurityContext; implementation that uses the servlet request:
+ </para>
+ <programlisting>
+@Immutable
+public class ServletSecurityContext implements &SecurityContext; {
+
+ private final String userName;
+ private final HttpServletRequest request;
+
+ /**
+ * Create a {@link ServletSecurityContext} with the supplied
+ * {@link HttpServletRequest servlet information}.
+ *
+ * @param request the servlet request; may not be null
+ */
+ public ServletSecurityContext( HttpServletRequest request ) {
+ this.request = request;
+ this.userName = request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : null;
+ }
+
+ /**
+ * Get the name of the authenticated user.
+ * @return the authenticated user's name
+ */
+ public &String; getUserName() {
+ return userName;
+ }
+
+ /**
+ * Determine whether the authenticated user has the given role.
+ * @param roleName the name of the role to check
+ * @return true if the user has the role and is logged in; false otherwise
+ */
+ boolean hasRole( String roleName ) {
+ request.isUserInRole(roleName);
+ }
+
+ /**
+ * Logs the user out of the authentication mechanism.
+ * For some authentication mechanisms, this will be implemented as a no-op.
+ */
+ public void logout() {
+ }
+}</programlisting>
+ <para>
+ Then use this to create a &Session;:
+ </para>
+ <programlisting>
+HttpServletRequest request = ...
+&Repository; repository = engine.getRepository("my repository");
+&SecurityContext; securityContext = new ServletSecurityContext(httpServletRequest);
+SecurityContextCredentials credentials = new SecurityContextCredentials(securityContext);
+&Session; session = repository.login(credentials, workspaceName);
+</programlisting>
+ </sect2>
+ </sect1>
+ <sect1>
+ <title>Summary</title>
+ <para>
+ In this chapter, we covered security and environment topics as used throughout JBoss DNA.
+ The <link linkend="repositories">next chapter</link> will cover JBoss DNA repositories, including the connector framework,
+ how DNA's JCR implementation works with connectors, what connectors are available (and how to use them),
+ and how to write your own connector.
+ </para>
+ </sect1>
+</chapter>
+
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/core/environment.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Copied: trunk/docs/reference/src/main/docbook/en-US/content/core/mimetypes.xml (from rev 994, trunk/docs/reference/src/main/docbook/en-US/content/mimetypes.xml)
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/core/mimetypes.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/core/mimetypes.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="mimetypes">
+ <title>MIME types</title>
+ <para>
+ JBoss DNA often needs the ability to determine the MIME type for some binary content. When uploading content into
+ a repository, we may want to add the MIME type as metadata. Or, we may want to make some processing decisions
+ based upon the MIME type. So, JBoss DNA created a small pluggable framework for determining the MIME type by using
+ the name of the file (e.g., extensions) and/or by reading the actual content. Technically, the framework
+ delegates this to one or more extensions. And we've provided one extension that does a very good job at
+ determining the MIME type from a large variety of file types. But if that isn't sufficient, you can always
+ incorporate your own detector into JBoss DNA.
+ </para>
+ <para>
+ To use this system, you simply invoke a static method and supply the name of the content (e.g., the name of the file, with the extension)
+ and the &InputStream; to the actual binary content:
+ </para>
+ <programlisting>&MimeType;.of(name,content)</programlisting>
+ <para>
+ The result is a &String; containing the <ulink url="http://www.iana.org/assignments/media-types/">MIME type</ulink>
+ (e.g., "text/plain") or null if the MIME type cannot be determined. Note that the name or &InputStream; may be
+ null, making this a very versatile utility.
+ </para>
+ <sect1 id="detectors">
+ <title>JBoss DNA MIME type detectors</title>
+ <para>
+ The principle component in this framework is the concept of a <emphasis role="strong">detector</emphasis>.
+ A detector attempts to determine the MIME type using the name of the content (e.g., the file name)
+ and the actual content itself. If the detector is able to determine the MIME type, it simply returns
+ it as a string. If not, it merely returns null. Note, however, that a detector must be thread-safe.
+ </para>
+ <para>
+ Here is the interface:
+ </para>
+ <programlisting>
+package org.jboss.dna.graph.mimetype;
+@ThreadSafe
+public interface &MimeTypeDetector; {
+
+ /**
+ * Returns the MIME-type of a data source, using its supplied content and/or
+ * its supplied name, depending upon the implementation. If the MIME-type
+ * cannot be determined, either a "default" MIME-type or <code>null</code> may
+ * be returned, where the former will prevent earlier registered MIME-type
+ * detectors from being consulted.
+ *
+ * @param name The name of the data source; may be <code>null</code>.
+ * @param content The content of the data source; may be <code>null</code>.
+ * @return The MIME-type of the data source, or optionally <code>null</code>
+ * if the MIME-type could not be determined.
+ * @throws &IOException; If an error occurs reading the supplied content.
+ */
+ &String; mimeTypeOf( &String; name,
+ &InputStream; content ) throws &IOException;;
+}</programlisting>
+ <para>
+ Detectors can be added to the &MimeType; class using the <code>addDetector(&MimeTypeDetectorConfig; config)</code>
+ method, where the &MimeTypeDetectorConfig; defines the name of the detector class, the name of the
+ <link linkend="classloaders">class loader</link>, a name, and a description. It is also possible
+ to set the &ClassLoaderFactory; that the &MimeType; singleton will use.
+ </para>
+ <para>
+ We'll next look at the MIME type detectors that are provided out by JBoss DNA out of the box, and how to write your own.
+ </para>
+ <sect2 id="dna-mimetype-detector-aperture">
+ <title>Aperture MIME type detector</title>
+ <para>
+ The &ApertureMimeTypeDetector; class is an implementation of &MimeTypeDetector; that uses the
+ <ulink url="http://aperture.sourceforge.net/">Aperture</ulink> open-source library, which
+ is a very capable utility for determining the MIME type for a wide range of file types,
+ using both the file name and the actual content.
+ </para>
+ </sect2>
+ </sect1>
+ <sect1 id="custom-detectors">
+ <title>Writing custom detectors</title>
+ <para>
+ Creating a custom detector involves the following steps:
+ <itemizedlist>
+ <listitem>
+ <para>Create a Maven 2 project for your detector;</para>
+ </listitem>
+ <listitem>
+ <para>Implement the &MimeTypeDetector; interface with your own implementation, and create unit tests to verify
+ the functionality and expected behavior;</para>
+ </listitem>
+ <listitem>
+ <para>Add a &MimeTypeDetectorConfig; to the &MimeType; class in your application
+ as described <link linkend="detectors">earlier</link>; and</para>
+ </listitem>
+ <listitem>
+ <para>Deploy the JAR file with your implementation (as well as any dependencies), and make them available to JBoss DNA
+ in your application.</para>
+ </listitem>
+ </itemizedlist>
+ It's that simple.
+ </para>
+ <sect2 id="custom_detector_project">
+ <title>Creating the Maven 2 project</title>
+ <para>The first step is to create the Maven 2 project that you can use to compile your code and build the JARs.
+ Maven 2 automates a lot of the work, and since you're already <link linkend="maven">set up to use Maven</link>,
+ using Maven for your project will save you a lot of time and effort. Of course, you don't have to use Maven 2, but then you'll
+ have to get the required libraries and manage the compiling and building process yourself.</para>
+ <note>
+ <para>JBoss DNA may provide in the future a Maven archetype for creating detector projects. If you'd find this useful
+ and would like to help create it, please <link linkend="preface">join the community</link>.</para>
+ </note>
+ <note>
+ <para>
+ The <emphasis role="strong">dna-mimetype-detector-aperture</emphasis> project is a small, self-contained detector implementation that
+ that you can use to help you get going. Starting with this project's source and modifying it to suit your needs
+ may be the easiest way to get started.
+ See the subversion repository:
+ <ulink url="&Subversion;trunk/extensions/dna-mimetype-detector-aperture/">&Subversion;trunk/sequencers/dna-mimetype-detector-aperture/</ulink>
+ </para>
+ </note>
+ <para>You can create your Maven project any way you'd like. For examples, see the <ulink url="http://maven.apache.org/guides/getting-started/index.html#How_do_I_make_m...">Maven 2 documentation</ulink>.
+ Once you've done that, just add the dependencies in your project's <code>pom.xml</code> dependencies section:</para>
+ <programlisting role="XML"><![CDATA[<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>0.1</version>
+</dependency>
+<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ <version>0.1</version>
+</dependency>
+<dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+</dependency>
+]]></programlisting>
+ <para>These are minimum dependencies required for compiling a detector. Of course, you'll have to add
+ other dependencies that your sequencer needs.</para>
+ <para>As for testing, you probably will want to add more dependencies, such as those listed here:</para>
+ <programlisting role="XML"><![CDATA[<dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-library</artifactId>
+ <version>1.1</version>
+ <scope>test</scope>
+</dependency>
+<!-- Logging with Log4J -->
+<dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.4.3</version>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ <scope>test</scope>
+</dependency>
+]]></programlisting>
+ <para>
+ After you've created the project, simply implement the &MimeTypeDetector; interface. And testing should be
+ quite straightforward, MIME type detectors don't require any other components. In your tests,
+ simply instantiate your &MimeTypeDetector; implementation, supply various combinations of names and/or &InputStream;s,
+ and verify the output is what you expect.
+ </para>
+ <para>
+ To use in your application, create a &MimeTypeDetectorConfig; object with the name, description, and class information
+ for your detector, and add to the &MimeType; class using the <code>addDetector(&MimeTypeDetectorConfig; config)</code> method.
+ Then, just use the &MimeType; class.
+ </para>
+ </sect2>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/core/mimetypes.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Copied: trunk/docs/reference/src/main/docbook/en-US/content/core/repositories.xml (from rev 994, trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml)
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/core/repositories.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/core/repositories.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -0,0 +1,1468 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="repositories">
+ <title>Repositories</title>
+ <para></para>
+ <para>There is a lot of information stored in many of different places: databases, repositories, SCM systems,
+ registries, file systems, services, etc. The purpose of the federation engine is to allow applications to use the JCR API
+ to access that information as if it were all stored in a single JCR repository, but to really leave the information where
+ it is.</para>
+ <para>Why not just copy or move the information into a JCR repository? Moving it is probably pretty difficult, since most
+ likely there are existing applications that rely upon that information being where it is. All of those applications
+ would break or have to change. And copying the information means that we'd have to continually synchronize the changes.
+ This not only is a lot of work, but it often makes it difficult to know whether information is accurate and "the master" data.
+ </para>
+ <para>JBoss DNA lets us leave information where it, yet access it through the JCR API as if it were in one big repository.
+ One major benefit is that existing applications that use the information in the original locations don't break, since they
+ can keep using the information. But now our JCR clients can also access all the information, too. And if our federating JBoss DNA repository is
+ configured to allow updates, JCR client applications can change the information in the repository and JBoss DNA will propagate
+ those changes down to the original source, making those changes visible to all the other applications.
+ </para>
+ <para>
+ In short, all clients see the correct information, even when it changes in the underlying systems. But the JCR clients can get to all of the information
+ in one spot, using one powerful standard API.
+ </para>
+ <sect1 id="connectors">
+ <title>Repository connectors</title>
+ <para>
+ With JBoss DNA, your applications use the <ulink url="&JSR170;">JCR API</ulink> to work with the repository,
+ but the DNA repository transparently fetches the information from different kinds of repositories and storage systems,
+ not just a single purpose-built store. This is fundamentally what makes JBoss DNA different.
+ </para>
+ <para>How does JBoss DNA do this? At the heart of JBoss DNA and it's JCR implementation is a simple graph-based
+ <emphasis>repository connector</emphasis> system. Essentially, JBoss DNA's JCR implementation uses a single
+ repository connector to access all content:
+ <figure id="dnajcr-and-connector">
+ <title>JBoss DNA's JCR implementation delegates to a repository connector</title>
+ <graphic align="center" scale="100" fileref="dnajcr-and-connector.png"/>
+ </figure>
+ That single repository connector could use an in-memory repository, a JBoss Cache instance (including those that are clustered and replicated),
+ or a federated repository where content from multiple sources is unified.
+ <figure id="dna-connectors-0.2">
+ <title>JBoss DNA can put JCR on top of multiple kinds of systems</title>
+ <graphic align="center" scale="100" fileref="dna-connectors-0.2.png"/>
+ </figure>
+ Really, the federated connector gives us all kinds of possibilities, since we can use that connector on top of lots of connectors
+ to other individual sources. This simple connector architecture is fundamentally what makes JBoss DNA so powerful and flexible.
+ Along with a good library of connectors, which is what we're planning to create.
+ </para>
+ <para>
+ For instance, we want to build a connector to <ulink url="&JIRA-39;">other JCR repositories</ulink>, and another that accesses
+ the <ulink url="&JIRA-34;">local file system</ulink>. We've already started on a <ulink url="&JIRA-36;">Subversion connector</ulink>,
+ which will allow JCR to access the files in a SVN repository (and perhaps push changes into SVN through a commit).
+ And of course we want to create a connector that accesses <ulink url="&JIRA-199;">data</ulink>
+ and <ulink url="&JIRA-37;">metadata</ulink> from relational databases. For more information, check out our
+ <ulink url="&JIRA;?report=com.atlassian.jira.plugin.system.project:roadmap-panel">roadmap</ulink>.
+ Of course, if we don't have a connector to suit your needs, you can <link linkend="custom-connectors">write your own</link>.
+ <figure id="dna-connectors-future">
+ <title>Future JBoss DNA connectors</title>
+ <graphic align="center" scale="100" fileref="dna-connectors-future.png"/>
+ </figure>
+ </para>
+ <para>
+ </para>
+ <para>
+ It's even possible to put a different API layer on top of the connectors. For example, the new <ulink url="&JSR203;">New I/O (JSR-203)</ulink>
+ API offers the opportunity to build new file system providers. This would be very straightforward to put on top of a JCR implementation,
+ but it could be made even simpler by putting it on top of a DNA connector. In both cases, it'd be a trivial mapping from nodes that represent
+ files and folders into JSR-203 files and directories, and events on those nodes could easily be translated into JSR-203 watch events.
+ Then, simply choose a DNA connector and configure it to use the source you want to use.
+ <figure id="dna-connectors-vfs">
+ <title>Virtual File System with JBoss DNA</title>
+ <graphic align="center" scale="100" fileref="vfs-and-connector.png"/>
+ </figure>
+ </para>
+ <para>Before we go further, let's define some terminology regarding connectors.</para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ A <emphasis role="strong">connector</emphasis> is the runnable code packaged in one or more JAR files that
+ contains implementations of several interfaces (described below). A Java developer <emphasis>writes</emphasis>
+ a connector to a type of source, such as a particular database management system, LDAP directory, source code
+ management system, etc. It is then packaged into one or more JAR files (including dependent JARs) and deployed
+ for use in applications that use JBoss DNA repositories.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The description of a particular source system (e.g., the "Customer" database, or the company LDAP system)
+ is called a <emphasis role="strong">repository source</emphasis>. JBoss DNA defines a &RepositorySource; interface
+ that defines methods describing the behavior and supported features and a method for establishing connections.
+ A connector will have a class that implements this interface and that has JavaBean properties for
+ all of the connector-specific properties required to fully describe an instance of the system. Use of JavaBean
+ properties is not required, but it is highly recommended, as it enables reflective configuration and administration.
+ Applications that use JBoss DNA create an instance of the connector's &RepositorySource; implementation and set
+ the properties for the external source that the application wants to access with that connector.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A repository source instance is then used to establish <emphasis role="strong">connections</emphasis> to
+ that source. A connector provides an implementation of the &RepositoryConnection; interface, which
+ defines methods for interacting with the external system. In particular, the <code>execute(...)</code> method
+ takes an &ExecutionContext; instance and a &Request; object. The &ExectuionContext; object defines the
+ environment in which the processing is occurring, including information about the JAAS &Subject; and &LoginContext;.
+ The &Request; object describes the requested operations on the content, with different concrete subclasses
+ representing each type of activity. Examples of commands include (but not limited to) getting a node, moving a node, creating a node,
+ changing a node, and deleting a node. And, if the repository source is able to participate in JTA/JTS distributed transactions, then the
+ &RepositoryConnection; must implement the <code>getXaResource()</code> method by returning
+ a valid <code>javax.transaction.xa.XAResource</code> object that can be used by the transaction monitor.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>As an example, consider that we want JBoss DNA to give us access through JCR to the schema information contained in a
+ relational databases. We first have to develop a connector that allows us to interact with relational databases using JDBC.
+ That connector would contain a <code>JdbcRepositorySource</code> Java class that implements &RepositorySource;,
+ and that has all of the various JavaBean properties for setting the name of the driver class, URL, username, password,
+ and other properties. (Or we might have a JavaBean property that defines the JNDI name where we can find a JDBC
+ <code>DataSource</code> instance pointing to our JDBC database.)
+ </para>
+ <para>
+ Our new connector would also have a <code>JdbcRepositoryConnection</code> Java class that implements the
+ &RepositoryConnection; interface. This class would probably wrap a JDBC database connection,
+ and would implement the <code>execute(...)</code> method such that the nodes exposed by the connector
+ describe the database schema of the database. For example, the connector might represent each database table
+ as a node with the table's name, with properties that describe the table (e.g., the description, whether it's a
+ temporary table), and with child nodes that represent each of the columns, keys and constraints.
+ </para>
+ <para>
+ To use our connector in an application that uses JBoss DNA, we need to create an instance of the
+ <classname>JdbcRepositorySource</classname> for each database instance that we want to access. If we have 3 MySQL databases,
+ 9 Oracle databases, and 4 PostgreSQL databases, then we'd need to create a total of 16 <classname>JdbcRepositorySource</classname>
+ instances, each with the properties describing a single database instance. Those sources are then available for use by
+ JBoss DNA components, including the <link linkend="jcr">JCR</link> implementation.
+ </para>
+ <para>
+ So, we've so far learned what a repository connector is and how they're used to establish connections to the underlying sources
+ and access the content in those sources. In the <link linkend="repository-service">next section</link>, we'll show how these
+ source instances can be configured, managed, and their connections pooled. After that, we'll look review JBoss DNA's
+ <link linkend="connector-library">existing connectors</link> and show how to <link linkend="custom-connectors">create your own connectors</link>.
+ </para>
+ </sect1>
+ <sect1 id="repository-workspaces">
+ <title>Workspaces</title>
+ <para>The previous section talked about how connector expose their information through the graph language of JBoss DNA.
+ This is true, except that we didn't dive into too much of the detail. JBoss DNA graphs have the notion of <emphasis>workspaces</emphasis>
+ in which the content appears, and its very easy for clients using the graph to switch between workspaces. In fact,
+ workspaces differ from each other in that they provide different views of the same information.
+ </para>
+ <para>Consider a source control system, like SVN or CVS. These systems provide different views of the source code:
+ a mainline development branch as well as other branches (or tags) commonly used for releases. So, just like one source
+ file might appear in the mainline branch as well as the previous two release branches, a node in a repository source
+ might appear in multiple workspaces.
+ </para>
+ <para>
+ However, each connector can kind of decide how (or whether) it uses workspaces. For example, there may be no overlap
+ in the content between workspaces. Or a connector might only expose a single workspace (in other words, there's only one
+ "default" workspace).
+ </para>
+ </sect1>
+ <sect1 id="repository-service">
+ <title>Repository Service</title>
+ <para>The JBoss DNA &RepositoryService; is the component that manages the <emphasis>repository sources</emphasis>
+ and the connections to them. &RepositorySource; instances can be programmatically added to the service, but
+ the service can actually read its configuration from a configuration repository (which, by the way, is represented by a
+ just another &RepositorySource; instance that's usually added programmatically to the service). The service connects to
+ the configuration repository, reads the content in a particular area, and automatically sets up the &RepositorySource; instances
+ per the information found in the configuration repository.
+ </para>
+ <para>
+ The &RepositoryService; also transparently maintains for each source a pool of reusable connections. The pooling properties
+ can be controlled via the configuration repository, or adjusted programmatically.
+ </para>
+ <para>
+ Using a repository, then, involves simply asking the &RepositoryService; for a &RepositoryConnection;
+ to the repository given the repository's name. If a source exists with that name, the service checks out a connection from
+ the source's pool. The resulting connection is actually a wrapper around the underlying pooled connection, so the
+ component that requested the connection can simply close it, and under the covers the actual connection is simply returned
+ to the pool.
+ </para>
+ <para>To instantiate the &RepositoryService;, we need to first have a few other objects:
+ <itemizedlist>
+ <listitem>
+ <para>
+ A &ExecutionContext; instance, as discussed <link linkend="execution-context">earlier</link>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A &RepositoryLibrary; instance that manages the list of &RepositorySource; instances,
+ properly injects the execution contexts into each repository source, and provides a configurable pool of connections
+ for each source.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A <emphasis>configuration repository</emphasis> that contains descriptions of all of the repository sources
+ as well as any information those sources need. Because this is a regular repository, this could be a simple
+ repository with content loaded from an XML file, or it could be a shared
+ central repository with information about all of the JBoss DNA repositories used across your organization.
+ </para>
+ </listitem>
+ </itemizedlist>
+ With these components in place, we can then instantiate the &RepositoryService; and start it (using its
+ &ServiceAdministrator;). During startup, the service reads the configuration repository and loads any
+ defined &RepositorySource; instances into the repository library, using the class loader factory
+ (available in the &ExecutionContext;) to obtain.
+ </para>
+ <para>
+ Here's sample code that shows how to set up and start the repository service. You can see something similar
+ in the example application in the <code>startRepositories()</code> method of the
+ <code>org.jboss.example.dna.repository.RepositoryClient</code> class.
+ </para>
+ <programlisting>
+ // Create the top-level execution context with all standard components ...
+ &ExecutionContext; context = new ExecutionContext();
+
+ // Create the library for the RepositorySource instances ...
+ &RepositoryLibrary; sources = new &RepositoryLibrary;(context);
+
+ // Load into the source manager the repository source for the configuration repository ...
+ &InMemoryRepositorySource; configSource = new &InMemoryRepositorySource;();
+ configSource.setName("Configuration");
+ sources.addSource(configSource);
+
+ // Now instantiate the Repository Service ...
+ &RepositoryService; service = new &RepositoryService;(sources, configSource.getName(), context);
+ service.getAdministrator().start();
+ </programlisting>
+
+ <para>After startup completes, the repositories are ready to be used. The client application obtains the list of repositories
+ and presents them to the user. When the user selects one, the client application starts navigating that repository
+ starting at its root node (e.g., the "/" path). As you type a command to list the contents of the current node or to
+ "change directories" to a different node, the client application obtains the information for the node using a simple
+ procedure:
+ <orderedlist>
+ <listitem>
+ <para>Get a connection to the repository.</para>
+ </listitem>
+ <listitem>
+ <para>Using the connection, find the current node and read its properties and children, putting the information
+ into a simple Java plain old Java object (POJO).</para>
+ </listitem>
+ <listitem>
+ <para>Close the connection to the repository (in a finally block to ensure it always happens).</para>
+ </listitem>
+ </orderedlist>
+ </para>
+ </sect1>
+ <sect1 id="connector-library">
+ <title>Out-of-the-box repository connectors</title>
+ <para>
+ A number of repository connectors are already available in JBoss DNA, and are outlined in the following sections.
+ Note that we do want to build <ulink url="https://jira.jboss.org/jira/secure/IssueNavigator.jspa?reset=true&mod...">more connectors</ulink>
+ in the upcoming releases.
+ </para>
+ <sect2 id="dna-connector-inmemory">
+ <title>In-memory connector</title>
+ <para>
+ The in-memory repository connector is a simple connector that creates a transient, in-memory repository.
+ This repository is used as a very simple in-memory cache or as a standalone transient repository.
+ </para>
+ <para>
+ The &InMemoryRepositorySource; class provides a number of JavaBean properties that control its behavior:
+ </para>
+ <table frame='all'>
+ <title>&InMemoryRepositorySource; properties</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Property</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>name</entry>
+ <entry>The name of the repository source, which is used by the &RepositoryService; when obtaining a &RepositoryConnection; by name.</entry>
+ </row>
+ <row>
+ <entry>jndiName</entry>
+ <entry>Optional property that, if used, specifies the name in JNDI where an &InMemoryRepository; instance can be found.
+ This is an advanced property that is infrequently used.</entry>
+ </row>
+ <row>
+ <entry>rootNodeUuid</entry>
+ <entry>Optional property that, if used, defines the UUID of the root node in the in-memory repository. If not used,
+ then a new UUID is generated.</entry>
+ </row>
+ <row>
+ <entry>retryLimit</entry>
+ <entry>Optional property that, if used, defines the number of times that any single operation on a &RepositoryConnection; to this source should be retried
+ following a communication failure. The default value is '0'.</entry>
+ </row>
+ <row>
+ <entry>defaultCachePolicy</entry>
+ <entry>Optional property that, if used, defines the default for how long this information provided by this source may to be
+ cached by other, higher-level components. The default value of null implies that this source does not define a specific
+ duration for caching information provided by this repository source.</entry>
+ </row>
+ <row>
+ <entry>defaultWorkspaceName</entry>
+ <entry>Optional property that is initialized to an empty string and which defines the name for the workspace that will be used by default
+ if none is specified.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect2>
+ <sect2 id="dna-connector-jbosscache">
+ <title>JBoss Cache connector</title>
+ <para>
+ The JBoss Cache repository connector allows a <ulink url="http://www.jboss.org/jbosscache/">JBoss Cache</ulink> instance to be
+ used as a JBoss DNA (and thus JCR) repository. This provides a repository that is an effective, scalable, and distributed cache,
+ and is often paired with other repository sources to provide a local or <link linkend="dna-connector-federation">federated</link>
+ repository.
+ </para>
+ <para>
+ The &JBossCacheSource; class provides a number of JavaBean properties that control its behavior:
+ </para>
+ <table frame='all'>
+ <title>&JBossCacheSource; properties</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Property</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>name</entry>
+ <entry>The name of the repository source, which is used by the &RepositoryService; when obtaining a &RepositoryConnection; by name.</entry>
+ </row>
+ <row>
+ <entry>cacheFactoryJndiName</entry>
+ <entry>Optional property that, if used, specifies the name in JNDI where an existing JBoss Cache Factory instance can be found.
+ That factory would then be used if needed to create a JBoss Cache instance. If no value is provided, then the
+ JBoss Cache <code>DefaultCacheFactory</code> class is used.</entry>
+ </row>
+ <row>
+ <entry>cacheConfigurationName</entry>
+ <entry>Optional property that, if used, specifies the name of the configuration that is supplied to the cache factory
+ when creating a new JBoss Cache instance.</entry>
+ </row>
+ <row>
+ <entry>cacheJndiName</entry>
+ <entry>Optional property that, if used, specifies the name in JNDI where an existing JBoss Cache instance can be found.
+ This should be used if your application already has a cache that is used, or if you need to configure the cache in
+ a special way.</entry>
+ </row>
+ <row>
+ <entry>uuidPropertyName</entry>
+ <entry>Optional property that, if used, defines the property that should be used to find the UUID value for each node
+ in the cache. "<code>dna:uuid</code>" is the default.</entry>
+ </row>
+ <row>
+ <entry>retryLimit</entry>
+ <entry>Optional property that, if used, defines the number of times that any single operation on a &RepositoryConnection; to this source should be retried
+ following a communication failure. The default value is '0'.</entry>
+ </row>
+ <row>
+ <entry>defaultCachePolicy</entry>
+ <entry>Optional property that, if used, defines the default for how long this information provided by this source may to be
+ cached by other, higher-level components. The default value of null implies that this source does not define a specific
+ duration for caching information provided by this repository source.</entry>
+ </row>
+ <row>
+ <entry>nameOfDefaultWorkspace</entry>
+ <entry>Optional property that is initialized to an empty string and which defines the name for the workspace that will be used by default
+ if none is specified.</entry>
+ </row>
+ <row>
+ <entry>predefinedWorkspaceNames</entry>
+ <entry>Optional property that defines the names of the workspaces that exist and that are available for use without having to create them.</entry>
+ </row>
+ <row>
+ <entry>creatingWorkspacesAllowed</entry>
+ <entry>Optional property that is by default 'true' that defines whether clients can create new workspaces.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect2>
+ <sect2 id="dna-connector-federation">
+ <title>Federating connector</title>
+ <para>
+ The federated repository source provides a unified repository consisting of information that is dynamically federated from multiple other
+ &RepositorySource; instances. This is a very powerful repository source that appears to be a single repository, when in
+ fact the content is stored and managed in multiple other systems. Each &FederatedRepositorySource; is typically configured
+ with the name of another &RepositorySource; that should be used as the local, unified cache of the federated content.
+ The configuration also contains the names of the other &RepositorySource; instances that are to be federated along with
+ the &Projection; definition describing where in the unified repository the content is to appear.
+ </para>
+ <figure id="dna-connector-federation-image">
+ <title>Federating multiple sources using the Federated Repository Connector</title>
+ <graphic align="center" scale="100" fileref="dna-connector-federation.png"/>
+ </figure>
+ <para> The federation connector works by effectively building up a single graph by querying each source and merging or
+ unifying the responses. This information is cached, which improves performance, reduces the number of (potentially
+ expensive) remote calls, reduces the load on the sources, and helps mitigate problems with source availability. As
+ clients interact with the repository, this cache is consulted first. When the requested portion of the graph (or
+ "subgraph") is contained completely in the cache, it is retuned immediately. However, if any part of the requested
+ subgraph is not in the cache, each source is consulted for their contributions to that subgraph, and any results are
+ cached.</para>
+ <para> This basic flow makes it possible for the federated repository to build up a local cache of the integrated graph
+ (or at least the portions that are used by clients). In fact, the federated repository caches information in a manner
+ that is similar to that of the Domain Name System (DNS). As sources are consulted for their contributions, the source
+ also specifies whether it is the authoritative source for this information (some sources that are themselves federated
+ may not be the information's authority), whether the information may be modified, the time-to-live (TTL) value (the time
+ after which the cached information should be refreshed), and the expiration time (the time after which the cached
+ information is no longer valid). In effect, the source has complete control over how the information it contributes is
+ cached and used.</para>
+ <para>
+ The federated repository also needs to incorporate <emphasis>negative caching</emphasis>, which is storage of the knowledge
+ that something does <emphasis>not</emphasis> exist. Sources can be configured to contribute information
+ only below certain paths (e.g., <code>/A/B/C</code>), and the federation engine can take advantage of this by never
+ consulting that source for contributions to information on other paths. However, below that path, any negative responses
+ must also be cached (with appropriate TTL and expiry parameters) to prevent the exclusion of that source (in case the source
+ has information to contribute at a later time) or the frequent checking with the source.
+ </para>
+ <para>
+ The federated repository uses other &RepositorySource;s that are to be federated and a &RepositorySource; that is to be used as the
+ cache of the unified contents. These are configured in another &RepositorySource; that is treated as a configuration repository.
+ The &FederatedRepositorySource; class uses JavaBean properties to define the name of the configuration repository and
+ the path to the "<code>dna:federation</code>" node in that configuration repository containing the information about the
+ cache and federated sources. This graph structure that is expected at this location is as follows:
+ </para>
+ <programlisting><![CDATA[<!-- Define the federation configuration. -->
+<dna:federatedRepository xmlns:dna="http://www.jboss.org/dna"
+ xmlns:jcr="http://www.jcp.org/jcr/1.0"
+ dna:timeToCache="100000" >
+ <dna:workspaces>
+ <dna:workspace jcr:name="default">
+ <!-- Define how the content in the 'Cache' source is to map to the federated cache -->
+ <dna:cache dna:sourceName="Cache" dna:workspaceName="default" dna:projectionRules="/a => /" />
+
+ <!-- Define how the content in the two sources maps to the federated/unified repository.
+ This example puts the 'Cars' and 'Aircraft' content underneath '/vehicles', but the
+ 'Configuration' content (which is defined by this file) will appear under '/'. -->
+ <dna:projections>
+ <dna:projection jcr:name="Cars" dna:projectionRules="/Vehicles => /" />
+ <dna:projection jcr:name="Aircraft" dna:projectionRules="/Vehicles => /" />
+ <dna:projection jcr:name="Configuration" dna:projectionRules="/ => /" />
+ </dna:projections>
+ </dna:workspace>
+ </dna:workspaces>
+</dna:federatedRepository>
+]]></programlisting>
+ <note>
+ <para>
+ We're using XML to represent a graph structure, since the two map pretty well. Each XML element represents
+ a node and XML attributes represent properties on a node. The name of the node is defined by either the
+ <code>jcr:name</code> attribute (if it exists) or the name of the XML element. And we use XML namespaces
+ to define the namespaces used in the node and property names. BTW, this is exactly how the XML graph importer
+ works.
+ </para>
+ </note>
+ <para>
+ Notice that there is a cache projection and three source projections, and each projection defines
+ one or more <emphasis>projection rules</emphasis> that are of the form:
+ </para>
+ <programlisting>pathInFederatedRepository => pathInSourceRepository</programlisting>
+ <para>
+ So, a projection rule <code>/Vehicles => /</code> projects the entire contents of the source so that
+ it appears in the federated repository under the "<code>/Vehicles</code>" node.
+ </para>
+ <para>
+ The &FederatedRepositorySource; class provides a number of JavaBean properties that control its behavior:
+ </para>
+ <table frame='all'>
+ <title>&FederatedRepositorySource; properties</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Property</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>name</entry>
+ <entry>The name of the repository source, which is used by the &RepositoryService; when obtaining a &RepositoryConnection; by name.</entry>
+ </row>
+ <row>
+ <entry>repositoryName</entry>
+ <entry>The name for the federated repository.</entry>
+ </row>
+ <row>
+ <entry>configurationSourceName</entry>
+ <entry>The name of the &RepositorySource; that should be used as the configuration repository, and in which is defined
+ how this federated repository is to be set up and configured.
+ This name is supplied to the &RepositoryConnectionFactory; that is provided to this instance when added to the
+ &RepositoryLibrary;.</entry>
+ </row>
+ <row>
+ <entry>configurationWorkspaceName</entry>
+ <entry>The name of the workspace in the configuration &RepositorySource; with the content defining
+ how this federated repository is to be set up and configured.</entry>
+ </row>
+ <row>
+ <entry>configurationSourcePath</entry>
+ <entry>The path to the node in the configuration repository below which a "dna:federation" node exists with the
+ graph structure describing how this federated repository is to be configured.</entry>
+ </row>
+ <row>
+ <entry>securityDomain</entry>
+ <entry>Optional property that, if used, specifies the name of the JAAS application context that should be used
+ to establish the <link linkend="execution-contenxt">execution context</link> for this repository.
+ This should correspond to the JAAS login configuration located within the JAAS login configuration file,
+ and should be used only if a "<code>username</code>" property is defined.</entry>
+ </row>
+ <row>
+ <entry>username</entry>
+ <entry>Optional property that, if used, defines the name of the JAAS subject that should be used
+ to establish the <link linkend="execution-contenxt">execution context</link> for this repository.
+ This should be used if a "<code>securityDomain</code>" property is defined.</entry>
+ </row>
+ <row>
+ <entry>password</entry>
+ <entry>Optional property that, if used, defines the password of the JAAS subject that should be used
+ to establish the <link linkend="execution-contenxt">execution context</link> for this repository.
+ If the password is not provided but values for the "<code>securityDomain</code>" and "<code>username</code>" properties are,
+ then authentication will use the default JAAS callback handlers.</entry>
+ </row>
+ <row>
+ <entry>retryLimit</entry>
+ <entry>Optional property that, if used, defines the number of times that any single operation on a &RepositoryConnection; to this source should be retried
+ following a communication failure. The default value is '0'.</entry>
+ </row>
+ <row>
+ <entry>defaultCachePolicy</entry>
+ <entry>Optional property that, if used, defines the default for how long this information provided by this source may to be
+ cached by other, higher-level components. The default value of null implies that this source does not define a specific
+ duration for caching information provided by this repository source.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect2>
+ </sect1>
+ <sect1 id="custom-connectors">
+ <title>Writing custom connectors</title>
+ <para>
+ There may come a time when you want to tackle creating your own repository connector. Maybe the connectors we provide out-of-the-box
+ don't work with your source. Maybe you want to use a different cache system.
+ Maybe you have a system that you want to make available through a JBoss DNA repository. Or, maybe you're
+ a contributor and want to help us round out our library with a new connector. No matter what the reason, creating a new connector
+ is pretty straightforward, as we'll see in this section.
+ </para>
+ <para>
+ Creating a custom connector involves the following steps:
+ <orderedlist>
+ <listitem>
+ <para>Create a Maven 2 project for your connector;</para>
+ </listitem>
+ <listitem>
+ <para>
+ Implement the &RepositorySource; interface, using JavaBean properties for each bit of information the implementation will
+ need to establish a connection to the source system.
+ </para>
+ <para>
+ Then, implement the &RepositoryConnection; interface with a class that represents a connection to the source. The
+ <code>execute(&ExecutionContext;, &Request;)</code> method should process any and all requests that may come down the pike,
+ and the results of each request can be put directly on that request.
+ </para>
+ <para>
+ Don't forget unit tests that verify that the connector is doing what it's expected to do. (If you'll be committing the connector
+ code to the JBoss DNA project, please ensure that the unit tests can be run by others that may not have access to the
+ source system. In this case, consider writing integration tests that can be easily configured to use different sources
+ in different environments, and try to make the failure messages clear when the tests can't connect to the underlying source.)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Configure JBoss DNA to use your connector. This may involve just registering the source with the &RepositoryService;,
+ or it may involve adding a source to a configuration repository used by the <link linkend="dna-connector-federation">federated repository</link>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Deploy the JAR file with your connector (as well as any dependencies), and make them available to JBoss DNA
+ in your application.
+ </para>
+ </listitem>
+ </orderedlist>
+ Let's go through each one of these steps in more detail.
+ </para>
+ <sect2 id="custom_connector_project">
+ <title>Creating the Maven 2 project</title>
+ <para>
+ The first step is to create the Maven 2 project that you can use to compile your code and build the JARs.
+ Maven 2 automates a lot of the work, and since you're already <link linkend="maven">set up to use Maven</link>,
+ using Maven for your project will save you a lot of time and effort. Of course, you don't have to use Maven 2, but then you'll
+ have to get the required libraries and manage the compiling and building process yourself.</para>
+ <note>
+ <para>JBoss DNA may provide in the future a Maven archetype for creating connector projects. If you'd find this useful
+ and would like to help create it, please <link linkend="preface">join the community</link>.
+ </para>
+ <para>In lieu of a Maven archetype, you may find it easier to start with a small existing connector project.
+ The <emphasis role="strong">dna-connector-filesystem</emphasis> project is small, but it may be tough to separate
+ the stuff that every connector needs from the extra code and data structures that manage the content.
+ See the subversion repository: <ulink url="&Subversion;trunk/extensions/dna-connector-filesystem/">&Subversion;trunk/extensions/dna-connector-filesystem/</ulink>
+ </para>
+ </note>
+ <para>
+ You can create your Maven project any way you'd like. For examples, see the
+ <ulink url="http://maven.apache.org/guides/getting-started/index.html#How_do_I_make_m...">Maven 2 documentation</ulink>.
+ Once you've done that, just add the dependencies in your project's <code>pom.xml</code> dependencies section:
+ </para>
+ <programlisting role="XML"><![CDATA[
+<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ <version>0.4</version>
+</dependency>
+ ]]></programlisting>
+ <para>
+ This is the only dependency required for compiling a connector - Maven pulls in all of the dependencies needed by
+ the 'dna-graph' artifact. Of course, you'll still have to add dependencies for any library your connector needs
+ to talk to its underlying system.
+ </para>
+ <para>
+ As for testing, you probably will want to add more dependencies, such as those listed here:
+ </para>
+ <programlisting role="XML"><![CDATA[
+<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ <version>0.4</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>0.4</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-library</artifactId>
+ <version>1.1</version>
+ <scope>test</scope>
+</dependency>
+<!-- Logging with Log4J -->
+<dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.4.3</version>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ <scope>test</scope>
+</dependency>
+ ]]></programlisting>
+ <para>
+ Testing JBoss DNA connectors does not require a JCR repository or the JBoss DNA services. (For more detail,
+ see the <link linkend="testing_custom_connectors">testing section</link>.) However, if you want to do
+ integration testing with a JCR repository and the JBoss DNA services, you'll need additional dependencies
+ (e.g., <code>dna-repository</code> and any other extensions).
+ </para>
+ <para>
+ At this point, your project should be set up correctly, and you're ready to move on to
+ <link linkend="implementing_repository_source">writing the Java implementation</link> for your connector.
+ </para>
+ </sect2>
+ <sect2 id="implementing_repository_source">
+ <title>Implementing a <code>RepositorySource</code></title>
+ <para>
+ As mentioned earlier, a <emphasis>connector</emphasis> consists of the Java code that is used to access content
+ from a system. Perhaps the most important class that makes up a connector is the implementation of the
+ &RepositorySource;. This class is analogous to JDBC's DataSource in that it is instantiated to represent
+ a single instance of a system that will be accessed, and it contains enough information (in the form of JavaBean properties)
+ so that it can create connections to the source.
+ </para>
+ <para>
+ Why is the &RepositorySource; implementation a JavaBean? Well, this is the class that is instantiated, usually
+ reflectively, and so a no-arg constructor is required. Using JavaBean properties makes it possible
+ to reflect upon the object's class to determine the properties that can be set (using setters) and read
+ (using getters). This means that an administrative application can instantiate, configure, and manage
+ the objects that represent the actual sources, without having to know anything about the actual implementation.
+ </para>
+ <para>
+ So, your connector will need a public class that implements &RepositorySource; and provides JavaBean properties
+ for any kind of inputs or options required to establish a connection to and interact with the underlying source.
+ Most of the semantics of the class are defined by the &RepositorySource; and inherited interface.
+ However, there are a few characteristics that are worth mentioning here.
+ </para>
+ <sect3 id="connector_cache_policy">
+ <title>Cache policy</title>
+ <para>
+ Each connector is responsible for determining whether and how long DNA is to cache the
+ content made available by the connector. This is referred to as the <emphasis>caching policy</emphasis>,
+ and consists of a <emphasis>time to live</emphasis> value representing the number of milliseconds that
+ a piece of data may be cached. After the TTL has passed, the information is no longer used.
+ </para>
+ <para>
+ DNA allows a connector to use a flexible and powerful caching policy. First, each connection returns the
+ <emphasis>default</emphasis> caching policy for all information returned by that connection.
+ Often this policy can be configured via properties on the &RepositorySource; implementation.
+ This is optional, meaning the connector can return <code>null</code> if it does not wish to
+ have a default caching policy.
+ </para>
+ <para>
+ Second, the connector is able to override its default caching policy on individual requests
+ (which we'll cover in the <link linkend="implementing_repository_connection">next section</link>).
+ Again, this is optional, meaning that a null caching policy on a request implies that the
+ request has no overridden caching policy.
+ </para>
+ <para>
+ Third, if the connector has no default caching policy and none is set on the individual requests,
+ DNA uses whatever caching policy is set up for that component using the connector. For example, the federating
+ connector allows a default caching policy to be specified, and this policy is used should the sources
+ being federated not define their own caching policy.
+ </para>
+ <para>
+ In summary, a connector has total control over whether and for how long the information it provides
+ is cached.
+ </para>
+ </sect3>
+ <sect3 id="repository_source_jndi">
+ <title>Leveraging JNDI</title>
+ <para>
+ Sometimes it is necessary (or easier) for a &RepositorySource; implementation to look up an object in JNDI.
+ One example of this is the JBoss Cache connector: while the connector can
+ instantiate a new JBoss Cache instance, more interesting use cases involve JBoss Cache instances that are
+ set up for clustering and replication, something that is generally difficult to configure in a single JavaBean.
+ Therefore the &JBossCacheSource; has optional JavaBean properties that define how it is to look up a
+ JBoss Cache instance in JNDI.
+ </para>
+ <para>
+ This is a simple pattern that you may find useful in your connector. Basically, if your source implementation
+ can look up an object in JNDI, simply use a single JavaBean String property that defines the
+ full name that should be used to locate that object in JNDI. Usually it's best to include "Jndi" in the
+ JavaBean property name so that administrative users understand the purpose of the property.
+ (And some may suggest that any optional property also use the word "optional" in the property name.)
+ </para>
+ </sect3>
+ <sect3 id="repository_source_capabilities">
+ <title>Capabilities</title>
+ <para>
+ Another characteristic of a &RepositorySource; implementation is that it provides some hint as to whether
+ it supports several features. This is defined on the interface as a method that returns a
+ &RepositorySourceCapabilities; object. This class currently provides methods that say whether the connector supports
+ updates, whether it supports same-name-siblings (SNS), and whether the connector supports listeners and events.
+ </para>
+ <para>
+ Note that these may be hard-coded values, or the connector's response may be determined at runtime by various factors.
+ For example, a connector may interrogate the underlying system to decide whether it can support updates.
+ </para>
+ <para>
+ The &RepositorySourceCapabilities; can be used as is (the class is immutable), or it can be subclassed
+ to provide more complex behavior. It is important, however, that the capabilities remain constant
+ throughout the lifetime of the &RepositorySource; instance.
+ </para>
+ <note>
+ <para>
+ Why a concrete class and not an interface? By using a concrete class, connectors inherit the default
+ behavior. If additional capabilities need to be added to the class in future releases, connectors may
+ not have to override the defaults. This provides some insulation against future enhancements to the connector framework.
+ </para>
+ </note>
+ </sect3>
+ <sect3 id="repository_source_security">
+ <title>Security and authentication</title>
+ <para>
+ As we'll see in the next section, the main method connectors have to process requests takes an &ExecutionContext;,
+ which contains the JAAS security information of the subject performing the request. This means that the connector
+ can use this to determine authentication and authorization information for each request.
+ </para>
+ <para>
+ Sometimes that is not sufficient. For example, it may be that the connector needs its own authorization information
+ so that it can establish a connection (even if user-level privileges still use the &ExecutionContext; provided with
+ each request). In this case, the &RepositorySource; implementation will probably need JavaBean properties
+ that represent the connector's authentication information. This may take the form of a username and password,
+ or it may be properties that are used to delegate authentication to JAAS.
+ Either way, just realize that it's perfectly acceptable for the connector to require its own security properties.
+ </para>
+ </sect3>
+ </sect2>
+ <sect2 id="implementing_repository_connection">
+ <title>Implementing a <code>RepositoryConnection</code></title>
+ <para>
+ One job of the &RepositorySource; implementation is to create connections to the underlying sources.
+ Connections are represented by classes that implement the &RepositoryConnection; interface, and creating this
+ class is the next step in writing a repository connector. This is what we'll cover in this section.
+ </para>
+ <para>
+ The &RepositoryConnection; interface is pretty straightforward:
+ </para>
+ <programlisting>
+/**
+ * A connection to a repository source.
+ * <p>
+ * These connections need not support concurrent operations by multiple threads.
+ * </p>
+ */
+@NotThreadSafe
+public interface &RepositoryConnection; {
+
+ /**
+ * Get the name for this repository source. This value should be the same as that returned
+ * by the same &RepositorySource; that created this connection.
+ *
+ * @return the identifier; never null or empty
+ */
+ String getSourceName();
+
+ /**
+ * Return the transactional resource associated with this connection. The transaction manager
+ * will use this resource to manage the participation of this connection in a distributed transaction.
+ *
+ * @return the XA resource, or null if this connection is not aware of distributed transactions
+ */
+ XAResource getXAResource();
+
+ /**
+ * Ping the underlying system to determine if the connection is still valid and alive.
+ *
+ * @param time the length of time to wait before timing out
+ * @param unit the time unit to use; may not be null
+ * @return true if this connection is still valid and can still be used, or false otherwise
+ * @throws InterruptedException if the thread has been interrupted during the operation
+ */
+ boolean ping( long time, &TimeUnit; unit ) throws InterruptedException;
+
+ /**
+ * Set the listener that is to receive notifications to changes to content within this source.
+ *
+ * @param listener the new listener, or null if no component is interested in the change notifications
+ */
+ void setListener( &RepositorySourceListener; listener );
+
+ /**
+ * Get the default cache policy for this repository. If none is provided, a global cache policy
+ * will be used.
+ *
+ * @return the default cache policy
+ */
+ &CachePolicy; getDefaultCachePolicy();
+
+ /**
+ * Execute the supplied commands against this repository source.
+ *
+ * @param context the environment in which the commands are being executed; never null
+ * @param request the request to be executed; never null
+ * @throws RepositorySourceException if there is a problem loading the node data
+ */
+ void execute( &ExecutionContext; context,
+ &Request; request ) throws &RepositorySourceException;;
+
+ /**
+ * Close this connection to signal that it is no longer needed and that any accumulated
+ * resources are to be released.
+ */
+ void close();
+}</programlisting>
+ <para>
+ While most of these methods are straightforward, a few warrant additional information.
+ The <code>ping(...)</code> allows DNA to check the connection to see if it is
+ alive. This method can be used in a variety of situations, ranging from verifying that a &RepositorySource;'s
+ JavaBean properties are correct to ensuring that a connection is still alive before returning the connection from
+ a connection pool.
+ </para>
+ <para>
+ DNA hasn't yet defined the event mechanism, so connectors don't have any methods to invoke on the &RepositorySourceListener;.
+ This will be defined in the next release, so feel free to manage the listeners now. Note that by default the &RepositorySourceCapabilities; returns
+ <code>false</code> for <code>supportsEvents()</code>.
+ </para>
+ <para>
+ The most important method on this interface, though, is the <code>execute(...)</code> method, which serves as the
+ mechanism by which the component using the connector access and manipulates the content exposed by the connector.
+ The first parameter to this method is the &ExecutionContext;, which contains the information about environment
+ as well as the subject performing the request. This was discussed <link linkend="execution-context">earlier</link>.
+ </para>
+ <para>
+ The second parameter, however, represents a request that is to be processed by the connector. Request objects can
+ take many different forms, as there are different classes for each kind of request (see the table below).
+ Each request contains the information a connector needs to do the processing, and it also is the place
+ where the connector places the results (or the error, if one occurs).
+ </para>
+ <para>
+ How do the requests reference a node (or nodes)? Since requests are coming from a client, the client
+ may identify a particular node using a &Location; object that is created with:
+ <itemizedlist>
+ <listitem>
+ <para>the &Path; to the node; or</para>
+ </listitem>
+ <listitem>
+ <para>one or more <emphasis>identification properties</emphasis> that are likely source=specific
+ and that are represented with &Property; objects; or</para>
+ </listitem>
+ <listitem>
+ <para>a combination of both.</para>
+ </listitem>
+ </itemizedlist>
+ So, when a client knows the path or the identification properties, they can create a &Location;. However,
+ all of the requests return &Location; objects, so often times the client simply uses the location
+ from a previous request. Since &Location; is an immutable class, it is perfectly safe to reuse them.
+ </para>
+ <para>
+ One more thing about locations: while the request may have an incomplete location (e.g., a path but no
+ identification properties), the connector is expected to set on the request the <emphasis>actual</emphasis>
+ location that contains the path and all identification properties. So as long as the client
+ reuses the actual locations in subsequent requests, the connectors will have the benefit of having
+ both the path and identification properties. Connectors can then be written to leverage this
+ information, although the connector should still perform as expected when requests have incomplete locations.
+ </para>
+ <table frame='all'>
+ <title>Types of Node Operation Requests</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>ReadNodeRequest</entry>
+ <entry>
+ A request to read from the named workspace in the source a node's properties and children.
+ The node may be specified by path and/or by identification properties.
+ The connector returns all properties and the locations for all children,
+ or sets a &PathNotFoundException; error on the request if the node did not exist in the workspace.
+ If the node is found, the connector sets on the request the actual location of the node (including the path and identification properties).
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>VerifyNodeExistsRequest</entry>
+ <entry>
+ A request to verify the existance of a node at the specified location in the named workspace of the source.
+ The connector returns all the actual location for the node if it exists, or
+ sets a &PathNotFoundException; error on the request if the node does not exist in the workspace.
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>ReadAllPropertiesRequest</entry>
+ <entry>
+ A request to read from the named workspace in the source all of the properties of a node.
+ The node may be specified by path and/or by identification properties.
+ The connector returns all properties that were found on the node,
+ or sets a &PathNotFoundException; error on the request if the node did not exist in the workspace.
+ If the node is found, the connector sets on the request the actual location of the node (including the path and identification properties).
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>ReadPropertyRequest</entry>
+ <entry>
+ A request to read from the named workspace in the source a single property of a node.
+ The node may be specified by path and/or by identification properties,
+ and the property is specified by name.
+ The connector returns the property if found on the node,
+ or sets a &PathNotFoundException; error on the request if the node or property did not exist in the workspace.
+ If the node is found, the connector sets on the request the actual location of the node (including the path and identification properties).
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>ReadAllChildrenRequest</entry>
+ <entry>
+ A request to read from the named workspace in the source all of the children of a node.
+ The node may be specified by path and/or by identification properties.
+ The connector returns an ordered list of locations for each child found on the node,
+ an empty list if the node had no children,
+ or sets a &PathNotFoundException; error on the request if the node did not exist in the workspace.
+ If the node is found, the connector sets on the request the actual location of the parent node (including the path and identification properties).
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>ReadBlockOfChildrenRequest</entry>
+ <entry>
+ A request to read from the named workspace in the source a block of children of a node, starting with the n<superscript>th</superscript> children.
+ This is designed to allow paging through the children, which is much more efficient for large numbers of children.
+ The node may be specified by path and/or by identification properties, and the block
+ is defined by a starting index and a count (i.e., the block size).
+ The connector returns an ordered list of locations for each of the node's children found in the block,
+ or an empty list if there are no children in that range.
+ The connector also sets on the request the actual location of the parent node (including the path and identification properties)
+ or sets a &PathNotFoundException; error on the request if the parent node did not exist in the workspace.
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>ReadNextBlockOfChildrenRequest</entry>
+ <entry>
+ A request to read from the named workspace in the source a block of children of a node, starting with the children that immediately follow
+ a previously-returned child.
+ This is designed to allow paging through the children, which is much more efficient for large numbers of children.
+ The node may be specified by path and/or by identification properties, and the block
+ is defined by the location of the node immediately preceding the block and a count (i.e., the block size).
+ The connector returns an ordered list of locations for each of the node's children found in the block,
+ or an empty list if there are no children in that range.
+ The connector also sets on the request the actual location of the parent node (including the path and identification properties)
+ or sets a &PathNotFoundException; error on the request if the parent node did not exist in the workspace.
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>ReadBranchRequest</entry>
+ <entry>
+ A request to read a portion of a subgraph that has as its root a particular node, up to a maximum depth.
+ This request is an efficient mechanism when a branch (or part of a branch) is to be navigated and processed,
+ and replaces some non-trivial code to read the branch iteratively using multiple <code>ReadNodeRequest</code>s.
+ The connector reads the branch to the specified maximum depth, returning the properties and children for all
+ nodes found in the branch.
+ The connector also sets on the request the actual location of the branch's root node (including the path and identification properties).
+ The connector sets a &PathNotFoundException; error on the request if the node at
+ the top of the branch does not exist in the workspace.
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>CreateNodeRequest</entry>
+ <entry>
+ A request to create a node at the specified location and setting on the new node the properties included in the request.
+ The connector creates the node at the desired location, adjusting any same-name-sibling indexes as required.
+ (If an SNS index is provided in the new node's location, existing children with the same name after that SNS index
+ will have their SNS indexes adjusted. However, if the requested location does not include a SNS index, the new
+ node is added after all existing children, and it's SNS index is set accordingly.)
+ The connector also sets on the request the actual location of the new node (including the path and identification properties)..
+ The connector sets a &PathNotFoundException; error on the request if the parent node does not exist in the workspace.
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>RemovePropertiesRequest</entry>
+ <entry>
+ A request to remove a set of properties on an existing node. The request contains the location of the node as well as the
+ names of the properties to be removed. The connector performs these changes and sets on the request the
+ actual location (including the path and identification properties) of the node.
+ The connector sets a &PathNotFoundException; error on the request if the node does not exist in the workspace.
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>UpdatePropertiesRequest</entry>
+ <entry>
+ A request to set or update properties on an existing node. The request contains the location of the node as well as the
+ properties to be set and those to be deleted. The connector performs these changes and sets on the request the
+ actual location (including the path and identification properties) of the node.
+ The connector sets a &PathNotFoundException; error on the request if the node does not exist in the workspace.
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>RenameNodeRequest</entry>
+ <entry>
+ A request to change the name of a node. The connector changes the node's name, adjusts all SNS indexes
+ accordingly, and returns the actual locations (including the path and identification properties) of both the original
+ location and the new location.
+ The connector sets a &PathNotFoundException; error on the request if the node does not exist in the workspace.
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>CopyBranchRequest</entry>
+ <entry>
+ A request to copy a portion of a subgraph that has as its root a particular node, up to a maximum depth.
+ The request includes the name of the workspace where the original node is located as well as the name of the
+ workspace where the copy is to be placed (these may be the same, but may be different).
+ The connector copies the branch from the original location, up to the specified maximum depth, and places a copy
+ of the node as a child of the new location.
+ The connector also sets on the request the actual location (including the path and identification properties)
+ of the original location as well as the location of the new copy.
+ The connector sets a &PathNotFoundException; error on the request if the node at
+ the top of the branch does not exist in the workspace.
+ The connector sets a &InvalidWorkspaceException; error on the request if one of the named workspaces does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>MoveBranchRequest</entry>
+ <entry>
+ A request to move a subgraph that has a particular node as its root.
+ The connector moves the branch from the original location and places it as child of the specified new location.
+ The connector also sets on the request the actual location (including the path and identification properties)
+ of the original and new locations. The connector will adjust SNS indexes accordingly.
+ The connector sets a &PathNotFoundException; error on the request if the node that is to be moved or the
+ new location do not exist in the workspace.
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>DeleteBranchRequest</entry>
+ <entry>
+ A request to delete an entire branch specified by a single node's location.
+ The connector deletes the specified node and all nodes below it, and sets the actual location,
+ including the path and identification properties, of the node that was deleted.
+ The connector sets a &PathNotFoundException; error on the request if the node being deleted does not exist in the workspace.
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>CompositeRequest</entry>
+ <entry>
+ A request that actually comprises multiple requests (none of which will be a composite).
+ The connector simply processes all of the requests in the composite request, but should set on the composite
+ request any error (usually the first error) that occurs during processing of the contained requests.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>There are also requests that deal with workspaces:</para>
+ <table frame='all'>
+ <title>Types of Workspace Requests</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>GetWorkspacesRequest</entry>
+ <entry>
+ A request to obtain the names of the existing workspaces that are accessible to the caller.
+ </entry>
+ </row>
+ <row>
+ <entry>VerifyWorkspaceRequest</entry>
+ <entry>
+ A request to verify that a workspace with a particular name exists.
+ The connector returns the actual location for the root node if the workspace exists, as well as the actual name of the workspace
+ (e.g., the default workspace name if a null name is supplied).
+ </entry>
+ </row>
+ <row>
+ <entry>CreateWorkspaceRequest</entry>
+ <entry>
+ A request to create a workspace with a particular name.
+ The connector returns the actual location for the root node if the workspace exists, as well as the actual name of the workspace
+ (e.g., the default workspace name if a null name is supplied).
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace already exists.
+ </entry>
+ </row>
+ <row>
+ <entry>DestroyWorkspaceRequest</entry>
+ <entry>
+ A request to destroy a workspace with a particular name.
+ The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
+ </entry>
+ </row>
+ <row>
+ <entry>CloneWorkspaceRequest</entry>
+ <entry>
+ A request to clone one named workspace as another new named workspace.
+ The connector sets a &InvalidWorkspaceException; error on the request if the original workspace does not exist,
+ or if the new workspace already exists.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>
+ Although there are over a dozen different kinds of requests, we do anticipate adding more in future releases.
+ For example, DNA will likely support searching repository content in sources through an additional subclass of &Request;.
+ Getting the version history for a node will likely be another kind of request added in an upcoming release.
+ </para>
+ <para>
+ A connector is technically free to implement the <code>execute(...)</code> method in any way, as long as the semantics
+ are maintained. But DNA provides a &RequestProcessor; class that can simplify writing your own connector and at the
+ same time help insulate your connector from new kinds of requests that may be added in the future. The &RequestProcessor;
+ is an abstract class that defines a <code>process(...)</code> method for each concrete &Request; subclass.
+ In other words, there is a <code>process(CompositeRequest)</code> method, a <code>process(ReadNodeRequest)</code> method,
+ and so on.
+ </para>
+ <para>
+ To use this in your connector, simply create a subclass of &RequestProcessor;, overriding all of the abstract methods and optionally
+ overriding any of the other methods that have a default implementation.
+ </para>
+ <note>
+ <para>
+ The &RequestProcessor; abstract class contains default implementations for quite a few of the <code>process(...)</code> methods,
+ and these will be <emphasis>sufficient</emphasis> but probably not efficient or optimum. If you can provide a more efficient
+ implementation given your source, feel free to do so. However, if performance is not a big issue, all of the concrete methods
+ will provide the correct behavior. Keep things simple to start out - you can always provide better implementations later.
+ </para>
+ </note>
+ <para>
+ Then, in your connector's <code>execute(&ExecutionContext;, &Request;)</code> method, instantiate your &RequestProcessor; subclass
+ and call its <code>process(&Request;) method, passing in the <code>execute(...)</code> method's &Request; parameter.</code>
+ The &RequestProcessor; will determine the appropriate method given the actual &Request; object and will then invoke that method:
+ </para>
+ <programlisting>
+public void execute( final &ExecutionContext; context,
+ final &Request; request ) throws RepositorySourceException {
+ RequestProcessor processor = new RequestProcessor(context);
+ try {
+ processor.process(request);
+ } finally {
+ processor.close();
+ }
+}</programlisting>
+ <para>
+ If you do this, the bulk of your connector implementation may be in the &RequestProcessor; implementation methods.
+ This not only is pretty maintainable, it also lends itself to easier testing. And should any new request types be added
+ in the future, your connector may work just fine without any changes. In fact, if the &RequestProcessor; class
+ can implement meaningful methods for those new request types, your connector may "just work". Or, at least
+ your connector will still be binary compatible, even if your connector won't support any of the new features.
+ </para>
+ <para>
+ Finally, how should the connector handle exceptions? As mentioned above, each &Request; object has a slot where the connector
+ can set any exception encountered during processing. This not only handles the exception, but in the case of &CompositeRequest;s
+ it also correctly associates the problem with the request. However, it is perfectly acceptable to throw an exception
+ if the connection becomes invalid (e.g., there is a communication failure) or if a fatal error would prevent subsequent
+ requests from being processed.
+ </para>
+ </sect2>
+ <sect2 id="testing_custom_connectors">
+ <title>Testing custom connectors</title>
+ <para>
+ Testing connectors is not really that much different than testing other classes. Using mocks may help to isolate your
+ instances so you can create more unit tests that don't require the underlying source system.
+ </para>
+ <para>
+ However, there may be times when you have to use the underlying source system in your tests. If this is the case,
+ we recommend using Maven integration tests, which run at a different point in the Maven lifecycle. The benefit of
+ using integration tests is that by convention they're able to rely upon external systems. Plus, your unit tests
+ don't become polluted with slow-running tests that break if the external system is not available.
+ </para>
+ </sect2>
+ <sect2 id="deploying_custom_connectors">
+ <title>Configuring and deploying custom connectors</title>
+ <para>
+ After building your connector project, you need to configure the JBoss DNA components your application is using so
+ that they use your connector. In a lot of cases, this will entail instantiating your connector's &RepositorySource; class,
+ setting the various properties, and registering it with a &RepositoryLibrary;. Or, it will entail using a configuration
+ repository to use your source and letting &RepositoryService; instantiate and set up your &RepositorySource; instance.
+ Or, you can just instantiate and set it up manually, passing the instance to whatever component needs it.
+ </para>
+ <para>
+ And of course you have to make the JAR file containing your connector (as well as any dependency JARs) available to
+ your application's classpath.
+ </para>
+ </sect2>
+ </sect1>
+ <sect1 id="dna_graph_api">
+ <title>Graph API for using connectors</title>
+ <para>
+ So far we've talked about repositories, repository connectors, and how connectors respond to the different kinds of requests.
+ Normally you'd code to the JCR API and use our JCR implementation. However, what does your code look like if you want
+ to use the connectors directly, without using our JCR implementation? After all, you may be a contributor to JBoss DNA,
+ or you may want to take advantage of our connectors without all the overhead of JCR.
+ </para>
+ <para>
+ One option, of course, is to explicitly create the different requests and pass them to the connector's <code>execute(...)</code> method.
+ While this is the most efficient approach (and one taken in some key DNA components), you probably want something that
+ is much less verbose and much easier to use. This is where the DNA graph API comes in.
+ </para>
+ <para>
+ JBoss DNA's <emphasis>Graph API</emphasis> was designed as a lightweight public API for working with graph information,
+ and it insulates components from the underlying requests and interacting with connectors.
+ The &Graph; class is the primary class in API, and each instance represents a single, independent
+ view of the graph of content from a single connector. &Graph; instances return snapshots of state, and those snapshots
+ never change after they're retrieved. To obtain a &Graph; instance, use the static <code>create(...)</code>
+ method, supplying the name of the source, a &RepositoryConnectionFactory; from which a &RepositoryConnection; can be obtained,
+ and the &ExecutionContext;.
+ </para>
+ <para>
+ The &Graph; class basically represents an <ulink url="http://www.martinfowler.com/bliki/DomainSpecificLanguage.html">internal domain specific language (DSL)</ulink>,
+ designed to be easy to use in an application.
+ The Graph API makes extensive use of interfaces and method chaining, so that methods return a concise interface that has only those
+ methods that make sense at that point. In fact, this should be really easy if your IDE has code completion.
+ Just remember that under the covers, a &Graph; is just building &Request; objects, submitting them to the connector,
+ and then exposing the results.
+ </para>
+ <sect2 id="dna_graph_api_workspaces">
+ <title>Using workspaces</title>
+ <para>
+ Let's look at some examples of how the Graph API works. This first example shows how to obtain the names of the available workspaces:
+ </para>
+ <programlisting>
+&Set;<&String;> workspaceNames = graph.getWorkspaces();
+</programlisting>
+ <para>Once you know the name of the workspace, you can specify that the graph should use it:
+ </para>
+ <programlisting>
+graph.useWorkspace("myWorkspace");
+</programlisting>
+ <para>
+ From this point forward, all requests will apply to the workspace named "myWorkspace". At any time, you can use a different workspace,
+ which will affect all subsequent requests made using the graph. Of course, creating a new workspace is just as easy:
+ </para>
+ <programlisting>
+graph.createWorkspace().named("newWorkspace");
+</programlisting>
+ <para>This will attempt to create a workspace named "newWorkspace", which will fail if that workspace already exists. You may
+ want to create a new workspace with a name that should be altered if the name you supply is already used. The following code shows
+ how you can do this:
+ </para>
+ <programlisting>
+graph.createWorkspace().namedSomethingLike("newWorkspace");
+</programlisting>
+ <para>If there is no existing workspace named "newWorkspace", a new one will be created with this name. However, if "newWorkspace" already
+ exists, this call will create a workspace with a name that is some alteration of the supplied name.
+ </para>
+ <para>
+ You can also clone workspaces, too:
+ </para>
+ <programlisting>
+graph.createWorkspace().clonedFrom("original").named("something");
+</programlisting>
+ <para>
+ or
+ </para>
+ <programlisting>
+graph.createWorkspace().clonedFrom("original").namedSomethingLike("something");
+</programlisting>
+ <para>
+ As you can see, it's very easy to specify which workspace you want to use or to create new workspaces. You can also find out which workspace
+ the graph is currently using:
+ </para>
+ <programlisting>
+&String; current = graph.getCurrentWorkspaceName();
+</programlisting>
+ <para>or, if you want, you can get more information about the workspace:
+ </para>
+ <programlisting>
+&Workspace; current = graph.getCurrentWorkspace();
+&String; name = current.getName();
+&Location; rootLocation = current.getRoot();
+</programlisting>
+ </sect2>
+ <sect2 id="dna_graph_api_nodes">
+ <title>Working with nodes</title>
+ <para>
+ Now let's switch to working with nodes. This first example returns a map of properties (keyed by property name)
+ for a node at a specific &Path;:
+ </para>
+ <programlisting>
+&Path; path = ...
+Map<&Name;,&Property;> propertiesByName = graph.getPropertiesByName().on(path);
+</programlisting>
+ <para>
+ This next example shows how the graph can be used to obtain and loop over the properties of a node:
+ </para>
+ <programlisting>
+&Path; path = ...
+for ( &Property; property : graph.getProperties().on(path) ) {
+ ...
+}
+</programlisting>
+ <para>
+ Likewise, the next example shows how the graph can be used to obtain and loop over the children of a node:
+ </para>
+ <programlisting>
+&Path; path = ...
+for ( &Location; child : graph.getChildren().of(path) ) {
+ &Path; childPath = child.getPath();
+ ...
+}
+</programlisting>
+ <para>
+ Notice that the examples pass a &Path; instance to the <code>on(...)</code> and <code>of(...)</code> methods. Many
+ of the Graph API methods take a variety of parameter types, including String, &Path;s, &Location;s, &UUID;, or &Property; parameters.
+ This should make it easy to use in many different situations.
+ </para>
+ <para>
+ Of course, changing content is more interesting and offers more interesting possibilities. Here are a few examples:
+ </para>
+ <programlisting>
+&Path; path = ...
+&Location; location = ...
+&Property; idProp1 = ...
+&Property; idProp2 = ...
+&UUID; uuid = ...
+graph.move(path).into(idProp1, idProp2);
+graph.copy(path).into(location);
+graph.delete(uuid);
+graph.delete(idProp1,idProp2);
+</programlisting>
+ <para>
+ The methods shown above work immediately, as soon as each request is built. However, there is another way to use
+ the &Graph; object, and that is in a <emphasis>batch</emphasis> mode. Simply create a &GraphBatch; object using the
+ <code>batch()</code> method, create the requests on that batch object, and then execute all of the commands on the
+ batch by calling its <code>execute()</code> method. That <code>execute()</code> method returns a &Results; interface
+ that can be used to read the node information retrieved by the batched requests.
+ </para>
+ <para>
+ Method chaining works really well with the batch mode, since multiple commands can be assembled together very easily:
+ </para>
+ <programlisting>
+&Path; path = ...
+String path2 = ...
+&Location; location = ...
+&Property; idProp1 = ...
+&Property; idProp2 = ...
+&UUID; uuid = ...
+graph.batch().move(path).into(idProp1, idProp2).and().copy(path2).into(location).and().delete(uuid).execute();
+&Results; results = graph.batch().read(path2).
+ and().readChildren().of(idProp1,idProp2).
+ and().readSugraphOfDepth(3).at(uuid2).
+ execute();
+for ( &Location; child : results.getNode(path2) ) {
+ ...
+}
+</programlisting>
+ <para>
+ Of course, this section provided just a hint of the Graph API.
+ The &Graph; interface is actually quite complete and offers a full-featured approach for reading and updating a graph.
+ For more information, see the &Graph; JavaDocs.
+ </para>
+ </sect2>
+ </sect1>
+ <sect1>
+ <title>Summary</title>
+ <para>
+ In this chapter, we covered all the aspects of JBoss DNA repositories, including the connector framework,
+ how DNA's JCR implementation works with connectors, what connectors are available (and how to use them),
+ and how to write your own connector. So now that you know how to set up and use JBoss DNA repositories,
+ the <link linkend="jcr">next chapter</link> describes how you can leverage JBoss DNA's JCR implementation.
+ </para>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/core/repositories.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Copied: trunk/docs/reference/src/main/docbook/en-US/content/core/sequencing.xml (from rev 994, trunk/docs/reference/src/main/docbook/en-US/content/sequencing.xml)
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/core/sequencing.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/core/sequencing.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -0,0 +1,793 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="sequencing">
+ <title>Sequencing content</title>
+ <para>As we've mentioned before, JBoss DNA is able to work with existing JCR repositories. Your client applications
+ make changes to the information in those repositories, and JBoss DNA automatically uses its sequencers to extract
+ additional information from the uploaded files.</para>
+ <para>
+ This chapter discusses the sequencing features of JBoss DNA and the components that are involved.
+ </para>
+ <sect1 id="sequencing-service">
+ <title>Sequencing Service</title>
+ <para>The JBoss DNA <emphasis>sequencing service</emphasis> is the component that manages the <emphasis>sequencers</emphasis>,
+ reacting to changes in JCR repositories and then running the appropriate sequencers.
+ This involves processing the changes on a node, determining which (if any) sequencers should be run on that node,
+ and for each sequencer constructing the execution environment, calling the sequencer, and saving the information
+ generated by the sequencer.</para>
+ <note>
+ <para>Configuring JBoss DNA services is a bit more manual than is ideal. As you'll see, JBoss DNA uses dependency
+ injection to allow a great deal of flexibility in how it can be configured and customized. But this flexibility
+ makes it more difficult for you to use. We understand this, and will soon provide a much easier way to set up
+ and manage JBoss DNA. Current plans are to use the <ulink url="http://www.jboss.org/jbossmc">JBoss Microcontainer</ulink>
+ along with a configuration repository.</para>
+ </note>
+ <para>To set up the sequencing service, an instance is created, and dependent components are injected into
+ the object. This includes among other things:
+ <itemizedlist>
+ <listitem>
+ <para>An <emphasis>execution context</emphasis> that defines the context in which the service runs, including
+ a factory for JCR sessions given names of the repository and workspace. This factory must be configured,
+ and is how JBoss DNA knows about your JCR repositories and how to connect to them. More on this a bit later.</para>
+ </listitem>
+ <listitem>
+ <para>An optional <emphasis>factory for class loaders</emphasis> used to load sequencers. If no factory is supplied,
+ the service uses the current thread's context class loader (or if that is null, the class loader that loaded the
+ sequencing service class).</para>
+ </listitem>
+ <listitem>
+ <para>An &ExecutorService; used to execute the sequencing activites. If none
+ is supplied, a new single-threaded executor is created by calling <code>Executors.newSingleThreadExecutor()</code>.
+ (This can easily be changed by subclassing and overriding the <code>SequencerService.createDefaultExecutorService()</code> method.)</para>
+ </listitem>
+ <listitem>
+ <para>Filters for sequencers and events. By default, all sequencers are considered for "node added", "property added"
+ and "property changed" events.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>As mentioned above, the &JcrExecutionContext; provides access to a &SessionFactory; that is used
+ by JBoss DNA to establish sessions to your JCR repositories. Two implementations are available:
+ <itemizedlist>
+ <listitem>
+ <para>The &JndiSessionFactory;> looks up JCR &Repository; instances in JNDI using
+ names that are supplied when creating sessions. This implementation also has methods to set the
+ JCR &Credentials; for a given workspace name.</para>
+ </listitem>
+ <listitem>
+ <para>The &SimpleSessionFactory; has methods to register the JCR &Repository; instances
+ with names, as well as methods to set the JCR &Credentials; for a given workspace name.</para>
+ </listitem>
+ </itemizedlist>
+ You can use the &JcrExecutionContext; and use one of these &SessionFactory; implementations or another
+ implementation that you provide.</para>
+ <para>Here's an example of how to instantiate and configure the &SequencingService;:</para>
+ <programlisting>
+&SimpleSessionFactory; sessionFactory = new &SimpleSessionFactory;();
+sessionFactory.registerRepository("Main Repository", this.repository);
+&Credentials; credentials = new &SimpleCredentials;("jsmith", "secret".toCharArray());
+sessionFactory.registerCredentials("Main Repository/Workspace1", credentials);
+// Now create the JCR execution context, with a reference to the session factory
+// and the name of the repository from which sessions will be obtained ...
+ExecutionContext executionContext = new &JcrExecutionContext;(sessionFactory,"Main Repository");
+
+// Create the sequencing service, passing in the execution context ...
+&SequencingService; sequencingService = new &SequencingService;();
+sequencingService.setExecutionContext(executionContext);
+</programlisting>
+ <para>After the sequencing service is created and configured, it must be started. The &SequencingService;
+ has an <emphasis>administration object</emphasis> (that is an instance of &ServiceAdministrator;)
+ with <code>start()</code>, <code>pause()</code>, and <code>shutdown()</code> methods. The latter method will
+ close the queue for sequencing, but will allow sequencing operations already running to complete normally.
+ To wait until all sequencing operations have completed, simply call the <code>awaitTermination</code> method
+ and pass it the maximum amount of time you want to wait.</para>
+ <programlisting>
+sequencingService.getAdministrator().start();
+</programlisting>
+ <para>The JBoss DNA services are utilizing resources and threads that must be released before your application is ready to shut down.
+ The safe way to do this is to simply obtain the &ServiceAdministrator; for each service (via the <code>getServiceAdministrator()</code> method)
+ and call <code>shutdown()</code>. As previously mentioned, the shutdown method will simply prevent new work from being processed
+ and will not wait for existing work to be completed. If you want to wait until the service completes all its work, you must wait
+ until the service terminates. Here's an example that shows how this is done:</para>
+ <programlisting>
+// Shut down the service and wait until it's all shut down ...
+sequencingService.getAdministrator().shutdown();
+sequencingService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
+
+// Shut down the observation service ...
+observationService.getAdministrator().shutdown();
+observationService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
+</programlisting>
+ </sect1>
+ <sect1 id="sequencer-configuration">
+ <title>Sequencer Configurations</title>
+ <para>The sequencing service must also be configured with the sequencers that it will use. This is done using the
+ <code>addSequencer(SequencerConfig)</code> method and passing a &SequencerConfig; instance that
+ you create. Here's the code that defines 3 sequencer configurations: 1 that places image metadata into
+ "<code><![CDATA[/images/<filename>]]></code>", another that places MP3 metadata into "<code><![CDATA[/mp3s/<filename>]]></code>",
+ and a third that places a structure that represents the classes, methods, and attributes found within Java source into
+ "<code><![CDATA[/java/<filename>]]></code>".</para>
+ <programlisting>
+String name = "Image Sequencer";
+String desc = "Sequences image files to extract the characteristics of the image";
+String classname = "org.jboss.dna.sequencer.images.ImageMetadataSequencer";
+String[] classpath = null; // Use the current classpath
+String[] pathExpressions = {"//(*.(jpg|jpeg|gif|bmp|pcx|png)[*])/jcr:content[@jcr:data] => /images/$1"};
+&SequencerConfig; imageSequencerConfig = new &SequencerConfig;(name, desc, classname,
+ classpath, pathExpressions);
+sequencingService.addSequencer(imageSequencerConfig);
+
+name = "MP3 Sequencer";
+desc = "Sequences MP3 files to extract the ID3 tags from the audio file";
+classname = "org.jboss.dna.sequencer.mp3.Mp3MetadataSequencer";
+pathExpressions = {"//(*.mp3[*])/jcr:content[@jcr:data] => /mp3s/$1"};
+&SequencerConfig; mp3SequencerConfig = new &SequencerConfig;(name, desc, classname,
+ classpath, pathExpressions);
+sequencingService.addSequencer(mp3SequencerConfig);
+
+name = "Java Sequencer";
+desc = "Sequences java files to extract the characteristics of the Java source";
+classname = "org.jboss.dna.sequencer.java.JavaMetadataSequencer";
+pathExpressions = {"//(*.java[*])/jcr:content[@jcr:data] => /java/$1"};
+&SequencerConfig; javaSequencerConfig = new &SequencerConfig;(name, desc, classname,
+ classpath, pathExpressions);
+this.sequencingService.addSequencer(javaSequencerConfig);
+</programlisting>
+ <para>Each configuration defines several things, including the name, description, and sequencer implementation class.
+ The configuration also defines the classpath information, which can be passed to the &ClassLoaderFactory; to get
+ a Java &ClassLoader; with which the sequencer class can be loaded. (If no classpath information is provided, as is done
+ in the code above, the application class loader is used.) The configuration also specifies the path expressions that
+ identify the nodes that should be sequenced with the sequencer and where to store the output generated by the sequencer.
+ Path expressions are pretty straightforward but are quite powerful, so before we go any further with the example,
+ let's dive into path expressions in more detail.</para>
+ <sect2 id="path_expressions">
+ <title>Path Expressions</title>
+ <para>Path expressions consist of two parts: a selection criteria (or an input path) and an output path:</para>
+ <programlisting><![CDATA[ inputPath => outputPath ]]></programlisting>
+ <para>The <emphasis>inputPath</emphasis> part defines an expression for the path of a node that is to be sequenced.
+ Input paths consist of '<code>/</code>' separated segments, where each segment represents a pattern for a single node's
+ name (including the same-name-sibling indexes) and '<code>@</code>' signifies a property name.</para>
+ <para>Let's first look at some simple examples:</para>
+ <table frame='all'>
+ <title>Simple Input Path Examples</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Input Path</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row><entry>/a/b</entry><entry>Match node "<code>b</code>" that is a child of the top level node "<code>a</code>". Neither node
+ may have any same-name-sibilings.</entry></row>
+ <row><entry>/a/*</entry><entry>Match any child node of the top level node "<code>a</code>".</entry></row>
+ <row><entry>/a/*.txt</entry><entry>Match any child node of the top level node "<code>a</code>" that also has a name ending in "<code>.txt</code>".</entry></row>
+ <row><entry>/a/*.txt</entry><entry>Match any child node of the top level node "<code>a</code>" that also has a name ending in "<code>.txt</code>".</entry></row>
+ <row><entry>/a/b@c</entry><entry>Match the property "<code>c</code>" of node "<code>/a/b</code>".</entry></row>
+ <row><entry>/a/b[2]</entry><entry>The second child named "<code>b</code>" below the top level node "<code>a</code>".</entry></row>
+ <row><entry>/a/b[2,3,4]</entry><entry>The second, third or fourth child named "<code>b</code>" below the top level node "<code>a</code>".</entry></row>
+ <row><entry>/a/b[*]</entry><entry>Any (and every) child named "<code>b</code>" below the top level node "<code>a</code>".</entry></row>
+ <row><entry>//a/b</entry><entry>Any node named "<code>b</code>" that exists below a node named "<code>a</code>", regardless
+ of where node "<code>a</code>" occurs. Again, neither node may have any same-name-sibilings.</entry></row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>With these simple examples, you can probably discern the most important rules. First, the '<code>*</code>' is a wildcard character
+ that matches any character or sequence of characters in a node's name (or index if appearing in between square brackets), and
+ can be used in conjunction with other characters (e.g., "<code>*.txt</code>").</para>
+ <para>Second, square brackets (i.e., '<code>[</code>' and '<code>]</code>') are used to match a node's same-name-sibiling index.
+ You can put a single non-negative number or a comma-separated list of non-negative numbers. Use '0' to match a node that has no
+ same-name-sibilings, or any positive number to match the specific same-name-sibling.</para>
+ <para>Third, combining two delimiters (e.g., "<code>//</code>") matches any sequence of nodes, regardless of what their names are
+ or how many nodes. Often used with other patterns to identify nodes at any level matching other patterns.
+ Three or more sequential slash characters are treated as two.</para>
+ <para>Many input paths can be created using just these simple rules. However, input paths can be more complicated. Here are some
+ more examples:</para>
+ <table frame='all'>
+ <title>More Complex Input Path Examples</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Input Path</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row><entry>/a/(b|c|d)</entry><entry>Match children of the top level node "<code>a</code>" that are named "<code>a</code>",
+ "<code>b</code>" or "<code>c</code>". None of the nodes may have same-name-sibling indexes.</entry></row>
+ <row><entry>/a/b[c/d]</entry><entry>Match node "<code>b</code>" child of the top level node "<code>a</code>", when node
+ "<code>b</code>" has a child named "<code>c</code>", and "<code>c</code>" has a child named "<code>d</code>".
+ Node "<code>b</code>" is the selected node, while nodes "<code>b</code>" and "<code>b</code>" are used as criteria but are not
+ selected.</entry></row>
+ <row><entry>/a(/(b|c|d|)/e)[f/g/@something]</entry><entry>Match node "<code>/a/b/e</code>", "<code>/a/c/e</code>", "<code>/a/d/e</code>",
+ or "<code>/a/e</code>" when they also have a child "<code>f</code>" that itself has a child "<code>g</code>" with property
+ "<code>something</code>". None of the nodes may have same-name-sibling indexes.</entry></row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>These examples show a few more advanced rules. Parentheses (i.e., '<code>(</code>' and '<code>)</code>') can be used
+ to define a set of options for names, as shown in the first and third rules. Whatever part of the selected node's path
+ appears between the parentheses is captured for use within the output path. Thus, the first input path in the previous table
+ would match node "<code>/a/b</code>", and "b" would be captured and could be used within the output path using "<code>$1</code>",
+ where the number used in the output path identifies the parentheses.</para>
+ <para>Square brackets can also be used to specify criteria on a node's properties or children. Whatever appears in between the square
+ brackets does not appear in the selected node.</para>
+ <para>Let's go back to the previous code fragment and look at the first path expression:</para>
+ <programlisting><![CDATA[ //(*.(jpg|jpeg|gif|bmp|pcx|png)[*])/jcr:content[@jcr:data] => /images/$1 ]]></programlisting>
+ <para>This matches a node named "<code>jcr:content</code>" with property "<code>jcr:data</code>" but no siblings with the same name,
+ and that is a child of a node whose name ends with "<code>.jpg</code>", "<code>.jpeg</code>", "<code>.gif</code>", "<code>.bmp</code>", "<code>.pcx</code>",
+ or "<code>.png</code>" that may have any same-name-sibling index. These nodes can appear at any level in the repository.
+ Note how the input path capture the filename (the segment containing the file extension), including any same-name-sibling index.
+ This filename is then used in the output path, which is where the sequenced content is placed.</para>
+ </sect2>
+ </sect1>
+ <sect1 id="sequencers">
+ <title>JBoss DNA Sequencers</title>
+ <para>
+ JBoss DNA includes a number of sequencers "out of the box". These sequencers can be used within your application to sequence
+ a variety of common file formats. To use them, the only thing you have to do is define the appropriate sequencer configurations
+ and include the appropriate JAR files.
+ </para>
+ <sect2 id="dna-sequencer-images">
+ <title>Image sequencer</title>
+ <para>
+ A sequencer that extracts metadata from JPEG, GIF, BMP, PCX, PNG, IFF, RAS, PBM, PGM, PPM and PSD image files.
+ This sequencer extracts the file format, image resolution, number of bits per pixel and optionally number of images, comments
+ and physical resolution, and then writes this information into the repository using the following structure:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis role="strong">image:metadata</emphasis> node of type <code>image:metadata</code>
+ </para>
+ </listitem>
+ <listitem>
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="strong">jcr:mimeType</emphasis> - optional string property for the mime type of the image</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong">jcr:encoding</emphasis> - optional string property for the encoding of the image</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong">image:formatName</emphasis> - string property for the name of the format</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong">image:width</emphasis> - optional integer property for the image's width in pixels</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong">image:height</emphasis> - optional integer property for the image's height in pixles</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong">image:bitsPerPixel</emphasis> - optional integer property for the number of bits per pixel</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong">image:progressive</emphasis> - optional boolean property specifying whether the image is stored in a progressive
+ (i.e., interlaced) form</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong">image:numberOfImages</emphasis> - optional integer property for the number of images stored in the file; defaults
+ to 1</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong">image:physicalWidthDpi</emphasis> - optional integer property for the physical width of the image in dots per inch</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong">image:physicalHeightDpi</emphasis> - optional integer property for the physical height of the image in dots per
+ inch</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong">image:physicalWidthInches</emphasis> - optional double property for the physical width of the image in inches</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong">image:physicalHeightInches</emphasis> - optional double property for the physical height of the image in inches</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ <para>
+ This structure could be extended in the future to add EXIF and IPTC metadata as child nodes. For example, EXIF metadata is
+ structured as tags in directories, where the directories form something like namespaces, and which are used by different camera
+ vendors to store custom metadata. This structure could be mapped with each directory (e.g. "EXIF" or "Nikon Makernote" or
+ "IPTC") as the name of a child node, with the EXIF tags values stored as either properties or child nodes.
+ </para>
+ <para>
+ To use this sequencer, simply include the <code>dna-sequencer-images</code> JAR
+ in your application and configure the Sequencing Service to use this sequencer using something similar to:
+ </para>
+ <programlisting>
+String name = "Image Sequencer";
+String desc = "Sequences image files to extract the characteristics of the image";
+String classname = "org.jboss.dna.sequencer.images.ImageMetadataSequencer";
+String[] classpath = null; // Use the current classpath
+String[] pathExpressions = {"//(*.(jpg|jpeg|gif|bmp|pcx|png|iff|ras|pbm|pgm|ppm|psd)[*])/jcr:content[@jcr:data] => /images/$1"};
+&SequencerConfig; sequencerConfig = new &SequencerConfig;(name, desc, classname,
+ classpath, pathExpressions);
+sequencingService.addSequencer(sequencerConfig);
+</programlisting>
+ </sect2>
+ <sect2 id="dna-sequencer-msoffice">
+ <title>Microsoft Office document sequencer</title>
+ <para>
+ This sequencer is included in JBoss DNA and processes Microsoft Office documents, including Word documents, Excel spreadsheets,
+ and PowerPoint presentations. With documents, the sequencer extracts the internal structure based on Heading styles.
+ With presentations, the sequencer extracts the slides, titles, text and slide thumbnails.
+ With spreadsheets, the sequencer extracts the names of the sheets. And, the sequencer extracts for all the files the
+ general file information, including the name of the author, title, keywords, subject, comments, and various dates.
+ </para>
+ <para>
+ To use this sequencer, simply include the <code>dna-sequencer-msoffice</code> JAR and all of the
+ <ulink url="http://poi.apache.org/">POI</ulink> JARs
+ in your application and configure the Sequencing Service to use this sequencer using something similar to:
+ </para>
+ <programlisting>
+String name = "Microsoft Office Document Sequencer";
+String desc = "Sequences MS Office documents, including spreadsheets and presentations";
+String classname = "org.jboss.dna.sequencer.msoffice.MSOfficeMetadataSequencer";
+String[] classpath = null; // Use the current classpath
+String[] pathExpressions = {"//(*.(doc|docx|ppt|pps|xls)[*])/jcr:content[@jcr:data] => /msoffice/$1"};
+&SequencerConfig; sequencerConfig = new &SequencerConfig;(name, desc, classname,
+ classpath, pathExpressions);
+sequencingService.addSequencer(sequencerConfig);
+</programlisting>
+ </sect2>
+ <sect2 id="dna-sequencer-zip">
+ <title>ZIP archive sequencer</title>
+ <para>
+ The ZIP file sequencer is included in JBoss DNA and extracts the files and folders contained in the ZIP archive file,
+ extracting the files and folders into the repository using JCR's <code>nt:file</code> and <code>nt:folder</code> node types.
+ </para>
+ <para>
+ To use this sequencer, simply include the <code>dna-sequencer-zip</code> JAR
+ in your application and configure the Sequencing Service to use this sequencer using something similar to:
+ </para>
+ <programlisting>
+String name = "ZIP Sequencer";
+String desc = "Sequences ZIP archives to extract the files and folders";
+String classname = "org.jboss.dna.sequencer.zip.ZipSequencer";
+String[] pathExpressions = {"//(*.zip[*])/jcr:content[@jcr:data] => /zips/$1"};
+&SequencerConfig; sequencerConfig = new &SequencerConfig;(name, desc, classname,
+ classpath, pathExpressions);
+this.sequencingService.addSequencer(sequencerConfig);
+</programlisting>
+ </sect2>
+ <sect2 id="dna-sequencer-java">
+ <title>Java source sequencer</title>
+ <para>
+ One of the sequencers that included in JBoss DNA is the <emphasis role="strong">dna-sequencer-java</emphasis> subproject.
+ This sequencer parses Java source code added to the repository and extracts the basic structure of the classes and enumerations
+ defined in the code.
+ This structure includes: the package structures, class declarations, class and member attribute declarations,
+ class and member method declarations with signature (but not implementation logic), enumerations with each enumeration literal value,
+ annotations, and JavaDoc information for all of the above.
+ After extracting this information from the source code, the sequencer then writes this structure into the repository,
+ where it can be further processed, analyzed, searched, navigated, or referenced.
+ </para>
+ <para>
+ To use this sequencer, simply include the <code>dna-sequencer-java</code> JAR (plus all of the JARs that it is dependent upon)
+ in your application and configure the Sequencing Service to use this sequencer using something similar to:
+ </para>
+ <programlisting>
+String name = "Java Sequencer";
+String desc = "Sequences java files to extract the characteristics of the Java source";
+String classname = "org.jboss.dna.sequencer.java.JavaMetadataSequencer";
+String[] classpath = null; // Use the current classpath
+String[] pathExpressions = {"//(*.java[*])/jcr:content[@jcr:data] => /java/$1"};
+&SequencerConfig; sequencerConfig = new &SequencerConfig;(name, desc, classname,
+ classpath, pathExpressions);
+this.sequencingService.addSequencer(sequencerConfig);
+</programlisting>
+ </sect2>
+ <sect2 id="dna-sequencer-mp3">
+ <title>MP3 audio file sequencer</title>
+ <para>
+ Another sequencer that is included in JBoss DNA is the <emphasis role="strong">dna-sequencer-mp3</emphasis> sequencer project.
+ This sequencer processes MP3 audio files added to a repository and extracts the <ulink url="http://www.id3.org/">ID3</ulink>
+ metadata for the file, including the track's title, author, album name, year, and comment.
+ After extracting this information from the audio files, the sequencer then writes this structure into the repository,
+ where it can be further processed, analyzed, searched, navigated, or referenced.
+ </para>
+ <para>
+ To use this sequencer, simply include the <code>dna-sequencer-mp3</code> JAR and the <ulink url="http://www.jthink.net/jaudiotagger/">JAudioTagger</ulink>
+ library in your application and configure the Sequencing Service to use this sequencer using something similar to:
+ </para>
+ <programlisting>
+String name = "MP3 Sequencer";
+String desc = "Sequences MP3 files to extract the ID3 tags of the audio file";
+String classname = "org.jboss.dna.sequencer.mp3.Mp3MetadataSequencer";
+String[] pathExpressions = {"//(*.mp3[*])/jcr:content[@jcr:data] => /mp3s/$1"};
+&SequencerConfig; sequencerConfig = new &SequencerConfig;(name, desc, classname,
+ classpath, pathExpressions);
+this.sequencingService.addSequencer(sequencerConfig);
+</programlisting>
+ </sect2>
+ <sect2 id="dna-sequencer-cnd">
+ <title>JCR Compact Node Definition (CND) file sequencer</title>
+ <para>
+ This sequencer processes JCR Compact Node Definition (CND) files
+ to extract the node definitions with their property definitions, and inserts these into the repository using JCR standard notation.
+ </para>
+ </sect2>
+ <sect2 id="dna-sequencer-jbpm-jpdl">
+ <title>jBPM JPDL file sequencer</title>
+ <para>
+ This sequencer is incomplete and is not currently usable. The purpose is to sequence jBPM JPDL files to identify metadata
+ about processes, their actors, and their dependencies.
+ </para>
+ </sect2>
+ <sect2 id="dna-sequencer-xml">
+ <title>XML file sequencer</title>
+ <para>
+ This sequencer stores the structure and data of an XML file into the repository.
+ </para>
+ </sect2>
+
+ </sect1>
+ <sect1 id="custom-sequencers">
+ <title>Creating custom sequencers</title>
+ <para>The current release of JBoss DNA comes with six sequencers. However, it's very easy to create your own
+ sequencers and to then configure JBoss DNA to use them in your own application.
+ </para>
+ <para>
+ Creating a custom sequencer involves the following steps:
+ <orderedlist>
+ <listitem>
+ <para>Create a Maven 2 project for your sequencer;</para>
+ </listitem>
+ <listitem>
+ <para>Implement the &StreamSequencer; interface with your own implementation, and create unit tests to verify
+ the functionality and expected behavior;</para>
+ </listitem>
+ <listitem>
+ <para>Add the sequencer configuration to the JBoss DNA &SequencingService; in your application
+ as described in the <link linkend="using_dna">previous chapter</link>; and</para>
+ </listitem>
+ <listitem>
+ <para>Deploy the JAR file with your implementation (as well as any dependencies), and make them available to JBoss DNA
+ in your application.</para>
+ </listitem>
+ </orderedlist>
+ It's that simple.
+ </para>
+ <sect2 id="custom_sequencer_project">
+ <title>Creating the Maven 2 project</title>
+ <para>The first step is to create the Maven 2 project that you can use to compile your code and build the JARs.
+ Maven 2 automates a lot of the work, and since you're already <link linkend="maven">set up to use Maven</link>,
+ using Maven for your project will save you a lot of time and effort. Of course, you don't have to use Maven 2, but then you'll
+ have to get the required libraries and manage the compiling and building process yourself.</para>
+ <note>
+ <para>JBoss DNA may provide in the future a Maven archetype for creating sequencer projects. If you'd find this useful
+ and would like to help create it, please <link linkend="preface">join the community</link>.
+ </para>
+ <para>In lieu of a Maven archetype, you may find it easier to start with a small existing sequencer project.
+ The <emphasis role="strong">dna-sequencer-images</emphasis> project is a small, self-contained sequencer implementation that
+ has only the minimal dependencies.
+ See the subversion repository: <ulink url="&Subversion;trunk/extensions/dna-sequencer-images/">&Subversion;trunk/extensions/dna-sequencer-images/</ulink>
+ </para>
+ </note>
+ <para>You can create your Maven project any way you'd like. For examples, see the <ulink url="http://maven.apache.org/guides/getting-started/index.html#How_do_I_make_m...">Maven 2 documentation</ulink>.
+ Once you've done that, just add the dependencies in your project's <code>pom.xml</code> dependencies section:</para>
+ <programlisting role="XML"><![CDATA[
+<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>0.3</version>
+</dependency>
+<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ <version>0.3</version>
+</dependency>
+ ]]></programlisting>
+ <para>These are minimum dependencies required for compiling a sequencer. Of course, you'll have to add
+ other dependencies that your sequencer needs.</para>
+ <para>As for testing, you probably will want to add more dependencies, such as those listed here:</para>
+ <programlisting role="XML"><![CDATA[
+<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ <version>0.5</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-library</artifactId>
+ <version>1.1</version>
+ <scope>test</scope>
+</dependency>
+<!-- Logging with Log4J -->
+<dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.4.3</version>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ <scope>test</scope>
+</dependency>
+ ]]></programlisting>
+ <para>Testing JBoss DNA sequencers does not require a JCR repository or the JBoss DNA services. (For more detail,
+ see the <link linkend="testing_custom_sequencers">testing section</link>.) However, if you want to do
+ integration testing with a JCR repository and the JBoss DNA services, you'll need additional dependencies for these libraries.</para>
+ <programlisting role="XML"><![CDATA[
+<!-- JBoss DNA JCR Repository -->
+<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-jcr</artifactId>
+ <version>0.5</version>
+ <scope>test</scope>
+</dependency>
+<!-- Java Content Repository API -->
+<dependency>
+ <groupId>javax.jcr</groupId>
+ <artifactId>jcr</artifactId>
+ <version>1.0.1</version>
+ <scope>test</scope>
+</dependency>
+ ]]></programlisting>
+ <para>At this point, your project should be set up correctly, and you're ready to move on to
+ <link linkend="custom_sequencer_implementation">writing the Java implementation</link> for your sequencer.</para>
+ </sect2>
+ <sect2 id="custom_sequencer_implementation">
+ <title>Implementing the StreamSequencer interface</title>
+ <para>After creating the project and setting up the dependencies, the next step is to create a Java class that implements
+ the &StreamSequencer; interface. This interface is very straightforward and involves a single method:</para>
+ <programlisting>
+public interface &StreamSequencer; {
+
+ /**
+ * Sequence the data found in the supplied stream, placing the output
+ * information into the supplied map.
+ *
+ * @param stream the stream with the data to be sequenced; never null
+ * @param output the output from the sequencing operation; never null
+ * @param context the context for the sequencing operation; never null
+ */
+ void sequence( &InputStream; stream, &SequencerOutput; output, &SequencerContext; context );
+}
+</programlisting>
+ <para>The job of a stream sequencer is to process the data in the supplied stream, and place into the &SequencerOutput;
+ any information that is to go into the JCR repository. JBoss DNA figures out when your sequencer should be called
+ (of course, using the sequencing configuration you'll add in a bit), and then makes sure the generated information
+ is saved in the correct place in the repository.
+ </para>
+ <para>The &SequencerContext; provides information about
+ the current sequencing operation, including the location and properties of the node being sequenced, the MIME type
+ of the node being sequenced, and a location to record problems that aren't severe enough to warrant throwing an exception.
+ </para>
+ <para>The &SequencerOutput; class is fairly easy to use. There are basically two methods you need to call.
+ One method sets the property values, while the other sets references to other nodes in the repository. Use these
+ methods to describe the properties of the nodes you want to create, using relative paths for the nodes and
+ valid JCR property names for properties and references. JBoss DNA will ensure that nodes are created or updated
+ whenever they're needed.</para>
+ <programlisting>
+public interface &SequencerOutput; {
+
+ /**
+ * Set the supplied property on the supplied node. The allowable
+ * values are any of the following:
+ * - primitives (which will be autoboxed)
+ * - String instances
+ * - String arrays
+ * - byte arrays
+ * - InputStream instances
+ * - Calendar instances
+ *
+ * @param nodePath the path to the node containing the property;
+ * may not be null
+ * @param property the name of the property to be set
+ * @param values the value(s) for the property; may be empty if
+ * any existing property is to be removed
+ */
+ void setProperty( String nodePath, String property, Object... values );
+
+ /**
+ * Set the supplied reference on the supplied node.
+ *
+ * @param nodePath the path to the node containing the property;
+ * may not be null
+ * @param property the name of the property to be set
+ * @param paths the paths to the referenced property, which may be
+ * absolute paths or relative to the sequencer output node;
+ * may be empty if any existing property is to be removed
+ */
+ void setReference( String nodePath, String property, String... paths );
+}
+</programlisting>
+ <para>JBoss DNA will create nodes of type <code>nt:unstructured</code> unless you specify the value for the
+ <code>jcr:primaryType</code> property. You can also specify the values for the <code>jcr:mixinTypes</code> property
+ if you want to add mixins to any node.</para>
+ <para>For a complete example of a sequencer, let's look at the &ImageMetadataSequencer;
+ implementation:</para>
+ <programlisting>
+public class &ImageMetadataSequencer; implements &StreamSequencer; {
+
+ public static final String METADATA_NODE = "image:metadata";
+ public static final String IMAGE_PRIMARY_TYPE = "jcr:primaryType";
+ public static final String IMAGE_MIXINS = "jcr:mixinTypes";
+ public static final String IMAGE_MIME_TYPE = "jcr:mimeType";
+ public static final String IMAGE_ENCODING = "jcr:encoding";
+ public static final String IMAGE_FORMAT_NAME = "image:formatName";
+ public static final String IMAGE_WIDTH = "image:width";
+ public static final String IMAGE_HEIGHT = "image:height";
+ public static final String IMAGE_BITS_PER_PIXEL = "image:bitsPerPixel";
+ public static final String IMAGE_PROGRESSIVE = "image:progressive";
+ public static final String IMAGE_NUMBER_OF_IMAGES = "image:numberOfImages";
+ public static final String IMAGE_PHYSICAL_WIDTH_DPI = "image:physicalWidthDpi";
+ public static final String IMAGE_PHYSICAL_HEIGHT_DPI = "image:physicalHeightDpi";
+ public static final String IMAGE_PHYSICAL_WIDTH_INCHES = "image:physicalWidthInches";
+ public static final String IMAGE_PHYSICAL_HEIGHT_INCHES = "image:physicalHeightInches";
+
+ /**
+ * {@inheritDoc}
+ */
+ public void sequence( &InputStream; stream, &SequencerOutput; output,
+ &SequencerContext; context ) {
+ &ImageMetadata; metadata = new &ImageMetadata;();
+ metadata.setInput(stream);
+ metadata.setDetermineImageNumber(true);
+ metadata.setCollectComments(true);
+
+ // Process the image stream and extract the metadata ...
+ if (!metadata.check()) {
+ metadata = null;
+ }
+ // Generate the output graph if we found useful metadata ...
+ if (metadata != null) {
+ // Place the image metadata into the output map ...
+ output.setProperty(METADATA_NODE, IMAGE_PRIMARY_TYPE, "image:metadata");
+ // output.psetProperty(METADATA_NODE, IMAGE_MIXINS, "");
+ output.setProperty(METADATA_NODE, IMAGE_MIME_TYPE, metadata.getMimeType());
+ // output.setProperty(METADATA_NODE, IMAGE_ENCODING, "");
+ output.setProperty(METADATA_NODE, IMAGE_FORMAT_NAME, metadata.getFormatName());
+ output.setProperty(METADATA_NODE, IMAGE_WIDTH, metadata.getWidth());
+ output.setProperty(METADATA_NODE, IMAGE_HEIGHT, metadata.getHeight());
+ output.setProperty(METADATA_NODE, IMAGE_BITS_PER_PIXEL, metadata.getBitsPerPixel());
+ output.setProperty(METADATA_NODE, IMAGE_PROGRESSIVE, metadata.isProgressive());
+ output.setProperty(METADATA_NODE, IMAGE_NUMBER_OF_IMAGES, metadata.getNumberOfImages());
+ output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_WIDTH_DPI, metadata.getPhysicalWidthDpi());
+ output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_HEIGHT_DPI, metadata.getPhysicalHeightDpi());
+ output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_WIDTH_INCHES, metadata.getPhysicalWidthInch());
+ output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_HEIGHT_INCHES, metadata.getPhysicalHeightInch());
+ }
+ }
+}
+</programlisting>
+ <para>
+ Notice how the image metadata is extracted and the output graph is generated. A single node is created with the name <code>image:metadata</code>
+ and with the <code>image:metadata</code> node type. No mixins are defined for the node, but several properties are set on the node
+ using the values obtained from the image metadata. After this method returns, the constructed graph will be saved to the repository
+ in all of the places defined by its configuration. (This is why only relative paths are used in the sequencer.)
+ </para>
+ </sect2>
+ <sect2 id="testing_custom_sequencers">
+ <title>Testing custom sequencers</title>
+ <para>The sequencing framework was designed to make testing sequencers much easier. In particular, the
+ &StreamSequencer; interface does not make use of the JCR API. So instead of requiring a fully-configured
+ JCR repository and JBoss DNA system, unit tests for a sequencer can focus on testing that the content is
+ processed correctly and the desired output graph is generated.</para>
+ <note>
+ <para>For a complete example of a sequencer unit test, see the <code>ImageMetadataSequencerTest</code> unit test
+ in the <code>org.jboss.dna.sequencer.images</code> package of the <code>dna-sequencers-image</code> project.
+ </para>
+ </note>
+ <para>The following code fragment shows one way of testing a sequencer, using JUnit 4.4 assertions and
+ some of the classes made available by JBoss DNA. Of course,
+ this example code does not do any error handling and does not make all the assertions a real test would.</para>
+ <programlisting>
+&StreamSequencer; sequencer = new &ImageMetadataSequencer;();
+&MockSequencerOutput; output = new &MockSequencerOutput;();
+&MockSequencerContext; context = new &MockSequencerContext;();
+&InputStream; stream = null;
+try {
+ stream = this.getClass().getClassLoader().getResource("caution.gif").openStream();
+ sequencer.sequence(stream,output,context); // writes to 'output'
+ assertThat(output.getPropertyValues("image:metadata", "jcr:primaryType"),
+ is(new Object[] {"image:metadata"}));
+ assertThat(output.getPropertyValues("image:metadata", "jcr:mimeType"),
+ is(new Object[] {"image/gif"}));
+ // ... make more assertions here
+ assertThat(output.hasReferences(), is(false));
+} finally {
+ stream.close();
+}
+</programlisting>
+ <para>It's also useful to test that a sequencer produces no output for something it should not understand:</para>
+ <programlisting>
+&Sequencer; sequencer = new &ImageMetadataSequencer;();
+&MockSequencerOutput; output = new &MockSequencerOutput;();
+&MockSequencerContext; context = new &MockSequencerContext;();
+&InputStream; stream = null;
+try {
+ stream = this.getClass().getClassLoader().getResource("caution.pict").openStream();
+ sequencer.sequence(stream,output,context); // writes to 'output'
+ assertThat(output.hasProperties(), is(false));
+ assertThat(output.hasReferences(), is(false));
+} finally {
+ stream.close();
+}
+</programlisting>
+ <para>These are just two simple tests that show ways of testing a sequencer. Some tests may get quite involved,
+ especially if a lot of output data is produced.
+ </para>
+ <para>It may also be useful to create some integration tests
+ that <link linkend="using_dna">configure JBoss DNA</link> to use a custom sequencer, and to then upload
+ content using the JCR API, verifying that the custom sequencer did run. However, remember that JBoss DNA
+ runs sequencers asynchronously in the background, and you must synchronize your tests to ensure that the
+ sequencers have a chance to run before checking the results. (One way of doing this (although, granted, not always reliable) is to wait for a second
+ after uploading your content, shutdown the &SequencingService; and await its termination,
+ and then check that the sequencer output has been saved to the JCR repository. For an example of this technique,
+ see the <code>SequencingClientTest</code> unit test in the example application.)
+ </para>
+ </sect2>
+ <sect2 id="deploying_custom_sequencers">
+ <title>Deploying custom sequencers</title>
+ <para>The first step of deploying a sequencer consists of adding/changing the sequencer configuration (e.g., &SequencerConfig;)
+ in the &SequencingService;. This was covered in the <link linkend="sequencing_service">previous chapter</link>.
+ </para>
+ <para>
+ The second step is to make the sequencer implementation available to JBoss DNA. At this time, the JAR containing
+ your new sequencer, as well as any JARs that your sequencer depends on, should be placed on your application classpath.</para>
+ <note>
+ <para>A future goal of JBoss DNA is to allow sequencers, connectors, and other extensions to be easily deployed into
+ a runtime repository. This process will not only be much simpler, but it will also provide JBoss DNA
+ with the information necessary to update configurations and create the appropriate class loaders for each extension.
+ Having separate class loaders for each extension helps prevent the pollution of the common classpath,
+ facilitates an isolated runtime environment to eliminate any dependency conflicts, and may potentially
+ enable hot redeployment of newer extension versions.
+ </para>
+ </note>
+ </sect2>
+ </sect1>
+ <sect1>
+ <title>Summary</title>
+ <para>
+ In this chapter, we described how JBoss DNA sequences files as they're uploaded into a repository.
+ And one of the things we mentioned was that each sequencer is handed (with other inputs) the MIME type of the file it is to process.
+ How does DNA know what the MIME type is?
+ JBoss DNA uses <emphasis>MIME type detectors</emphasis>, and this is the topic of the <link linkend="mimetypes">next chapter</link>.
+ </para>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/core/sequencing.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Copied: trunk/docs/reference/src/main/docbook/en-US/content/developers/testing.xml (from rev 994, trunk/docs/reference/src/main/docbook/en-US/content/testing.xml)
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/developers/testing.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/developers/testing.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="testing">
+ <title>Testing</title>
+ <para>
+ The JBoss DNA project uses automated testing to verify that the software is doing what it's supposed to
+ and not doing what it shouldn't do. These automated tests are run continuously and also act as regression tests,
+ ensuring that we known if any problems we find and fix reappear later. All of our tests are executed as part of
+ our <link linkend="maven">Maven</link> build process, and the entire build process (including the tests)
+ is automatically run using <link linkend="hudson">Hudson</link> continuous integration system.
+ </para>
+ <sect1 id="unit-tests">
+ <title>Unit tests</title>
+ <para>
+ <emphasis role="strong">Unit tests</emphasis> verify the behavior of a single class (or small set of classes) in isolation
+ from other classes.
+ We use the JUnit 4.4 testing framework, which has significant improvements over earlier versions and makes
+ it very easy to quickly write unit tests with little extra code. We also frequently use the Mockito library
+ to help create mock implementations of other classes that are not under test but are used in the tests.
+ </para>
+ <para>
+ Unit tests should generally run quickly and should not require large assemblies of components. Additionally,
+ they may rely upon the file resources included in the project, but these tests should require no external resources
+ (like databases or servers). Note that our unit tests are run during the "test" phase of the standard
+ <ulink url="http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle...">Maven lifecycle</ulink>.
+ This means that they are executed against the raw .class files created during complication.
+ </para>
+ <para>
+ Developers are expected to run all of the JBoss DNA unit tests in their local environment before committing changes to SVN.
+ So, if you're a developer and you've made changes to your local copy of the source, you can run those tests that are
+ related to your changes using your IDE or with Maven (or any other mechanism). But before you commit your changes,
+ you are expected to run a full Maven build using <code>mvn clean install</code> (in the "trunk/" directory).
+ Please do <emphasis>not</emphasis> rely upon continuous integration to run all of the tests for you - the CI
+ system is there to catch the occasional mistakes and to also run the <link linkend="integration-tests">integration tests</link>.
+ </para>
+ </sect1>
+ <sect1 id="integration-tests">
+ <title>Integration tests</title>
+ <para>
+ While <link linkend="unit-tests">unit tests</link> test individual classes in (relative) isolation, the purpose of
+ <emphasis role="strong">integration tests</emphasis> are to verify that assemblies of classes and components are
+ behaving correctly. These assemblies are often the same ones that end users will actually use. In fact,
+ integration tests are executed during the "integration-test" phase of the standard
+ <ulink url="http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle...">Maven lifecycle</ulink>,
+ meaning they are executed against the packaged JARs and artifacts of the project.
+ </para>
+ <para>
+ Integration tests also use the JUnit 4.4 framework, so they are again easy to write and follow the same pattern
+ as unit tests. However, because they're working with larger assemblies of components, they often will take longer
+ to set up, longer to run, and longer to tear down. They also may require initializing "external resources", like
+ databases or servers.
+ </para>
+ <para>
+ Note, that while external resources may be required, care should be taken to minimize these dependencies and to
+ ensure that most (if not all) integration tests may be run by anyone who downloads the source code. This means
+ that these external resources should be available and set up within the tests. For example, use in-memory databases
+ where possible. Or, if a database is required, use an open-source database (e.g., MySQL or PostgreSQL). And when
+ these external resources are not available, it should be obvious from the test class names and/or test method names
+ that it involved an external resource (e.g., "<code>MySqlConnectorIntegrationTest.shouldFindNodeStoredInDatabase()</code>").
+ </para>
+ </sect1>
+ <sect1 id="writing-tests">
+ <title>Writing tests</title>
+ <para>
+ As mentioned in <link linkend="methodology">the introduction</link>, the JBoss DNA project doesn't follow any one methodology
+ or process. Instead, we simply have a goal that as much code as possible is tested to ensure it behaves as expected.
+ Do we expect 100% of the code is covered by automated tests? No, but we do want to test as much as we can.
+ Maybe a simple JavaBean class doesn't need many tests, but any class with non-trivial logic should be tested.
+ </para>
+ <para>
+ We do encourage writing tests either before or while you write the code. Again, we're not blindly following a methodology.
+ Instead, there's a very practical reason: writing the tests early on helps you write classes that are testable.
+ If you wait until after the class (or classes) are done, you'll probably find that it's not easy to test all
+ of the logic (especially the complicated logic).
+ </para>
+ <para>
+ Another suggestion is to write tests so that they specify and verify the behavior that is expected from a class or component.
+ One challenge developers often have is knowing what they should even test and what the tests should look like.
+ This is where <emphasis role="strong"><ulink url="http://behaviour-driven.org/">Behavior-driven development (BDD)</ulink></emphasis>
+ helps out. If you think about what a class' behaviors are supposed to be (e.g., requirements), simply capture those
+ requirements as test methods (with no implementations). For example, a test class for sequencer
+ implementation might have a test method <code>shouldNotThrowAnErrorWhenTheSuppliedStreamIsNull() { }</code>. Then, after you enumerate
+ all the requirements you can think of, go back and start implementing the test methods.
+ </para>
+ <para>
+ If you look at the existing test cases, you'll find that the names of the unit and integration tests in JBoss DNA
+ follow a naming style, where the test method names are readable sentences. Actually, we try to name the test methods
+ <emphasis>and</emphasis> the test classes such that they form a concisely-worded requirement. For example,
+ </para>
+ <programlisting>InMemorySequencerTest.shouldNotThrowAnErrorWhenTheSuppliedStreamIsNull()</programlisting>
+ <para>
+ is easily translated into a readable requirement:
+ </para>
+ <programlisting>InMemorySequencer should not throw an error when the supplied stream is null.</programlisting>
+ <para>
+ In fact, at some point in the future, we'd like to process the source to automatically generate a list of the behavior specifications
+ that are asserted by the tests.
+ </para>
+ <para>
+ But for now, we write tests - a lot of them. And by following a few simple conventions and practices, we're able
+ to do it quickly and in a way that makes it easy to understand what the code is supposed to do (or not do).
+ </para>
+ </sect1>
+ <sect1 id="tck-tests">
+ <title>Technology Compatibility Kit (TCK) tests</title>
+ <para>
+ Many Java specifications provide TCK test suites that can be used to check or verify that an implementation
+ correctly implements the API or SPI defined by the specification. These TCK tests vary by technology, but
+ <ulink url="&JSR170;">JSR-170</ulink> does provide TCK tests that ensure that a JCR repository implementation exhibits the correct and expected
+ behavior.
+ </para>
+ <para>
+ JBoss DNA has not yet passed enough of the TCK tests to publish the results. We still have to implement
+ queries, which is a required feature of Level 1 repositories. However, suffice to say that JBoss DNA has passed
+ many of the individual tests that make up the Level 1 and Level 2 tests, and it is a major objective of the next
+ release to pass the remaining Level 1 and Level 2 tests (along with some other optional features).
+ </para>
+ <para>
+ JBoss DNA also frequently runs the JCR unit tests from the Apache Jackrabbit project. (Those these tests are not
+ the official TCK, they apparently are used within the official TCK.) These unit tests are set up in the
+ <code>dna-jcr-tck</code> project.
+ </para>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/developers/testing.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Copied: trunk/docs/reference/src/main/docbook/en-US/content/developers/tools.xml (from rev 994, trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml)
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/developers/tools.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/developers/tools.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -0,0 +1,502 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="development-tools">
+ <title>Developer tools</title>
+ <para>
+ The JBoss DNA project uses <link linkend="maven">Maven</link> as its primary build tool, <link linkend="svn">Subversion</link>
+ for its source code repository, <link linkend="jira">JIRA</link> for the issue management and bug tracking system,
+ and <link linkend="hudson">Hudson</link> for the continuous integration system. We do not stipulate a specific integrated
+ development environment (IDE), although most of us use <link linkend="eclipse">Eclipse</link> and rely upon the code formatting
+ and compile preferences to ensure no warnings or errors.
+ </para>
+ <para>
+ The rest of this chapter talks in more detail about these different tools and how to set them up.
+ </para>
+ <sect1 id="jdk">
+ <title>JDK</title>
+ <para>
+ Currently, JBoss DNA is developed and built using <ulink url="http://java.sun.com/javase/downloads/index_jdk5.jsp">JDK 5</ulink>.
+ So if you're trying to get JBoss DNA to compile locally, you should make sure you have the JDK 5 installed and are using it.
+ If you're a contributor, you should make sure that you're using JDK 5 before committing any changes.
+ </para>
+ <note>
+ <para>
+ You should be able to use the <ulink url="http://java.sun.com/javase/downloads/index.jsp">latest JDK</ulink>,
+ which is currently JDK 6. It is possible to build JBoss DNA using JDK 6 without any code changes, but it's
+ not our official JDK (yet).
+ </para>
+ <para>
+ Why do we build using JDK 5 and not 6? The main reason is that if we were to use JDK 6, then JBoss DNA couldn't really be used in any
+ applications or projects that still used JDK 5. Plus, anybody using JDK 6 can still use JBoss DNA.
+ However, considering that the end-of-life for Java 5 is
+ <ulink url="http://java.sun.com/products/archive/eol.policy.html">October 2009</ulink>, we may be switching to
+ Java 6 sometime in 2009.
+ </para>
+ </note>
+ <para>
+ When installing a JDK, simply follow the procedure for your particular platform. On most platforms, this should set the
+ <code>JAVA_HOME</code> environment variable. But if you run into any problems, first check that this environment
+ variable was set to the correct location, and then check that you're running the version you expect by running
+ the following command:
+ </para>
+ <programlisting>$ java -version</programlisting>
+ <para>
+ If you don't see the correct version, double-check your JDK installation.
+ </para>
+ </sect1>
+ <sect1 id="jira">
+ <title>JIRA</title>
+ <para>
+ JBoss DNA uses <ulink url="&JIRA;">JIRA</ulink> as its bug tracking, issue tracking, and project management tool.
+ This is a browser-based tool, with very good functionality for managing the different tasks. It also serves as
+ the community's roadmap, since we can define new features and manage them along side the bugs and other issues.
+ Although most of the issues have been created by community members, we encourage any users to suggest new features,
+ log defects, or identify shortcomings in JBoss DNA.
+ </para>
+ <para>
+ The JBoss DNA community also encourages its members to work only issues that are managed in JIRA, and preferably those
+ that are targeted to the current release effort. If something isn't in JIRA but needs to get done, then create an
+ issue before you start working on the code changes. Once you have code changes, you can upload a patch to the JIRA issue
+ if the change is complex, if you want someone to review it, or if you don't have commit privileges and have fixed
+ a bug.
+ </para>
+ </sect1>
+ <sect1 id="svn">
+ <title>Subversion</title>
+ <para>JBoss DNA uses Subversion as its source code management system, and specifically the instance at
+ <ulink url="http://www.jboss.org">JBoss.org</ulink>. Although you can view the
+ <ulink url="&Subversion;trunk/">trunk</ulink> of the Subversion repository directly
+ (or using <ulink url="&Fisheye;trunk">FishEye</ulink>) through your browser,
+ it order to get more than just a few files of the latest version of the source code, you probably want
+ to have an SVN client installed. Several IDE's have SVN support included (or available as plugins),
+ but having the command-line SVN client is recommended. See
+ <ulink url="http://subversion.tigris.org/">http://subversion.tigris.org/</ulink> for downloads and instructions for your
+ particular platform.
+ </para>
+ <para>
+ Here are some useful URLs for the JBoss DNA Subversion:
+ </para>
+ <table frame='all'>
+ <title>SVN URLs for JBoss DNA</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Repository</entry>
+ <entry>URL</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>Anonymous Access URL</entry>
+ <entry><ulink url="&Subversion;trunk/">&Subversion;trunk/</ulink></entry>
+ </row>
+ <row>
+ <entry>Secure Developer Access URL</entry>
+ <entry><ulink url="&Fisheye;trunk/">&Fisheye;trunk/</ulink></entry>
+ </row>
+ <row>
+ <entry>FishEye Code Browser</entry>
+ <entry><ulink url="&SecureSubversion;trunk/">&SecureSubversion;trunk/</ulink></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>
+ When committing to SVN, be sure to include in a commit comment that includes the JIRA issue that the commit applies to and a very
+ good and thorough description of what was done. It only takes a minute or two to be very clear about the change. And including
+ the JIRA issue (e.g., "DNA-123") in the comment allows the JIRA system to track the changes that have been made for each issue.
+ </para>
+ <para>
+ Also, any single SVN commit should apply to one and only one JIRA issue. Doing this helps ensure that each commit is atomic
+ and focused on a single activity. There are exceptions to this rule, but they are rare.
+ </para>
+ <para>
+ Sometimes you may have some local changes that you don't want to (or aren't allowed to) commit. You can make a patch file
+ and upload it to the JIRA issue, allowing other committers to review the patch. However, to ensure that patches are easily
+ applied, please use SVN to create the patch. To do this, simply do the following in the top of the codebase (e.g., the
+ <code>trunk</code> directory):
+ </para>
+ <programlisting>$ svn diff . > ~/DNA-000.patch</programlisting>
+ <para>
+ where <code>DNA-000</code> represents the DNA issue number. Note that the above command places the patch file in your home directory,
+ but you can place the patch file anywhere. Then, simply use JIRA to attach the patch file to the particular issue, also adding
+ a comment that describes the version number against which the patch was created.
+ </para>
+ <para>
+ To apply a patch, you usually want to start with a workspace that has no changes. Download the patch file, then issue the
+ following command (again, from the top-level of the workspace):
+ </para>
+ <programlisting>$ patch -E -p0 < ~/DNA-000.patch</programlisting>
+ <para>
+ The "-E" option specifies to delete any files that were made empty by the application of the patch, and the "-p0" option instructs
+ the patch tool to not change any of the paths. After you run this command, your working area should have the changes defined
+ by the patch.
+ </para>
+ </sect1>
+ <sect1 id="maven">
+ <title>Maven</title>
+ <para>JBoss DNA uses Maven 2 for its build system, as is this example. Using Maven 2 has several advantages, including
+ the ability to manage dependencies. If a library is needed, Maven automatically finds and downloads that library, plus
+ everything that library needs. This means that it's very easy to build the examples - or even create a maven project that
+ depends on the JBoss DNA JARs.</para>
+ <para>
+ To use Maven with JBoss DNA, you'll need to have <link linkend="jdk">JDK 5 or 6</link> and Maven 2.0.9 (or higher).</para>
+ <para>
+ Maven can be downloaded from <ulink url="http://maven.apache.org/">http://maven.apache.org/</ulink>, and is installed by unzipping the
+ <code>maven-2.0.9-bin.zip</code> file to a convenient location on your local disk. Simply add <code>$MAVEN_HOME/bin</code>
+ to your path and add the following profile to your <code>~/.m2/settings.xml</code> file:
+ </para>
+ <programlisting role="XML"><![CDATA[
+<settings>
+ <profiles>
+ <profile>
+ <id>jboss.repository</id>
+ <activation>
+ <property>
+ <name>!jboss.repository.off</name>
+ </property>
+ </activation>
+ <repositories>
+ <repository>
+ <id>snapshots.jboss.org</id>
+ <url>http://snapshots.jboss.org/maven2</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ <repository>
+ <id>repository.jboss.org</id>
+ <url>http://repository.jboss.org/maven2</url>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>repository.jboss.org</id>
+ <url>http://repository.jboss.org/maven2</url>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </pluginRepository>
+ <pluginRepository>
+ <id>snapshots.jboss.org</id>
+ <url>http://snapshots.jboss.org/maven2</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </pluginRepository>
+ </pluginRepositories>
+ </profile>
+ </profiles>
+</settings>
+]]></programlisting>
+ <para>This profile informs Maven of the two JBoss repositories (<ulink url="http://repository.jboss.org/maven2">snapshots</ulink>
+ and <ulink url="http://snapshots.jboss.org/maven2">releases</ulink>) that contain all of the JARs for JBoss DNA and all dependent libraries.
+ </para>
+ <para>While you're adding <code>$MAVEN_HOME/bin</code> to your path, you should also set the <code>$MAVEN_OPTS</code> environment variable
+ to "<code>-Xmx256m</code>". If you don't do this, you'll likely see an <code>java.lang.OutOfMemoryError</code> sometime during a full
+ build.
+ </para>
+ <note>
+ <para>
+ The JBoss Maven repository provides a central location for not only the artifacts produced by the JBoss.org projects (well, at least those
+ that use Maven), but also is where those projects can place the artifacts that they depend on. JBoss DNA has a policy that
+ the <emphasis>source code and JARs</emphasis> for <emphasis>all</emphasis> dependencies <emphasis>must</emphasis> be loaded into the
+ JBoss Maven repository. It may be a little bit more work for the developers, but it does help ensure that developers have easy
+ access to the source and that the project (and dependencies) can always be rebuilt when needed.
+ </para>
+ <para>
+ For more information about the JBoss Maven repository, including instructions for adding source and JAR artifacts,
+ see the <ulink url="http://wiki.jboss.org/wiki/Maven">JBoss.org Wiki</ulink>.
+ </para>
+ </note>
+ <para>
+ There are just a few commands that are useful for building JBoss DNA (and it's <link linkend="modules">subprojects</link>).
+ Usually, these are issued while at the top level of the code (usually just below <code>trunk/</code>), although issuing
+ them inside a subproject just applies to that subproject.
+ </para>
+ <table frame='all'>
+ <title>Useful Maven commands</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Command</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><code>mvn clean</code></entry>
+ <entry>Clean up all built artifacts (e.g., the <code>target/</code> directory in each project)</entry>
+ </row>
+ <row>
+ <entry><code>mvn clean install</code></entry>
+ <entry>Clean up all built artifacts, then compile, run the unit tests, and install the resulting JAR artifact(s)
+ into your local Maven repository (e.g, usually <code>~/.m2/repository</code>).
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+ <sect1 id="hudson">
+ <title>Continuous integration with Hudson</title>
+ <para>JBoss DNA's continuous integration is done with several Hudson jobs on <ulink url="http://www.jboss.org">JBoss.org</ulink>.
+ These jobs run periodically and basically run the Maven build process. Any build failures or test failures are reported,
+ as are basic statistics and history for each job.
+ </para>
+ <table frame='all'>
+ <title>Continuous integration jobs</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Job</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><ulink url="http://hudson.jboss.org/hudson/job/DNA%20continuous%20on%20JDK1.5/">Continuous on JDK 5</ulink></entry>
+ <entry>Continuous build that runs after changes are committed to SVN. SVN is polled every 15 minutes.</entry>
+ </row>
+ <row>
+ <entry><ulink url="http://hudson.jboss.org/hudson/job/DNA%20nightly%20integration%20on%20JDK...">Nightly on JDK 5</ulink></entry>
+ <entry>Build that runs every night (usually around 2 a.m. EDT), regardless of whether changes have been committed to SVN
+ since the previous night.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+ <sect1 id="eclipse">
+ <title>Eclipse IDE</title>
+ <para>Many of the JBoss DNA committers use the Eclipse IDE, and all project files required by Eclipse are committed in SVN, making
+ it pretty easy to get an Eclipse workspace running with all of the JBoss DNA projects.
+ Many of the JBoss DNA committers use the Eclipse IDE, and all project files required by Eclipse are committed in SVN, making
+ it pretty easy to get an Eclipse workspace running with all of the JBoss DNA projects.
+ </para>
+ <para>We're using the latest released version of Eclipse (3.4, called "Ganymede"),
+ available from <ulink url="http://www.eclipse.org/">Eclipse.org</ulink>. Simply follow the instructions for your platform.
+ </para>
+ <para>
+ After Eclipse is installed, create a new workspace. Before importing the JBoss DNA projects, import (via
+ <emphasis role="strong">File->Import->Preferences</emphasis>) the subset of the Eclipse preferences by importing the
+ <code>eclipse-preferences.epf</code> file (located under <code>trunk</code>). Then, open the Eclipse preferences and
+ open the <emphasis role="strong">Java->Code Style-> Formatter</emphasis> preference page, and press the "Import" button and
+ choose the <code>eclipse-code-formatter-profile.xml</code> file (also located under <code>trunk</code>). This will load the code
+ formatting preferences for the JBoss DNA project.
+ </para>
+ <para>
+ Then install Eclipse plugins for SVN and Maven. (Remember, you will have to restart Eclipse after installing them.)
+ We use the following plugins:
+ </para>
+ <table frame='all'>
+ <title>Eclipse Subversion Plugins</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Eclipse Plugins</entry>
+ <entry>Update Site URLs</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>Subversive SVN Client</entry>
+ <entry>
+ <ulink url="http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-s...">http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-s...</ulink>
+ <ulink url="http://www.polarion.org/projects/subversive/download/integrations/update-...">http://www.polarion.org/projects/subversive/download/integrations/update-...</ulink>
+ </entry>
+ </row>
+ <row>
+ <entry>Maven Integration for Eclipse</entry>
+ <entry><ulink url="http://m2eclipse.sonatype.org/update/">http://m2eclipse.sonatype.org/update/</ulink></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>
+ After you check out the JBoss DNA codebase, you can import the JBoss DNA Maven projects into Eclipse as Eclipse projects.
+ To do this, go to "File->Import->Existing Projects", navigate to the <code>trunk/</code> folder in the import wizard,
+ and then check each of the <link linkend="modules">subprojects</link> that you want to have in your workspace.
+ Don't forget about the projects under <code>extensions/</code> or <code>docs/</code>.
+ </para>
+ </sect1>
+ <sect1 id="releasing">
+ <title>Releasing</title>
+ <para>
+ This section outlines the basic process of releasing JBoss DNA. This <emphasis role="strong">must</emphasis> be done
+ either by the project lead or only after communicating with the project lead.
+ </para>
+ <para>
+ Before continuing, your local workspace should contain no changes and should be a perfect reflection of Subversion.
+ You can verify this by getting the latest from Subversion
+ </para>
+ <programlisting>$ svn update</programlisting>
+ <para>
+ and ensuring that you have no additional changes with
+ </para>
+ <programlisting>$ svn status</programlisting>
+ <para>
+ You may also want to note the revision number for use later on in the process. The release number is returned by
+ the <code>svn update</code> command, but may also be found using
+ </para>
+ <programlisting>$ svn info</programlisting>
+ <para>
+ At this point, you're ready to verify that everything builds normally.
+ </para>
+ <sect2 id="build-all-artifacts-and-assemblies">
+ <title>Building all artifacts and assemblies</title>
+ <para>
+ By default, the project's Maven build process is does <emphasis>not</emphasis> build the documentation, JavaDocs, or assemblies.
+ These take extra time, and most of our builds don't require them. So the first step of releasing JBoss DNA
+ is to use Maven to build all of regular artifacts (e.g., JARs) and these extra documents and assemblies.
+ </para>
+ <note>
+ <para>
+ Before running Maven commands to build the releases, increase the memory available to Maven with this command:
+ <code>$ export MAVEN_OPTS=-Xmx256m</code>
+ </para>
+ </note>
+ <para>
+ To perform this complete build, issue the following command while in the <code>target/</code> directory:
+ </para>
+ <programlisting>$ mvn -P assembly clean javadoc:javadoc install</programlisting>
+ <para>
+ This command runs the "clean", "javadoc:javadoc", and "install" goals using the "assembly" profile,
+ which adds the production of JavaDocs, the Getting Started document, the Reference Guide document,
+ the Getting Started examples, and several ZIP archives. The order of the goals is important,
+ since the "install" goal attempts to include the JavaDoc in the archives.
+ </para>
+ <para>
+ After this build has completed, verify that the assemblies under <code>target/</code> have actually been created and that
+ they contain the correct information.
+ At this point, we know that the actual Maven build process is building
+ everything we want and will complete without errors. We can now proceed with preparing for the release.
+ </para>
+ </sect2>
+ <sect2 id="determine-version">
+ <title>Determine the version to be released</title>
+ <para>
+ The version being released should match the <ulink url="&JIRA;">JIRA</ulink> road map. Make sure that all issues related to the release are closed.
+ The project lead should be notified and approve that the release is taking place.
+ </para>
+ </sect2>
+ <sect2 id="release-dry-run">
+ <title>Release dry run</title>
+ <para>
+ The next step is to ensure that all information in the POM is correct and contains all the information required for
+ the release process. This is called a <emphasis>dry run</emphasis>, and is done with the Maven "release" plugin:
+ </para>
+ <programlisting>$ mvn -Passembly release:prepare -DdryRun=true</programlisting>
+ <para>
+ This may download a lot of Maven plugins if they already haven't been downloaded, but it will eventually prompt you for
+ the release version of each of the Maven projects, the tag name for the release, and the next development versions
+ (again for each of the Maven projects). The default values are probably acceptable; if not, then check that the
+ "<code><version></code>" tags in each of the POM files is correct and end with "-SNAPSHOT".
+ </para>
+ <para>
+ After the dry run completes you should clean up the files that the release plugin created in the dry run:
+ </para>
+ <programlisting>$ mvn -Passembly release:clean</programlisting>
+ </sect2>
+ <sect2 id="prepare-release">
+ <title>Prepare for the release</title>
+ <para>
+ Run the prepare step (without the <code>dryRun</code> option):
+ </para>
+ <programlisting>$ mvn -Passembly release:prepare</programlisting>
+ <para>
+ You will again be prompted for the release versions and tag name. These should be the same as what was used during the dry run.
+ This will run the same steps as the dry run, with the additional step of tagging the release in SVN.
+ </para>
+ <para>
+ If there are any problems during this step, you should go back and try the dry run option. But after this runs successfully,
+ the release will be tagged in SVN, and the <code>pom.xml</code> files in SVN under <code>/trunk</code> will have the
+ next version in the "<version>" values.
+ However, the artifacts for the release are not yet published. That's the next step.
+ </para>
+ </sect2>
+ <sect2 id="release">
+ <title>Perform the release</title>
+ <para>
+ At this point, the release's artifacts need to be published to the JBoss Maven repository. This next command check outs the
+ files from the release tag created earlier (into a <code>trunk/target/checkout</code> directory), runs a build, and then
+ deploys the generated artifacts. Note that this ensures that the artifacts are built from the tagged code.
+ </para>
+ <programlisting>$ mvn release:perform -DuseReleaseProfile=false</programlisting>
+ <note>
+ <para>
+ If during this process you get an error finding the released artifacts in your local Maven repository, you may
+ need to go into the <code>trunk/target/checkout</code> folder and run <code>$ mvn install</code>. This is a simple
+ workaround to make the artifacts available locally. Another option to try is adding <code>-Dgoals=install,assembly</code>
+ to the <code>$ mvn release:perform... </code> command above.
+ </para>
+ </note>
+ <para>
+ The artifacts are deployed to the local file system, which is comprised of a local checkout of the JBoss Maven2 repository
+ in a location specified by a combination of the <code><distributionManagement></code> section of several <code>pom.xml</code>
+ files and your personal <code>settings.xml</code> file. Once this Maven command completes, you will need to
+ commit the new files after they are deployed. For more information, see the
+ <ulink url="http://wiki.jboss.org/wiki/Maven">JBoss wiki</ulink>.
+ </para>
+ <para>
+ At this point, the software has been released and tagged, and it's been deployed to a local checked-out copy of the
+ JBoss DNA Maven 2 repository (via the "<distribution>" section of the pom.xml files). Those need to be committed
+ into the Maven 2 repository using SVN. And finally, the last thing is to publish the release onto
+ the project's <ulink url="&Downloads;">downloads</ulink> and <ulink url="&Home;/docs">documentation</ulink> pages.
+ </para>
+ <para>
+ The assemblies of the source, binaries, etc. also need to be published onto the &Downloads; area of the
+ <ulink url="http://www.jboss.org/dna">the project page</ulink>. This process is expected to change, as <ulink url="http://www.jboss.org">JBoss.org</ulink>
+ improves its infrastructure.
+ </para>
+ </sect2>
+ </sect1>
+ <sect1>
+ <title>Summary</title>
+ <para>
+ In this chapter, we described the various aspects of developing code for the JBoss DNA project. Before we start talking
+ about some of the details of JBoss DNA repositories, connectors, and sequencers, we'll first talk about
+ some very ubiquitous information: how does JBoss DNA load all of the extension classes?
+ This is the topic of the <link linkend="classloaders">next chapter</link>.
+ </para>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/developers/tools.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml 2009-06-08 00:52:09 UTC (rev 994)
+++ trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -1,502 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
-%CustomDTD;
-]>
-<chapter id="development-tools">
- <title>Developer tools</title>
- <para>
- The JBoss DNA project uses <link linkend="maven">Maven</link> as its primary build tool, <link linkend="svn">Subversion</link>
- for its source code repository, <link linkend="jira">JIRA</link> for the issue management and bug tracking system,
- and <link linkend="hudson">Hudson</link> for the continuous integration system. We do not stipulate a specific integrated
- development environment (IDE), although most of us use <link linkend="eclipse">Eclipse</link> and rely upon the code formatting
- and compile preferences to ensure no warnings or errors.
- </para>
- <para>
- The rest of this chapter talks in more detail about these different tools and how to set them up.
- </para>
- <sect1 id="jdk">
- <title>JDK</title>
- <para>
- Currently, JBoss DNA is developed and built using <ulink url="http://java.sun.com/javase/downloads/index_jdk5.jsp">JDK 5</ulink>.
- So if you're trying to get JBoss DNA to compile locally, you should make sure you have the JDK 5 installed and are using it.
- If you're a contributor, you should make sure that you're using JDK 5 before committing any changes.
- </para>
- <note>
- <para>
- You should be able to use the <ulink url="http://java.sun.com/javase/downloads/index.jsp">latest JDK</ulink>,
- which is currently JDK 6. It is possible to build JBoss DNA using JDK 6 without any code changes, but it's
- not our official JDK (yet).
- </para>
- <para>
- Why do we build using JDK 5 and not 6? The main reason is that if we were to use JDK 6, then JBoss DNA couldn't really be used in any
- applications or projects that still used JDK 5. Plus, anybody using JDK 6 can still use JBoss DNA.
- However, considering that the end-of-life for Java 5 is
- <ulink url="http://java.sun.com/products/archive/eol.policy.html">October 2009</ulink>, we may be switching to
- Java 6 sometime in 2009.
- </para>
- </note>
- <para>
- When installing a JDK, simply follow the procedure for your particular platform. On most platforms, this should set the
- <code>JAVA_HOME</code> environment variable. But if you run into any problems, first check that this environment
- variable was set to the correct location, and then check that you're running the version you expect by running
- the following command:
- </para>
- <programlisting>$ java -version</programlisting>
- <para>
- If you don't see the correct version, double-check your JDK installation.
- </para>
- </sect1>
- <sect1 id="jira">
- <title>JIRA</title>
- <para>
- JBoss DNA uses <ulink url="&JIRA;">JIRA</ulink> as its bug tracking, issue tracking, and project management tool.
- This is a browser-based tool, with very good functionality for managing the different tasks. It also serves as
- the community's roadmap, since we can define new features and manage them along side the bugs and other issues.
- Although most of the issues have been created by community members, we encourage any users to suggest new features,
- log defects, or identify shortcomings in JBoss DNA.
- </para>
- <para>
- The JBoss DNA community also encourages its members to work only issues that are managed in JIRA, and preferably those
- that are targeted to the current release effort. If something isn't in JIRA but needs to get done, then create an
- issue before you start working on the code changes. Once you have code changes, you can upload a patch to the JIRA issue
- if the change is complex, if you want someone to review it, or if you don't have commit privileges and have fixed
- a bug.
- </para>
- </sect1>
- <sect1 id="svn">
- <title>Subversion</title>
- <para>JBoss DNA uses Subversion as its source code management system, and specifically the instance at
- <ulink url="http://www.jboss.org">JBoss.org</ulink>. Although you can view the
- <ulink url="&Subversion;trunk/">trunk</ulink> of the Subversion repository directly
- (or using <ulink url="&Fisheye;trunk">FishEye</ulink>) through your browser,
- it order to get more than just a few files of the latest version of the source code, you probably want
- to have an SVN client installed. Several IDE's have SVN support included (or available as plugins),
- but having the command-line SVN client is recommended. See
- <ulink url="http://subversion.tigris.org/">http://subversion.tigris.org/</ulink> for downloads and instructions for your
- particular platform.
- </para>
- <para>
- Here are some useful URLs for the JBoss DNA Subversion:
- </para>
- <table frame='all'>
- <title>SVN URLs for JBoss DNA</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Repository</entry>
- <entry>URL</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>Anonymous Access URL</entry>
- <entry><ulink url="&Subversion;trunk/">&Subversion;trunk/</ulink></entry>
- </row>
- <row>
- <entry>Secure Developer Access URL</entry>
- <entry><ulink url="&Fisheye;trunk/">&Fisheye;trunk/</ulink></entry>
- </row>
- <row>
- <entry>FishEye Code Browser</entry>
- <entry><ulink url="&SecureSubversion;trunk/">&SecureSubversion;trunk/</ulink></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>
- When committing to SVN, be sure to include in a commit comment that includes the JIRA issue that the commit applies to and a very
- good and thorough description of what was done. It only takes a minute or two to be very clear about the change. And including
- the JIRA issue (e.g., "DNA-123") in the comment allows the JIRA system to track the changes that have been made for each issue.
- </para>
- <para>
- Also, any single SVN commit should apply to one and only one JIRA issue. Doing this helps ensure that each commit is atomic
- and focused on a single activity. There are exceptions to this rule, but they are rare.
- </para>
- <para>
- Sometimes you may have some local changes that you don't want to (or aren't allowed to) commit. You can make a patch file
- and upload it to the JIRA issue, allowing other committers to review the patch. However, to ensure that patches are easily
- applied, please use SVN to create the patch. To do this, simply do the following in the top of the codebase (e.g., the
- <code>trunk</code> directory):
- </para>
- <programlisting>$ svn diff . > ~/DNA-000.patch</programlisting>
- <para>
- where <code>DNA-000</code> represents the DNA issue number. Note that the above command places the patch file in your home directory,
- but you can place the patch file anywhere. Then, simply use JIRA to attach the patch file to the particular issue, also adding
- a comment that describes the version number against which the patch was created.
- </para>
- <para>
- To apply a patch, you usually want to start with a workspace that has no changes. Download the patch file, then issue the
- following command (again, from the top-level of the workspace):
- </para>
- <programlisting>$ patch -E -p0 < ~/DNA-000.patch</programlisting>
- <para>
- The "-E" option specifies to delete any files that were made empty by the application of the patch, and the "-p0" option instructs
- the patch tool to not change any of the paths. After you run this command, your working area should have the changes defined
- by the patch.
- </para>
- </sect1>
- <sect1 id="maven">
- <title>Maven</title>
- <para>JBoss DNA uses Maven 2 for its build system, as is this example. Using Maven 2 has several advantages, including
- the ability to manage dependencies. If a library is needed, Maven automatically finds and downloads that library, plus
- everything that library needs. This means that it's very easy to build the examples - or even create a maven project that
- depends on the JBoss DNA JARs.</para>
- <para>
- To use Maven with JBoss DNA, you'll need to have <link linkend="jdk">JDK 5 or 6</link> and Maven 2.0.9 (or higher).</para>
- <para>
- Maven can be downloaded from <ulink url="http://maven.apache.org/">http://maven.apache.org/</ulink>, and is installed by unzipping the
- <code>maven-2.0.9-bin.zip</code> file to a convenient location on your local disk. Simply add <code>$MAVEN_HOME/bin</code>
- to your path and add the following profile to your <code>~/.m2/settings.xml</code> file:
- </para>
- <programlisting role="XML"><![CDATA[
-<settings>
- <profiles>
- <profile>
- <id>jboss.repository</id>
- <activation>
- <property>
- <name>!jboss.repository.off</name>
- </property>
- </activation>
- <repositories>
- <repository>
- <id>snapshots.jboss.org</id>
- <url>http://snapshots.jboss.org/maven2</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </repository>
- <repository>
- <id>repository.jboss.org</id>
- <url>http://repository.jboss.org/maven2</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </repository>
- </repositories>
- <pluginRepositories>
- <pluginRepository>
- <id>repository.jboss.org</id>
- <url>http://repository.jboss.org/maven2</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </pluginRepository>
- <pluginRepository>
- <id>snapshots.jboss.org</id>
- <url>http://snapshots.jboss.org/maven2</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </pluginRepository>
- </pluginRepositories>
- </profile>
- </profiles>
-</settings>
-]]></programlisting>
- <para>This profile informs Maven of the two JBoss repositories (<ulink url="http://repository.jboss.org/maven2">snapshots</ulink>
- and <ulink url="http://snapshots.jboss.org/maven2">releases</ulink>) that contain all of the JARs for JBoss DNA and all dependent libraries.
- </para>
- <para>While you're adding <code>$MAVEN_HOME/bin</code> to your path, you should also set the <code>$MAVEN_OPTS</code> environment variable
- to "<code>-Xmx256m</code>". If you don't do this, you'll likely see an <code>java.lang.OutOfMemoryError</code> sometime during a full
- build.
- </para>
- <note>
- <para>
- The JBoss Maven repository provides a central location for not only the artifacts produced by the JBoss.org projects (well, at least those
- that use Maven), but also is where those projects can place the artifacts that they depend on. JBoss DNA has a policy that
- the <emphasis>source code and JARs</emphasis> for <emphasis>all</emphasis> dependencies <emphasis>must</emphasis> be loaded into the
- JBoss Maven repository. It may be a little bit more work for the developers, but it does help ensure that developers have easy
- access to the source and that the project (and dependencies) can always be rebuilt when needed.
- </para>
- <para>
- For more information about the JBoss Maven repository, including instructions for adding source and JAR artifacts,
- see the <ulink url="http://wiki.jboss.org/wiki/Maven">JBoss.org Wiki</ulink>.
- </para>
- </note>
- <para>
- There are just a few commands that are useful for building JBoss DNA (and it's <link linkend="modules">subprojects</link>).
- Usually, these are issued while at the top level of the code (usually just below <code>trunk/</code>), although issuing
- them inside a subproject just applies to that subproject.
- </para>
- <table frame='all'>
- <title>Useful Maven commands</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Command</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><code>mvn clean</code></entry>
- <entry>Clean up all built artifacts (e.g., the <code>target/</code> directory in each project)</entry>
- </row>
- <row>
- <entry><code>mvn clean install</code></entry>
- <entry>Clean up all built artifacts, then compile, run the unit tests, and install the resulting JAR artifact(s)
- into your local Maven repository (e.g, usually <code>~/.m2/repository</code>).
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect1>
- <sect1 id="hudson">
- <title>Continuous integration with Hudson</title>
- <para>JBoss DNA's continuous integration is done with several Hudson jobs on <ulink url="http://www.jboss.org">JBoss.org</ulink>.
- These jobs run periodically and basically run the Maven build process. Any build failures or test failures are reported,
- as are basic statistics and history for each job.
- </para>
- <table frame='all'>
- <title>Continuous integration jobs</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Job</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><ulink url="http://hudson.jboss.org/hudson/job/DNA%20continuous%20on%20JDK1.5/">Continuous on JDK 5</ulink></entry>
- <entry>Continuous build that runs after changes are committed to SVN. SVN is polled every 15 minutes.</entry>
- </row>
- <row>
- <entry><ulink url="http://hudson.jboss.org/hudson/job/DNA%20nightly%20integration%20on%20JDK...">Nightly on JDK 5</ulink></entry>
- <entry>Build that runs every night (usually around 2 a.m. EDT), regardless of whether changes have been committed to SVN
- since the previous night.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect1>
- <sect1 id="eclipse">
- <title>Eclipse IDE</title>
- <para>Many of the JBoss DNA committers use the Eclipse IDE, and all project files required by Eclipse are committed in SVN, making
- it pretty easy to get an Eclipse workspace running with all of the JBoss DNA projects.
- Many of the JBoss DNA committers use the Eclipse IDE, and all project files required by Eclipse are committed in SVN, making
- it pretty easy to get an Eclipse workspace running with all of the JBoss DNA projects.
- </para>
- <para>We're using the latest released version of Eclipse (3.4, called "Ganymede"),
- available from <ulink url="http://www.eclipse.org/">Eclipse.org</ulink>. Simply follow the instructions for your platform.
- </para>
- <para>
- After Eclipse is installed, create a new workspace. Before importing the JBoss DNA projects, import (via
- <emphasis role="strong">File->Import->Preferences</emphasis>) the subset of the Eclipse preferences by importing the
- <code>eclipse-preferences.epf</code> file (located under <code>trunk</code>). Then, open the Eclipse preferences and
- open the <emphasis role="strong">Java->Code Style-> Formatter</emphasis> preference page, and press the "Import" button and
- choose the <code>eclipse-code-formatter-profile.xml</code> file (also located under <code>trunk</code>). This will load the code
- formatting preferences for the JBoss DNA project.
- </para>
- <para>
- Then install Eclipse plugins for SVN and Maven. (Remember, you will have to restart Eclipse after installing them.)
- We use the following plugins:
- </para>
- <table frame='all'>
- <title>Eclipse Subversion Plugins</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Eclipse Plugins</entry>
- <entry>Update Site URLs</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>Subversive SVN Client</entry>
- <entry>
- <ulink url="http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-s...">http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-s...</ulink>
- <ulink url="http://www.polarion.org/projects/subversive/download/integrations/update-...">http://www.polarion.org/projects/subversive/download/integrations/update-...</ulink>
- </entry>
- </row>
- <row>
- <entry>Maven Integration for Eclipse</entry>
- <entry><ulink url="http://m2eclipse.sonatype.org/update/">http://m2eclipse.sonatype.org/update/</ulink></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>
- After you check out the JBoss DNA codebase, you can import the JBoss DNA Maven projects into Eclipse as Eclipse projects.
- To do this, go to "File->Import->Existing Projects", navigate to the <code>trunk/</code> folder in the import wizard,
- and then check each of the <link linkend="modules">subprojects</link> that you want to have in your workspace.
- Don't forget about the projects under <code>extensions/</code> or <code>docs/</code>.
- </para>
- </sect1>
- <sect1 id="releasing">
- <title>Releasing</title>
- <para>
- This section outlines the basic process of releasing JBoss DNA. This <emphasis role="strong">must</emphasis> be done
- either by the project lead or only after communicating with the project lead.
- </para>
- <para>
- Before continuing, your local workspace should contain no changes and should be a perfect reflection of Subversion.
- You can verify this by getting the latest from Subversion
- </para>
- <programlisting>$ svn update</programlisting>
- <para>
- and ensuring that you have no additional changes with
- </para>
- <programlisting>$ svn status</programlisting>
- <para>
- You may also want to note the revision number for use later on in the process. The release number is returned by
- the <code>svn update</code> command, but may also be found using
- </para>
- <programlisting>$ svn info</programlisting>
- <para>
- At this point, you're ready to verify that everything builds normally.
- </para>
- <sect2 id="build-all-artifacts-and-assemblies">
- <title>Building all artifacts and assemblies</title>
- <para>
- By default, the project's Maven build process is does <emphasis>not</emphasis> build the documentation, JavaDocs, or assemblies.
- These take extra time, and most of our builds don't require them. So the first step of releasing JBoss DNA
- is to use Maven to build all of regular artifacts (e.g., JARs) and these extra documents and assemblies.
- </para>
- <note>
- <para>
- Before running Maven commands to build the releases, increase the memory available to Maven with this command:
- <code>$ export MAVEN_OPTS=-Xmx256m</code>
- </para>
- </note>
- <para>
- To perform this complete build, issue the following command while in the <code>target/</code> directory:
- </para>
- <programlisting>$ mvn -P assembly clean javadoc:javadoc install</programlisting>
- <para>
- This command runs the "clean", "javadoc:javadoc", and "install" goals using the "assembly" profile,
- which adds the production of JavaDocs, the Getting Started document, the Reference Guide document,
- the Getting Started examples, and several ZIP archives. The order of the goals is important,
- since the "install" goal attempts to include the JavaDoc in the archives.
- </para>
- <para>
- After this build has completed, verify that the assemblies under <code>target/</code> have actually been created and that
- they contain the correct information.
- At this point, we know that the actual Maven build process is building
- everything we want and will complete without errors. We can now proceed with preparing for the release.
- </para>
- </sect2>
- <sect2 id="determine-version">
- <title>Determine the version to be released</title>
- <para>
- The version being released should match the <ulink url="&JIRA;">JIRA</ulink> road map. Make sure that all issues related to the release are closed.
- The project lead should be notified and approve that the release is taking place.
- </para>
- </sect2>
- <sect2 id="release-dry-run">
- <title>Release dry run</title>
- <para>
- The next step is to ensure that all information in the POM is correct and contains all the information required for
- the release process. This is called a <emphasis>dry run</emphasis>, and is done with the Maven "release" plugin:
- </para>
- <programlisting>$ mvn -Passembly release:prepare -DdryRun=true</programlisting>
- <para>
- This may download a lot of Maven plugins if they already haven't been downloaded, but it will eventually prompt you for
- the release version of each of the Maven projects, the tag name for the release, and the next development versions
- (again for each of the Maven projects). The default values are probably acceptable; if not, then check that the
- "<code><version></code>" tags in each of the POM files is correct and end with "-SNAPSHOT".
- </para>
- <para>
- After the dry run completes you should clean up the files that the release plugin created in the dry run:
- </para>
- <programlisting>$ mvn -Passembly release:clean</programlisting>
- </sect2>
- <sect2 id="prepare-release">
- <title>Prepare for the release</title>
- <para>
- Run the prepare step (without the <code>dryRun</code> option):
- </para>
- <programlisting>$ mvn -Passembly release:prepare</programlisting>
- <para>
- You will again be prompted for the release versions and tag name. These should be the same as what was used during the dry run.
- This will run the same steps as the dry run, with the additional step of tagging the release in SVN.
- </para>
- <para>
- If there are any problems during this step, you should go back and try the dry run option. But after this runs successfully,
- the release will be tagged in SVN, and the <code>pom.xml</code> files in SVN under <code>/trunk</code> will have the
- next version in the "<version>" values.
- However, the artifacts for the release are not yet published. That's the next step.
- </para>
- </sect2>
- <sect2 id="release">
- <title>Perform the release</title>
- <para>
- At this point, the release's artifacts need to be published to the JBoss Maven repository. This next command check outs the
- files from the release tag created earlier (into a <code>trunk/target/checkout</code> directory), runs a build, and then
- deploys the generated artifacts. Note that this ensures that the artifacts are built from the tagged code.
- </para>
- <programlisting>$ mvn release:perform -DuseReleaseProfile=false</programlisting>
- <note>
- <para>
- If during this process you get an error finding the released artifacts in your local Maven repository, you may
- need to go into the <code>trunk/target/checkout</code> folder and run <code>$ mvn install</code>. This is a simple
- workaround to make the artifacts available locally. Another option to try is adding <code>-Dgoals=install,assembly</code>
- to the <code>$ mvn release:perform... </code> command above.
- </para>
- </note>
- <para>
- The artifacts are deployed to the local file system, which is comprised of a local checkout of the JBoss Maven2 repository
- in a location specified by a combination of the <code><distributionManagement></code> section of several <code>pom.xml</code>
- files and your personal <code>settings.xml</code> file. Once this Maven command completes, you will need to
- commit the new files after they are deployed. For more information, see the
- <ulink url="http://wiki.jboss.org/wiki/Maven">JBoss wiki</ulink>.
- </para>
- <para>
- At this point, the software has been released and tagged, and it's been deployed to a local checked-out copy of the
- JBoss DNA Maven 2 repository (via the "<distribution>" section of the pom.xml files). Those need to be committed
- into the Maven 2 repository using SVN. And finally, the last thing is to publish the release onto
- the project's <ulink url="&Downloads;">downloads</ulink> and <ulink url="&Home;/docs">documentation</ulink> pages.
- </para>
- <para>
- The assemblies of the source, binaries, etc. also need to be published onto the &Downloads; area of the
- <ulink url="http://www.jboss.org/dna">the project page</ulink>. This process is expected to change, as <ulink url="http://www.jboss.org">JBoss.org</ulink>
- improves its infrastructure.
- </para>
- </sect2>
- </sect1>
- <sect1>
- <title>Summary</title>
- <para>
- In this chapter, we described the various aspects of developing code for the JBoss DNA project. Before we start talking
- about some of the details of JBoss DNA repositories, connectors, and sequencers, we'll first talk about
- some very ubiquitous information: how does JBoss DNA load all of the extension classes?
- This is the topic of the <link linkend="classloaders">next chapter</link>.
- </para>
- </sect1>
-</chapter>
Deleted: trunk/docs/reference/src/main/docbook/en-US/content/environment.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/environment.xml 2009-06-08 00:52:09 UTC (rev 994)
+++ trunk/docs/reference/src/main/docbook/en-US/content/environment.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -1,310 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
-%CustomDTD;
-]>
-<chapter id="environment">
- <title>Environment</title>
- <para>
- The various components of JBoss DNA are designed as plain old Java objects, or POJOs. And rather than making assumptions
- about their environment, each component instead requires that any external dependencies necessary for it to operate
- must be supplied to it. This pattern is known as Dependency Injection, and it allows the components to be simpler
- and allows for a great deal of flexibility and customization in how the components are configured.
- And, JBoss DNA will soon provide a higher-level component that leverages the
- <ulink url="http://www.jboss.org/jbossmc">JBoss Microcontainer</ulink> to automatically assemble and wire together
- all the lower-level components.
- </para>
- <sect1 id="execution-context">
- <title>Execution contexts</title>
- <para>
- One of the objects that must be supplied to many JBoss DNA components is an &ExecutionContext;. Some components
- require this context to be passed into individual methods, allowing the context to vary with each method invocation.
- Other components require the context to be provided before it's used, and will use that context for all its operations
- (until it is given a different one).
- </para>
- <para>
- What does an &ExecutionContext; represent? Quite simply, it's the set of objects that define the environment
- or context in which the method or component is currently operating. It includes a way for recording and reporting
- errors and problems. It includes the ability to <link linkend="classloaders">create class loaders</link>
- given a classpath of class loader names. It also includes information about the current <link linkend="security">user</link>.
- It includes access to factories that can be used to create and convert property values. And it includes factories
- for working with namespaces and fully-qualified names. In fact, as JBoss DNA evolves, more things may need to be
- added. Here is what the &ExecutionContext; interface looks like:
- </para>
- <programlisting>
-public class &ExecutionContext; implements &ClassLoaderFactory; {
-
- /**
- * Get the factories that should be used to create values for {@link Property properties}.
- * @return the property value factory; never null
- */
- public &ValueFactories; getValueFactories() {...}
-
- /**
- * Get the namespace registry for this context.
- * @return the namespace registry; never null
- */
- public &NamespaceRegistry; getNamespaceRegistry() {...}
-
- /**
- * Get the factory for creating {@link Property} objects.
- * @return the property factory; never null
- */
- public &PropertyFactory; getPropertyFactory() {...}
-
- /**
- * Get the security context for this environment.
- * @return the security context; never <code>null</code>
- */
- public &SecurityContext; getSecurityContext() {...}
-
- /**
- * Return a logger associated with this context. This logger records only those activities within the
- * context and provide a way to capture the context-specific activities. All log messages are also
- * sent to the system logger, so classes that log via this mechanism should <i>not</i> also
- * {@link Logger#getLogger(Class) obtain a system logger}.
- * @param clazz the class that is doing the logging
- * @return the logger, named after <code>clazz</code>; never null
- */
- public &Logger; getLogger( Class<?> clazz ) {...}
-
- /**
- * Return a logger associated with this context. This logger records only those activities within the
- * context and provide a way to capture the context-specific activities. All log messages are also
- * sent to the system logger, so classes that log via this mechanism should <i>not</i> also
- * {@link Logger#getLogger(Class) obtain a system logger}.
- * @param name the name for the logger
- * @return the logger, named after <code>clazz</code>; never null
- */
- public &Logger; getLogger( String name ) {...}
-
- ...
-}
-</programlisting>
- <para>
- Notice that &ExecutionContext; implements the &ClassLoaderFactory; interface described in the
- <link linkend="classloaders">previous chapter</link>, meaning it can be used to create other contexts. These other methods are not shown,
- but can be used to create create subcontexts with different <link linkend="security">security contexts</link>,
- with different namespace registry, or with different combinations of components.
- </para>
- <para>
- The fact that so many of the JBoss DNA components take &ExecutionContext; instances gives us some interesting possibilities.
- For example, one execution context instance can be used as the highest-level (or "application-level") context for all of the services
- (e.g., &RepositoryService;, &SequencingService;, etc.).
- Then, an execution context could be created for each user that will be performing operations, and that user's context can
- be passed around to not only provide security information about the user but also to allow the activities being performed
- to be recorded for user feedback, monitoring and/or auditing purposes.
- </para>
- <para>
- The following code fragment shows how easy it is to create various execution contexts:
- </para>
- <programlisting>
-&ExecutionContext; context1 = new &ExecutionContext;();
-String jaasRealm = ...;
-
-// Create a context for a user, authenticating using a JAAS LoginContext...
-char[] password = "password".toCharArray();
-&SecurityContext; securityContext = new JaasSecurityContext(jaasRealm, "username", password);
-&ExecutionContext; context2 = context1.with(securityContext);
-
-// Create a context for the same user, authenticating using JAAS, and using a different callback handler ...
-&CallbackHandler; callbackHandler = ...
-&ExecutionContext; context3 = context1.with(new JaasSecurityContext(jaasRealm, callbackHandler);
-
-// Create a context that uses a provided &SecurityContext; (see the <link linkend="security">next section</link>)...
-&SecurityContext; mySecurityContext = ...
-&ExecutionContext; context4 = context1.with(mySecurityContext);
-</programlisting>
- <para>
- These contexts can then be passed to the various components as needed.
- </para>
- </sect1>
- <sect1 id="security">
- <title>Security</title>
- <para>
- JBoss DNA uses a simple abstraction layer to isolate it from the security infrastructure used within an application.
- The &SecurityContext; interface is defined as follows:
- </para>
- <programlisting>
-public interface &SecurityContext; {
-
- /**
- * Get the name of the authenticated user.
- * @return the authenticated user's name
- */
- &String; getUserName();
-
- /**
- * Determine whether the authenticated user has the given role.
- * @param roleName the name of the role to check
- * @return true if the user has the role and is logged in; false otherwise
- */
- boolean hasRole( String roleName );
-
- /**
- * Logs the user out of the authentication mechanism.
- * For some authentication mechanisms, this will be implemented as a no-op.
- */
- void logout();
-}
-</programlisting>
- <para>
- As noted below, this security context is made available through the &ExecutionContext; described above.
- </para>
- <sect2 id="jaas_security">
- <title>JAAS</title>
- <para>
- One such implementation is the &JaasSecurityContext;, which delegates any authentication or authorization requests to a
- <ulink url="http://java.sun.com/javase/technologies/security/">Java Authentication and Authorization Service (JAAS)</ulink>
- provider. This is the standard approach for authenticating and authorizing in Java, and is the default mechanism
- used by the &JcrEngine;.
- </para>
- <para>
- There are quite a few JAAS providers available, but one of the best and most powerful providers is
- <ulink url="http://www.jboss.org/jbosssecurity/">JBoss Security</ulink>, the open source
- security framework used by JBoss. JBoss Security offers a number of JAAS login modules, including:
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">User-Roles Login Module</emphasis>
- is a simple
- <code>javax.security.auth.login.LoginContext</code>
- implementation that uses usernames and passwords stored in a properties file.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Client Login Module</emphasis>
- prompts the user for their username and password.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Database Server Login Module</emphasis>
- uses a JDBC database to authenticate principals and associate them with roles.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">LDAP Login Module</emphasis>
- uses an LDAP directory to authenticate principals. Two implementations are available.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Certificate Login Module</emphasis>
- authenticates using X509 certificates, obtaining roles from either property files or a JDBC database.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Operating System Login Module</emphasis>
- authenticates using the operating system's mechanism.
- </para>
- </listitem>
- </itemizedlist>
- and many others. Plus, JBoss Security also provides other capabilities, such as using XACML policies or using federated single sign-on.
- For more detail, see the <ulink url="http://www.jboss.org/jbosssecurity/">JBoss Security</ulink> project.
- </para>
- </sect2>
- <sect2 id="web_security">
- <title>Web application security</title>
- <para>
- If JBoss DNA is being used within a web application, then it is probably desirable to reuse the security infrastructure
- of the application server. This can be accomplished by implementing the &SecurityContext; interface with an implementation
- that delegates to the <interface>HttpServletRequest</interface>. Then, for each request, create a &SecurityContextCredentials;
- instance around your &SecurityContext;, and use that credentials to obtain a JCR &Session;.
- </para>
- <para>
- Here is an example of the &SecurityContext; implementation that uses the servlet request:
- </para>
- <programlisting>
-@Immutable
-public class ServletSecurityContext implements &SecurityContext; {
-
- private final String userName;
- private final HttpServletRequest request;
-
- /**
- * Create a {@link ServletSecurityContext} with the supplied
- * {@link HttpServletRequest servlet information}.
- *
- * @param request the servlet request; may not be null
- */
- public ServletSecurityContext( HttpServletRequest request ) {
- this.request = request;
- this.userName = request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : null;
- }
-
- /**
- * Get the name of the authenticated user.
- * @return the authenticated user's name
- */
- public &String; getUserName() {
- return userName;
- }
-
- /**
- * Determine whether the authenticated user has the given role.
- * @param roleName the name of the role to check
- * @return true if the user has the role and is logged in; false otherwise
- */
- boolean hasRole( String roleName ) {
- request.isUserInRole(roleName);
- }
-
- /**
- * Logs the user out of the authentication mechanism.
- * For some authentication mechanisms, this will be implemented as a no-op.
- */
- public void logout() {
- }
-}</programlisting>
- <para>
- Then use this to create a &Session;:
- </para>
- <programlisting>
-HttpServletRequest request = ...
-&Repository; repository = engine.getRepository("my repository");
-&SecurityContext; securityContext = new ServletSecurityContext(httpServletRequest);
-SecurityContextCredentials credentials = new SecurityContextCredentials(securityContext);
-&Session; session = repository.login(credentials, workspaceName);
-</programlisting>
- </sect2>
- </sect1>
- <sect1>
- <title>Summary</title>
- <para>
- In this chapter, we covered security and environment topics as used throughout JBoss DNA.
- The <link linkend="repositories">next chapter</link> will cover JBoss DNA repositories, including the connector framework,
- how DNA's JCR implementation works with connectors, what connectors are available (and how to use them),
- and how to write your own connector.
- </para>
- </sect1>
-</chapter>
-
Copied: trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml (from rev 994, trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml)
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="jcr">
+ <title>Content Repositories for Java (JCR)</title>
+ <para>
+ The
+ <ulink url="&JSR170;">Content Repository for Java technology API</ulink>
+ provides a standard Java API for working with content repositories. Abbreviated "JCR", this API was developed as part of the
+ Java Community Process under <ulink url="&JSR170;">JSR-170</ulink> (JCR 1.0) and is being revised under <ulink url="&JSR283;">JSR-283</ulink>.
+ 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 <ulink url="&JSR170;">JSR-170</ulink> specification.
+ </para>
+ <sect1 id="jcr-repositories">
+ <title>Obtaining JCR repositories</title>
+ <para>The JCR API doesn't define how your application first obtains a reference to a &Repository; implementation.
+ With JBoss DNA, you simply creating a &JcrRepository; object and supply
+ an &ExecutionContextFactory; and a &RepositoryConnectionFactory; (such as a &RepositoryLibrary; or &RepositoryService;).
+ Since &JcrRepository; implements the JCR &Repository; interface, from this point forward you can just use the
+ standard JCR API.
+ </para>
+ <note>
+ <para>
+ For more information about the &ExecutionContextFactory; and &RepositoryConnectionFactory; classes, see
+ the chapter on <link linkend="environment">setting up a JBoss DNA environment</link> and
+ <link linkend="repositories">setting up the &RepositoryService;</link>.
+ </para>
+ </note>
+ </sect1>
+ <sect1 id="jcr-sessions">
+ <title>Creating JCR sessions</title>
+ <para>Creating sessions is done using a &Repository; one of its <code>login(...)</code> methods, where the
+ name of the workspace corresponds to the name of the &RepositorySource;:
+ </para>
+ <programlisting>
+&JcrRepository; jcrRepository = new &JcrRepository;(contextFactory, sources);
+&Session; session = jcrRepository.login(sourceName);
+</programlisting>
+ <para>
+ Now, this code doesn't do any authentication; it essentially trusts the caller has the appropriate privileges.
+ Normally, your application will need to authenticate the user, so let's look at how that's done.
+ </para>
+ <para>
+ As we mentioned in the <link linkend="security">security section</link>, JBoss DNA uses JAAS for authentication
+ and authorization. So how does this work with the JCR API?
+ </para>
+ <para>The JCR API defines a &Credentials; marker interface, an instance of which can be passed to the
+ <code>&Session;.login(...)</code> method. Rather than provide a concrete implementation of this interface, JBoss DNA
+ allows you to pass any implementation of &Credentials; that also has one of the following methods:
+ <itemizedlist>
+ <listitem>
+ <para><code>getLoginContext()</code> that returns a &LoginContext; instance.</para>
+ </listitem>
+ <listitem>
+ <para><code>getAccessControlContext()</code> that returns a &AccessControlContext; instance.</para>
+ </listitem>
+ </itemizedlist>
+ This way, your application can obtain the JAAS &LoginContext; or &AccessControlContext; however it wants,
+ and then merely passes that into DNA through the JCR &Credentials;. No interfaces or classes specific to JBoss DNA are required.
+ </para>
+ <para>
+ The following code shows how this is done, using an anonymous inner class for the &Credentials; implementation.
+ </para>
+ <programlisting>
+&CallbackHandler; callbackHandler = // as needed by your app, according to JAAS
+final &LoginContext; loginContext = new &LoginContext;("MyAppContextName",callbackHandler);
+
+// Now pass to JBoss DNA to create a JCR Session ...
+&Credentials; credentials = new &Credentials;() {
+public &LoginContext; getLoginContext() { return loginContext; }
+};
+&JcrRepository; jcrRepository = new &JcrRepository;(contextFactory, sources);
+&Session; session = jcrRepository.login(credentials, sourceName);
+</programlisting>
+ </sect1>
+ <sect1>
+ <title>JCR Support</title>
+ <para>
+ JBoss DNA currently supports most of the Level 1 and Level 2 feature set defined by the <ulink url="&JSR170;">JSR-170</ulink> specification.
+ Queries, which are part of Level 1, are not implemented, nor are all of the update methods that make up Level 2.
+ So while the current implementation provides 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.
+ </para>
+ </sect1>
+ <sect1>
+ <title>Summary</title>
+ <para>
+ In this chapter, we covered how to use JCR with JBoss DNA. 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 <link linkend="sequencing">next chapter</link> to describing in detail how the sequencing of file content works.
+ </para>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="rest-service">
+ <title>RESTful Web Service</title>
+ <para>
+ blah blah
+ </para>
+ <sect1>
+ <title>Summary</title>
+ <para>
+ In this chapter, we covered .... something .... FIX ME.
+ </para>
+ </sect1>
+</chapter>
+
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml 2009-06-08 00:52:09 UTC (rev 994)
+++ trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -1,120 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
-%CustomDTD;
-]>
-<chapter id="jcr">
- <title>Content Repositories for Java (JCR)</title>
- <para>
- The
- <ulink url="&JSR170;">Content Repository for Java technology API</ulink>
- provides a standard Java API for working with content repositories. Abbreviated "JCR", this API was developed as part of the
- Java Community Process under <ulink url="&JSR170;">JSR-170</ulink> (JCR 1.0) and is being revised under <ulink url="&JSR283;">JSR-283</ulink>.
- 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 <ulink url="&JSR170;">JSR-170</ulink> specification.
- </para>
- <sect1 id="jcr-repositories">
- <title>Obtaining JCR repositories</title>
- <para>The JCR API doesn't define how your application first obtains a reference to a &Repository; implementation.
- With JBoss DNA, you simply creating a &JcrRepository; object and supply
- an &ExecutionContextFactory; and a &RepositoryConnectionFactory; (such as a &RepositoryLibrary; or &RepositoryService;).
- Since &JcrRepository; implements the JCR &Repository; interface, from this point forward you can just use the
- standard JCR API.
- </para>
- <note>
- <para>
- For more information about the &ExecutionContextFactory; and &RepositoryConnectionFactory; classes, see
- the chapter on <link linkend="environment">setting up a JBoss DNA environment</link> and
- <link linkend="repositories">setting up the &RepositoryService;</link>.
- </para>
- </note>
- </sect1>
- <sect1 id="jcr-sessions">
- <title>Creating JCR sessions</title>
- <para>Creating sessions is done using a &Repository; one of its <code>login(...)</code> methods, where the
- name of the workspace corresponds to the name of the &RepositorySource;:
- </para>
- <programlisting>
-&JcrRepository; jcrRepository = new &JcrRepository;(contextFactory, sources);
-&Session; session = jcrRepository.login(sourceName);
-</programlisting>
- <para>
- Now, this code doesn't do any authentication; it essentially trusts the caller has the appropriate privileges.
- Normally, your application will need to authenticate the user, so let's look at how that's done.
- </para>
- <para>
- As we mentioned in the <link linkend="security">security section</link>, JBoss DNA uses JAAS for authentication
- and authorization. So how does this work with the JCR API?
- </para>
- <para>The JCR API defines a &Credentials; marker interface, an instance of which can be passed to the
- <code>&Session;.login(...)</code> method. Rather than provide a concrete implementation of this interface, JBoss DNA
- allows you to pass any implementation of &Credentials; that also has one of the following methods:
- <itemizedlist>
- <listitem>
- <para><code>getLoginContext()</code> that returns a &LoginContext; instance.</para>
- </listitem>
- <listitem>
- <para><code>getAccessControlContext()</code> that returns a &AccessControlContext; instance.</para>
- </listitem>
- </itemizedlist>
- This way, your application can obtain the JAAS &LoginContext; or &AccessControlContext; however it wants,
- and then merely passes that into DNA through the JCR &Credentials;. No interfaces or classes specific to JBoss DNA are required.
- </para>
- <para>
- The following code shows how this is done, using an anonymous inner class for the &Credentials; implementation.
- </para>
- <programlisting>
-&CallbackHandler; callbackHandler = // as needed by your app, according to JAAS
-final &LoginContext; loginContext = new &LoginContext;("MyAppContextName",callbackHandler);
-
-// Now pass to JBoss DNA to create a JCR Session ...
-&Credentials; credentials = new &Credentials;() {
-public &LoginContext; getLoginContext() { return loginContext; }
-};
-&JcrRepository; jcrRepository = new &JcrRepository;(contextFactory, sources);
-&Session; session = jcrRepository.login(credentials, sourceName);
-</programlisting>
- </sect1>
- <sect1>
- <title>JCR Support</title>
- <para>
- JBoss DNA currently supports most of the Level 1 and Level 2 feature set defined by the <ulink url="&JSR170;">JSR-170</ulink> specification.
- Queries, which are part of Level 1, are not implemented, nor are all of the update methods that make up Level 2.
- So while the current implementation provides 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.
- </para>
- </sect1>
- <sect1>
- <title>Summary</title>
- <para>
- In this chapter, we covered how to use JCR with JBoss DNA. 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 <link linkend="sequencing">next chapter</link> to describing in detail how the sequencing of file content works.
- </para>
- </sect1>
-</chapter>
Deleted: trunk/docs/reference/src/main/docbook/en-US/content/mimetypes.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/mimetypes.xml 2009-06-08 00:52:09 UTC (rev 994)
+++ trunk/docs/reference/src/main/docbook/en-US/content/mimetypes.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -1,204 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
-%CustomDTD;
-]>
-<chapter id="mimetypes">
- <title>MIME types</title>
- <para>
- JBoss DNA often needs the ability to determine the MIME type for some binary content. When uploading content into
- a repository, we may want to add the MIME type as metadata. Or, we may want to make some processing decisions
- based upon the MIME type. So, JBoss DNA created a small pluggable framework for determining the MIME type by using
- the name of the file (e.g., extensions) and/or by reading the actual content. Technically, the framework
- delegates this to one or more extensions. And we've provided one extension that does a very good job at
- determining the MIME type from a large variety of file types. But if that isn't sufficient, you can always
- incorporate your own detector into JBoss DNA.
- </para>
- <para>
- To use this system, you simply invoke a static method and supply the name of the content (e.g., the name of the file, with the extension)
- and the &InputStream; to the actual binary content:
- </para>
- <programlisting>&MimeType;.of(name,content)</programlisting>
- <para>
- The result is a &String; containing the <ulink url="http://www.iana.org/assignments/media-types/">MIME type</ulink>
- (e.g., "text/plain") or null if the MIME type cannot be determined. Note that the name or &InputStream; may be
- null, making this a very versatile utility.
- </para>
- <sect1 id="detectors">
- <title>JBoss DNA MIME type detectors</title>
- <para>
- The principle component in this framework is the concept of a <emphasis role="strong">detector</emphasis>.
- A detector attempts to determine the MIME type using the name of the content (e.g., the file name)
- and the actual content itself. If the detector is able to determine the MIME type, it simply returns
- it as a string. If not, it merely returns null. Note, however, that a detector must be thread-safe.
- </para>
- <para>
- Here is the interface:
- </para>
- <programlisting>
-package org.jboss.dna.graph.mimetype;
-@ThreadSafe
-public interface &MimeTypeDetector; {
-
- /**
- * Returns the MIME-type of a data source, using its supplied content and/or
- * its supplied name, depending upon the implementation. If the MIME-type
- * cannot be determined, either a "default" MIME-type or <code>null</code> may
- * be returned, where the former will prevent earlier registered MIME-type
- * detectors from being consulted.
- *
- * @param name The name of the data source; may be <code>null</code>.
- * @param content The content of the data source; may be <code>null</code>.
- * @return The MIME-type of the data source, or optionally <code>null</code>
- * if the MIME-type could not be determined.
- * @throws &IOException; If an error occurs reading the supplied content.
- */
- &String; mimeTypeOf( &String; name,
- &InputStream; content ) throws &IOException;;
-}</programlisting>
- <para>
- Detectors can be added to the &MimeType; class using the <code>addDetector(&MimeTypeDetectorConfig; config)</code>
- method, where the &MimeTypeDetectorConfig; defines the name of the detector class, the name of the
- <link linkend="classloaders">class loader</link>, a name, and a description. It is also possible
- to set the &ClassLoaderFactory; that the &MimeType; singleton will use.
- </para>
- <para>
- We'll next look at the MIME type detectors that are provided out by JBoss DNA out of the box, and how to write your own.
- </para>
- <sect2 id="dna-mimetype-detector-aperture">
- <title>Aperture MIME type detector</title>
- <para>
- The &ApertureMimeTypeDetector; class is an implementation of &MimeTypeDetector; that uses the
- <ulink url="http://aperture.sourceforge.net/">Aperture</ulink> open-source library, which
- is a very capable utility for determining the MIME type for a wide range of file types,
- using both the file name and the actual content.
- </para>
- </sect2>
- </sect1>
- <sect1 id="custom-detectors">
- <title>Writing custom detectors</title>
- <para>
- Creating a custom detector involves the following steps:
- <itemizedlist>
- <listitem>
- <para>Create a Maven 2 project for your detector;</para>
- </listitem>
- <listitem>
- <para>Implement the &MimeTypeDetector; interface with your own implementation, and create unit tests to verify
- the functionality and expected behavior;</para>
- </listitem>
- <listitem>
- <para>Add a &MimeTypeDetectorConfig; to the &MimeType; class in your application
- as described <link linkend="detectors">earlier</link>; and</para>
- </listitem>
- <listitem>
- <para>Deploy the JAR file with your implementation (as well as any dependencies), and make them available to JBoss DNA
- in your application.</para>
- </listitem>
- </itemizedlist>
- It's that simple.
- </para>
- <sect2 id="custom_detector_project">
- <title>Creating the Maven 2 project</title>
- <para>The first step is to create the Maven 2 project that you can use to compile your code and build the JARs.
- Maven 2 automates a lot of the work, and since you're already <link linkend="maven">set up to use Maven</link>,
- using Maven for your project will save you a lot of time and effort. Of course, you don't have to use Maven 2, but then you'll
- have to get the required libraries and manage the compiling and building process yourself.</para>
- <note>
- <para>JBoss DNA may provide in the future a Maven archetype for creating detector projects. If you'd find this useful
- and would like to help create it, please <link linkend="preface">join the community</link>.</para>
- </note>
- <note>
- <para>
- The <emphasis role="strong">dna-mimetype-detector-aperture</emphasis> project is a small, self-contained detector implementation that
- that you can use to help you get going. Starting with this project's source and modifying it to suit your needs
- may be the easiest way to get started.
- See the subversion repository:
- <ulink url="&Subversion;trunk/extensions/dna-mimetype-detector-aperture/">&Subversion;trunk/sequencers/dna-mimetype-detector-aperture/</ulink>
- </para>
- </note>
- <para>You can create your Maven project any way you'd like. For examples, see the <ulink url="http://maven.apache.org/guides/getting-started/index.html#How_do_I_make_m...">Maven 2 documentation</ulink>.
- Once you've done that, just add the dependencies in your project's <code>pom.xml</code> dependencies section:</para>
- <programlisting role="XML"><![CDATA[<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-common</artifactId>
- <version>0.1</version>
-</dependency>
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-graph</artifactId>
- <version>0.1</version>
-</dependency>
-<dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
-</dependency>
-]]></programlisting>
- <para>These are minimum dependencies required for compiling a detector. Of course, you'll have to add
- other dependencies that your sequencer needs.</para>
- <para>As for testing, you probably will want to add more dependencies, such as those listed here:</para>
- <programlisting role="XML"><![CDATA[<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.4</version>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>org.hamcrest</groupId>
- <artifactId>hamcrest-library</artifactId>
- <version>1.1</version>
- <scope>test</scope>
-</dependency>
-<!-- Logging with Log4J -->
-<dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.3</version>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- <scope>test</scope>
-</dependency>
-]]></programlisting>
- <para>
- After you've created the project, simply implement the &MimeTypeDetector; interface. And testing should be
- quite straightforward, MIME type detectors don't require any other components. In your tests,
- simply instantiate your &MimeTypeDetector; implementation, supply various combinations of names and/or &InputStream;s,
- and verify the output is what you expect.
- </para>
- <para>
- To use in your application, create a &MimeTypeDetectorConfig; object with the name, description, and class information
- for your detector, and add to the &MimeType; class using the <code>addDetector(&MimeTypeDetectorConfig; config)</code> method.
- Then, just use the &MimeType; class.
- </para>
- </sect2>
- </sect1>
-</chapter>
Deleted: trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml 2009-06-08 00:52:09 UTC (rev 994)
+++ trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -1,1468 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
-%CustomDTD;
-]>
-<chapter id="repositories">
- <title>Repositories</title>
- <para></para>
- <para>There is a lot of information stored in many of different places: databases, repositories, SCM systems,
- registries, file systems, services, etc. The purpose of the federation engine is to allow applications to use the JCR API
- to access that information as if it were all stored in a single JCR repository, but to really leave the information where
- it is.</para>
- <para>Why not just copy or move the information into a JCR repository? Moving it is probably pretty difficult, since most
- likely there are existing applications that rely upon that information being where it is. All of those applications
- would break or have to change. And copying the information means that we'd have to continually synchronize the changes.
- This not only is a lot of work, but it often makes it difficult to know whether information is accurate and "the master" data.
- </para>
- <para>JBoss DNA lets us leave information where it, yet access it through the JCR API as if it were in one big repository.
- One major benefit is that existing applications that use the information in the original locations don't break, since they
- can keep using the information. But now our JCR clients can also access all the information, too. And if our federating JBoss DNA repository is
- configured to allow updates, JCR client applications can change the information in the repository and JBoss DNA will propagate
- those changes down to the original source, making those changes visible to all the other applications.
- </para>
- <para>
- In short, all clients see the correct information, even when it changes in the underlying systems. But the JCR clients can get to all of the information
- in one spot, using one powerful standard API.
- </para>
- <sect1 id="connectors">
- <title>Repository connectors</title>
- <para>
- With JBoss DNA, your applications use the <ulink url="&JSR170;">JCR API</ulink> to work with the repository,
- but the DNA repository transparently fetches the information from different kinds of repositories and storage systems,
- not just a single purpose-built store. This is fundamentally what makes JBoss DNA different.
- </para>
- <para>How does JBoss DNA do this? At the heart of JBoss DNA and it's JCR implementation is a simple graph-based
- <emphasis>repository connector</emphasis> system. Essentially, JBoss DNA's JCR implementation uses a single
- repository connector to access all content:
- <figure id="dnajcr-and-connector">
- <title>JBoss DNA's JCR implementation delegates to a repository connector</title>
- <graphic align="center" scale="100" fileref="dnajcr-and-connector.png"/>
- </figure>
- That single repository connector could use an in-memory repository, a JBoss Cache instance (including those that are clustered and replicated),
- or a federated repository where content from multiple sources is unified.
- <figure id="dna-connectors-0.2">
- <title>JBoss DNA can put JCR on top of multiple kinds of systems</title>
- <graphic align="center" scale="100" fileref="dna-connectors-0.2.png"/>
- </figure>
- Really, the federated connector gives us all kinds of possibilities, since we can use that connector on top of lots of connectors
- to other individual sources. This simple connector architecture is fundamentally what makes JBoss DNA so powerful and flexible.
- Along with a good library of connectors, which is what we're planning to create.
- </para>
- <para>
- For instance, we want to build a connector to <ulink url="&JIRA-39;">other JCR repositories</ulink>, and another that accesses
- the <ulink url="&JIRA-34;">local file system</ulink>. We've already started on a <ulink url="&JIRA-36;">Subversion connector</ulink>,
- which will allow JCR to access the files in a SVN repository (and perhaps push changes into SVN through a commit).
- And of course we want to create a connector that accesses <ulink url="&JIRA-199;">data</ulink>
- and <ulink url="&JIRA-37;">metadata</ulink> from relational databases. For more information, check out our
- <ulink url="&JIRA;?report=com.atlassian.jira.plugin.system.project:roadmap-panel">roadmap</ulink>.
- Of course, if we don't have a connector to suit your needs, you can <link linkend="custom-connectors">write your own</link>.
- <figure id="dna-connectors-future">
- <title>Future JBoss DNA connectors</title>
- <graphic align="center" scale="100" fileref="dna-connectors-future.png"/>
- </figure>
- </para>
- <para>
- </para>
- <para>
- It's even possible to put a different API layer on top of the connectors. For example, the new <ulink url="&JSR203;">New I/O (JSR-203)</ulink>
- API offers the opportunity to build new file system providers. This would be very straightforward to put on top of a JCR implementation,
- but it could be made even simpler by putting it on top of a DNA connector. In both cases, it'd be a trivial mapping from nodes that represent
- files and folders into JSR-203 files and directories, and events on those nodes could easily be translated into JSR-203 watch events.
- Then, simply choose a DNA connector and configure it to use the source you want to use.
- <figure id="dna-connectors-vfs">
- <title>Virtual File System with JBoss DNA</title>
- <graphic align="center" scale="100" fileref="vfs-and-connector.png"/>
- </figure>
- </para>
- <para>Before we go further, let's define some terminology regarding connectors.</para>
- <itemizedlist>
- <listitem>
- <para>
- A <emphasis role="strong">connector</emphasis> is the runnable code packaged in one or more JAR files that
- contains implementations of several interfaces (described below). A Java developer <emphasis>writes</emphasis>
- a connector to a type of source, such as a particular database management system, LDAP directory, source code
- management system, etc. It is then packaged into one or more JAR files (including dependent JARs) and deployed
- for use in applications that use JBoss DNA repositories.
- </para>
- </listitem>
- <listitem>
- <para>
- The description of a particular source system (e.g., the "Customer" database, or the company LDAP system)
- is called a <emphasis role="strong">repository source</emphasis>. JBoss DNA defines a &RepositorySource; interface
- that defines methods describing the behavior and supported features and a method for establishing connections.
- A connector will have a class that implements this interface and that has JavaBean properties for
- all of the connector-specific properties required to fully describe an instance of the system. Use of JavaBean
- properties is not required, but it is highly recommended, as it enables reflective configuration and administration.
- Applications that use JBoss DNA create an instance of the connector's &RepositorySource; implementation and set
- the properties for the external source that the application wants to access with that connector.
- </para>
- </listitem>
- <listitem>
- <para>
- A repository source instance is then used to establish <emphasis role="strong">connections</emphasis> to
- that source. A connector provides an implementation of the &RepositoryConnection; interface, which
- defines methods for interacting with the external system. In particular, the <code>execute(...)</code> method
- takes an &ExecutionContext; instance and a &Request; object. The &ExectuionContext; object defines the
- environment in which the processing is occurring, including information about the JAAS &Subject; and &LoginContext;.
- The &Request; object describes the requested operations on the content, with different concrete subclasses
- representing each type of activity. Examples of commands include (but not limited to) getting a node, moving a node, creating a node,
- changing a node, and deleting a node. And, if the repository source is able to participate in JTA/JTS distributed transactions, then the
- &RepositoryConnection; must implement the <code>getXaResource()</code> method by returning
- a valid <code>javax.transaction.xa.XAResource</code> object that can be used by the transaction monitor.
- </para>
- </listitem>
- </itemizedlist>
- <para>As an example, consider that we want JBoss DNA to give us access through JCR to the schema information contained in a
- relational databases. We first have to develop a connector that allows us to interact with relational databases using JDBC.
- That connector would contain a <code>JdbcRepositorySource</code> Java class that implements &RepositorySource;,
- and that has all of the various JavaBean properties for setting the name of the driver class, URL, username, password,
- and other properties. (Or we might have a JavaBean property that defines the JNDI name where we can find a JDBC
- <code>DataSource</code> instance pointing to our JDBC database.)
- </para>
- <para>
- Our new connector would also have a <code>JdbcRepositoryConnection</code> Java class that implements the
- &RepositoryConnection; interface. This class would probably wrap a JDBC database connection,
- and would implement the <code>execute(...)</code> method such that the nodes exposed by the connector
- describe the database schema of the database. For example, the connector might represent each database table
- as a node with the table's name, with properties that describe the table (e.g., the description, whether it's a
- temporary table), and with child nodes that represent each of the columns, keys and constraints.
- </para>
- <para>
- To use our connector in an application that uses JBoss DNA, we need to create an instance of the
- <classname>JdbcRepositorySource</classname> for each database instance that we want to access. If we have 3 MySQL databases,
- 9 Oracle databases, and 4 PostgreSQL databases, then we'd need to create a total of 16 <classname>JdbcRepositorySource</classname>
- instances, each with the properties describing a single database instance. Those sources are then available for use by
- JBoss DNA components, including the <link linkend="jcr">JCR</link> implementation.
- </para>
- <para>
- So, we've so far learned what a repository connector is and how they're used to establish connections to the underlying sources
- and access the content in those sources. In the <link linkend="repository-service">next section</link>, we'll show how these
- source instances can be configured, managed, and their connections pooled. After that, we'll look review JBoss DNA's
- <link linkend="connector-library">existing connectors</link> and show how to <link linkend="custom-connectors">create your own connectors</link>.
- </para>
- </sect1>
- <sect1 id="repository-workspaces">
- <title>Workspaces</title>
- <para>The previous section talked about how connector expose their information through the graph language of JBoss DNA.
- This is true, except that we didn't dive into too much of the detail. JBoss DNA graphs have the notion of <emphasis>workspaces</emphasis>
- in which the content appears, and its very easy for clients using the graph to switch between workspaces. In fact,
- workspaces differ from each other in that they provide different views of the same information.
- </para>
- <para>Consider a source control system, like SVN or CVS. These systems provide different views of the source code:
- a mainline development branch as well as other branches (or tags) commonly used for releases. So, just like one source
- file might appear in the mainline branch as well as the previous two release branches, a node in a repository source
- might appear in multiple workspaces.
- </para>
- <para>
- However, each connector can kind of decide how (or whether) it uses workspaces. For example, there may be no overlap
- in the content between workspaces. Or a connector might only expose a single workspace (in other words, there's only one
- "default" workspace).
- </para>
- </sect1>
- <sect1 id="repository-service">
- <title>Repository Service</title>
- <para>The JBoss DNA &RepositoryService; is the component that manages the <emphasis>repository sources</emphasis>
- and the connections to them. &RepositorySource; instances can be programmatically added to the service, but
- the service can actually read its configuration from a configuration repository (which, by the way, is represented by a
- just another &RepositorySource; instance that's usually added programmatically to the service). The service connects to
- the configuration repository, reads the content in a particular area, and automatically sets up the &RepositorySource; instances
- per the information found in the configuration repository.
- </para>
- <para>
- The &RepositoryService; also transparently maintains for each source a pool of reusable connections. The pooling properties
- can be controlled via the configuration repository, or adjusted programmatically.
- </para>
- <para>
- Using a repository, then, involves simply asking the &RepositoryService; for a &RepositoryConnection;
- to the repository given the repository's name. If a source exists with that name, the service checks out a connection from
- the source's pool. The resulting connection is actually a wrapper around the underlying pooled connection, so the
- component that requested the connection can simply close it, and under the covers the actual connection is simply returned
- to the pool.
- </para>
- <para>To instantiate the &RepositoryService;, we need to first have a few other objects:
- <itemizedlist>
- <listitem>
- <para>
- A &ExecutionContext; instance, as discussed <link linkend="execution-context">earlier</link>.
- </para>
- </listitem>
- <listitem>
- <para>
- A &RepositoryLibrary; instance that manages the list of &RepositorySource; instances,
- properly injects the execution contexts into each repository source, and provides a configurable pool of connections
- for each source.
- </para>
- </listitem>
- <listitem>
- <para>
- A <emphasis>configuration repository</emphasis> that contains descriptions of all of the repository sources
- as well as any information those sources need. Because this is a regular repository, this could be a simple
- repository with content loaded from an XML file, or it could be a shared
- central repository with information about all of the JBoss DNA repositories used across your organization.
- </para>
- </listitem>
- </itemizedlist>
- With these components in place, we can then instantiate the &RepositoryService; and start it (using its
- &ServiceAdministrator;). During startup, the service reads the configuration repository and loads any
- defined &RepositorySource; instances into the repository library, using the class loader factory
- (available in the &ExecutionContext;) to obtain.
- </para>
- <para>
- Here's sample code that shows how to set up and start the repository service. You can see something similar
- in the example application in the <code>startRepositories()</code> method of the
- <code>org.jboss.example.dna.repository.RepositoryClient</code> class.
- </para>
- <programlisting>
- // Create the top-level execution context with all standard components ...
- &ExecutionContext; context = new ExecutionContext();
-
- // Create the library for the RepositorySource instances ...
- &RepositoryLibrary; sources = new &RepositoryLibrary;(context);
-
- // Load into the source manager the repository source for the configuration repository ...
- &InMemoryRepositorySource; configSource = new &InMemoryRepositorySource;();
- configSource.setName("Configuration");
- sources.addSource(configSource);
-
- // Now instantiate the Repository Service ...
- &RepositoryService; service = new &RepositoryService;(sources, configSource.getName(), context);
- service.getAdministrator().start();
- </programlisting>
-
- <para>After startup completes, the repositories are ready to be used. The client application obtains the list of repositories
- and presents them to the user. When the user selects one, the client application starts navigating that repository
- starting at its root node (e.g., the "/" path). As you type a command to list the contents of the current node or to
- "change directories" to a different node, the client application obtains the information for the node using a simple
- procedure:
- <orderedlist>
- <listitem>
- <para>Get a connection to the repository.</para>
- </listitem>
- <listitem>
- <para>Using the connection, find the current node and read its properties and children, putting the information
- into a simple Java plain old Java object (POJO).</para>
- </listitem>
- <listitem>
- <para>Close the connection to the repository (in a finally block to ensure it always happens).</para>
- </listitem>
- </orderedlist>
- </para>
- </sect1>
- <sect1 id="connector-library">
- <title>Out-of-the-box repository connectors</title>
- <para>
- A number of repository connectors are already available in JBoss DNA, and are outlined in the following sections.
- Note that we do want to build <ulink url="https://jira.jboss.org/jira/secure/IssueNavigator.jspa?reset=true&mod...">more connectors</ulink>
- in the upcoming releases.
- </para>
- <sect2 id="dna-connector-inmemory">
- <title>In-memory connector</title>
- <para>
- The in-memory repository connector is a simple connector that creates a transient, in-memory repository.
- This repository is used as a very simple in-memory cache or as a standalone transient repository.
- </para>
- <para>
- The &InMemoryRepositorySource; class provides a number of JavaBean properties that control its behavior:
- </para>
- <table frame='all'>
- <title>&InMemoryRepositorySource; properties</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Property</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>name</entry>
- <entry>The name of the repository source, which is used by the &RepositoryService; when obtaining a &RepositoryConnection; by name.</entry>
- </row>
- <row>
- <entry>jndiName</entry>
- <entry>Optional property that, if used, specifies the name in JNDI where an &InMemoryRepository; instance can be found.
- This is an advanced property that is infrequently used.</entry>
- </row>
- <row>
- <entry>rootNodeUuid</entry>
- <entry>Optional property that, if used, defines the UUID of the root node in the in-memory repository. If not used,
- then a new UUID is generated.</entry>
- </row>
- <row>
- <entry>retryLimit</entry>
- <entry>Optional property that, if used, defines the number of times that any single operation on a &RepositoryConnection; to this source should be retried
- following a communication failure. The default value is '0'.</entry>
- </row>
- <row>
- <entry>defaultCachePolicy</entry>
- <entry>Optional property that, if used, defines the default for how long this information provided by this source may to be
- cached by other, higher-level components. The default value of null implies that this source does not define a specific
- duration for caching information provided by this repository source.</entry>
- </row>
- <row>
- <entry>defaultWorkspaceName</entry>
- <entry>Optional property that is initialized to an empty string and which defines the name for the workspace that will be used by default
- if none is specified.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect2>
- <sect2 id="dna-connector-jbosscache">
- <title>JBoss Cache connector</title>
- <para>
- The JBoss Cache repository connector allows a <ulink url="http://www.jboss.org/jbosscache/">JBoss Cache</ulink> instance to be
- used as a JBoss DNA (and thus JCR) repository. This provides a repository that is an effective, scalable, and distributed cache,
- and is often paired with other repository sources to provide a local or <link linkend="dna-connector-federation">federated</link>
- repository.
- </para>
- <para>
- The &JBossCacheSource; class provides a number of JavaBean properties that control its behavior:
- </para>
- <table frame='all'>
- <title>&JBossCacheSource; properties</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Property</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>name</entry>
- <entry>The name of the repository source, which is used by the &RepositoryService; when obtaining a &RepositoryConnection; by name.</entry>
- </row>
- <row>
- <entry>cacheFactoryJndiName</entry>
- <entry>Optional property that, if used, specifies the name in JNDI where an existing JBoss Cache Factory instance can be found.
- That factory would then be used if needed to create a JBoss Cache instance. If no value is provided, then the
- JBoss Cache <code>DefaultCacheFactory</code> class is used.</entry>
- </row>
- <row>
- <entry>cacheConfigurationName</entry>
- <entry>Optional property that, if used, specifies the name of the configuration that is supplied to the cache factory
- when creating a new JBoss Cache instance.</entry>
- </row>
- <row>
- <entry>cacheJndiName</entry>
- <entry>Optional property that, if used, specifies the name in JNDI where an existing JBoss Cache instance can be found.
- This should be used if your application already has a cache that is used, or if you need to configure the cache in
- a special way.</entry>
- </row>
- <row>
- <entry>uuidPropertyName</entry>
- <entry>Optional property that, if used, defines the property that should be used to find the UUID value for each node
- in the cache. "<code>dna:uuid</code>" is the default.</entry>
- </row>
- <row>
- <entry>retryLimit</entry>
- <entry>Optional property that, if used, defines the number of times that any single operation on a &RepositoryConnection; to this source should be retried
- following a communication failure. The default value is '0'.</entry>
- </row>
- <row>
- <entry>defaultCachePolicy</entry>
- <entry>Optional property that, if used, defines the default for how long this information provided by this source may to be
- cached by other, higher-level components. The default value of null implies that this source does not define a specific
- duration for caching information provided by this repository source.</entry>
- </row>
- <row>
- <entry>nameOfDefaultWorkspace</entry>
- <entry>Optional property that is initialized to an empty string and which defines the name for the workspace that will be used by default
- if none is specified.</entry>
- </row>
- <row>
- <entry>predefinedWorkspaceNames</entry>
- <entry>Optional property that defines the names of the workspaces that exist and that are available for use without having to create them.</entry>
- </row>
- <row>
- <entry>creatingWorkspacesAllowed</entry>
- <entry>Optional property that is by default 'true' that defines whether clients can create new workspaces.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect2>
- <sect2 id="dna-connector-federation">
- <title>Federating connector</title>
- <para>
- The federated repository source provides a unified repository consisting of information that is dynamically federated from multiple other
- &RepositorySource; instances. This is a very powerful repository source that appears to be a single repository, when in
- fact the content is stored and managed in multiple other systems. Each &FederatedRepositorySource; is typically configured
- with the name of another &RepositorySource; that should be used as the local, unified cache of the federated content.
- The configuration also contains the names of the other &RepositorySource; instances that are to be federated along with
- the &Projection; definition describing where in the unified repository the content is to appear.
- </para>
- <figure id="dna-connector-federation-image">
- <title>Federating multiple sources using the Federated Repository Connector</title>
- <graphic align="center" scale="100" fileref="dna-connector-federation.png"/>
- </figure>
- <para> The federation connector works by effectively building up a single graph by querying each source and merging or
- unifying the responses. This information is cached, which improves performance, reduces the number of (potentially
- expensive) remote calls, reduces the load on the sources, and helps mitigate problems with source availability. As
- clients interact with the repository, this cache is consulted first. When the requested portion of the graph (or
- "subgraph") is contained completely in the cache, it is retuned immediately. However, if any part of the requested
- subgraph is not in the cache, each source is consulted for their contributions to that subgraph, and any results are
- cached.</para>
- <para> This basic flow makes it possible for the federated repository to build up a local cache of the integrated graph
- (or at least the portions that are used by clients). In fact, the federated repository caches information in a manner
- that is similar to that of the Domain Name System (DNS). As sources are consulted for their contributions, the source
- also specifies whether it is the authoritative source for this information (some sources that are themselves federated
- may not be the information's authority), whether the information may be modified, the time-to-live (TTL) value (the time
- after which the cached information should be refreshed), and the expiration time (the time after which the cached
- information is no longer valid). In effect, the source has complete control over how the information it contributes is
- cached and used.</para>
- <para>
- The federated repository also needs to incorporate <emphasis>negative caching</emphasis>, which is storage of the knowledge
- that something does <emphasis>not</emphasis> exist. Sources can be configured to contribute information
- only below certain paths (e.g., <code>/A/B/C</code>), and the federation engine can take advantage of this by never
- consulting that source for contributions to information on other paths. However, below that path, any negative responses
- must also be cached (with appropriate TTL and expiry parameters) to prevent the exclusion of that source (in case the source
- has information to contribute at a later time) or the frequent checking with the source.
- </para>
- <para>
- The federated repository uses other &RepositorySource;s that are to be federated and a &RepositorySource; that is to be used as the
- cache of the unified contents. These are configured in another &RepositorySource; that is treated as a configuration repository.
- The &FederatedRepositorySource; class uses JavaBean properties to define the name of the configuration repository and
- the path to the "<code>dna:federation</code>" node in that configuration repository containing the information about the
- cache and federated sources. This graph structure that is expected at this location is as follows:
- </para>
- <programlisting><![CDATA[<!-- Define the federation configuration. -->
-<dna:federatedRepository xmlns:dna="http://www.jboss.org/dna"
- xmlns:jcr="http://www.jcp.org/jcr/1.0"
- dna:timeToCache="100000" >
- <dna:workspaces>
- <dna:workspace jcr:name="default">
- <!-- Define how the content in the 'Cache' source is to map to the federated cache -->
- <dna:cache dna:sourceName="Cache" dna:workspaceName="default" dna:projectionRules="/a => /" />
-
- <!-- Define how the content in the two sources maps to the federated/unified repository.
- This example puts the 'Cars' and 'Aircraft' content underneath '/vehicles', but the
- 'Configuration' content (which is defined by this file) will appear under '/'. -->
- <dna:projections>
- <dna:projection jcr:name="Cars" dna:projectionRules="/Vehicles => /" />
- <dna:projection jcr:name="Aircraft" dna:projectionRules="/Vehicles => /" />
- <dna:projection jcr:name="Configuration" dna:projectionRules="/ => /" />
- </dna:projections>
- </dna:workspace>
- </dna:workspaces>
-</dna:federatedRepository>
-]]></programlisting>
- <note>
- <para>
- We're using XML to represent a graph structure, since the two map pretty well. Each XML element represents
- a node and XML attributes represent properties on a node. The name of the node is defined by either the
- <code>jcr:name</code> attribute (if it exists) or the name of the XML element. And we use XML namespaces
- to define the namespaces used in the node and property names. BTW, this is exactly how the XML graph importer
- works.
- </para>
- </note>
- <para>
- Notice that there is a cache projection and three source projections, and each projection defines
- one or more <emphasis>projection rules</emphasis> that are of the form:
- </para>
- <programlisting>pathInFederatedRepository => pathInSourceRepository</programlisting>
- <para>
- So, a projection rule <code>/Vehicles => /</code> projects the entire contents of the source so that
- it appears in the federated repository under the "<code>/Vehicles</code>" node.
- </para>
- <para>
- The &FederatedRepositorySource; class provides a number of JavaBean properties that control its behavior:
- </para>
- <table frame='all'>
- <title>&FederatedRepositorySource; properties</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Property</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>name</entry>
- <entry>The name of the repository source, which is used by the &RepositoryService; when obtaining a &RepositoryConnection; by name.</entry>
- </row>
- <row>
- <entry>repositoryName</entry>
- <entry>The name for the federated repository.</entry>
- </row>
- <row>
- <entry>configurationSourceName</entry>
- <entry>The name of the &RepositorySource; that should be used as the configuration repository, and in which is defined
- how this federated repository is to be set up and configured.
- This name is supplied to the &RepositoryConnectionFactory; that is provided to this instance when added to the
- &RepositoryLibrary;.</entry>
- </row>
- <row>
- <entry>configurationWorkspaceName</entry>
- <entry>The name of the workspace in the configuration &RepositorySource; with the content defining
- how this federated repository is to be set up and configured.</entry>
- </row>
- <row>
- <entry>configurationSourcePath</entry>
- <entry>The path to the node in the configuration repository below which a "dna:federation" node exists with the
- graph structure describing how this federated repository is to be configured.</entry>
- </row>
- <row>
- <entry>securityDomain</entry>
- <entry>Optional property that, if used, specifies the name of the JAAS application context that should be used
- to establish the <link linkend="execution-contenxt">execution context</link> for this repository.
- This should correspond to the JAAS login configuration located within the JAAS login configuration file,
- and should be used only if a "<code>username</code>" property is defined.</entry>
- </row>
- <row>
- <entry>username</entry>
- <entry>Optional property that, if used, defines the name of the JAAS subject that should be used
- to establish the <link linkend="execution-contenxt">execution context</link> for this repository.
- This should be used if a "<code>securityDomain</code>" property is defined.</entry>
- </row>
- <row>
- <entry>password</entry>
- <entry>Optional property that, if used, defines the password of the JAAS subject that should be used
- to establish the <link linkend="execution-contenxt">execution context</link> for this repository.
- If the password is not provided but values for the "<code>securityDomain</code>" and "<code>username</code>" properties are,
- then authentication will use the default JAAS callback handlers.</entry>
- </row>
- <row>
- <entry>retryLimit</entry>
- <entry>Optional property that, if used, defines the number of times that any single operation on a &RepositoryConnection; to this source should be retried
- following a communication failure. The default value is '0'.</entry>
- </row>
- <row>
- <entry>defaultCachePolicy</entry>
- <entry>Optional property that, if used, defines the default for how long this information provided by this source may to be
- cached by other, higher-level components. The default value of null implies that this source does not define a specific
- duration for caching information provided by this repository source.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect2>
- </sect1>
- <sect1 id="custom-connectors">
- <title>Writing custom connectors</title>
- <para>
- There may come a time when you want to tackle creating your own repository connector. Maybe the connectors we provide out-of-the-box
- don't work with your source. Maybe you want to use a different cache system.
- Maybe you have a system that you want to make available through a JBoss DNA repository. Or, maybe you're
- a contributor and want to help us round out our library with a new connector. No matter what the reason, creating a new connector
- is pretty straightforward, as we'll see in this section.
- </para>
- <para>
- Creating a custom connector involves the following steps:
- <orderedlist>
- <listitem>
- <para>Create a Maven 2 project for your connector;</para>
- </listitem>
- <listitem>
- <para>
- Implement the &RepositorySource; interface, using JavaBean properties for each bit of information the implementation will
- need to establish a connection to the source system.
- </para>
- <para>
- Then, implement the &RepositoryConnection; interface with a class that represents a connection to the source. The
- <code>execute(&ExecutionContext;, &Request;)</code> method should process any and all requests that may come down the pike,
- and the results of each request can be put directly on that request.
- </para>
- <para>
- Don't forget unit tests that verify that the connector is doing what it's expected to do. (If you'll be committing the connector
- code to the JBoss DNA project, please ensure that the unit tests can be run by others that may not have access to the
- source system. In this case, consider writing integration tests that can be easily configured to use different sources
- in different environments, and try to make the failure messages clear when the tests can't connect to the underlying source.)
- </para>
- </listitem>
- <listitem>
- <para>
- Configure JBoss DNA to use your connector. This may involve just registering the source with the &RepositoryService;,
- or it may involve adding a source to a configuration repository used by the <link linkend="dna-connector-federation">federated repository</link>.
- </para>
- </listitem>
- <listitem>
- <para>
- Deploy the JAR file with your connector (as well as any dependencies), and make them available to JBoss DNA
- in your application.
- </para>
- </listitem>
- </orderedlist>
- Let's go through each one of these steps in more detail.
- </para>
- <sect2 id="custom_connector_project">
- <title>Creating the Maven 2 project</title>
- <para>
- The first step is to create the Maven 2 project that you can use to compile your code and build the JARs.
- Maven 2 automates a lot of the work, and since you're already <link linkend="maven">set up to use Maven</link>,
- using Maven for your project will save you a lot of time and effort. Of course, you don't have to use Maven 2, but then you'll
- have to get the required libraries and manage the compiling and building process yourself.</para>
- <note>
- <para>JBoss DNA may provide in the future a Maven archetype for creating connector projects. If you'd find this useful
- and would like to help create it, please <link linkend="preface">join the community</link>.
- </para>
- <para>In lieu of a Maven archetype, you may find it easier to start with a small existing connector project.
- The <emphasis role="strong">dna-connector-filesystem</emphasis> project is small, but it may be tough to separate
- the stuff that every connector needs from the extra code and data structures that manage the content.
- See the subversion repository: <ulink url="&Subversion;trunk/extensions/dna-connector-filesystem/">&Subversion;trunk/extensions/dna-connector-filesystem/</ulink>
- </para>
- </note>
- <para>
- You can create your Maven project any way you'd like. For examples, see the
- <ulink url="http://maven.apache.org/guides/getting-started/index.html#How_do_I_make_m...">Maven 2 documentation</ulink>.
- Once you've done that, just add the dependencies in your project's <code>pom.xml</code> dependencies section:
- </para>
- <programlisting role="XML"><![CDATA[
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-graph</artifactId>
- <version>0.4</version>
-</dependency>
- ]]></programlisting>
- <para>
- This is the only dependency required for compiling a connector - Maven pulls in all of the dependencies needed by
- the 'dna-graph' artifact. Of course, you'll still have to add dependencies for any library your connector needs
- to talk to its underlying system.
- </para>
- <para>
- As for testing, you probably will want to add more dependencies, such as those listed here:
- </para>
- <programlisting role="XML"><![CDATA[
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-graph</artifactId>
- <version>0.4</version>
- <type>test-jar</type>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-common</artifactId>
- <version>0.4</version>
- <type>test-jar</type>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.4</version>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>org.hamcrest</groupId>
- <artifactId>hamcrest-library</artifactId>
- <version>1.1</version>
- <scope>test</scope>
-</dependency>
-<!-- Logging with Log4J -->
-<dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.3</version>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- <scope>test</scope>
-</dependency>
- ]]></programlisting>
- <para>
- Testing JBoss DNA connectors does not require a JCR repository or the JBoss DNA services. (For more detail,
- see the <link linkend="testing_custom_connectors">testing section</link>.) However, if you want to do
- integration testing with a JCR repository and the JBoss DNA services, you'll need additional dependencies
- (e.g., <code>dna-repository</code> and any other extensions).
- </para>
- <para>
- At this point, your project should be set up correctly, and you're ready to move on to
- <link linkend="implementing_repository_source">writing the Java implementation</link> for your connector.
- </para>
- </sect2>
- <sect2 id="implementing_repository_source">
- <title>Implementing a <code>RepositorySource</code></title>
- <para>
- As mentioned earlier, a <emphasis>connector</emphasis> consists of the Java code that is used to access content
- from a system. Perhaps the most important class that makes up a connector is the implementation of the
- &RepositorySource;. This class is analogous to JDBC's DataSource in that it is instantiated to represent
- a single instance of a system that will be accessed, and it contains enough information (in the form of JavaBean properties)
- so that it can create connections to the source.
- </para>
- <para>
- Why is the &RepositorySource; implementation a JavaBean? Well, this is the class that is instantiated, usually
- reflectively, and so a no-arg constructor is required. Using JavaBean properties makes it possible
- to reflect upon the object's class to determine the properties that can be set (using setters) and read
- (using getters). This means that an administrative application can instantiate, configure, and manage
- the objects that represent the actual sources, without having to know anything about the actual implementation.
- </para>
- <para>
- So, your connector will need a public class that implements &RepositorySource; and provides JavaBean properties
- for any kind of inputs or options required to establish a connection to and interact with the underlying source.
- Most of the semantics of the class are defined by the &RepositorySource; and inherited interface.
- However, there are a few characteristics that are worth mentioning here.
- </para>
- <sect3 id="connector_cache_policy">
- <title>Cache policy</title>
- <para>
- Each connector is responsible for determining whether and how long DNA is to cache the
- content made available by the connector. This is referred to as the <emphasis>caching policy</emphasis>,
- and consists of a <emphasis>time to live</emphasis> value representing the number of milliseconds that
- a piece of data may be cached. After the TTL has passed, the information is no longer used.
- </para>
- <para>
- DNA allows a connector to use a flexible and powerful caching policy. First, each connection returns the
- <emphasis>default</emphasis> caching policy for all information returned by that connection.
- Often this policy can be configured via properties on the &RepositorySource; implementation.
- This is optional, meaning the connector can return <code>null</code> if it does not wish to
- have a default caching policy.
- </para>
- <para>
- Second, the connector is able to override its default caching policy on individual requests
- (which we'll cover in the <link linkend="implementing_repository_connection">next section</link>).
- Again, this is optional, meaning that a null caching policy on a request implies that the
- request has no overridden caching policy.
- </para>
- <para>
- Third, if the connector has no default caching policy and none is set on the individual requests,
- DNA uses whatever caching policy is set up for that component using the connector. For example, the federating
- connector allows a default caching policy to be specified, and this policy is used should the sources
- being federated not define their own caching policy.
- </para>
- <para>
- In summary, a connector has total control over whether and for how long the information it provides
- is cached.
- </para>
- </sect3>
- <sect3 id="repository_source_jndi">
- <title>Leveraging JNDI</title>
- <para>
- Sometimes it is necessary (or easier) for a &RepositorySource; implementation to look up an object in JNDI.
- One example of this is the JBoss Cache connector: while the connector can
- instantiate a new JBoss Cache instance, more interesting use cases involve JBoss Cache instances that are
- set up for clustering and replication, something that is generally difficult to configure in a single JavaBean.
- Therefore the &JBossCacheSource; has optional JavaBean properties that define how it is to look up a
- JBoss Cache instance in JNDI.
- </para>
- <para>
- This is a simple pattern that you may find useful in your connector. Basically, if your source implementation
- can look up an object in JNDI, simply use a single JavaBean String property that defines the
- full name that should be used to locate that object in JNDI. Usually it's best to include "Jndi" in the
- JavaBean property name so that administrative users understand the purpose of the property.
- (And some may suggest that any optional property also use the word "optional" in the property name.)
- </para>
- </sect3>
- <sect3 id="repository_source_capabilities">
- <title>Capabilities</title>
- <para>
- Another characteristic of a &RepositorySource; implementation is that it provides some hint as to whether
- it supports several features. This is defined on the interface as a method that returns a
- &RepositorySourceCapabilities; object. This class currently provides methods that say whether the connector supports
- updates, whether it supports same-name-siblings (SNS), and whether the connector supports listeners and events.
- </para>
- <para>
- Note that these may be hard-coded values, or the connector's response may be determined at runtime by various factors.
- For example, a connector may interrogate the underlying system to decide whether it can support updates.
- </para>
- <para>
- The &RepositorySourceCapabilities; can be used as is (the class is immutable), or it can be subclassed
- to provide more complex behavior. It is important, however, that the capabilities remain constant
- throughout the lifetime of the &RepositorySource; instance.
- </para>
- <note>
- <para>
- Why a concrete class and not an interface? By using a concrete class, connectors inherit the default
- behavior. If additional capabilities need to be added to the class in future releases, connectors may
- not have to override the defaults. This provides some insulation against future enhancements to the connector framework.
- </para>
- </note>
- </sect3>
- <sect3 id="repository_source_security">
- <title>Security and authentication</title>
- <para>
- As we'll see in the next section, the main method connectors have to process requests takes an &ExecutionContext;,
- which contains the JAAS security information of the subject performing the request. This means that the connector
- can use this to determine authentication and authorization information for each request.
- </para>
- <para>
- Sometimes that is not sufficient. For example, it may be that the connector needs its own authorization information
- so that it can establish a connection (even if user-level privileges still use the &ExecutionContext; provided with
- each request). In this case, the &RepositorySource; implementation will probably need JavaBean properties
- that represent the connector's authentication information. This may take the form of a username and password,
- or it may be properties that are used to delegate authentication to JAAS.
- Either way, just realize that it's perfectly acceptable for the connector to require its own security properties.
- </para>
- </sect3>
- </sect2>
- <sect2 id="implementing_repository_connection">
- <title>Implementing a <code>RepositoryConnection</code></title>
- <para>
- One job of the &RepositorySource; implementation is to create connections to the underlying sources.
- Connections are represented by classes that implement the &RepositoryConnection; interface, and creating this
- class is the next step in writing a repository connector. This is what we'll cover in this section.
- </para>
- <para>
- The &RepositoryConnection; interface is pretty straightforward:
- </para>
- <programlisting>
-/**
- * A connection to a repository source.
- * <p>
- * These connections need not support concurrent operations by multiple threads.
- * </p>
- */
-@NotThreadSafe
-public interface &RepositoryConnection; {
-
- /**
- * Get the name for this repository source. This value should be the same as that returned
- * by the same &RepositorySource; that created this connection.
- *
- * @return the identifier; never null or empty
- */
- String getSourceName();
-
- /**
- * Return the transactional resource associated with this connection. The transaction manager
- * will use this resource to manage the participation of this connection in a distributed transaction.
- *
- * @return the XA resource, or null if this connection is not aware of distributed transactions
- */
- XAResource getXAResource();
-
- /**
- * Ping the underlying system to determine if the connection is still valid and alive.
- *
- * @param time the length of time to wait before timing out
- * @param unit the time unit to use; may not be null
- * @return true if this connection is still valid and can still be used, or false otherwise
- * @throws InterruptedException if the thread has been interrupted during the operation
- */
- boolean ping( long time, &TimeUnit; unit ) throws InterruptedException;
-
- /**
- * Set the listener that is to receive notifications to changes to content within this source.
- *
- * @param listener the new listener, or null if no component is interested in the change notifications
- */
- void setListener( &RepositorySourceListener; listener );
-
- /**
- * Get the default cache policy for this repository. If none is provided, a global cache policy
- * will be used.
- *
- * @return the default cache policy
- */
- &CachePolicy; getDefaultCachePolicy();
-
- /**
- * Execute the supplied commands against this repository source.
- *
- * @param context the environment in which the commands are being executed; never null
- * @param request the request to be executed; never null
- * @throws RepositorySourceException if there is a problem loading the node data
- */
- void execute( &ExecutionContext; context,
- &Request; request ) throws &RepositorySourceException;;
-
- /**
- * Close this connection to signal that it is no longer needed and that any accumulated
- * resources are to be released.
- */
- void close();
-}</programlisting>
- <para>
- While most of these methods are straightforward, a few warrant additional information.
- The <code>ping(...)</code> allows DNA to check the connection to see if it is
- alive. This method can be used in a variety of situations, ranging from verifying that a &RepositorySource;'s
- JavaBean properties are correct to ensuring that a connection is still alive before returning the connection from
- a connection pool.
- </para>
- <para>
- DNA hasn't yet defined the event mechanism, so connectors don't have any methods to invoke on the &RepositorySourceListener;.
- This will be defined in the next release, so feel free to manage the listeners now. Note that by default the &RepositorySourceCapabilities; returns
- <code>false</code> for <code>supportsEvents()</code>.
- </para>
- <para>
- The most important method on this interface, though, is the <code>execute(...)</code> method, which serves as the
- mechanism by which the component using the connector access and manipulates the content exposed by the connector.
- The first parameter to this method is the &ExecutionContext;, which contains the information about environment
- as well as the subject performing the request. This was discussed <link linkend="execution-context">earlier</link>.
- </para>
- <para>
- The second parameter, however, represents a request that is to be processed by the connector. Request objects can
- take many different forms, as there are different classes for each kind of request (see the table below).
- Each request contains the information a connector needs to do the processing, and it also is the place
- where the connector places the results (or the error, if one occurs).
- </para>
- <para>
- How do the requests reference a node (or nodes)? Since requests are coming from a client, the client
- may identify a particular node using a &Location; object that is created with:
- <itemizedlist>
- <listitem>
- <para>the &Path; to the node; or</para>
- </listitem>
- <listitem>
- <para>one or more <emphasis>identification properties</emphasis> that are likely source=specific
- and that are represented with &Property; objects; or</para>
- </listitem>
- <listitem>
- <para>a combination of both.</para>
- </listitem>
- </itemizedlist>
- So, when a client knows the path or the identification properties, they can create a &Location;. However,
- all of the requests return &Location; objects, so often times the client simply uses the location
- from a previous request. Since &Location; is an immutable class, it is perfectly safe to reuse them.
- </para>
- <para>
- One more thing about locations: while the request may have an incomplete location (e.g., a path but no
- identification properties), the connector is expected to set on the request the <emphasis>actual</emphasis>
- location that contains the path and all identification properties. So as long as the client
- reuses the actual locations in subsequent requests, the connectors will have the benefit of having
- both the path and identification properties. Connectors can then be written to leverage this
- information, although the connector should still perform as expected when requests have incomplete locations.
- </para>
- <table frame='all'>
- <title>Types of Node Operation Requests</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>ReadNodeRequest</entry>
- <entry>
- A request to read from the named workspace in the source a node's properties and children.
- The node may be specified by path and/or by identification properties.
- The connector returns all properties and the locations for all children,
- or sets a &PathNotFoundException; error on the request if the node did not exist in the workspace.
- If the node is found, the connector sets on the request the actual location of the node (including the path and identification properties).
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>VerifyNodeExistsRequest</entry>
- <entry>
- A request to verify the existance of a node at the specified location in the named workspace of the source.
- The connector returns all the actual location for the node if it exists, or
- sets a &PathNotFoundException; error on the request if the node does not exist in the workspace.
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>ReadAllPropertiesRequest</entry>
- <entry>
- A request to read from the named workspace in the source all of the properties of a node.
- The node may be specified by path and/or by identification properties.
- The connector returns all properties that were found on the node,
- or sets a &PathNotFoundException; error on the request if the node did not exist in the workspace.
- If the node is found, the connector sets on the request the actual location of the node (including the path and identification properties).
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>ReadPropertyRequest</entry>
- <entry>
- A request to read from the named workspace in the source a single property of a node.
- The node may be specified by path and/or by identification properties,
- and the property is specified by name.
- The connector returns the property if found on the node,
- or sets a &PathNotFoundException; error on the request if the node or property did not exist in the workspace.
- If the node is found, the connector sets on the request the actual location of the node (including the path and identification properties).
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>ReadAllChildrenRequest</entry>
- <entry>
- A request to read from the named workspace in the source all of the children of a node.
- The node may be specified by path and/or by identification properties.
- The connector returns an ordered list of locations for each child found on the node,
- an empty list if the node had no children,
- or sets a &PathNotFoundException; error on the request if the node did not exist in the workspace.
- If the node is found, the connector sets on the request the actual location of the parent node (including the path and identification properties).
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>ReadBlockOfChildrenRequest</entry>
- <entry>
- A request to read from the named workspace in the source a block of children of a node, starting with the n<superscript>th</superscript> children.
- This is designed to allow paging through the children, which is much more efficient for large numbers of children.
- The node may be specified by path and/or by identification properties, and the block
- is defined by a starting index and a count (i.e., the block size).
- The connector returns an ordered list of locations for each of the node's children found in the block,
- or an empty list if there are no children in that range.
- The connector also sets on the request the actual location of the parent node (including the path and identification properties)
- or sets a &PathNotFoundException; error on the request if the parent node did not exist in the workspace.
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>ReadNextBlockOfChildrenRequest</entry>
- <entry>
- A request to read from the named workspace in the source a block of children of a node, starting with the children that immediately follow
- a previously-returned child.
- This is designed to allow paging through the children, which is much more efficient for large numbers of children.
- The node may be specified by path and/or by identification properties, and the block
- is defined by the location of the node immediately preceding the block and a count (i.e., the block size).
- The connector returns an ordered list of locations for each of the node's children found in the block,
- or an empty list if there are no children in that range.
- The connector also sets on the request the actual location of the parent node (including the path and identification properties)
- or sets a &PathNotFoundException; error on the request if the parent node did not exist in the workspace.
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>ReadBranchRequest</entry>
- <entry>
- A request to read a portion of a subgraph that has as its root a particular node, up to a maximum depth.
- This request is an efficient mechanism when a branch (or part of a branch) is to be navigated and processed,
- and replaces some non-trivial code to read the branch iteratively using multiple <code>ReadNodeRequest</code>s.
- The connector reads the branch to the specified maximum depth, returning the properties and children for all
- nodes found in the branch.
- The connector also sets on the request the actual location of the branch's root node (including the path and identification properties).
- The connector sets a &PathNotFoundException; error on the request if the node at
- the top of the branch does not exist in the workspace.
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>CreateNodeRequest</entry>
- <entry>
- A request to create a node at the specified location and setting on the new node the properties included in the request.
- The connector creates the node at the desired location, adjusting any same-name-sibling indexes as required.
- (If an SNS index is provided in the new node's location, existing children with the same name after that SNS index
- will have their SNS indexes adjusted. However, if the requested location does not include a SNS index, the new
- node is added after all existing children, and it's SNS index is set accordingly.)
- The connector also sets on the request the actual location of the new node (including the path and identification properties)..
- The connector sets a &PathNotFoundException; error on the request if the parent node does not exist in the workspace.
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>RemovePropertiesRequest</entry>
- <entry>
- A request to remove a set of properties on an existing node. The request contains the location of the node as well as the
- names of the properties to be removed. The connector performs these changes and sets on the request the
- actual location (including the path and identification properties) of the node.
- The connector sets a &PathNotFoundException; error on the request if the node does not exist in the workspace.
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>UpdatePropertiesRequest</entry>
- <entry>
- A request to set or update properties on an existing node. The request contains the location of the node as well as the
- properties to be set and those to be deleted. The connector performs these changes and sets on the request the
- actual location (including the path and identification properties) of the node.
- The connector sets a &PathNotFoundException; error on the request if the node does not exist in the workspace.
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>RenameNodeRequest</entry>
- <entry>
- A request to change the name of a node. The connector changes the node's name, adjusts all SNS indexes
- accordingly, and returns the actual locations (including the path and identification properties) of both the original
- location and the new location.
- The connector sets a &PathNotFoundException; error on the request if the node does not exist in the workspace.
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>CopyBranchRequest</entry>
- <entry>
- A request to copy a portion of a subgraph that has as its root a particular node, up to a maximum depth.
- The request includes the name of the workspace where the original node is located as well as the name of the
- workspace where the copy is to be placed (these may be the same, but may be different).
- The connector copies the branch from the original location, up to the specified maximum depth, and places a copy
- of the node as a child of the new location.
- The connector also sets on the request the actual location (including the path and identification properties)
- of the original location as well as the location of the new copy.
- The connector sets a &PathNotFoundException; error on the request if the node at
- the top of the branch does not exist in the workspace.
- The connector sets a &InvalidWorkspaceException; error on the request if one of the named workspaces does not exist.
- </entry>
- </row>
- <row>
- <entry>MoveBranchRequest</entry>
- <entry>
- A request to move a subgraph that has a particular node as its root.
- The connector moves the branch from the original location and places it as child of the specified new location.
- The connector also sets on the request the actual location (including the path and identification properties)
- of the original and new locations. The connector will adjust SNS indexes accordingly.
- The connector sets a &PathNotFoundException; error on the request if the node that is to be moved or the
- new location do not exist in the workspace.
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>DeleteBranchRequest</entry>
- <entry>
- A request to delete an entire branch specified by a single node's location.
- The connector deletes the specified node and all nodes below it, and sets the actual location,
- including the path and identification properties, of the node that was deleted.
- The connector sets a &PathNotFoundException; error on the request if the node being deleted does not exist in the workspace.
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>CompositeRequest</entry>
- <entry>
- A request that actually comprises multiple requests (none of which will be a composite).
- The connector simply processes all of the requests in the composite request, but should set on the composite
- request any error (usually the first error) that occurs during processing of the contained requests.
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>There are also requests that deal with workspaces:</para>
- <table frame='all'>
- <title>Types of Workspace Requests</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Name</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>GetWorkspacesRequest</entry>
- <entry>
- A request to obtain the names of the existing workspaces that are accessible to the caller.
- </entry>
- </row>
- <row>
- <entry>VerifyWorkspaceRequest</entry>
- <entry>
- A request to verify that a workspace with a particular name exists.
- The connector returns the actual location for the root node if the workspace exists, as well as the actual name of the workspace
- (e.g., the default workspace name if a null name is supplied).
- </entry>
- </row>
- <row>
- <entry>CreateWorkspaceRequest</entry>
- <entry>
- A request to create a workspace with a particular name.
- The connector returns the actual location for the root node if the workspace exists, as well as the actual name of the workspace
- (e.g., the default workspace name if a null name is supplied).
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace already exists.
- </entry>
- </row>
- <row>
- <entry>DestroyWorkspaceRequest</entry>
- <entry>
- A request to destroy a workspace with a particular name.
- The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
- </entry>
- </row>
- <row>
- <entry>CloneWorkspaceRequest</entry>
- <entry>
- A request to clone one named workspace as another new named workspace.
- The connector sets a &InvalidWorkspaceException; error on the request if the original workspace does not exist,
- or if the new workspace already exists.
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>
- Although there are over a dozen different kinds of requests, we do anticipate adding more in future releases.
- For example, DNA will likely support searching repository content in sources through an additional subclass of &Request;.
- Getting the version history for a node will likely be another kind of request added in an upcoming release.
- </para>
- <para>
- A connector is technically free to implement the <code>execute(...)</code> method in any way, as long as the semantics
- are maintained. But DNA provides a &RequestProcessor; class that can simplify writing your own connector and at the
- same time help insulate your connector from new kinds of requests that may be added in the future. The &RequestProcessor;
- is an abstract class that defines a <code>process(...)</code> method for each concrete &Request; subclass.
- In other words, there is a <code>process(CompositeRequest)</code> method, a <code>process(ReadNodeRequest)</code> method,
- and so on.
- </para>
- <para>
- To use this in your connector, simply create a subclass of &RequestProcessor;, overriding all of the abstract methods and optionally
- overriding any of the other methods that have a default implementation.
- </para>
- <note>
- <para>
- The &RequestProcessor; abstract class contains default implementations for quite a few of the <code>process(...)</code> methods,
- and these will be <emphasis>sufficient</emphasis> but probably not efficient or optimum. If you can provide a more efficient
- implementation given your source, feel free to do so. However, if performance is not a big issue, all of the concrete methods
- will provide the correct behavior. Keep things simple to start out - you can always provide better implementations later.
- </para>
- </note>
- <para>
- Then, in your connector's <code>execute(&ExecutionContext;, &Request;)</code> method, instantiate your &RequestProcessor; subclass
- and call its <code>process(&Request;) method, passing in the <code>execute(...)</code> method's &Request; parameter.</code>
- The &RequestProcessor; will determine the appropriate method given the actual &Request; object and will then invoke that method:
- </para>
- <programlisting>
-public void execute( final &ExecutionContext; context,
- final &Request; request ) throws RepositorySourceException {
- RequestProcessor processor = new RequestProcessor(context);
- try {
- processor.process(request);
- } finally {
- processor.close();
- }
-}</programlisting>
- <para>
- If you do this, the bulk of your connector implementation may be in the &RequestProcessor; implementation methods.
- This not only is pretty maintainable, it also lends itself to easier testing. And should any new request types be added
- in the future, your connector may work just fine without any changes. In fact, if the &RequestProcessor; class
- can implement meaningful methods for those new request types, your connector may "just work". Or, at least
- your connector will still be binary compatible, even if your connector won't support any of the new features.
- </para>
- <para>
- Finally, how should the connector handle exceptions? As mentioned above, each &Request; object has a slot where the connector
- can set any exception encountered during processing. This not only handles the exception, but in the case of &CompositeRequest;s
- it also correctly associates the problem with the request. However, it is perfectly acceptable to throw an exception
- if the connection becomes invalid (e.g., there is a communication failure) or if a fatal error would prevent subsequent
- requests from being processed.
- </para>
- </sect2>
- <sect2 id="testing_custom_connectors">
- <title>Testing custom connectors</title>
- <para>
- Testing connectors is not really that much different than testing other classes. Using mocks may help to isolate your
- instances so you can create more unit tests that don't require the underlying source system.
- </para>
- <para>
- However, there may be times when you have to use the underlying source system in your tests. If this is the case,
- we recommend using Maven integration tests, which run at a different point in the Maven lifecycle. The benefit of
- using integration tests is that by convention they're able to rely upon external systems. Plus, your unit tests
- don't become polluted with slow-running tests that break if the external system is not available.
- </para>
- </sect2>
- <sect2 id="deploying_custom_connectors">
- <title>Configuring and deploying custom connectors</title>
- <para>
- After building your connector project, you need to configure the JBoss DNA components your application is using so
- that they use your connector. In a lot of cases, this will entail instantiating your connector's &RepositorySource; class,
- setting the various properties, and registering it with a &RepositoryLibrary;. Or, it will entail using a configuration
- repository to use your source and letting &RepositoryService; instantiate and set up your &RepositorySource; instance.
- Or, you can just instantiate and set it up manually, passing the instance to whatever component needs it.
- </para>
- <para>
- And of course you have to make the JAR file containing your connector (as well as any dependency JARs) available to
- your application's classpath.
- </para>
- </sect2>
- </sect1>
- <sect1 id="dna_graph_api">
- <title>Graph API for using connectors</title>
- <para>
- So far we've talked about repositories, repository connectors, and how connectors respond to the different kinds of requests.
- Normally you'd code to the JCR API and use our JCR implementation. However, what does your code look like if you want
- to use the connectors directly, without using our JCR implementation? After all, you may be a contributor to JBoss DNA,
- or you may want to take advantage of our connectors without all the overhead of JCR.
- </para>
- <para>
- One option, of course, is to explicitly create the different requests and pass them to the connector's <code>execute(...)</code> method.
- While this is the most efficient approach (and one taken in some key DNA components), you probably want something that
- is much less verbose and much easier to use. This is where the DNA graph API comes in.
- </para>
- <para>
- JBoss DNA's <emphasis>Graph API</emphasis> was designed as a lightweight public API for working with graph information,
- and it insulates components from the underlying requests and interacting with connectors.
- The &Graph; class is the primary class in API, and each instance represents a single, independent
- view of the graph of content from a single connector. &Graph; instances return snapshots of state, and those snapshots
- never change after they're retrieved. To obtain a &Graph; instance, use the static <code>create(...)</code>
- method, supplying the name of the source, a &RepositoryConnectionFactory; from which a &RepositoryConnection; can be obtained,
- and the &ExecutionContext;.
- </para>
- <para>
- The &Graph; class basically represents an <ulink url="http://www.martinfowler.com/bliki/DomainSpecificLanguage.html">internal domain specific language (DSL)</ulink>,
- designed to be easy to use in an application.
- The Graph API makes extensive use of interfaces and method chaining, so that methods return a concise interface that has only those
- methods that make sense at that point. In fact, this should be really easy if your IDE has code completion.
- Just remember that under the covers, a &Graph; is just building &Request; objects, submitting them to the connector,
- and then exposing the results.
- </para>
- <sect2 id="dna_graph_api_workspaces">
- <title>Using workspaces</title>
- <para>
- Let's look at some examples of how the Graph API works. This first example shows how to obtain the names of the available workspaces:
- </para>
- <programlisting>
-&Set;<&String;> workspaceNames = graph.getWorkspaces();
-</programlisting>
- <para>Once you know the name of the workspace, you can specify that the graph should use it:
- </para>
- <programlisting>
-graph.useWorkspace("myWorkspace");
-</programlisting>
- <para>
- From this point forward, all requests will apply to the workspace named "myWorkspace". At any time, you can use a different workspace,
- which will affect all subsequent requests made using the graph. Of course, creating a new workspace is just as easy:
- </para>
- <programlisting>
-graph.createWorkspace().named("newWorkspace");
-</programlisting>
- <para>This will attempt to create a workspace named "newWorkspace", which will fail if that workspace already exists. You may
- want to create a new workspace with a name that should be altered if the name you supply is already used. The following code shows
- how you can do this:
- </para>
- <programlisting>
-graph.createWorkspace().namedSomethingLike("newWorkspace");
-</programlisting>
- <para>If there is no existing workspace named "newWorkspace", a new one will be created with this name. However, if "newWorkspace" already
- exists, this call will create a workspace with a name that is some alteration of the supplied name.
- </para>
- <para>
- You can also clone workspaces, too:
- </para>
- <programlisting>
-graph.createWorkspace().clonedFrom("original").named("something");
-</programlisting>
- <para>
- or
- </para>
- <programlisting>
-graph.createWorkspace().clonedFrom("original").namedSomethingLike("something");
-</programlisting>
- <para>
- As you can see, it's very easy to specify which workspace you want to use or to create new workspaces. You can also find out which workspace
- the graph is currently using:
- </para>
- <programlisting>
-&String; current = graph.getCurrentWorkspaceName();
-</programlisting>
- <para>or, if you want, you can get more information about the workspace:
- </para>
- <programlisting>
-&Workspace; current = graph.getCurrentWorkspace();
-&String; name = current.getName();
-&Location; rootLocation = current.getRoot();
-</programlisting>
- </sect2>
- <sect2 id="dna_graph_api_nodes">
- <title>Working with nodes</title>
- <para>
- Now let's switch to working with nodes. This first example returns a map of properties (keyed by property name)
- for a node at a specific &Path;:
- </para>
- <programlisting>
-&Path; path = ...
-Map<&Name;,&Property;> propertiesByName = graph.getPropertiesByName().on(path);
-</programlisting>
- <para>
- This next example shows how the graph can be used to obtain and loop over the properties of a node:
- </para>
- <programlisting>
-&Path; path = ...
-for ( &Property; property : graph.getProperties().on(path) ) {
- ...
-}
-</programlisting>
- <para>
- Likewise, the next example shows how the graph can be used to obtain and loop over the children of a node:
- </para>
- <programlisting>
-&Path; path = ...
-for ( &Location; child : graph.getChildren().of(path) ) {
- &Path; childPath = child.getPath();
- ...
-}
-</programlisting>
- <para>
- Notice that the examples pass a &Path; instance to the <code>on(...)</code> and <code>of(...)</code> methods. Many
- of the Graph API methods take a variety of parameter types, including String, &Path;s, &Location;s, &UUID;, or &Property; parameters.
- This should make it easy to use in many different situations.
- </para>
- <para>
- Of course, changing content is more interesting and offers more interesting possibilities. Here are a few examples:
- </para>
- <programlisting>
-&Path; path = ...
-&Location; location = ...
-&Property; idProp1 = ...
-&Property; idProp2 = ...
-&UUID; uuid = ...
-graph.move(path).into(idProp1, idProp2);
-graph.copy(path).into(location);
-graph.delete(uuid);
-graph.delete(idProp1,idProp2);
-</programlisting>
- <para>
- The methods shown above work immediately, as soon as each request is built. However, there is another way to use
- the &Graph; object, and that is in a <emphasis>batch</emphasis> mode. Simply create a &GraphBatch; object using the
- <code>batch()</code> method, create the requests on that batch object, and then execute all of the commands on the
- batch by calling its <code>execute()</code> method. That <code>execute()</code> method returns a &Results; interface
- that can be used to read the node information retrieved by the batched requests.
- </para>
- <para>
- Method chaining works really well with the batch mode, since multiple commands can be assembled together very easily:
- </para>
- <programlisting>
-&Path; path = ...
-String path2 = ...
-&Location; location = ...
-&Property; idProp1 = ...
-&Property; idProp2 = ...
-&UUID; uuid = ...
-graph.batch().move(path).into(idProp1, idProp2).and().copy(path2).into(location).and().delete(uuid).execute();
-&Results; results = graph.batch().read(path2).
- and().readChildren().of(idProp1,idProp2).
- and().readSugraphOfDepth(3).at(uuid2).
- execute();
-for ( &Location; child : results.getNode(path2) ) {
- ...
-}
-</programlisting>
- <para>
- Of course, this section provided just a hint of the Graph API.
- The &Graph; interface is actually quite complete and offers a full-featured approach for reading and updating a graph.
- For more information, see the &Graph; JavaDocs.
- </para>
- </sect2>
- </sect1>
- <sect1>
- <title>Summary</title>
- <para>
- In this chapter, we covered all the aspects of JBoss DNA repositories, including the connector framework,
- how DNA's JCR implementation works with connectors, what connectors are available (and how to use them),
- and how to write your own connector. So now that you know how to set up and use JBoss DNA repositories,
- the <link linkend="jcr">next chapter</link> describes how you can leverage JBoss DNA's JCR implementation.
- </para>
- </sect1>
-</chapter>
Added: trunk/docs/reference/src/main/docbook/en-US/content/sequencers/zip.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/sequencers/zip.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/sequencers/zip.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="zip-file-sequencer">
+ <title>ZIP File Sequencer</title>
+ <para>
+ blah blah
+ </para>
+</chapter>
\ No newline at end of file
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/sequencers/zip.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: trunk/docs/reference/src/main/docbook/en-US/content/sequencing.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/sequencing.xml 2009-06-08 00:52:09 UTC (rev 994)
+++ trunk/docs/reference/src/main/docbook/en-US/content/sequencing.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -1,793 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
-%CustomDTD;
-]>
-<chapter id="sequencing">
- <title>Sequencing content</title>
- <para>As we've mentioned before, JBoss DNA is able to work with existing JCR repositories. Your client applications
- make changes to the information in those repositories, and JBoss DNA automatically uses its sequencers to extract
- additional information from the uploaded files.</para>
- <para>
- This chapter discusses the sequencing features of JBoss DNA and the components that are involved.
- </para>
- <sect1 id="sequencing-service">
- <title>Sequencing Service</title>
- <para>The JBoss DNA <emphasis>sequencing service</emphasis> is the component that manages the <emphasis>sequencers</emphasis>,
- reacting to changes in JCR repositories and then running the appropriate sequencers.
- This involves processing the changes on a node, determining which (if any) sequencers should be run on that node,
- and for each sequencer constructing the execution environment, calling the sequencer, and saving the information
- generated by the sequencer.</para>
- <note>
- <para>Configuring JBoss DNA services is a bit more manual than is ideal. As you'll see, JBoss DNA uses dependency
- injection to allow a great deal of flexibility in how it can be configured and customized. But this flexibility
- makes it more difficult for you to use. We understand this, and will soon provide a much easier way to set up
- and manage JBoss DNA. Current plans are to use the <ulink url="http://www.jboss.org/jbossmc">JBoss Microcontainer</ulink>
- along with a configuration repository.</para>
- </note>
- <para>To set up the sequencing service, an instance is created, and dependent components are injected into
- the object. This includes among other things:
- <itemizedlist>
- <listitem>
- <para>An <emphasis>execution context</emphasis> that defines the context in which the service runs, including
- a factory for JCR sessions given names of the repository and workspace. This factory must be configured,
- and is how JBoss DNA knows about your JCR repositories and how to connect to them. More on this a bit later.</para>
- </listitem>
- <listitem>
- <para>An optional <emphasis>factory for class loaders</emphasis> used to load sequencers. If no factory is supplied,
- the service uses the current thread's context class loader (or if that is null, the class loader that loaded the
- sequencing service class).</para>
- </listitem>
- <listitem>
- <para>An &ExecutorService; used to execute the sequencing activites. If none
- is supplied, a new single-threaded executor is created by calling <code>Executors.newSingleThreadExecutor()</code>.
- (This can easily be changed by subclassing and overriding the <code>SequencerService.createDefaultExecutorService()</code> method.)</para>
- </listitem>
- <listitem>
- <para>Filters for sequencers and events. By default, all sequencers are considered for "node added", "property added"
- and "property changed" events.</para>
- </listitem>
- </itemizedlist>
- </para>
- <para>As mentioned above, the &JcrExecutionContext; provides access to a &SessionFactory; that is used
- by JBoss DNA to establish sessions to your JCR repositories. Two implementations are available:
- <itemizedlist>
- <listitem>
- <para>The &JndiSessionFactory;> looks up JCR &Repository; instances in JNDI using
- names that are supplied when creating sessions. This implementation also has methods to set the
- JCR &Credentials; for a given workspace name.</para>
- </listitem>
- <listitem>
- <para>The &SimpleSessionFactory; has methods to register the JCR &Repository; instances
- with names, as well as methods to set the JCR &Credentials; for a given workspace name.</para>
- </listitem>
- </itemizedlist>
- You can use the &JcrExecutionContext; and use one of these &SessionFactory; implementations or another
- implementation that you provide.</para>
- <para>Here's an example of how to instantiate and configure the &SequencingService;:</para>
- <programlisting>
-&SimpleSessionFactory; sessionFactory = new &SimpleSessionFactory;();
-sessionFactory.registerRepository("Main Repository", this.repository);
-&Credentials; credentials = new &SimpleCredentials;("jsmith", "secret".toCharArray());
-sessionFactory.registerCredentials("Main Repository/Workspace1", credentials);
-// Now create the JCR execution context, with a reference to the session factory
-// and the name of the repository from which sessions will be obtained ...
-ExecutionContext executionContext = new &JcrExecutionContext;(sessionFactory,"Main Repository");
-
-// Create the sequencing service, passing in the execution context ...
-&SequencingService; sequencingService = new &SequencingService;();
-sequencingService.setExecutionContext(executionContext);
-</programlisting>
- <para>After the sequencing service is created and configured, it must be started. The &SequencingService;
- has an <emphasis>administration object</emphasis> (that is an instance of &ServiceAdministrator;)
- with <code>start()</code>, <code>pause()</code>, and <code>shutdown()</code> methods. The latter method will
- close the queue for sequencing, but will allow sequencing operations already running to complete normally.
- To wait until all sequencing operations have completed, simply call the <code>awaitTermination</code> method
- and pass it the maximum amount of time you want to wait.</para>
- <programlisting>
-sequencingService.getAdministrator().start();
-</programlisting>
- <para>The JBoss DNA services are utilizing resources and threads that must be released before your application is ready to shut down.
- The safe way to do this is to simply obtain the &ServiceAdministrator; for each service (via the <code>getServiceAdministrator()</code> method)
- and call <code>shutdown()</code>. As previously mentioned, the shutdown method will simply prevent new work from being processed
- and will not wait for existing work to be completed. If you want to wait until the service completes all its work, you must wait
- until the service terminates. Here's an example that shows how this is done:</para>
- <programlisting>
-// Shut down the service and wait until it's all shut down ...
-sequencingService.getAdministrator().shutdown();
-sequencingService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
-
-// Shut down the observation service ...
-observationService.getAdministrator().shutdown();
-observationService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
-</programlisting>
- </sect1>
- <sect1 id="sequencer-configuration">
- <title>Sequencer Configurations</title>
- <para>The sequencing service must also be configured with the sequencers that it will use. This is done using the
- <code>addSequencer(SequencerConfig)</code> method and passing a &SequencerConfig; instance that
- you create. Here's the code that defines 3 sequencer configurations: 1 that places image metadata into
- "<code><![CDATA[/images/<filename>]]></code>", another that places MP3 metadata into "<code><![CDATA[/mp3s/<filename>]]></code>",
- and a third that places a structure that represents the classes, methods, and attributes found within Java source into
- "<code><![CDATA[/java/<filename>]]></code>".</para>
- <programlisting>
-String name = "Image Sequencer";
-String desc = "Sequences image files to extract the characteristics of the image";
-String classname = "org.jboss.dna.sequencer.images.ImageMetadataSequencer";
-String[] classpath = null; // Use the current classpath
-String[] pathExpressions = {"//(*.(jpg|jpeg|gif|bmp|pcx|png)[*])/jcr:content[@jcr:data] => /images/$1"};
-&SequencerConfig; imageSequencerConfig = new &SequencerConfig;(name, desc, classname,
- classpath, pathExpressions);
-sequencingService.addSequencer(imageSequencerConfig);
-
-name = "MP3 Sequencer";
-desc = "Sequences MP3 files to extract the ID3 tags from the audio file";
-classname = "org.jboss.dna.sequencer.mp3.Mp3MetadataSequencer";
-pathExpressions = {"//(*.mp3[*])/jcr:content[@jcr:data] => /mp3s/$1"};
-&SequencerConfig; mp3SequencerConfig = new &SequencerConfig;(name, desc, classname,
- classpath, pathExpressions);
-sequencingService.addSequencer(mp3SequencerConfig);
-
-name = "Java Sequencer";
-desc = "Sequences java files to extract the characteristics of the Java source";
-classname = "org.jboss.dna.sequencer.java.JavaMetadataSequencer";
-pathExpressions = {"//(*.java[*])/jcr:content[@jcr:data] => /java/$1"};
-&SequencerConfig; javaSequencerConfig = new &SequencerConfig;(name, desc, classname,
- classpath, pathExpressions);
-this.sequencingService.addSequencer(javaSequencerConfig);
-</programlisting>
- <para>Each configuration defines several things, including the name, description, and sequencer implementation class.
- The configuration also defines the classpath information, which can be passed to the &ClassLoaderFactory; to get
- a Java &ClassLoader; with which the sequencer class can be loaded. (If no classpath information is provided, as is done
- in the code above, the application class loader is used.) The configuration also specifies the path expressions that
- identify the nodes that should be sequenced with the sequencer and where to store the output generated by the sequencer.
- Path expressions are pretty straightforward but are quite powerful, so before we go any further with the example,
- let's dive into path expressions in more detail.</para>
- <sect2 id="path_expressions">
- <title>Path Expressions</title>
- <para>Path expressions consist of two parts: a selection criteria (or an input path) and an output path:</para>
- <programlisting><![CDATA[ inputPath => outputPath ]]></programlisting>
- <para>The <emphasis>inputPath</emphasis> part defines an expression for the path of a node that is to be sequenced.
- Input paths consist of '<code>/</code>' separated segments, where each segment represents a pattern for a single node's
- name (including the same-name-sibling indexes) and '<code>@</code>' signifies a property name.</para>
- <para>Let's first look at some simple examples:</para>
- <table frame='all'>
- <title>Simple Input Path Examples</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Input Path</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row><entry>/a/b</entry><entry>Match node "<code>b</code>" that is a child of the top level node "<code>a</code>". Neither node
- may have any same-name-sibilings.</entry></row>
- <row><entry>/a/*</entry><entry>Match any child node of the top level node "<code>a</code>".</entry></row>
- <row><entry>/a/*.txt</entry><entry>Match any child node of the top level node "<code>a</code>" that also has a name ending in "<code>.txt</code>".</entry></row>
- <row><entry>/a/*.txt</entry><entry>Match any child node of the top level node "<code>a</code>" that also has a name ending in "<code>.txt</code>".</entry></row>
- <row><entry>/a/b@c</entry><entry>Match the property "<code>c</code>" of node "<code>/a/b</code>".</entry></row>
- <row><entry>/a/b[2]</entry><entry>The second child named "<code>b</code>" below the top level node "<code>a</code>".</entry></row>
- <row><entry>/a/b[2,3,4]</entry><entry>The second, third or fourth child named "<code>b</code>" below the top level node "<code>a</code>".</entry></row>
- <row><entry>/a/b[*]</entry><entry>Any (and every) child named "<code>b</code>" below the top level node "<code>a</code>".</entry></row>
- <row><entry>//a/b</entry><entry>Any node named "<code>b</code>" that exists below a node named "<code>a</code>", regardless
- of where node "<code>a</code>" occurs. Again, neither node may have any same-name-sibilings.</entry></row>
- </tbody>
- </tgroup>
- </table>
- <para>With these simple examples, you can probably discern the most important rules. First, the '<code>*</code>' is a wildcard character
- that matches any character or sequence of characters in a node's name (or index if appearing in between square brackets), and
- can be used in conjunction with other characters (e.g., "<code>*.txt</code>").</para>
- <para>Second, square brackets (i.e., '<code>[</code>' and '<code>]</code>') are used to match a node's same-name-sibiling index.
- You can put a single non-negative number or a comma-separated list of non-negative numbers. Use '0' to match a node that has no
- same-name-sibilings, or any positive number to match the specific same-name-sibling.</para>
- <para>Third, combining two delimiters (e.g., "<code>//</code>") matches any sequence of nodes, regardless of what their names are
- or how many nodes. Often used with other patterns to identify nodes at any level matching other patterns.
- Three or more sequential slash characters are treated as two.</para>
- <para>Many input paths can be created using just these simple rules. However, input paths can be more complicated. Here are some
- more examples:</para>
- <table frame='all'>
- <title>More Complex Input Path Examples</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Input Path</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row><entry>/a/(b|c|d)</entry><entry>Match children of the top level node "<code>a</code>" that are named "<code>a</code>",
- "<code>b</code>" or "<code>c</code>". None of the nodes may have same-name-sibling indexes.</entry></row>
- <row><entry>/a/b[c/d]</entry><entry>Match node "<code>b</code>" child of the top level node "<code>a</code>", when node
- "<code>b</code>" has a child named "<code>c</code>", and "<code>c</code>" has a child named "<code>d</code>".
- Node "<code>b</code>" is the selected node, while nodes "<code>b</code>" and "<code>b</code>" are used as criteria but are not
- selected.</entry></row>
- <row><entry>/a(/(b|c|d|)/e)[f/g/@something]</entry><entry>Match node "<code>/a/b/e</code>", "<code>/a/c/e</code>", "<code>/a/d/e</code>",
- or "<code>/a/e</code>" when they also have a child "<code>f</code>" that itself has a child "<code>g</code>" with property
- "<code>something</code>". None of the nodes may have same-name-sibling indexes.</entry></row>
- </tbody>
- </tgroup>
- </table>
- <para>These examples show a few more advanced rules. Parentheses (i.e., '<code>(</code>' and '<code>)</code>') can be used
- to define a set of options for names, as shown in the first and third rules. Whatever part of the selected node's path
- appears between the parentheses is captured for use within the output path. Thus, the first input path in the previous table
- would match node "<code>/a/b</code>", and "b" would be captured and could be used within the output path using "<code>$1</code>",
- where the number used in the output path identifies the parentheses.</para>
- <para>Square brackets can also be used to specify criteria on a node's properties or children. Whatever appears in between the square
- brackets does not appear in the selected node.</para>
- <para>Let's go back to the previous code fragment and look at the first path expression:</para>
- <programlisting><![CDATA[ //(*.(jpg|jpeg|gif|bmp|pcx|png)[*])/jcr:content[@jcr:data] => /images/$1 ]]></programlisting>
- <para>This matches a node named "<code>jcr:content</code>" with property "<code>jcr:data</code>" but no siblings with the same name,
- and that is a child of a node whose name ends with "<code>.jpg</code>", "<code>.jpeg</code>", "<code>.gif</code>", "<code>.bmp</code>", "<code>.pcx</code>",
- or "<code>.png</code>" that may have any same-name-sibling index. These nodes can appear at any level in the repository.
- Note how the input path capture the filename (the segment containing the file extension), including any same-name-sibling index.
- This filename is then used in the output path, which is where the sequenced content is placed.</para>
- </sect2>
- </sect1>
- <sect1 id="sequencers">
- <title>JBoss DNA Sequencers</title>
- <para>
- JBoss DNA includes a number of sequencers "out of the box". These sequencers can be used within your application to sequence
- a variety of common file formats. To use them, the only thing you have to do is define the appropriate sequencer configurations
- and include the appropriate JAR files.
- </para>
- <sect2 id="dna-sequencer-images">
- <title>Image sequencer</title>
- <para>
- A sequencer that extracts metadata from JPEG, GIF, BMP, PCX, PNG, IFF, RAS, PBM, PGM, PPM and PSD image files.
- This sequencer extracts the file format, image resolution, number of bits per pixel and optionally number of images, comments
- and physical resolution, and then writes this information into the repository using the following structure:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">image:metadata</emphasis> node of type <code>image:metadata</code>
- </para>
- </listitem>
- <listitem>
- <itemizedlist>
- <listitem>
- <para><emphasis role="strong">jcr:mimeType</emphasis> - optional string property for the mime type of the image</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong">jcr:encoding</emphasis> - optional string property for the encoding of the image</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong">image:formatName</emphasis> - string property for the name of the format</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong">image:width</emphasis> - optional integer property for the image's width in pixels</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong">image:height</emphasis> - optional integer property for the image's height in pixles</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong">image:bitsPerPixel</emphasis> - optional integer property for the number of bits per pixel</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong">image:progressive</emphasis> - optional boolean property specifying whether the image is stored in a progressive
- (i.e., interlaced) form</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong">image:numberOfImages</emphasis> - optional integer property for the number of images stored in the file; defaults
- to 1</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong">image:physicalWidthDpi</emphasis> - optional integer property for the physical width of the image in dots per inch</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong">image:physicalHeightDpi</emphasis> - optional integer property for the physical height of the image in dots per
- inch</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong">image:physicalWidthInches</emphasis> - optional double property for the physical width of the image in inches</para>
- </listitem>
- <listitem>
- <para><emphasis role="strong">image:physicalHeightInches</emphasis> - optional double property for the physical height of the image in inches</para>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- <para>
- This structure could be extended in the future to add EXIF and IPTC metadata as child nodes. For example, EXIF metadata is
- structured as tags in directories, where the directories form something like namespaces, and which are used by different camera
- vendors to store custom metadata. This structure could be mapped with each directory (e.g. "EXIF" or "Nikon Makernote" or
- "IPTC") as the name of a child node, with the EXIF tags values stored as either properties or child nodes.
- </para>
- <para>
- To use this sequencer, simply include the <code>dna-sequencer-images</code> JAR
- in your application and configure the Sequencing Service to use this sequencer using something similar to:
- </para>
- <programlisting>
-String name = "Image Sequencer";
-String desc = "Sequences image files to extract the characteristics of the image";
-String classname = "org.jboss.dna.sequencer.images.ImageMetadataSequencer";
-String[] classpath = null; // Use the current classpath
-String[] pathExpressions = {"//(*.(jpg|jpeg|gif|bmp|pcx|png|iff|ras|pbm|pgm|ppm|psd)[*])/jcr:content[@jcr:data] => /images/$1"};
-&SequencerConfig; sequencerConfig = new &SequencerConfig;(name, desc, classname,
- classpath, pathExpressions);
-sequencingService.addSequencer(sequencerConfig);
-</programlisting>
- </sect2>
- <sect2 id="dna-sequencer-msoffice">
- <title>Microsoft Office document sequencer</title>
- <para>
- This sequencer is included in JBoss DNA and processes Microsoft Office documents, including Word documents, Excel spreadsheets,
- and PowerPoint presentations. With documents, the sequencer extracts the internal structure based on Heading styles.
- With presentations, the sequencer extracts the slides, titles, text and slide thumbnails.
- With spreadsheets, the sequencer extracts the names of the sheets. And, the sequencer extracts for all the files the
- general file information, including the name of the author, title, keywords, subject, comments, and various dates.
- </para>
- <para>
- To use this sequencer, simply include the <code>dna-sequencer-msoffice</code> JAR and all of the
- <ulink url="http://poi.apache.org/">POI</ulink> JARs
- in your application and configure the Sequencing Service to use this sequencer using something similar to:
- </para>
- <programlisting>
-String name = "Microsoft Office Document Sequencer";
-String desc = "Sequences MS Office documents, including spreadsheets and presentations";
-String classname = "org.jboss.dna.sequencer.msoffice.MSOfficeMetadataSequencer";
-String[] classpath = null; // Use the current classpath
-String[] pathExpressions = {"//(*.(doc|docx|ppt|pps|xls)[*])/jcr:content[@jcr:data] => /msoffice/$1"};
-&SequencerConfig; sequencerConfig = new &SequencerConfig;(name, desc, classname,
- classpath, pathExpressions);
-sequencingService.addSequencer(sequencerConfig);
-</programlisting>
- </sect2>
- <sect2 id="dna-sequencer-zip">
- <title>ZIP archive sequencer</title>
- <para>
- The ZIP file sequencer is included in JBoss DNA and extracts the files and folders contained in the ZIP archive file,
- extracting the files and folders into the repository using JCR's <code>nt:file</code> and <code>nt:folder</code> node types.
- </para>
- <para>
- To use this sequencer, simply include the <code>dna-sequencer-zip</code> JAR
- in your application and configure the Sequencing Service to use this sequencer using something similar to:
- </para>
- <programlisting>
-String name = "ZIP Sequencer";
-String desc = "Sequences ZIP archives to extract the files and folders";
-String classname = "org.jboss.dna.sequencer.zip.ZipSequencer";
-String[] pathExpressions = {"//(*.zip[*])/jcr:content[@jcr:data] => /zips/$1"};
-&SequencerConfig; sequencerConfig = new &SequencerConfig;(name, desc, classname,
- classpath, pathExpressions);
-this.sequencingService.addSequencer(sequencerConfig);
-</programlisting>
- </sect2>
- <sect2 id="dna-sequencer-java">
- <title>Java source sequencer</title>
- <para>
- One of the sequencers that included in JBoss DNA is the <emphasis role="strong">dna-sequencer-java</emphasis> subproject.
- This sequencer parses Java source code added to the repository and extracts the basic structure of the classes and enumerations
- defined in the code.
- This structure includes: the package structures, class declarations, class and member attribute declarations,
- class and member method declarations with signature (but not implementation logic), enumerations with each enumeration literal value,
- annotations, and JavaDoc information for all of the above.
- After extracting this information from the source code, the sequencer then writes this structure into the repository,
- where it can be further processed, analyzed, searched, navigated, or referenced.
- </para>
- <para>
- To use this sequencer, simply include the <code>dna-sequencer-java</code> JAR (plus all of the JARs that it is dependent upon)
- in your application and configure the Sequencing Service to use this sequencer using something similar to:
- </para>
- <programlisting>
-String name = "Java Sequencer";
-String desc = "Sequences java files to extract the characteristics of the Java source";
-String classname = "org.jboss.dna.sequencer.java.JavaMetadataSequencer";
-String[] classpath = null; // Use the current classpath
-String[] pathExpressions = {"//(*.java[*])/jcr:content[@jcr:data] => /java/$1"};
-&SequencerConfig; sequencerConfig = new &SequencerConfig;(name, desc, classname,
- classpath, pathExpressions);
-this.sequencingService.addSequencer(sequencerConfig);
-</programlisting>
- </sect2>
- <sect2 id="dna-sequencer-mp3">
- <title>MP3 audio file sequencer</title>
- <para>
- Another sequencer that is included in JBoss DNA is the <emphasis role="strong">dna-sequencer-mp3</emphasis> sequencer project.
- This sequencer processes MP3 audio files added to a repository and extracts the <ulink url="http://www.id3.org/">ID3</ulink>
- metadata for the file, including the track's title, author, album name, year, and comment.
- After extracting this information from the audio files, the sequencer then writes this structure into the repository,
- where it can be further processed, analyzed, searched, navigated, or referenced.
- </para>
- <para>
- To use this sequencer, simply include the <code>dna-sequencer-mp3</code> JAR and the <ulink url="http://www.jthink.net/jaudiotagger/">JAudioTagger</ulink>
- library in your application and configure the Sequencing Service to use this sequencer using something similar to:
- </para>
- <programlisting>
-String name = "MP3 Sequencer";
-String desc = "Sequences MP3 files to extract the ID3 tags of the audio file";
-String classname = "org.jboss.dna.sequencer.mp3.Mp3MetadataSequencer";
-String[] pathExpressions = {"//(*.mp3[*])/jcr:content[@jcr:data] => /mp3s/$1"};
-&SequencerConfig; sequencerConfig = new &SequencerConfig;(name, desc, classname,
- classpath, pathExpressions);
-this.sequencingService.addSequencer(sequencerConfig);
-</programlisting>
- </sect2>
- <sect2 id="dna-sequencer-cnd">
- <title>JCR Compact Node Definition (CND) file sequencer</title>
- <para>
- This sequencer processes JCR Compact Node Definition (CND) files
- to extract the node definitions with their property definitions, and inserts these into the repository using JCR standard notation.
- </para>
- </sect2>
- <sect2 id="dna-sequencer-jbpm-jpdl">
- <title>jBPM JPDL file sequencer</title>
- <para>
- This sequencer is incomplete and is not currently usable. The purpose is to sequence jBPM JPDL files to identify metadata
- about processes, their actors, and their dependencies.
- </para>
- </sect2>
- <sect2 id="dna-sequencer-xml">
- <title>XML file sequencer</title>
- <para>
- This sequencer stores the structure and data of an XML file into the repository.
- </para>
- </sect2>
-
- </sect1>
- <sect1 id="custom-sequencers">
- <title>Creating custom sequencers</title>
- <para>The current release of JBoss DNA comes with six sequencers. However, it's very easy to create your own
- sequencers and to then configure JBoss DNA to use them in your own application.
- </para>
- <para>
- Creating a custom sequencer involves the following steps:
- <orderedlist>
- <listitem>
- <para>Create a Maven 2 project for your sequencer;</para>
- </listitem>
- <listitem>
- <para>Implement the &StreamSequencer; interface with your own implementation, and create unit tests to verify
- the functionality and expected behavior;</para>
- </listitem>
- <listitem>
- <para>Add the sequencer configuration to the JBoss DNA &SequencingService; in your application
- as described in the <link linkend="using_dna">previous chapter</link>; and</para>
- </listitem>
- <listitem>
- <para>Deploy the JAR file with your implementation (as well as any dependencies), and make them available to JBoss DNA
- in your application.</para>
- </listitem>
- </orderedlist>
- It's that simple.
- </para>
- <sect2 id="custom_sequencer_project">
- <title>Creating the Maven 2 project</title>
- <para>The first step is to create the Maven 2 project that you can use to compile your code and build the JARs.
- Maven 2 automates a lot of the work, and since you're already <link linkend="maven">set up to use Maven</link>,
- using Maven for your project will save you a lot of time and effort. Of course, you don't have to use Maven 2, but then you'll
- have to get the required libraries and manage the compiling and building process yourself.</para>
- <note>
- <para>JBoss DNA may provide in the future a Maven archetype for creating sequencer projects. If you'd find this useful
- and would like to help create it, please <link linkend="preface">join the community</link>.
- </para>
- <para>In lieu of a Maven archetype, you may find it easier to start with a small existing sequencer project.
- The <emphasis role="strong">dna-sequencer-images</emphasis> project is a small, self-contained sequencer implementation that
- has only the minimal dependencies.
- See the subversion repository: <ulink url="&Subversion;trunk/extensions/dna-sequencer-images/">&Subversion;trunk/extensions/dna-sequencer-images/</ulink>
- </para>
- </note>
- <para>You can create your Maven project any way you'd like. For examples, see the <ulink url="http://maven.apache.org/guides/getting-started/index.html#How_do_I_make_m...">Maven 2 documentation</ulink>.
- Once you've done that, just add the dependencies in your project's <code>pom.xml</code> dependencies section:</para>
- <programlisting role="XML"><![CDATA[
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-common</artifactId>
- <version>0.3</version>
-</dependency>
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-graph</artifactId>
- <version>0.3</version>
-</dependency>
- ]]></programlisting>
- <para>These are minimum dependencies required for compiling a sequencer. Of course, you'll have to add
- other dependencies that your sequencer needs.</para>
- <para>As for testing, you probably will want to add more dependencies, such as those listed here:</para>
- <programlisting role="XML"><![CDATA[
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-graph</artifactId>
- <version>0.5</version>
- <type>test-jar</type>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.4</version>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>org.hamcrest</groupId>
- <artifactId>hamcrest-library</artifactId>
- <version>1.1</version>
- <scope>test</scope>
-</dependency>
-<!-- Logging with Log4J -->
-<dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.3</version>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- <scope>test</scope>
-</dependency>
- ]]></programlisting>
- <para>Testing JBoss DNA sequencers does not require a JCR repository or the JBoss DNA services. (For more detail,
- see the <link linkend="testing_custom_sequencers">testing section</link>.) However, if you want to do
- integration testing with a JCR repository and the JBoss DNA services, you'll need additional dependencies for these libraries.</para>
- <programlisting role="XML"><![CDATA[
-<!-- JBoss DNA JCR Repository -->
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-jcr</artifactId>
- <version>0.5</version>
- <scope>test</scope>
-</dependency>
-<!-- Java Content Repository API -->
-<dependency>
- <groupId>javax.jcr</groupId>
- <artifactId>jcr</artifactId>
- <version>1.0.1</version>
- <scope>test</scope>
-</dependency>
- ]]></programlisting>
- <para>At this point, your project should be set up correctly, and you're ready to move on to
- <link linkend="custom_sequencer_implementation">writing the Java implementation</link> for your sequencer.</para>
- </sect2>
- <sect2 id="custom_sequencer_implementation">
- <title>Implementing the StreamSequencer interface</title>
- <para>After creating the project and setting up the dependencies, the next step is to create a Java class that implements
- the &StreamSequencer; interface. This interface is very straightforward and involves a single method:</para>
- <programlisting>
-public interface &StreamSequencer; {
-
- /**
- * Sequence the data found in the supplied stream, placing the output
- * information into the supplied map.
- *
- * @param stream the stream with the data to be sequenced; never null
- * @param output the output from the sequencing operation; never null
- * @param context the context for the sequencing operation; never null
- */
- void sequence( &InputStream; stream, &SequencerOutput; output, &SequencerContext; context );
-}
-</programlisting>
- <para>The job of a stream sequencer is to process the data in the supplied stream, and place into the &SequencerOutput;
- any information that is to go into the JCR repository. JBoss DNA figures out when your sequencer should be called
- (of course, using the sequencing configuration you'll add in a bit), and then makes sure the generated information
- is saved in the correct place in the repository.
- </para>
- <para>The &SequencerContext; provides information about
- the current sequencing operation, including the location and properties of the node being sequenced, the MIME type
- of the node being sequenced, and a location to record problems that aren't severe enough to warrant throwing an exception.
- </para>
- <para>The &SequencerOutput; class is fairly easy to use. There are basically two methods you need to call.
- One method sets the property values, while the other sets references to other nodes in the repository. Use these
- methods to describe the properties of the nodes you want to create, using relative paths for the nodes and
- valid JCR property names for properties and references. JBoss DNA will ensure that nodes are created or updated
- whenever they're needed.</para>
- <programlisting>
-public interface &SequencerOutput; {
-
- /**
- * Set the supplied property on the supplied node. The allowable
- * values are any of the following:
- * - primitives (which will be autoboxed)
- * - String instances
- * - String arrays
- * - byte arrays
- * - InputStream instances
- * - Calendar instances
- *
- * @param nodePath the path to the node containing the property;
- * may not be null
- * @param property the name of the property to be set
- * @param values the value(s) for the property; may be empty if
- * any existing property is to be removed
- */
- void setProperty( String nodePath, String property, Object... values );
-
- /**
- * Set the supplied reference on the supplied node.
- *
- * @param nodePath the path to the node containing the property;
- * may not be null
- * @param property the name of the property to be set
- * @param paths the paths to the referenced property, which may be
- * absolute paths or relative to the sequencer output node;
- * may be empty if any existing property is to be removed
- */
- void setReference( String nodePath, String property, String... paths );
-}
-</programlisting>
- <para>JBoss DNA will create nodes of type <code>nt:unstructured</code> unless you specify the value for the
- <code>jcr:primaryType</code> property. You can also specify the values for the <code>jcr:mixinTypes</code> property
- if you want to add mixins to any node.</para>
- <para>For a complete example of a sequencer, let's look at the &ImageMetadataSequencer;
- implementation:</para>
- <programlisting>
-public class &ImageMetadataSequencer; implements &StreamSequencer; {
-
- public static final String METADATA_NODE = "image:metadata";
- public static final String IMAGE_PRIMARY_TYPE = "jcr:primaryType";
- public static final String IMAGE_MIXINS = "jcr:mixinTypes";
- public static final String IMAGE_MIME_TYPE = "jcr:mimeType";
- public static final String IMAGE_ENCODING = "jcr:encoding";
- public static final String IMAGE_FORMAT_NAME = "image:formatName";
- public static final String IMAGE_WIDTH = "image:width";
- public static final String IMAGE_HEIGHT = "image:height";
- public static final String IMAGE_BITS_PER_PIXEL = "image:bitsPerPixel";
- public static final String IMAGE_PROGRESSIVE = "image:progressive";
- public static final String IMAGE_NUMBER_OF_IMAGES = "image:numberOfImages";
- public static final String IMAGE_PHYSICAL_WIDTH_DPI = "image:physicalWidthDpi";
- public static final String IMAGE_PHYSICAL_HEIGHT_DPI = "image:physicalHeightDpi";
- public static final String IMAGE_PHYSICAL_WIDTH_INCHES = "image:physicalWidthInches";
- public static final String IMAGE_PHYSICAL_HEIGHT_INCHES = "image:physicalHeightInches";
-
- /**
- * {@inheritDoc}
- */
- public void sequence( &InputStream; stream, &SequencerOutput; output,
- &SequencerContext; context ) {
- &ImageMetadata; metadata = new &ImageMetadata;();
- metadata.setInput(stream);
- metadata.setDetermineImageNumber(true);
- metadata.setCollectComments(true);
-
- // Process the image stream and extract the metadata ...
- if (!metadata.check()) {
- metadata = null;
- }
- // Generate the output graph if we found useful metadata ...
- if (metadata != null) {
- // Place the image metadata into the output map ...
- output.setProperty(METADATA_NODE, IMAGE_PRIMARY_TYPE, "image:metadata");
- // output.psetProperty(METADATA_NODE, IMAGE_MIXINS, "");
- output.setProperty(METADATA_NODE, IMAGE_MIME_TYPE, metadata.getMimeType());
- // output.setProperty(METADATA_NODE, IMAGE_ENCODING, "");
- output.setProperty(METADATA_NODE, IMAGE_FORMAT_NAME, metadata.getFormatName());
- output.setProperty(METADATA_NODE, IMAGE_WIDTH, metadata.getWidth());
- output.setProperty(METADATA_NODE, IMAGE_HEIGHT, metadata.getHeight());
- output.setProperty(METADATA_NODE, IMAGE_BITS_PER_PIXEL, metadata.getBitsPerPixel());
- output.setProperty(METADATA_NODE, IMAGE_PROGRESSIVE, metadata.isProgressive());
- output.setProperty(METADATA_NODE, IMAGE_NUMBER_OF_IMAGES, metadata.getNumberOfImages());
- output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_WIDTH_DPI, metadata.getPhysicalWidthDpi());
- output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_HEIGHT_DPI, metadata.getPhysicalHeightDpi());
- output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_WIDTH_INCHES, metadata.getPhysicalWidthInch());
- output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_HEIGHT_INCHES, metadata.getPhysicalHeightInch());
- }
- }
-}
-</programlisting>
- <para>
- Notice how the image metadata is extracted and the output graph is generated. A single node is created with the name <code>image:metadata</code>
- and with the <code>image:metadata</code> node type. No mixins are defined for the node, but several properties are set on the node
- using the values obtained from the image metadata. After this method returns, the constructed graph will be saved to the repository
- in all of the places defined by its configuration. (This is why only relative paths are used in the sequencer.)
- </para>
- </sect2>
- <sect2 id="testing_custom_sequencers">
- <title>Testing custom sequencers</title>
- <para>The sequencing framework was designed to make testing sequencers much easier. In particular, the
- &StreamSequencer; interface does not make use of the JCR API. So instead of requiring a fully-configured
- JCR repository and JBoss DNA system, unit tests for a sequencer can focus on testing that the content is
- processed correctly and the desired output graph is generated.</para>
- <note>
- <para>For a complete example of a sequencer unit test, see the <code>ImageMetadataSequencerTest</code> unit test
- in the <code>org.jboss.dna.sequencer.images</code> package of the <code>dna-sequencers-image</code> project.
- </para>
- </note>
- <para>The following code fragment shows one way of testing a sequencer, using JUnit 4.4 assertions and
- some of the classes made available by JBoss DNA. Of course,
- this example code does not do any error handling and does not make all the assertions a real test would.</para>
- <programlisting>
-&StreamSequencer; sequencer = new &ImageMetadataSequencer;();
-&MockSequencerOutput; output = new &MockSequencerOutput;();
-&MockSequencerContext; context = new &MockSequencerContext;();
-&InputStream; stream = null;
-try {
- stream = this.getClass().getClassLoader().getResource("caution.gif").openStream();
- sequencer.sequence(stream,output,context); // writes to 'output'
- assertThat(output.getPropertyValues("image:metadata", "jcr:primaryType"),
- is(new Object[] {"image:metadata"}));
- assertThat(output.getPropertyValues("image:metadata", "jcr:mimeType"),
- is(new Object[] {"image/gif"}));
- // ... make more assertions here
- assertThat(output.hasReferences(), is(false));
-} finally {
- stream.close();
-}
-</programlisting>
- <para>It's also useful to test that a sequencer produces no output for something it should not understand:</para>
- <programlisting>
-&Sequencer; sequencer = new &ImageMetadataSequencer;();
-&MockSequencerOutput; output = new &MockSequencerOutput;();
-&MockSequencerContext; context = new &MockSequencerContext;();
-&InputStream; stream = null;
-try {
- stream = this.getClass().getClassLoader().getResource("caution.pict").openStream();
- sequencer.sequence(stream,output,context); // writes to 'output'
- assertThat(output.hasProperties(), is(false));
- assertThat(output.hasReferences(), is(false));
-} finally {
- stream.close();
-}
-</programlisting>
- <para>These are just two simple tests that show ways of testing a sequencer. Some tests may get quite involved,
- especially if a lot of output data is produced.
- </para>
- <para>It may also be useful to create some integration tests
- that <link linkend="using_dna">configure JBoss DNA</link> to use a custom sequencer, and to then upload
- content using the JCR API, verifying that the custom sequencer did run. However, remember that JBoss DNA
- runs sequencers asynchronously in the background, and you must synchronize your tests to ensure that the
- sequencers have a chance to run before checking the results. (One way of doing this (although, granted, not always reliable) is to wait for a second
- after uploading your content, shutdown the &SequencingService; and await its termination,
- and then check that the sequencer output has been saved to the JCR repository. For an example of this technique,
- see the <code>SequencingClientTest</code> unit test in the example application.)
- </para>
- </sect2>
- <sect2 id="deploying_custom_sequencers">
- <title>Deploying custom sequencers</title>
- <para>The first step of deploying a sequencer consists of adding/changing the sequencer configuration (e.g., &SequencerConfig;)
- in the &SequencingService;. This was covered in the <link linkend="sequencing_service">previous chapter</link>.
- </para>
- <para>
- The second step is to make the sequencer implementation available to JBoss DNA. At this time, the JAR containing
- your new sequencer, as well as any JARs that your sequencer depends on, should be placed on your application classpath.</para>
- <note>
- <para>A future goal of JBoss DNA is to allow sequencers, connectors, and other extensions to be easily deployed into
- a runtime repository. This process will not only be much simpler, but it will also provide JBoss DNA
- with the information necessary to update configurations and create the appropriate class loaders for each extension.
- Having separate class loaders for each extension helps prevent the pollution of the common classpath,
- facilitates an isolated runtime environment to eliminate any dependency conflicts, and may potentially
- enable hot redeployment of newer extension versions.
- </para>
- </note>
- </sect2>
- </sect1>
- <sect1>
- <title>Summary</title>
- <para>
- In this chapter, we described how JBoss DNA sequences files as they're uploaded into a repository.
- And one of the things we mentioned was that each sequencer is handed (with other inputs) the MIME type of the file it is to process.
- How does DNA know what the MIME type is?
- JBoss DNA uses <emphasis>MIME type detectors</emphasis>, and this is the topic of the <link linkend="mimetypes">next chapter</link>.
- </para>
- </sect1>
-</chapter>
Deleted: trunk/docs/reference/src/main/docbook/en-US/content/testing.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/testing.xml 2009-06-08 00:52:09 UTC (rev 994)
+++ trunk/docs/reference/src/main/docbook/en-US/content/testing.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -1,152 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
-%CustomDTD;
-]>
-<chapter id="testing">
- <title>Testing</title>
- <para>
- The JBoss DNA project uses automated testing to verify that the software is doing what it's supposed to
- and not doing what it shouldn't do. These automated tests are run continuously and also act as regression tests,
- ensuring that we known if any problems we find and fix reappear later. All of our tests are executed as part of
- our <link linkend="maven">Maven</link> build process, and the entire build process (including the tests)
- is automatically run using <link linkend="hudson">Hudson</link> continuous integration system.
- </para>
- <sect1 id="unit-tests">
- <title>Unit tests</title>
- <para>
- <emphasis role="strong">Unit tests</emphasis> verify the behavior of a single class (or small set of classes) in isolation
- from other classes.
- We use the JUnit 4.4 testing framework, which has significant improvements over earlier versions and makes
- it very easy to quickly write unit tests with little extra code. We also frequently use the Mockito library
- to help create mock implementations of other classes that are not under test but are used in the tests.
- </para>
- <para>
- Unit tests should generally run quickly and should not require large assemblies of components. Additionally,
- they may rely upon the file resources included in the project, but these tests should require no external resources
- (like databases or servers). Note that our unit tests are run during the "test" phase of the standard
- <ulink url="http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle...">Maven lifecycle</ulink>.
- This means that they are executed against the raw .class files created during complication.
- </para>
- <para>
- Developers are expected to run all of the JBoss DNA unit tests in their local environment before committing changes to SVN.
- So, if you're a developer and you've made changes to your local copy of the source, you can run those tests that are
- related to your changes using your IDE or with Maven (or any other mechanism). But before you commit your changes,
- you are expected to run a full Maven build using <code>mvn clean install</code> (in the "trunk/" directory).
- Please do <emphasis>not</emphasis> rely upon continuous integration to run all of the tests for you - the CI
- system is there to catch the occasional mistakes and to also run the <link linkend="integration-tests">integration tests</link>.
- </para>
- </sect1>
- <sect1 id="integration-tests">
- <title>Integration tests</title>
- <para>
- While <link linkend="unit-tests">unit tests</link> test individual classes in (relative) isolation, the purpose of
- <emphasis role="strong">integration tests</emphasis> are to verify that assemblies of classes and components are
- behaving correctly. These assemblies are often the same ones that end users will actually use. In fact,
- integration tests are executed during the "integration-test" phase of the standard
- <ulink url="http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle...">Maven lifecycle</ulink>,
- meaning they are executed against the packaged JARs and artifacts of the project.
- </para>
- <para>
- Integration tests also use the JUnit 4.4 framework, so they are again easy to write and follow the same pattern
- as unit tests. However, because they're working with larger assemblies of components, they often will take longer
- to set up, longer to run, and longer to tear down. They also may require initializing "external resources", like
- databases or servers.
- </para>
- <para>
- Note, that while external resources may be required, care should be taken to minimize these dependencies and to
- ensure that most (if not all) integration tests may be run by anyone who downloads the source code. This means
- that these external resources should be available and set up within the tests. For example, use in-memory databases
- where possible. Or, if a database is required, use an open-source database (e.g., MySQL or PostgreSQL). And when
- these external resources are not available, it should be obvious from the test class names and/or test method names
- that it involved an external resource (e.g., "<code>MySqlConnectorIntegrationTest.shouldFindNodeStoredInDatabase()</code>").
- </para>
- </sect1>
- <sect1 id="writing-tests">
- <title>Writing tests</title>
- <para>
- As mentioned in <link linkend="methodology">the introduction</link>, the JBoss DNA project doesn't follow any one methodology
- or process. Instead, we simply have a goal that as much code as possible is tested to ensure it behaves as expected.
- Do we expect 100% of the code is covered by automated tests? No, but we do want to test as much as we can.
- Maybe a simple JavaBean class doesn't need many tests, but any class with non-trivial logic should be tested.
- </para>
- <para>
- We do encourage writing tests either before or while you write the code. Again, we're not blindly following a methodology.
- Instead, there's a very practical reason: writing the tests early on helps you write classes that are testable.
- If you wait until after the class (or classes) are done, you'll probably find that it's not easy to test all
- of the logic (especially the complicated logic).
- </para>
- <para>
- Another suggestion is to write tests so that they specify and verify the behavior that is expected from a class or component.
- One challenge developers often have is knowing what they should even test and what the tests should look like.
- This is where <emphasis role="strong"><ulink url="http://behaviour-driven.org/">Behavior-driven development (BDD)</ulink></emphasis>
- helps out. If you think about what a class' behaviors are supposed to be (e.g., requirements), simply capture those
- requirements as test methods (with no implementations). For example, a test class for sequencer
- implementation might have a test method <code>shouldNotThrowAnErrorWhenTheSuppliedStreamIsNull() { }</code>. Then, after you enumerate
- all the requirements you can think of, go back and start implementing the test methods.
- </para>
- <para>
- If you look at the existing test cases, you'll find that the names of the unit and integration tests in JBoss DNA
- follow a naming style, where the test method names are readable sentences. Actually, we try to name the test methods
- <emphasis>and</emphasis> the test classes such that they form a concisely-worded requirement. For example,
- </para>
- <programlisting>InMemorySequencerTest.shouldNotThrowAnErrorWhenTheSuppliedStreamIsNull()</programlisting>
- <para>
- is easily translated into a readable requirement:
- </para>
- <programlisting>InMemorySequencer should not throw an error when the supplied stream is null.</programlisting>
- <para>
- In fact, at some point in the future, we'd like to process the source to automatically generate a list of the behavior specifications
- that are asserted by the tests.
- </para>
- <para>
- But for now, we write tests - a lot of them. And by following a few simple conventions and practices, we're able
- to do it quickly and in a way that makes it easy to understand what the code is supposed to do (or not do).
- </para>
- </sect1>
- <sect1 id="tck-tests">
- <title>Technology Compatibility Kit (TCK) tests</title>
- <para>
- Many Java specifications provide TCK test suites that can be used to check or verify that an implementation
- correctly implements the API or SPI defined by the specification. These TCK tests vary by technology, but
- <ulink url="&JSR170;">JSR-170</ulink> does provide TCK tests that ensure that a JCR repository implementation exhibits the correct and expected
- behavior.
- </para>
- <para>
- JBoss DNA has not yet passed enough of the TCK tests to publish the results. We still have to implement
- queries, which is a required feature of Level 1 repositories. However, suffice to say that JBoss DNA has passed
- many of the individual tests that make up the Level 1 and Level 2 tests, and it is a major objective of the next
- release to pass the remaining Level 1 and Level 2 tests (along with some other optional features).
- </para>
- <para>
- JBoss DNA also frequently runs the JCR unit tests from the Apache Jackrabbit project. (Those these tests are not
- the official TCK, they apparently are used within the official TCK.) These unit tests are set up in the
- <code>dna-jcr-tck</code> project.
- </para>
- </sect1>
-</chapter>
Modified: trunk/docs/reference/src/main/docbook/en-US/master.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/master.xml 2009-06-08 00:52:09 UTC (rev 994)
+++ trunk/docs/reference/src/main/docbook/en-US/master.xml 2009-06-08 14:57:17 UTC (rev 995)
@@ -52,14 +52,32 @@
</bookinfo>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/preface.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/introduction.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/development_tools.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/classloaders.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/environment.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/repositories.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/jcr.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/sequencing.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/mimetypes.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/configuration.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/testing.xml"/>
+ <part>
+ <title>Developers and Contributors</title>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/developers/tools.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/developers/testing.xml"/>
+ </part>
+ <part>
+ <title>JBoss DNA Core</title>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/core/classloaders.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/core/environment.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/core/repositories.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/core/sequencing.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/core/mimetypes.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/core/configuration.xml"/>
+ </part>
+ <part>
+ <title>JBoss DNA JCR</title>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/jcr/jcr.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/jcr/rest_service.xml"/>
+ </part>
+ <part>
+ <title>Provided Connectors</title>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/connectors/in_memory.xml"/>
+ </part>
+ <part>
+ <title>Provided Sequencers</title>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/sequencers/zip.xml"/>
+ </part>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/future.xml"/>
</book>
16 years, 6 months
DNA SVN: r994 - trunk/docs/reference/src/main/docbook/en-US/content.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-06-07 20:52:09 -0400 (Sun, 07 Jun 2009)
New Revision: 994
Modified:
trunk/docs/reference/src/main/docbook/en-US/content/environment.xml
trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml
Log:
Added in references to REST subprojects and cleaned up some security info/examples
Modified: trunk/docs/reference/src/main/docbook/en-US/content/environment.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/environment.xml 2009-06-08 00:18:10 UTC (rev 993)
+++ trunk/docs/reference/src/main/docbook/en-US/content/environment.xml 2009-06-08 00:52:09 UTC (rev 994)
@@ -125,15 +125,16 @@
</para>
<programlisting>
&ExecutionContext; context1 = new &ExecutionContext;();
+String jaasRealm = ...;
-// Create a context for a user, authenticating using JAAS ...
-&LoginContext; loginContext = new LoginContext("username",callbackHandler);
-&ExecutionContext; context2 = context1.with(new LoginContext("username"));
+// Create a context for a user, authenticating using a JAAS LoginContext...
+char[] password = "password".toCharArray();
+&SecurityContext; securityContext = new JaasSecurityContext(jaasRealm, "username", password);
+&ExecutionContext; context2 = context1.with(securityContext);
// Create a context for the same user, authenticating using JAAS, and using a different callback handler ...
&CallbackHandler; callbackHandler = ...
-&LoginContext; loginContext = new LoginContext("username",callbackHandler);
-&ExecutionContext; context3 = context1.with(loginContext);
+&ExecutionContext; context3 = context1.with(new JaasSecurityContext(jaasRealm, callbackHandler);
// Create a context that uses a provided &SecurityContext; (see the <link linkend="security">next section</link>)...
&SecurityContext; mySecurityContext = ...
@@ -185,7 +186,7 @@
</para>
<para>
There are quite a few JAAS providers available, but one of the best and most powerful providers is
- <ulink url="http://www.jboss.org/jbosssecurity/">JBoss Security</ulink>, which is the open source
+ <ulink url="http://www.jboss.org/jbosssecurity/">JBoss Security</ulink>, the open source
security framework used by JBoss. JBoss Security offers a number of JAAS login modules, including:
<itemizedlist>
<listitem>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml 2009-06-08 00:18:10 UTC (rev 993)
+++ trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml 2009-06-08 00:52:09 UTC (rev 994)
@@ -457,6 +457,22 @@
library to determine the best MIME type from the filename and file contents.
</para>
</listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">dna-web-jcr-rest</emphasis>
+ provides a set of JSR-311 (JAX-RS) objects that form the basis of a RESTful server for Java Content Repositories. This project
+ provides integration with DNA's JCR implementation (of course) but also contains a service provider interface (SPI) that can be
+ used to integrate other JCR implementations with these RESTful services in the future. For ease of packaging, these classes are
+ provided as a JAR that can be placed in the WEB-INF/lib of a deployed RESTful server WAR.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">dna-web-jcr-rest-war</emphasis>
+ wraps the RESTful services from the dna-web-jcr-rest JAR into a WAR and provides in-container integration tests. This project
+ can be consulted as a template for how to deploy the RESTful services in a custom implementation.
+ </para>
+ </listitem>
</itemizedlist>
There are also documentation modules (located in the source under the
<code>docs/</code>
16 years, 6 months
DNA SVN: r993 - trunk/docs/reference/src/main/docbook/en-US/content.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-06-07 20:18:10 -0400 (Sun, 07 Jun 2009)
New Revision: 993
Modified:
trunk/docs/reference/src/main/docbook/en-US/content/environment.xml
Log:
Corrected an error in the Reference Guide docbook.
Modified: trunk/docs/reference/src/main/docbook/en-US/content/environment.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/environment.xml 2009-06-08 00:08:30 UTC (rev 992)
+++ trunk/docs/reference/src/main/docbook/en-US/content/environment.xml 2009-06-08 00:18:10 UTC (rev 993)
@@ -84,12 +84,6 @@
public &SecurityContext; getSecurityContext() {...}
/**
- * Get the JAAS subject for which this context was created.
- * @return the subject; never null
- */
- public &Subject; getSubject() {...}
-
- /**
* Return a logger associated with this context. This logger records only those activities within the
* context and provide a way to capture the context-specific activities. All log messages are also
* sent to the system logger, so classes that log via this mechanism should <i>not</i> also
@@ -256,7 +250,8 @@
private final HttpServletRequest request;
/**
- * Create a {@link ServletSecurityContext} with the supplied {@link HttpServletRequest servlet information}.
+ * Create a {@link ServletSecurityContext} with the supplied
+ * {@link HttpServletRequest servlet information}.
*
* @param request the servlet request; may not be null
*/
@@ -270,8 +265,8 @@
* @return the authenticated user's name
*/
public &String; getUserName() {
- return userName;
- }
+ return userName;
+ }
/**
* Determine whether the authenticated user has the given role.
@@ -279,15 +274,15 @@
* @return true if the user has the role and is logged in; false otherwise
*/
boolean hasRole( String roleName ) {
- request.isUserInRole(roleName);
- }
+ request.isUserInRole(roleName);
+ }
/**
* Logs the user out of the authentication mechanism.
* For some authentication mechanisms, this will be implemented as a no-op.
*/
public void logout() {
- }
+ }
}</programlisting>
<para>
Then use this to create a &Session;:
16 years, 6 months
DNA SVN: r992 - trunk/docs/reference/src/main/docbook/en-US/content.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-06-07 20:08:30 -0400 (Sun, 07 Jun 2009)
New Revision: 992
Modified:
trunk/docs/reference/src/main/docbook/en-US/content/environment.xml
Log:
Corrected an error in the Reference Guide docbook.
Modified: trunk/docs/reference/src/main/docbook/en-US/content/environment.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/environment.xml 2009-06-08 00:07:22 UTC (rev 991)
+++ trunk/docs/reference/src/main/docbook/en-US/content/environment.xml 2009-06-08 00:08:30 UTC (rev 992)
@@ -181,7 +181,7 @@
<para>
As noted below, this security context is made available through the &ExecutionContext; described above.
</para>
- <sect1 id="jaas_security">
+ <sect2 id="jaas_security">
<title>JAAS</title>
<para>
One such implementation is the &JaasSecurityContext;, which delegates any authentication or authorization requests to a
16 years, 6 months
DNA SVN: r991 - trunk/docs/gettingstarted/src/main/docbook/en-US.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-06-07 20:07:22 -0400 (Sun, 07 Jun 2009)
New Revision: 991
Modified:
trunk/docs/gettingstarted/src/main/docbook/en-US/custom.dtd
Log:
Changed the name of the ReferenceGuide entity from Getting Started to Reference Guide
Modified: trunk/docs/gettingstarted/src/main/docbook/en-US/custom.dtd
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/custom.dtd 2009-06-08 00:03:34 UTC (rev 990)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/custom.dtd 2009-06-08 00:07:22 UTC (rev 991)
@@ -25,7 +25,7 @@
<!ENTITY Java "http://java.sun.com/j2se/1.5.0/docs/api/">
<!ENTITY GettingStarted "<ulink url='&DocHome;docs/&versionNumber;/manuals/gettingstarted/html/index.html'>Getting Started</ulink>">
-<!ENTITY ReferenceGuide "<ulink url='&DocHome;docs/&versionNumber;/manuals/reference/html/index.html'>Getting Started</ulink>">
+<!ENTITY ReferenceGuide "<ulink url='&DocHome;docs/&versionNumber;/manuals/reference/html/index.html'>Reference Guide</ulink>">
<!-- Types in JRE -->
16 years, 6 months
DNA SVN: r990 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph and 8 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-06-07 20:03:34 -0400 (Sun, 07 Jun 2009)
New Revision: 990
Modified:
trunk/.gitignore
trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
trunk/docs/examples/gettingstarted/pom.xml
trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
trunk/docs/examples/gettingstarted/sequencers/pom.xml
trunk/docs/examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer/SequencingClient.java
trunk/docs/gettingstarted/src/main/docbook/en-US/content/sequencer_example.xml
trunk/docs/reference/src/main/docbook/en-US/content/configuration.xml
trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml
trunk/docs/reference/src/main/docbook/en-US/content/environment.xml
trunk/docs/reference/src/main/docbook/en-US/custom.dtd
Log:
DNA-389 Updated the documents to reflect the recent changes in the SecurityContext and configuration.
Modified: trunk/.gitignore
===================================================================
--- trunk/.gitignore 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/.gitignore 2009-06-08 00:03:34 UTC (rev 990)
@@ -49,6 +49,12 @@
# /docs/reference/
/docs/reference/target
+# /extensions/dna-web-jcr-rest/
+/extensions/dna-web-jcr-rest/target/
+
+# /extensions/dna-web-jcr-rest-war/
+/extensions/dna-web-jcr-rest-war/target/
+
# /extensions/dna-classloader-maven/
/extensions/dna-classloader-maven/target
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java 2009-06-08 00:03:34 UTC (rev 990)
@@ -73,6 +73,7 @@
* , with default implementations for all other components (including default namespaces in the
* {@link #getNamespaceRegistry() namespace registry}.
*/
+ @SuppressWarnings( "synthetic-access" )
public ExecutionContext() {
this(new NullSecurityContext(), null, null, null, null, null);
initializeDefaultNamespaces(this.getNamespaceRegistry());
@@ -193,7 +194,7 @@
/**
* Get the {@link SecurityContext security context} for this context.
*
- * @return the security context; may be <code>null</code>
+ * @return the security context; never <code>null</code>
*/
public SecurityContext getSecurityContext() {
return this.securityContext;
@@ -347,6 +348,6 @@
public void logout() {
}
-
+
}
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java 2009-06-08 00:03:34 UTC (rev 990)
@@ -79,8 +79,6 @@
}
}
-
-
@Before
public void before() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -93,7 +91,7 @@
// Set up the execution context ...
context = new ExecutionContext();
credentials = new SimpleCredentials("superuser", "superuser".toCharArray());
-
+
// Stub out the connection factory ...
connectionFactory = new RepositoryConnectionFactory() {
/**
@@ -180,28 +178,28 @@
assertThat(repository.getDescriptor("property"), is("value"));
}
- @Test(expected=javax.jcr.LoginException.class)
+ @Test( expected = javax.jcr.LoginException.class )
public void shouldNotAllowLoginWithNoCredentials() throws Exception {
// This would work iff this code was executing in a privileged block, but it's not
repository.login();
}
-
- @SuppressWarnings("cast")
+
@Test
public void shouldAllowLoginWithNoCredentialsInPrivilegedBlock() throws Exception {
LoginContext login = new LoginContext("dna-jcr", new UserPasswordCallbackHandler("superuser", "superuser".toCharArray()));
login.login();
-
+
Subject subject = login.getSubject();
-
- Session session = (Session) Subject.doAsPrivileged(subject, new PrivilegedExceptionAction<Session>() {
+ Session session = (Session)Subject.doAsPrivileged(subject, new PrivilegedExceptionAction<Session>() {
+
+ @SuppressWarnings( "synthetic-access" )
public Session run() throws Exception {
return repository.login();
}
-
+
}, AccessController.getContext());
-
+
assertThat(session, is(notNullValue()));
assertThat(session.getUserID(), is("superuser"));
login.logout();
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java 2009-06-08 00:03:34 UTC (rev 990)
@@ -43,7 +43,6 @@
import org.apache.jackrabbit.test.api.RepositoryLoginTest;
import org.apache.jackrabbit.test.api.SerializationTest;
import org.apache.jackrabbit.test.api.SessionTest;
-import org.apache.jackrabbit.test.api.SessionUUIDTest;
import org.apache.jackrabbit.test.api.SetPropertyAssumeTypeTest;
import org.apache.jackrabbit.test.api.SetPropertyBooleanTest;
import org.apache.jackrabbit.test.api.SetPropertyCalendarTest;
Modified: trunk/docs/examples/gettingstarted/pom.xml
===================================================================
--- trunk/docs/examples/gettingstarted/pom.xml 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/docs/examples/gettingstarted/pom.xml 2009-06-08 00:03:34 UTC (rev 990)
@@ -10,7 +10,7 @@
<modules>
<module>sequencers</module>
- <module>repositories</module>
+ <!--module>repositories</module-->
</modules>
<dependencyManagement>
Modified: trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java 2009-06-08 00:03:34 UTC (rev 990)
@@ -44,6 +44,7 @@
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.JaasSecurityContext;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
@@ -306,7 +307,11 @@
case DNA: {
try {
// Use the DNA Graph API to read the properties and children of the node ...
- ExecutionContext context = loginContext != null ? this.context.create(loginContext) : this.context;
+ ExecutionContext context = this.context;
+ if (loginContext != null) {
+ JaasSecurityContext security = new JaasSecurityContext(loginContext);
+ context = this.context.with(security);
+ }
Graph graph = engine.getGraph(context, sourceName);
graph.useWorkspace("default");
org.jboss.dna.graph.Node node = graph.getNodeAt(pathToNode);
Modified: trunk/docs/examples/gettingstarted/sequencers/pom.xml
===================================================================
--- trunk/docs/examples/gettingstarted/sequencers/pom.xml 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/docs/examples/gettingstarted/sequencers/pom.xml 2009-06-08 00:03:34 UTC (rev 990)
@@ -63,34 +63,6 @@
<artifactId>jcr</artifactId>
</dependency>
<!--
- JAAS implementation (and dependencies)
- -->
- <dependency>
- <groupId>org.jboss.security</groupId>
- <artifactId>jboss-idtrust</artifactId>
- <version>2.0.2.CR1</version>
- </dependency>
- <dependency>
- <groupId>org.jboss.security</groupId>
- <artifactId>jboss-security-spi-bare</artifactId>
- <version>2.0.2.SP6</version>
- </dependency>
- <dependency>
- <groupId>org.jboss.security</groupId>
- <artifactId>jbosssx-bare</artifactId>
- <version>2.0.2.SP6</version>
- <exclusions>
- <exclusion>
- <groupId>apache-xalan</groupId>
- <artifactId>xalan</artifactId>
- </exclusion>
- <exclusion>
- <groupId>apache-xalan</groupId>
- <artifactId>serializer</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <!--
Test cases use JUnit
-->
<dependency>
Modified: trunk/docs/examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer/SequencingClient.java
===================================================================
--- trunk/docs/examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer/SequencingClient.java 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/docs/examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer/SequencingClient.java 2009-06-08 00:03:34 UTC (rev 990)
@@ -41,13 +41,13 @@
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
+import org.jboss.dna.graph.SecurityContext;
import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
import org.jboss.dna.jcr.JcrConfiguration;
import org.jboss.dna.jcr.JcrEngine;
-import org.jboss.dna.jcr.JcrRepository;
+import org.jboss.dna.jcr.SecurityContextCredentials;
import org.jboss.dna.repository.sequencer.SequencingService;
import org.jboss.dna.repository.util.SessionFactory;
-import org.jboss.security.config.IDTrustConfiguration;
/**
* @author Randall Hauch
@@ -60,14 +60,6 @@
public static final char[] DEFAULT_PASSWORD = "secret".toCharArray();
public static void main( String[] args ) {
- // Set up the JAAS provider (IDTrust) and a policy file (which defines the "dna-jcr" login config name)
- IDTrustConfiguration idtrustConfig = new IDTrustConfiguration();
- try {
- idtrustConfig.config("security/jaas.conf.xml");
- } catch (Exception ex) {
- throw new IllegalStateException(ex);
- }
-
// Configure the DNA configuration. This could be done by loading a configuration from a file, or by
// using a (local or remote) configuration repository, or by setting up the configuration programmatically.
// This example uses the programmatic approach...
@@ -80,10 +72,7 @@
.setDescription("The repository for our content")
.setProperty("defaultWorkspaceName", workspaceName);
// Set up the JCR repository to use the source ...
- config.repository(repositoryId)
- .addNodeTypes("sequencing.cnd")
- .setSource("store")
- .setOption(JcrRepository.Option.JAAS_LOGIN_CONFIG_NAME, "dna-jcr");
+ config.repository(repositoryId).addNodeTypes("sequencing.cnd").setSource("store");
// Set up the image sequencer ...
config.sequencer("Image Sequencer")
.usingClass("org.jboss.dna.sequencer.image.ImageMetadataSequencer")
@@ -433,7 +422,14 @@
* @throws RepositoryException
*/
protected Session createSession() throws RepositoryException {
- return this.repository.login(workspaceName);
+ // Normally we'd just use SimpleCredentials or some other custom Credentials implementation,
+ // but that would require JAAS (since JBoss DNA uses that used by default). Since we don't
+ // have a JAAS implementation, we will use the SecurityContextCredentials to wrap
+ // another SecurityContext implementation. This is how you might integrate a non-JAAS security
+ // system into JBoss DNA. See the repository example for how to set up with JAAS.
+ SecurityContext securityContext = new MyCustomSecurityContext();
+ SecurityContextCredentials credentials = new SecurityContextCredentials(securityContext);
+ return this.repository.login(credentials, workspaceName);
}
protected String getMimeType( URL file ) {
@@ -451,4 +447,33 @@
return null;
}
+ protected class MyCustomSecurityContext implements SecurityContext {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.SecurityContext#getUserName()
+ */
+ public String getUserName() {
+ return "Fred";
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.SecurityContext#hasRole(java.lang.String)
+ */
+ public boolean hasRole( String roleName ) {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.SecurityContext#logout()
+ */
+ public void logout() {
+ // do something
+ }
+ }
+
}
Modified: trunk/docs/gettingstarted/src/main/docbook/en-US/content/sequencer_example.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/sequencer_example.xml 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/sequencer_example.xml 2009-06-08 00:03:34 UTC (rev 990)
@@ -161,14 +161,6 @@
creates the JBoss DNA configuration using the programmatic style.
</para>
<programlisting role="JAVA"><![CDATA[
-// Set up the JAAS provider (IDTrust) and a policy file (which defines the "dna-jcr" login config name)
-IDTrustConfiguration idtrustConfig = new IDTrustConfiguration();
-try {
- idtrustConfig.config("security/jaas.conf.xml");
-} catch (Exception ex) {
- throw new IllegalStateException(ex);
-}
-
// Create the configuration.
String repositoryId = "content";
String workspaceName = "default";
@@ -181,8 +173,7 @@
// Set up the JCR repository to use the source ...
config.repository(repositoryId)
.addNodeTypes("sequencing.cnd")
- .setSource("store")
- .setOption(JcrRepository.Option.JAAS_LOGIN_CONFIG_NAME, "dna-jcr");
+ .setSource("store");
// Set up the image sequencer ...
config.sequencer("Image Sequencer")
.usingClass("org.jboss.dna.sequencer.image.ImageMetadataSequencer")
@@ -210,16 +201,13 @@
client.setUserInterface(new ConsoleInput(client));
]]></programlisting>
<para>
- The first block sets up the JAAS provider to be the IDTrust library and a policy file that defines the "dna-jcr" JAAS configuration.
- </para>
- <para>
- The second block of code configures the <code>JcrConfiguration</code> and sets up the "store" source, the "content" repository,
+ The first block of code configures the <code>JcrConfiguration</code> and sets up the "store" source, the "content" repository,
and three sequencers. Again, this is done via the programmatic style. An alternative would be to load the entire configuration
from a configuration file or from an existing configuration repository. (The repository example shown in the
<link linkend="repository_example">next chapter</link> shows how to load the configuration from a file.)
</para>
<para>
- The third block simply instantiates the <code>SequencingClient</code> class, passing the configuration and the name of the repository
+ The second block simply instantiates the <code>SequencingClient</code> class, passing the configuration and the name of the repository
and workspace, and finally sets the user interface (which then executes its behavior, which we'll see below).
</para>
<para>
@@ -298,6 +286,58 @@
}
}
]]></programlisting>
+ <para>
+ There is one more aspect of this example that is worth discussing. While the repository example in the
+ <link linkend="repository_example">next chapter</link> does show how to use JAAS, this example intentionally shows how
+ you might integrate a different security system into JBoss DNA. In the <code>createSession()</code> method,
+ the <code>RepositoryClient</code> creates a <code>SecurityContextCredentials</code> wrapper around a custom
+ <code>SecurityContext</code> implementation, then passes that credentials into the <code>login(Credentials,String)</code>
+ method:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+protected Session createSession() throws RepositoryException {
+ SecurityContext securityContext = new MyCustomSecurityContext();
+ SecurityContextCredentials credentials = new SecurityContextCredentials(securityContext);
+ return this.repository.login(credentials, workspaceName);
+}
+ ]]></programlisting>
+ <para>
+ where the custom <code>SecurityContext</code> implementation is as follows:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+protected class MyCustomSecurityContext implements SecurityContext {
+ /**
+ * @see org.jboss.dna.graph.SecurityContext#getUserName()
+ */
+ public String getUserName() {
+ return "Fred";
+ }
+
+ /**
+ * @see org.jboss.dna.graph.SecurityContext#hasRole(java.lang.String)
+ */
+ public boolean hasRole( String roleName ) {
+ return true;
+ }
+
+ /**
+ * @see org.jboss.dna.graph.SecurityContext#logout()
+ */
+ public void logout() {
+ // do something
+ }
+}
+ ]]></programlisting>
+ <para>
+ Obviously you would want to implement this correctly. If you're using JBoss DNA in a web application, your <code>SecurityContext</code>
+ implementation would likely delegate to the <code>HttpServletRequest</code>.
+ </para>
+ <para>
+ But if you're using JAAS, then you could just pass in a <code>javax.jcr.SimpleCredentials</code> with the username and password,
+ as long as your <code>JcrConfiguration</code>'s repository definitions are set up to use the correct JAAS login context name
+ (see the repository example in the <link linkend="repository_example">next chapter</link>). Or, you could use the approach listed
+ above and supply an instance of the <code>JaasSecurityContext</code> to the <code>SecurityContextCredentials</code>.
+ </para>
<para>At this point, we've reviewed all of the interesting code in the example application related to JBoss DNA. However, feel free
to play with the application, trying different things.</para>
</sect1>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/configuration.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/configuration.xml 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/docs/reference/src/main/docbook/en-US/content/configuration.xml 2009-06-08 00:03:34 UTC (rev 990)
@@ -29,12 +29,343 @@
%CustomDTD;
]>
<chapter id="configuration">
- <title>Configuration</title>
- <para>
- Configuring JBoss DNA services is a bit more manual than is ideal. JBoss DNA currently consists of classes that uses dependency
- injection to allow a great deal of flexibility in how it can be configured and customized. But this flexibility
- makes it more difficult for you to configure. We understand this, and will soon provide a much easier way to set up
- and manage JBoss DNA. Current plans are to use the <ulink url="http://www.jboss.org/jbossmc">JBoss Microcontainer</ulink>
- along with a configuration repository.
+ <title>Configuring and Using JBoss DNA</title>
+ <para>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 <code>JcrEngine</code>. After that, you obtain the
+ <code>javax.jcr.Repository</code> instance for a named repository and just use the standard JCR API throughout your
+ application.
</para>
+ <sect1 id="jcr_engine">
+ <title>JBoss DNA's JcrEngine</title>
+ <para>
+ JBoss DNA encapsulates everything necessary to run one or more JCR repositories into a single &JcrEngine; instance.
+ This includes all underlying repository sources, the pools of connections to the sources, the sequencers,
+ the MIME type detector(s), and the &Repository; implementations.
+ </para>
+ <para>
+ Obtaining a &JcrEngine; instance is very easy - assuming that you have a valid &JcrConfiguration; instance. We'll see
+ how to get one of those in a little bit, but if you have one then all you have to do is build and start the engine:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+JcrEngine engine = config.build();
+engine.start();
+ ]]></programlisting>
+ <para>
+ Obtaining a JCR &Repository; instance is a matter of simply asking the engine for it by the name defined in the configuration:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+javax.jcr.Repository repository = engine.getRepository("Name of repository");
+ ]]></programlisting>
+ <para>
+ At this point, your application can proceed by working with the JCR API.
+ </para>
+ <para>
+ And, once you're finished with the &JcrEngine;, you should shut it down:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+engine.shutdown();
+engine.awaitTermination(3,TimeUnit.SECONDS); // optional
+ ]]></programlisting>
+ <para>
+ When the <code>shutdown()</code> method is called, the &Repository; instances managed by the engine are marked as being shut down,
+ and they will not be able to create new &Session;s. However, any existing &Session;s or ongoing operations (e.g., event notifications)
+ present at the time of the <code>shutdown()</code> call will be allowed to finish.
+ In essence, <code>shutdown()</code> is a <emphasis>graceful</emphasis> request, and since it may take some time to complete,
+ you can wait until the shutdown has completed by simply calling <code>awaitTermination(...)</code> as shown above.
+ This method will block until the engine has indeed shutdown or until the supplied time duration has passed (whichever comes first).
+ And, yes, you can call the <code>awaitTermination(...)</code> method repeatedly if needed.
+ </para>
+ </sect1>
+ <sect1 id="jcr_configuration">
+ <title>JcrConfiguration</title>
+ <para>
+ The previous section assumed the existence of a &JcrConfiguration;. It's not really that creating an instance is all that difficult.
+ In fact, there's only one no-argument constructor, so actually creating the instance is a piece of cake. What can be a little more challenging,
+ though, is setting up the &JcrConfiguration; instance, which must define the following components:
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="strong"><code>Repository sources</code></emphasis> are the POJO objects that each describe a particular
+ location where content is stored. Each repository source object is an instance of a JBoss DNA connector, and is configured
+ with the properties that particular source. JBoss DNA'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. </para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>Repositories</code></emphasis> define the JCR repositories that are available. Each
+ repository has a unique name that is used to obtain the &Repository; instance from the &JcrEngine;'s <code>getRepository(String)</code>
+ method, but each repository definition also can include the predefined namespaces (other than those automatically defined by
+ JBoss DNA), various options, and the node types that are to be available in the repository without explicit registration
+ through the JCR API.</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>Sequencers</code></emphasis> 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.</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>MIME type detectors</code></emphasis> 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. JBoss DNA 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.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ There really are three options:
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="strong"><code>Load from a file</code></emphasis> is conceptually the easiest and requires the least amount
+ of Java code, but it now requires a configuration file.</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>Load from a configuration repository</code></emphasis> is not much more complicated than loading
+ from a file, but it does allow multiple &JcrEngine; instances (usually in different processes perhaps on different machines)
+ to easily access their (shared) configuration. And technically, loading the configuration from a file really just creates an
+ &InMemoryRepositorySource;, imports the configuration file into that source, and then proceeds with this approach.</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>Programmatic configuration</code></emphasis> is always possible, even if the configuration is loaded
+ from a file or repository. Using the &JcrConfiguration;'s API, you can define (or update or remove) all of the definitions that make
+ up a configuration.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Each of these approaches has their obvious advantages, so the choice of which one to use is entirely up to you.
+ </para>
+ <sect2 id="loading_from_file">
+ <title>Loading from a configuration file</title>
+ <para>
+ Loading the JBoss DNA configuration from a file is actually very simple:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = new JcrConfiguration();
+configuration.loadFrom(file);
+ ]]></programlisting>
+ <para>
+ where the <code>file</code> parameter can actually be a &File; instance, a &URL; to the file, an &InputStream;
+ containing the contents of the file, or even a &String; containing the contents of the file.
+ </para>
+ <note>
+ <para>The <code>loadFrom(...)</code> method can be called any number of times, but each time it is called it completely wipes
+ out any current notion of the configuration and replaces it with the configuration found in the file.
+ </para>
+ </note>
+ <para>
+ There is an optional second parameter that defines the &Path; within the configuration file identifying the parent node of the various
+ configuration nodes. If not specified, it assumes "/". This makes it possible for the configuration content to be
+ located at a different location in the hierarchical structure. (This is not often required, but when it is required
+ this second parameter is very useful.)
+ </para>
+ <para>
+ 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):
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration xmlns="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <!--
+ Define the JCR repositories
+ -->
+ <dna:repositories>
+ <!--
+ Define a JCR repository that accesses the 'Cars' source directly.
+ This of course is optional, since we could access the same content through 'vehicles'.
+ -->
+ <dna:repository jcr:name="car repository" dna:source="Cars">
+ <options jcr:primaryType="dna:options"/>
+ <jaasLoginConfigName jcr:primaryType="dna:option" dna:value="dna-jcr"/>
+ </options>
+ </dna:repository>
+ </dna:repositories>
+ <!--
+ Define the sources for the content. These sources are directly accessible using the DNA-specific Graph API.
+ -->
+ <dna:sources jcr:primaryType="nt:unstructured">
+ <dna:source jcr:name="Cars" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" dna:retryLimit="3" dna:defaultWorkspaceName="workspace1"/>
+ <dna:source jcr:name="Aircraft" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource">
+ <!-- Define the name of the workspace used by default. Optional, but convenient. -->
+ <defaultWorkspaceName>workspace2</defaultWorkspaceName>
+ </dna:source>
+ </dna:sources>
+ <!--
+ Define the sequencers. This is an optional section. For this example, we're not using any sequencers.
+ -->
+ <dna:sequencers>
+ <!--dna:sequencer jcr:name="Image Sequencer" dna:classname="org.jboss.dna.sequencer.image.ImageMetadataSequencer">
+ <dna:description>Image metadata sequencer</dna:description>
+ <dna:pathExpression>/foo/source => /foo/target</dna:pathExpression>
+ <dna:pathExpression>/bar/source => /bar/target</dna:pathExpression>
+ </dna:sequencer-->
+ </dna:sequencers>
+ <dna:mimeTypeDetectors>
+ <dna:mimeTypeDetector jcr:name="Detector" dna:description="Standard extension-based MIME type detector"/>
+ </dna:mimeTypeDetectors>
+</configuration>
+ ]]></programlisting>
+ </sect2>
+ <sect2 id="loading_from_repository">
+ <title>Loading from a configuration repository</title>
+ <para>
+ Loading the JBoss DNA configuration from an existing repository is also pretty straightforward. Simply create and configure the
+ &RepositorySource; instance to point to the desired repository, and then call the <code>loadFrom(&RepositorySource; source)</code>
+ method:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+RepositorySource configSource = ...
+JcrConfiguration config = new JcrConfiguration();
+configuration.loadFrom(configSource);
+ ]]></programlisting>
+ <para>
+ This really is a more advanced way to define your configuration, so we won't go into how you configure a &RepositorySource;.
+ For more information, consult the &ReferenceGuide;.
+ </para>
+ <note>
+ <para>The <code>loadFrom(...)</code> method can be called any number of times, but each time it is called it completely wipes
+ out any current notion of the configuration and replaces it with the configuration found in the file.
+ </para>
+ </note>
+ <para>
+ There is an optional second parameter that defines the name of the workspace in the supplied source where the configuration content
+ can be found. It is not needed if the workspace is the source's default workspace.
+ There is an optional third parameter that defines the &Path; within the configuration repository identifying the parent node of the various
+ configuration nodes. If not specified, it assumes "/". This makes it possible for the configuration content to be
+ located at a different location in the hierarchical structure. (This is not often required, but when it is required
+ this second parameter is very useful.)
+ </para>
+ </sect2>
+ <sect2 id="programmatic_configuration">
+ <title>Programmatic configuration</title>
+ <para>
+ Defining the configuration programmatically is not terribly complicated, and it for obvious reasons results in more verbose Java code.
+ But this approach is very useful and often the easiest approach when the configuration must change or is a reflection of other
+ dynamic information.
+ </para>
+ <para>
+ The &JcrConfiguration; class was designed to have an easy-to-use API that makes it easy to configure each of the different kinds of
+ components, especially when using an IDE with code completion. Here are several examples:
+ </para>
+ <sect3 id="programmatically_configuring_sources">
+ <title>Repository sources</title>
+ <para>Each repository source definition must include the name of the &RepositorySource; class as well as each bean property
+ that should be set on the object:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+config.repositorySource("source A")
+ .usingClass(InMemoryRepositorySource.class)
+ .setDescription("The repository for our content")
+ .setProperty("defaultWorkspaceName", workspaceName);
+ ]]></programlisting>
+ <para>
+ This example defines an in-memory source with the name "source A", a description, and a single "defaultWorkspaceName" bean property.
+ Different &RepositorySource; implementations will the bean properties that are required and optional.
+ Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
+ the classpath or from a specific classpath).
+ </para>
+ <note>
+ <para>Each time <code>repositorySource(String)</code> is called, it will either load the existing definition with the supplied
+ name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
+ on the result of <code>repositorySource(String)</code>.
+ The set of existing definitions can be accessed with the <code>repositorySources()</code> method.
+ </para>
+ </note>
+ </sect3>
+ <sect3 id="programmatically_configuring_repositories">
+ <title>Repositories</title>
+ <para>Each repository must be defined to use a named repository source, but all other aspects (e.g., namespaces, node types, options)
+ are optional.</para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+config.repository("repository A")
+ .addNodeTypes("myCustomNodeTypes.cnd")
+ .setSource("source 1")
+ .registerNamespace("acme","http://www.example.com/acme")
+ .setOption(JcrRepository.Option.JAAS_LOGIN_CONFIG_NAME, "dna-jcr");
+ ]]></programlisting>
+ <para>
+ This example defines a repository that uses the "source 1" repository source (which could be a federated source, an in-memory source,
+ a database store, or any other source). Additionally, this example adds the node types in the "myCustomNodeTypes.cnd" file as those
+ that will be made available when the repository is accessed. It also defines the "http://www.example.com/acme" namespace,
+ and finally sets the "JAAS_LOGIN_CONFIG_NAME" option to define the name of the JAAS login configuration that should be used by
+ the JBoss DNA repository.
+ </para>
+ <note>
+ <para>Each time <code>repository(String)</code> is called, it will either load the existing definition with the supplied
+ name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
+ on the result of <code>repository(String)</code>.
+ The set of existing definitions can be accessed with the <code>repositories()</code> method.
+ </para>
+ </note>
+ </sect3>
+ <sect3 id="programmatically_configuring_sequencers">
+ <title>Sequencers</title>
+ <para>Each defined sequencer must specify the name of the &StreamSequencer; implementation class as well as the path expressions
+ defining which nodes should be sequenced and the output paths defining where the sequencer output should be placed (often as a function
+ of the input path expression).</para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+config.sequencer("Image Sequencer")
+ .usingClass("org.jboss.dna.sequencer.image.ImageMetadataSequencer")
+ .loadedFromClasspath()
+ .setDescription("Sequences image files to extract the characteristics of the image")
+ .sequencingFrom("//(*.(jpg|jpeg|gif|bmp|pcx|png|iff|ras|pbm|pgm|ppm|psd)[*])/jcr:content[@jcr:data]")
+ .andOutputtingTo("/images/$1");
+ ]]></programlisting>
+ <para>
+ This shows an example of a sequencer definition named "Image Sequencer" that uses the &ImageMetadataSequencer; class
+ (loaded from the classpath), that is to sequence the "jcr:data" property on any new or changed nodes that are named
+ "jcr:content" below a parent node with a name ending in ".jpg", ".jpeg", ".gif", ".bmp", ".pcx", ".iff", ".ras",
+ ".pbm", ".pgm", ".ppm" or ".psd". The output of the sequencing operation should be placed at the "/images/$1" node,
+ where the "$1" value is captured as the name of the parent node. (The capture groups work the same was as regular expressions;
+ see the &ReferenceGuide; for more details.)
+ Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
+ the classpath or from a specific classpath).
+ </para>
+ <note>
+ <para>Each time <code>sequencer(String)</code> is called, it will either load the existing definition with the supplied
+ name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
+ on the result of <code>sequencer(String)</code>.
+ The set of existing definitions can be accessed with the <code>sequencers()</code> method.
+ </para>
+ </note>
+ </sect3>
+ <sect3 id="programmatically_configuring_mime_type_detectors">
+ <title>MIME type detectors</title>
+ <para>Each defined MIME type detector must specify the name of the &MimeTypeDetector; implementation class as well as any
+ other bean properties required by the implementation.</para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+config.mimeTypeDetector("Extension Detector")
+ .usingClass(org.jboss.dna.graph.mimetype.ExtensionBasedMimeTypeDetector.class);
+ ]]></programlisting>
+ <para>
+ Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
+ the classpath or from a specific classpath).
+ </para>
+ <note>
+ <para>Each time <code>mimeTypeDetector(String)</code> is called, it will either load the existing definition with the supplied
+ name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
+ on the result of <code>mimeTypeDetector(String)</code>.
+ The set of existing definitions can be accessed with the <code>mimeTypeDetectors()</code> method.
+ </para>
+ </note>
+ </sect3>
+ </sect2>
+ </sect1>
+ <sect1 id="using_dna_whats_next">
+ <title>What's next</title>
+ <para>
+ This chapter outline how you configure JBoss DNA, how you then access a <code>javax.jcr.Repository</code> instance,
+ and use the standard JCR API to interact with the repository. The
+ <link linkend="downloading_and_running">next chapter </link> walks you through downloading
+ and running the JBoss DNA examples.
+ </para>
+ </sect1>
</chapter>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml 2009-06-08 00:03:34 UTC (rev 990)
@@ -228,6 +228,7 @@
<para>While you're adding <code>$MAVEN_HOME/bin</code> to your path, you should also set the <code>$MAVEN_OPTS</code> environment variable
to "<code>-Xmx256m</code>". If you don't do this, you'll likely see an <code>java.lang.OutOfMemoryError</code> sometime during a full
build.
+ </para>
<note>
<para>
The JBoss Maven repository provides a central location for not only the artifacts produced by the JBoss.org projects (well, at least those
Modified: trunk/docs/reference/src/main/docbook/en-US/content/environment.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/environment.xml 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/docs/reference/src/main/docbook/en-US/content/environment.xml 2009-06-08 00:03:34 UTC (rev 990)
@@ -39,86 +39,6 @@
<ulink url="http://www.jboss.org/jbossmc">JBoss Microcontainer</ulink> to automatically assemble and wire together
all the lower-level components.
</para>
- <sect1 id="security">
- <title>Security</title>
- <para>
- JBoss DNA uses the
- <ulink url="http://java.sun.com/javase/technologies/security/">Java Authentication and Authorization Service (JAAS)</ulink>
- for its security mechanism. Not only is this the standard approach for authenticating and authorizing in Java, but
- it also enables JBoss DNA to integrate existing security systems.
- </para>
- <para>
- There are quite a few JAAS providers available, but one of the best and most powerful providers is
- <ulink url="http://www.jboss.org/jbosssecurity/">JBoss Security</ulink>, which is the open source
- security framework used by JBoss. JBoss Security offers a number of JAAS login modules, including:
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">User-Roles Login Module</emphasis>
- is a simple
- <code>javax.security.auth.login.LoginContext</code>
- implementation that uses usernames and passwords stored in a properties file.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Client Login Module</emphasis>
- prompts the user for their username and password.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Database Server Login Module</emphasis>
- uses a JDBC database to authenticate principals and associate them with roles.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">LDAP Login Module</emphasis>
- uses an LDAP directory to authenticate principals. Two implementations are available.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Certificate Login Module</emphasis>
- authenticates using X509 certificates, obtaining roles from either property files or a JDBC database.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Operating System Login Module</emphasis>
- authenticates using the operating system's mechanism.
- </para>
- </listitem>
- </itemizedlist>
- and many others. Plus, JBoss Security also provides other capabilities, such as using XACML policies or using federated single sign-on.
- For more detail, see the <ulink url="http://www.jboss.org/jbosssecurity/">JBoss Security</ulink> project.
- </para>
- <sect2 id="authentication">
- <title>Authenticating with JAAS</title>
- <para>
- JBoss DNA defers to JAAS to authenticate clients creating repository connections (known as JCR Sessions if using the JCR API),
- and generally expects the client application to obtain the JAAS &LoginContext; or &AppControlContext;.
- These are then passed to JBoss DNA, which merely verifies that authentication has been done.
- </para>
- <para>
- As we'll see in the <link linkend="execution-context">next section</link>, JBoss DNA has the notion of an &ExecutionContext;
- that can be created using JAAS login or access control contexts. These execution contexts therefore contain information
- about the subject.
- </para>
- <para>
- We'll also see in the <link linkend="jcr">chapter on JCR</link> how JAAS can be used for authentication when
- JCR Sessions are created.
- </para>
- </sect2>
- <sect2 id="authorization">
- <title>Authorization with JAAS</title>
- <para>
- JBoss DNA does not currently use any of the authorization features of JAAS. However, in future releases where authorization
- is supported, JBoss DNA will rely upon JAAS authorization just as it currently does for authentication.
- </para>
- </sect2>
- </sect1>
<sect1 id="execution-context">
<title>Execution contexts</title>
<para>
@@ -158,18 +78,12 @@
public &PropertyFactory; getPropertyFactory() {...}
/**
- * Get the current JAAS access control context.
- * @return the access control context; may be <code>null</code>
+ * Get the security context for this environment.
+ * @return the security context; never <code>null</code>
*/
- public &AccessControlContext; getAccessControlContext() {...}
+ public &SecurityContext; getSecurityContext() {...}
/**
- * Get the current JAAS login context.
- * @return the login context; may be <code>null</code>
- */
- public &LoginContext; getLoginContext() {...}
-
- /**
* Get the JAAS subject for which this context was created.
* @return the subject; never null
*/
@@ -201,8 +115,8 @@
<para>
Notice that &ExecutionContext; implements the &ClassLoaderFactory; interface described in the
<link linkend="classloaders">previous chapter</link>, meaning it can be used to create other contexts. These other methods are not shown,
- but can be used to create create subcontexts with different <link linkend="security">JAAS</link>
- login or access control contexts, with different namespace registry, or with different combinations of components.
+ but can be used to create create subcontexts with different <link linkend="security">security contexts</link>,
+ with different namespace registry, or with different combinations of components.
</para>
<para>
The fact that so many of the JBoss DNA components take &ExecutionContext; instances gives us some interesting possibilities.
@@ -226,11 +140,167 @@
&CallbackHandler; callbackHandler = ...
&LoginContext; loginContext = new LoginContext("username",callbackHandler);
&ExecutionContext; context3 = context1.with(loginContext);
+
+// Create a context that uses a provided &SecurityContext; (see the <link linkend="security">next section</link>)...
+&SecurityContext; mySecurityContext = ...
+&ExecutionContext; context4 = context1.with(mySecurityContext);
</programlisting>
<para>
These contexts can then be passed to the various components as needed.
</para>
</sect1>
+ <sect1 id="security">
+ <title>Security</title>
+ <para>
+ JBoss DNA uses a simple abstraction layer to isolate it from the security infrastructure used within an application.
+ The &SecurityContext; interface is defined as follows:
+ </para>
+ <programlisting>
+public interface &SecurityContext; {
+
+ /**
+ * Get the name of the authenticated user.
+ * @return the authenticated user's name
+ */
+ &String; getUserName();
+
+ /**
+ * Determine whether the authenticated user has the given role.
+ * @param roleName the name of the role to check
+ * @return true if the user has the role and is logged in; false otherwise
+ */
+ boolean hasRole( String roleName );
+
+ /**
+ * Logs the user out of the authentication mechanism.
+ * For some authentication mechanisms, this will be implemented as a no-op.
+ */
+ void logout();
+}
+</programlisting>
+ <para>
+ As noted below, this security context is made available through the &ExecutionContext; described above.
+ </para>
+ <sect1 id="jaas_security">
+ <title>JAAS</title>
+ <para>
+ One such implementation is the &JaasSecurityContext;, which delegates any authentication or authorization requests to a
+ <ulink url="http://java.sun.com/javase/technologies/security/">Java Authentication and Authorization Service (JAAS)</ulink>
+ provider. This is the standard approach for authenticating and authorizing in Java, and is the default mechanism
+ used by the &JcrEngine;.
+ </para>
+ <para>
+ There are quite a few JAAS providers available, but one of the best and most powerful providers is
+ <ulink url="http://www.jboss.org/jbosssecurity/">JBoss Security</ulink>, which is the open source
+ security framework used by JBoss. JBoss Security offers a number of JAAS login modules, including:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis role="strong">User-Roles Login Module</emphasis>
+ is a simple
+ <code>javax.security.auth.login.LoginContext</code>
+ implementation that uses usernames and passwords stored in a properties file.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Client Login Module</emphasis>
+ prompts the user for their username and password.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Database Server Login Module</emphasis>
+ uses a JDBC database to authenticate principals and associate them with roles.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">LDAP Login Module</emphasis>
+ uses an LDAP directory to authenticate principals. Two implementations are available.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Certificate Login Module</emphasis>
+ authenticates using X509 certificates, obtaining roles from either property files or a JDBC database.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Operating System Login Module</emphasis>
+ authenticates using the operating system's mechanism.
+ </para>
+ </listitem>
+ </itemizedlist>
+ and many others. Plus, JBoss Security also provides other capabilities, such as using XACML policies or using federated single sign-on.
+ For more detail, see the <ulink url="http://www.jboss.org/jbosssecurity/">JBoss Security</ulink> project.
+ </para>
+ </sect2>
+ <sect2 id="web_security">
+ <title>Web application security</title>
+ <para>
+ If JBoss DNA is being used within a web application, then it is probably desirable to reuse the security infrastructure
+ of the application server. This can be accomplished by implementing the &SecurityContext; interface with an implementation
+ that delegates to the <interface>HttpServletRequest</interface>. Then, for each request, create a &SecurityContextCredentials;
+ instance around your &SecurityContext;, and use that credentials to obtain a JCR &Session;.
+ </para>
+ <para>
+ Here is an example of the &SecurityContext; implementation that uses the servlet request:
+ </para>
+ <programlisting>
+@Immutable
+public class ServletSecurityContext implements &SecurityContext; {
+
+ private final String userName;
+ private final HttpServletRequest request;
+
+ /**
+ * Create a {@link ServletSecurityContext} with the supplied {@link HttpServletRequest servlet information}.
+ *
+ * @param request the servlet request; may not be null
+ */
+ public ServletSecurityContext( HttpServletRequest request ) {
+ this.request = request;
+ this.userName = request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : null;
+ }
+
+ /**
+ * Get the name of the authenticated user.
+ * @return the authenticated user's name
+ */
+ public &String; getUserName() {
+ return userName;
+ }
+
+ /**
+ * Determine whether the authenticated user has the given role.
+ * @param roleName the name of the role to check
+ * @return true if the user has the role and is logged in; false otherwise
+ */
+ boolean hasRole( String roleName ) {
+ request.isUserInRole(roleName);
+ }
+
+ /**
+ * Logs the user out of the authentication mechanism.
+ * For some authentication mechanisms, this will be implemented as a no-op.
+ */
+ public void logout() {
+ }
+}</programlisting>
+ <para>
+ Then use this to create a &Session;:
+ </para>
+ <programlisting>
+HttpServletRequest request = ...
+&Repository; repository = engine.getRepository("my repository");
+&SecurityContext; securityContext = new ServletSecurityContext(httpServletRequest);
+SecurityContextCredentials credentials = new SecurityContextCredentials(securityContext);
+&Session; session = repository.login(credentials, workspaceName);
+</programlisting>
+ </sect2>
+ </sect1>
<sect1>
<title>Summary</title>
<para>
Modified: trunk/docs/reference/src/main/docbook/en-US/custom.dtd
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/custom.dtd 2009-06-07 22:33:45 UTC (rev 989)
+++ trunk/docs/reference/src/main/docbook/en-US/custom.dtd 2009-06-08 00:03:34 UTC (rev 990)
@@ -1,4 +1,4 @@
-<!ENTITY versionNumber "0.4">
+<!ENTITY versionNumber "0.5">
<!ENTITY copyrightYears "2008-2009">
<!ENTITY copyrightHolder "Red Hat, Inc.">
@@ -10,6 +10,7 @@
<!ENTITY DocHome "http://www.jboss.org/file-access/default/members/dna/freezone/">
<!ENTITY API "&DocHome;docs/&versionNumber;/apidocs/org/jboss/dna/">
<!ENTITY JIRA "http://jira.jboss.org/jira/browse/DNA">
+<!ENTITY Roadmap "&JIRA;?report=com.atlassian.jira.plugin.system.project:roadmap-panel">
<!ENTITY Subversion "http://anonsvn.jboss.org/repos/dna/">
<!ENTITY Fisheye "http://fisheye.jboss.org/browse/DNA/">
<!ENTITY SecureSubversion "https://svn.jboss.org/repos/dna/">
@@ -24,10 +25,14 @@
<!ENTITY Java "http://java.sun.com/j2se/1.5.0/docs/api/">
<!ENTITY GettingStarted "<ulink url='&DocHome;docs/&versionNumber;/manuals/gettingstarted/html/index.html'>Getting Started</ulink>">
+<!ENTITY ReferenceGuide "<ulink url='&DocHome;docs/&versionNumber;/manuals/reference/html/index.html'>Getting Started</ulink>">
<!-- Types in JRE -->
<!ENTITY String "<ulink url='&Java;java/lang/String.html'><interface>String</interface></ulink>">
+<!ENTITY File "<ulink url='&Java;java/io/File.html'><classname>File</classname></ulink>">
+<!ENTITY URL "<ulink url='&Java;java/net/URL.html'><classname>URL</classname></ulink>">
+<!ENTITY URI "<ulink url='&Java;java/net/URL.html'><classname>URI</classname></ulink>">
<!ENTITY InputStream "<ulink url='&Java;java/io/InputStream.html'><interface>InputStream</interface></ulink>">
<!ENTITY IOException "<ulink url='&Java;java/io/IOException.html'><classname>IOException</classname></ulink>">
<!ENTITY ClassLoader "<ulink url='&Java;java/lang/ClassLoader.html'><interface>ClassLoader</interface></ulink>">
@@ -38,6 +43,7 @@
<!ENTITY ExecutorService "<ulink url='&Java;java/util/concurrent/ExecutorService.html'><interface>ExecutorService</interface></ulink>">
<!ENTITY TimeUnit "<ulink url='&Java;java/util/concurrent/TimeUnit.html'><interface>TimeUnit</interface></ulink>">
<!ENTITY UUID "<ulink url='&Java;java/util/UUID.html'><classname>UUID</classname></ulink>">
+<!ENTITY DataSource "<ulink url='&Java;javax/sql/DataSource.html'><classname>DataSource</classname></ulink>">
<!-- Types in JCR API -->
@@ -45,6 +51,7 @@
<!ENTITY Repository "<interface>Repository</interface>">
<!ENTITY Session "<interface>Session</interface>">
<!ENTITY Credentials "<interface>Credentials</interface>">
+<!ENTITY SimpleCredentials "<interface>SimpleCredentials</interface>">
<!-- Types in dna-common -->
@@ -62,6 +69,8 @@
<!ENTITY Results "<ulink url='&API;graph/Results.html'><interface>Results</interface></ulink>">
<!ENTITY Location "<ulink url='&API;graph/Location.html'><classname>Location</classname></ulink>">
<!ENTITY ExecutionContext "<ulink url='&API;graph/ExecutionContext.html'><classname>ExecutionContext</classname></ulink>">
+<!ENTITY SecurityContext "<ulink url='&API;graph/SecurityContext.html'><interface>SecurityContext</interface></ulink>">
+<!ENTITY JaasSecurityContext "<ulink url='&API;graph/JaasSecurityContext.html'><classname>JaasSecurityContext</classname></ulink>">
<!ENTITY Name "<ulink url='&API;graph/property/Name.html'><interface>Name</interface></ulink>">
<!ENTITY Path "<ulink url='&API;graph/property/Path.html'><interface>Path</interface></ulink>">
<!ENTITY PathSegment "<ulink url='&API;graph/property/Path.Segment.html'><interface>Path.Segment</interface></ulink>">
@@ -77,6 +86,9 @@
<!ENTITY RepositorySourceCapabilities "<ulink url='&API;graph/connector/RepositorySourceCapabilities.html'><classname>RepositorySourceCapabilities</classname></ulink>">
<!ENTITY InMemoryRepository "<ulink url='&API;graph/connector/inmemory/InMemoryRepository.html'><classname>InMemoryRepository</classname></ulink>">
<!ENTITY InMemoryRepositorySource "<ulink url='&API;graph/connector/inmemory/InMemoryRepositorySource.html'><classname>InMemoryRepositorySource</classname></ulink>">
+<!ENTITY FederatedRepository "<ulink url='&API;graph/connector/federation/FederatedRepository.html'><classname>FederatedRepository</classname></ulink>">
+<!ENTITY FederatedRepositorySource "<ulink url='&API;graph/connector/federation/FederatedRepositorySource.html'><classname>FederatedRepositorySource</classname></ulink>">
+<!ENTITY Projection "<ulink url='&API;graph/connector/federation/Projection.html'><classname>Projection</classname></ulink>">
<!ENTITY CachePolicy "<ulink url='&API;graph/cache/CachePolicy.html'><interface>CachePolicy</interface></ulink>">
<!ENTITY Request "<ulink url='&API;graph/request/Request.html'><classname>Request</classname></ulink>">
<!ENTITY CompositeRequest "<ulink url='&API;graph/request/CompositeRequest.html'><classname>CompositeRequest</classname></ulink>">
@@ -95,6 +107,8 @@
<!-- Types in dna-repository -->
+<!ENTITY DnaEngine "<ulink url='&API;repository/DnaEngine.html'><classname>DnaEngine</classname></ulink>">
+<!ENTITY DnaConfiguration "<ulink url='&API;repository/DnaConfiguration.html'><classname>DnaConfiguration</classname></ulink>">
<!ENTITY RepositoryLibrary "<ulink url='&API;repository/RepositoryLibrary.html'><classname>RepositoryLibrary</classname></ulink>">
<!ENTITY RepositoryService "<ulink url='&API;repository/RepositoryService.html'><classname>RepositoryService</classname></ulink>">
<!ENTITY ServiceAdministrator "<ulink url='&API;repository/service/ServiceAdministrator.html'><interface>ServiceAdministrator</interface></ulink>">
@@ -110,16 +124,16 @@
<!-- Types in dna-jcr -->
+<!ENTITY JcrEngine "<ulink url='&API;jcr/JcrEngine.html'><classname>JcrEngine</classname></ulink>">
+<!ENTITY JcrConfiguration "<ulink url='&API;jcr/JcrConfiguration.html'><classname>JcrConfiguration</classname></ulink>">
<!ENTITY JcrRepository "<ulink url='&API;jcr/JcrRepository.html'><classname>JcrRepository</classname></ulink>">
<!ENTITY JcrSession "<ulink url='&API;jcr/JcrSession.html'><classname>JcrSession</classname></ulink>">
+<!ENTITY SecurityContextCredentials "<ulink url='&API;jcr/SecurityContextCredentials.html'><classname>SecurityContextCredentials</classname></ulink>">
<!-- Types in extensions/ -->
<!ENTITY JBossCacheRepository "<ulink url='&API;connector/jbosscache/JBossCacheRepository.html'><classname>JBossCacheRepository</classname></ulink>">
<!ENTITY JBossCacheSource "<ulink url='&API;connector/jbosscache/JBossCacheSource.html'><classname>JBossCacheSource</classname></ulink>">
-<!ENTITY FederatedRepositorySource "<ulink url='&API;connector/federation/FederatedRepositorySource.html'><classname>FederatedRepositorySource</classname></ulink>">
-<!ENTITY FederatedRepository "<ulink url='&API;connector/federation/FederatedRepository.html'><classname>FederatedRepository</classname></ulink>">
-<!ENTITY Projection "<ulink url='&API;connector/federation/Projection.html'><classname>Projection</classname></ulink>">
<!ENTITY ImageMetadataSequencer "<ulink url='&API;sequencer/image/ImageMetadataSequencer.html'><classname>ImageMetadataSequencer</classname></ulink>">
<!ENTITY ImageMetadata "<ulink url='&API;sequencer/image/ImageMetadata.html'><classname>ImageMetadata</classname></ulink>">
<!ENTITY ImageSequencerI18n "<ulink url='&API;sequencer/image/ImageSequencerI18n.html'><classname>ImageSequencerI18n</classname></ulink>">
16 years, 6 months
DNA SVN: r989 - in trunk/docs: examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer and 3 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-06-07 18:33:45 -0400 (Sun, 07 Jun 2009)
New Revision: 989
Added:
trunk/docs/gettingstarted/src/main/docbook/en-US/content/conclusion.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/repository_example.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/sequencer_example.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/use_cases.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/custom.dtd
Removed:
trunk/docs/gettingstarted/src/main/docbook/en-US/content/custom_sequencers.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/future.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/understanding_dna.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna_for_sequencing.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna_repositories.xml
Modified:
trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/ConsoleInput.java
trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
trunk/docs/examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer/SequencingClient.java
trunk/docs/gettingstarted/src/main/docbook/en-US/content/author_group.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/downloading_and_running.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/introduction.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/legal_notice.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/preface.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/master.xml
trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml
Log:
DNA-389 Updated the Getting Started document to reflect the new configuration approach, and restructured the document to better focus on the examples and high-level introduction, leaving the more detailed discussions for the Reference Guide (and removing more of the duplication).
Modified: trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/ConsoleInput.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/ConsoleInput.java 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/ConsoleInput.java 2009-06-07 22:33:45 UTC (rev 989)
@@ -125,14 +125,13 @@
try {
// Terminate ...
System.out.println();
- System.out.print("done.\nShutting down repositories and services ... ");
+ System.out.print("done.\nShutting down repositories ... ");
client.shutdown();
System.out.print("done.");
System.out.println();
System.out.println();
} catch (Exception err) {
- System.out.println("Error shutting down sequencing service and repository: "
- + err.getLocalizedMessage());
+ System.out.println("Error shutting down repository: " + err.getLocalizedMessage());
err.printStackTrace(System.err);
}
}
Modified: trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java 2009-06-07 22:33:45 UTC (rev 989)
@@ -202,7 +202,7 @@
if (loginContext == null) {
if (jaasContextName != null) {
loginContext = new LoginContext(jaasContextName, this.userInterface.getCallbackHandler());
- loginContext.login();
+ loginContext.login(); // This authenticates the user
}
}
return loginContext;
Modified: trunk/docs/examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer/SequencingClient.java
===================================================================
--- trunk/docs/examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer/SequencingClient.java 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer/SequencingClient.java 2009-06-07 22:33:45 UTC (rev 989)
@@ -68,7 +68,7 @@
throw new IllegalStateException(ex);
}
- // Configure the DNA JCR engine. This could be done by loading a configuration from a file, or by
+ // Configure the DNA configuration. This could be done by loading a configuration from a file, or by
// using a (local or remote) configuration repository, or by setting up the configuration programmatically.
// This example uses the programmatic approach...
String repositoryId = "content";
Modified: trunk/docs/gettingstarted/src/main/docbook/en-US/content/author_group.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/author_group.xml 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/author_group.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -24,7 +24,10 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-<!DOCTYPE authorgroup PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!DOCTYPE authorgroup PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
+%CustomDTD;
+]>
<authorgroup>
<corpauthor>Randall M. Hauch</corpauthor>
<corpauthor>John Verhaeg</corpauthor>
Added: trunk/docs/gettingstarted/src/main/docbook/en-US/content/conclusion.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/conclusion.xml (rev 0)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/conclusion.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="conclusion">
+ <title>Wrapping Up</title>
+ <para>
+ This document provided a very high-level overview of JBoss DNA, introducing you to what would be required to use JBoss DNA
+ in your own application. We saw two simple examples that showed two different aspects of JBoss DNA: the sequencing system
+ and the connector system. Each of these examples showed how to create a JBoss DNA configuration, how to start up
+ the JBoss DNA engine, and how to then access a <code>javax.jcr.Repository</code> instance, and after that your application
+ just uses the standard JCR API.
+ </para>
+ <para>
+ For a more in-depth description of JBoss DNA and the internal workings, see our &ReferenceGuide;.
+ This also describes how to write your own custom sequencers or connectors.
+ If you have any questions or comments, please feel free to contact JBoss DNA's
+ <ulink url="mailto:dna-users@jboss.org">user mailing list</ulink>
+ or use the
+ <ulink url="http://www.jboss.com/index.html?module=bb&op=viewforum&f=272">user forums</ulink>
+ or (preferably) the
+ <ulink url="http://www.jboss.org/dna/lists.html">mailing lists</ulink>. If you find a bug or have a suggestion, please
+ create a new issue in the project's
+ <ulink url="http://jira.jboss.org/jira/browse/DNA">JIRA issue management system</ulink>
+ . If there's something in particular you're interested in, talk with the community - there may be others interested in the
+ same thing.
+ </para>
+ <sect1 id="future">
+ <title>Future directions</title>
+ <para>
+ What's next for JBoss DNA? Well, the sequencing system is just the beginning. With this release, the sequencing system
+ is stable enough so that more <link linkend="sequencers">sequencers</link> can be developed and used within your own applications.
+ We've also established the foundation for JBoss DNA repositories, including a number of <link linkend="repository-connectors">connectors</link>.
+ We'll continue to expand our library of sequencers and connectors, as well as expand our support of JCR.
+ Other components on our roadmap include a web user interface, a REST-ful server, and a view system that allows domain-specific
+ views of information in the repository. These components are farther out on our roadmap, and at this time have not been
+ targeted to a particular release.
+ </para>
+ </sect1>
+ <sect1 id="get_involved">
+ <title>Getting involved</title>
+ <para>
+ If you're interested in getting involved with the JBoss DNA project, consider picking up one of the sequencers or connectors on our
+ <ulink url="&Roadmap;">roadmap</ulink>.
+ Or, check out <ulink url="&JIRA;">JIRA</ulink>
+ for the list of features we've thought of. If you think of one that's not there, please add it to JIRA!
+ </para>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/gettingstarted/src/main/docbook/en-US/content/conclusion.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: trunk/docs/gettingstarted/src/main/docbook/en-US/content/custom_sequencers.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/custom_sequencers.xml 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/custom_sequencers.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -1,346 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="custom_sequencers">
- <title>Creating custom sequencers</title>
- <para>The current release of JBoss DNA comes with six sequencers. However, it's very easy to create your own
- sequencers and to then configure JBoss DNA to use them in your own application.
- </para>
- <para>
- Creating a custom sequencer involves the following steps:
- <itemizedlist>
- <listitem>
- <para>Create a Maven 2 project for your sequencer;</para>
- </listitem>
- <listitem>
- <para>Implement the <code>org.jboss.dna.spi.sequencers.StreamSequencer</code> interface with your own implementation, and create unit tests to verify
- the functionality and expected behavior;</para>
- </listitem>
- <listitem>
- <para>Add the sequencer configuration to the JBoss DNA <code>SequencingService</code> in your application
- as described in the <link linkend="using_dna">previous chapter</link>; and</para>
- </listitem>
- <listitem>
- <para>Deploy the JAR file with your implementation (as well as any dependencies), and make them available to JBoss DNA
- in your application.</para>
- </listitem>
- </itemizedlist>
- It's that simple.
- </para>
- <sect1 id="custom_sequencer_project">
- <title>Creating the Maven 2 project</title>
- <para>The first step is to create the Maven 2 project that you can use to compile your code and build the JARs.
- Maven 2 automates a lot of the work, and since you're already <link linkend="downloading_and_running">set up to use Maven</link>,
- using Maven for your project will save you a lot of time and effort. Of course, you don't have to use Maven 2, but then you'll
- have to get the required libraries and manage the compiling and building process yourself.</para>
- <note>
- <para>JBoss DNA may provide in the future a Maven archetype for creating sequencer projects. If you'd find this useful
- and would like to help create it, please <link linkend="preface">join the community</link>.</para>
- </note>
- <note>
- <para>The <code>dna-sequencer-images</code> project is a small, self-contained sequencer implementation that
- has only the minimal dependencies. Starting with this project's source and modifying it to suit your needs may be the easiest way to get started.
- See the subversion repository: <ulink url="http://anonsvn.jboss.org/repos/dna/trunk/extensions/dna-sequencer-images/">http://anonsvn.jboss.org/repos/dna/trunk/sequencers/dna-sequencer-images/</ulink>
- </para>
- </note>
- <para>You can create your Maven project any way you'd like. For examples, see the <ulink url="http://maven.apache.org/guides/getting-started/index.html#How_do_I_make_m...">Maven 2 documentation</ulink>.
- Once you've done that, just add the dependencies in your project's <code>pom.xml</code> dependencies section:</para>
- <programlisting role="XML"><![CDATA[
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-common</artifactId>
- <version>0.5</version>
-</dependency>
-<dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
-</dependency>
- ]]></programlisting>
- <para>These are minimum dependencies required for compiling a sequencer. Of course, you'll have to add
- other dependencies that your sequencer needs.</para>
- <para>As for testing, you probably will want to add more dependencies, such as those listed here:</para>
- <programlisting role="XML"><![CDATA[
-<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.4</version>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>org.hamcrest</groupId>
- <artifactId>hamcrest-library</artifactId>
- <version>1.1</version>
- <scope>test</scope>
-</dependency>
-<!-- Logging with Log4J -->
-<dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.3</version>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- <scope>test</scope>
-</dependency>
- ]]></programlisting>
- <para>Testing JBoss DNA sequencers does not require a JCR repository or the JBoss DNA services. (For more detail,
- see the <link linkend="testing_custom_sequencers">testing section</link>.) However, if you want to do
- integration testing with a JCR repository and the JBoss DNA services, you'll need additional dependencies for these libraries.</para>
- <programlisting role="XML"><![CDATA[
-<!-- JBoss DNA JCR Repository -->
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-jcr</artifactId>
- <version>0.5</version>
- <scope>test</scope>
-</dependency>
-<!-- Java Content Repository API -->
-<dependency>
- <groupId>javax.jcr</groupId>
- <artifactId>jcr</artifactId>
- <version>1.0.1</version>
- <scope>test</scope>
-</dependency>
- ]]></programlisting>
- <para>At this point, your project should be set up correctly, and you're ready to move on to
- <link linkend="custom_sequencer_implementation">writing the Java implementation</link> for your sequencer.</para>
- </sect1>
- <sect1 id="custom_sequencer_implementation">
- <title>Implementing the StreamSequencer interface</title>
- <para>After creating the project and setting up the dependencies, the next step is to create a Java class that implements
- the <code>org.jboss.dna.spi.sequencers.StreamSequencer</code> interface. This interface is very straightforward
- and involves a single method:</para>
- <programlisting role="JAVA"><![CDATA[
-public interface StreamSequencer {
-
- /**
- * Sequence the data found in the supplied stream, placing the output
- * information into the supplied map.
- *
- * @param stream the stream with the data to be sequenced; never null
- * @param output the output from the sequencing operation; never null
- * @param context the context for the sequencing operation; never null
- */
- void sequence( InputStream stream, SequencerOutput output, SequencerContext context );
- ]]></programlisting>
- <para>The job of a stream sequencer is to process the data in the supplied stream, and place into the <code>SequencerOutput</code>
- any information that is to go into the JCR repository. JBoss DNA figures out when your sequencer should be called
- (of course, using the sequencing configuration you'll add in a bit), and then makes sure the generated information
- is saved in the correct place in the repository.
- </para>
- <para>The <code>SequencerContext</code> provides information about
- the current sequencing operation, including the location and properties of the node being sequenced, the MIME type
- of the node being sequenced, and a location to record problems that aren't severe enough to warrant throwing an exception.
- </para>
- <para>The <code>SequencerOutput</code> class is fairly easy to use. There are basically two methods you need to call.
- One method sets the property values, while the other sets references to other nodes in the repository. Use these
- methods to describe the properties of the nodes you want to create, using relative paths for the nodes and
- valid JCR property names for properties and references. JBoss DNA will ensure that nodes are created or updated
- whenever they're needed.</para>
- <programlisting role="JAVA"><![CDATA[
-public interface SequencerOutput {
-
- /**
- * Set the supplied property on the supplied node. The allowable
- * values are any of the following:
- * - primitives (which will be autoboxed)
- * - String instances
- * - String arrays
- * - byte arrays
- * - InputStream instances
- * - Calendar instances
- *
- * @param nodePath the path to the node containing the property;
- * may not be null
- * @param property the name of the property to be set
- * @param values the value(s) for the property; may be empty if
- * any existing property is to be removed
- */
- void setProperty( String nodePath, String property, Object... values );
-
- /**
- * Set the supplied reference on the supplied node.
- *
- * @param nodePath the path to the node containing the property;
- * may not be null
- * @param property the name of the property to be set
- * @param paths the paths to the referenced property, which may be
- * absolute paths or relative to the sequencer output node;
- * may be empty if any existing property is to be removed
- */
- void setReference( String nodePath, String property, String... paths );
-}
- ]]></programlisting>
- <para>JBoss DNA will create nodes of type <code>nt:unstructured</code> unless you specify the value for the
- <code>jcr:primaryType</code> property. You can also specify the values for the <code>jcr:mixinTypes</code> property
- if you want to add mixins to any node.</para>
- <para>For a complete example of a sequencer, let's look at the <code>org.jboss.dna.sequencers.image.ImageMetadataSequencer</code>
- implementation:</para>
- <programlisting role="JAVA"><![CDATA[
-public class ImageMetadataSequencer implements StreamSequencer {
-
- public static final String METADATA_NODE = "image:metadata";
- public static final String IMAGE_PRIMARY_TYPE = "jcr:primaryType";
- public static final String IMAGE_MIXINS = "jcr:mixinTypes";
- public static final String IMAGE_MIME_TYPE = "jcr:mimeType";
- public static final String IMAGE_ENCODING = "jcr:encoding";
- public static final String IMAGE_FORMAT_NAME = "image:formatName";
- public static final String IMAGE_WIDTH = "image:width";
- public static final String IMAGE_HEIGHT = "image:height";
- public static final String IMAGE_BITS_PER_PIXEL = "image:bitsPerPixel";
- public static final String IMAGE_PROGRESSIVE = "image:progressive";
- public static final String IMAGE_NUMBER_OF_IMAGES = "image:numberOfImages";
- public static final String IMAGE_PHYSICAL_WIDTH_DPI = "image:physicalWidthDpi";
- public static final String IMAGE_PHYSICAL_HEIGHT_DPI = "image:physicalHeightDpi";
- public static final String IMAGE_PHYSICAL_WIDTH_INCHES = "image:physicalWidthInches";
- public static final String IMAGE_PHYSICAL_HEIGHT_INCHES = "image:physicalHeightInches";
-
- /**
- * {@inheritDoc}
- */
- public void sequence( InputStream stream, SequencerOutput output,
- SequencerContext context ) {
- ImageMetadata metadata = new ImageMetadata();
- metadata.setInput(stream);
- metadata.setDetermineImageNumber(true);
- metadata.setCollectComments(true);
-
- // Process the image stream and extract the metadata ...
- if (!metadata.check()) {
- metadata = null;
- }
-
- // Generate the output graph if we found useful metadata ...
- if (metadata != null) {
- // Place the image metadata into the output map ...
- output.setProperty(METADATA_NODE, IMAGE_PRIMARY_TYPE, "image:metadata");
- // output.psetProperty(METADATA_NODE, IMAGE_MIXINS, "");
- output.setProperty(METADATA_NODE, IMAGE_MIME_TYPE, metadata.getMimeType());
- // output.setProperty(METADATA_NODE, IMAGE_ENCODING, "");
- output.setProperty(METADATA_NODE, IMAGE_FORMAT_NAME, metadata.getFormatName());
- output.setProperty(METADATA_NODE, IMAGE_WIDTH, metadata.getWidth());
- output.setProperty(METADATA_NODE, IMAGE_HEIGHT, metadata.getHeight());
- output.setProperty(METADATA_NODE, IMAGE_BITS_PER_PIXEL, metadata.getBitsPerPixel());
- output.setProperty(METADATA_NODE, IMAGE_PROGRESSIVE, metadata.isProgressive());
- output.setProperty(METADATA_NODE, IMAGE_NUMBER_OF_IMAGES, metadata.getNumberOfImages());
- output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_WIDTH_DPI, metadata.getPhysicalWidthDpi());
- output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_HEIGHT_DPI, metadata.getPhysicalHeightDpi());
- output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_WIDTH_INCHES, metadata.getPhysicalWidthInch());
- output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_HEIGHT_INCHES, metadata.getPhysicalHeightInch());
- }
- }
-}
- ]]></programlisting>
- <para>
- Notice how the image metadata is extracted and the output graph is generated. A single node is created with the name <code>image:metadata</code>
- and with the <code>image:metadata</code> node type. No mixins are defined for the node, but several properties are set on the node
- using the values obtained from the image metadata. After this method returns, the constructed graph will be saved to the repository
- in all of the places defined by its configuration. (This is why only relative paths are used in the sequencer.)
- </para>
- </sect1>
- <sect1 id="testing_custom_sequencers">
- <title>Testing custom sequencers</title>
- <para>The sequencing framework was designed to make testing sequencers much easier. In particular, the
- <code>StreamSequencer</code> interface does not make use of the JCR API. So instead of requiring a fully-configured
- JCR repository and JBoss DNA system, unit tests for a sequencer can focus on testing that the content is
- processed correctly and the desired output graph is generated.</para>
- <note>
- <para>For a complete example of a sequencer unit test, see the <code>ImageMetadataSequencerTest</code> unit test
- in the <code>org.jboss.dna.sequencer.images</code> package of the <code>dna-sequencers-image</code> project.
- </para>
- </note>
- <para>The following code fragment shows one way of testing a sequencer, using JUnit 4.4 assertions and
- some of the classes made available by JBoss DNA. Of course,
- this example code does not do any error handling and does not make all the assertions a real test would.</para>
- <programlisting role="JAVA"><![CDATA[
-Sequencer sequencer = new ImageMetadataSequencer();
-MockSequencerOutput output = new MockSequencerOutput();
-MockSequencerContext context = new MockSequencerContext();
-InputStream stream = null;
-try {
- stream = this.getClass().getClassLoader().getResource("caution.gif").openStream();
- sequencer.sequence(stream,output,context); // writes to 'output'
- assertThat(output.getPropertyValues("image:metadata", "jcr:primaryType"),
- is(new Object[] {"image:metadata"}));
- assertThat(output.getPropertyValues("image:metadata", "jcr:mimeType"),
- is(new Object[] {"image/gif"}));
- // ... make more assertions here
- assertThat(output.hasReferences(), is(false));
-} finally {
- stream.close();
-}
- ]]></programlisting>
- <para>It's also useful to test that a sequencer produces no output for something it should not understand:</para>
- <programlisting role="JAVA"><![CDATA[
-Sequencer sequencer = new ImageMetadataSequencer();
-MockSequencerOutput output = new MockSequencerOutput();
-MockSequencerContext context = new MockSequencerContext();
-InputStream stream = null;
-try {
- stream = this.getClass().getClassLoader().getResource("caution.pict").openStream();
- sequencer.sequence(stream,output,context); // writes to 'output'
- assertThat(output.hasProperties(), is(false));
- assertThat(output.hasReferences(), is(false));
-} finally {
- stream.close();
-}
- ]]></programlisting>
- <para>These are just two simple tests that show ways of testing a sequencer. Some tests may get quite involved,
- especially if a lot of output data is produced.
- </para>
- <para>It may also be useful to create some integration tests
- that <link linkend="using_dna">configure JBoss DNA</link> to use a custom sequencer, and to then upload
- content using the JCR API, verifying that the custom sequencer did run. However, remember that JBoss DNA
- runs sequencers asynchronously in the background, and you must sychronize your tests to ensure that the
- sequencers have a chance to run before checking the results. (One way of doing this (although, granted, not always reliable) is to wait for a second
- after uploading your content, shutdown the <code>SequencingService</code> and await its termination,
- and then check that the sequencer output has been saved to the JCR repository. For an example of this technique,
- see the <code>SequencingClientTest</code> unit test in the example application.)
- </para>
- </sect1>
- <sect1 id="deploying_custom_sequencers">
- <title>Deploying custom sequencers</title>
- <para>The first step of deploying a sequencer consists of adding/changing the sequencer configuration (e.g., <code>SequencerConfig</code>)
- in the <code>SequencingService</code>. This was covered in the <link linkend="sequencing_service">previous chapter</link>.
- </para>
- <para>
- The second step is to make the sequencer implementation available to JBoss DNA. At this time, the JAR containing
- your new sequencer, as well as any JARs that your sequencer depends on, should be placed on your application classpath.</para>
- <note>
- <para>A future goal of JBoss DNA is to allow sequencers, connectors, and other extensions to be easily deployed into
- a runtime repository. This process will not only be much simpler, but it will also provide JBoss DNA
- with the information necessary to update configurations and create the appropriate class loaders for each extension.
- Having separate class loaders for each extension helps prevent the pollution of the common classpath,
- facilitates an isolated runtime environment to eliminate any dependency conflicts, and may potentially
- enable hot redeployment of newer extension versions.
- </para>
- </note>
- </sect1>
-</chapter>
Modified: trunk/docs/gettingstarted/src/main/docbook/en-US/content/downloading_and_running.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/downloading_and_running.xml 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/downloading_and_running.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -24,14 +24,17 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
+%CustomDTD;
+]>
<chapter id="downloading_and_running">
<title>Running the example applications</title>
<para>
This chapter provides instructions for downloading and running a sample application that demonstrates how JBoss DNA works
with a JCR repository to automatically sequence changing content to extract useful information. So read on to get the simple
- application running, and then in the <link linkend="using_dna">next chapter</link>
- we'll dive into the source code for the example and show how to use JBoss DNA in your own applications. </para>
+ application running.
+ </para>
<para>JBoss DNA uses Maven 2 for its build system, as is this example. Using Maven 2 has several advantages, including
the ability to manage dependencies. If a library is needed, Maven automatically finds and downloads that library, plus
everything that library needs. This means that it's very easy to build the examples - or even create a maven project that
@@ -244,165 +247,10 @@
</itemizedlist>
</para>
</sect1>
- <sect1 id="running_sequencer_example">
- <title>Running the sequencing example</title>
- <para>The sequencing example consists of a client application that sets up an in-memory JCR repository and that allows a user to
- upload files into that repository. The client also sets up the DNA services with two sequencers so that if any of the
- uploaded files are PNG, JPEG, GIF, BMP or other images, DNA will automatically extract the image's metadata (e.g., image
- format, physical size, pixel density, etc.) and store that in the repository. Alternatively, if the uploaded file
- is an MP3 audio file, DNA will extract some of the ID3 metadata (e.g., the author, title, album, year and comment)
- and store that in the repository.</para>
- <para>
- To run the client application, go to the <code>examples/sequencers/target/dna-example-sequencers-basic.dir/</code>
- directory and type <code>./run.sh</code>. You should see the command-line client and its menus in your terminal:
- <figure id="xample-sequencer-cli-client">
- <title>Example client</title>
- <graphic align="center" scale="100" fileref="example-sequencer-client.png"/>
- </figure>
- From this menu, you can upload a file into the repository, search for media in the repository, print sequencing statistics,
- or quit the application.</para>
- <para>
- The first step is to upload one of the example images. If you type 'u' and press return, you'll be prompted to supply the
- path to the file you want to upload. Since the application is running from within the
- <code>examples/sequencers/target/dna-example-sequencers-basic.dir/</code> directory, you can specify any of the files
- in that directory without specifying the path:
- <figure id="example-sequencer-upload">
- <title>Uploading an image using the example client</title>
- <graphic align="center" scale="100" fileref="example-sequencer-upload.png"/>
- </figure>
- You can specify any fully-qualified or relative path. The application will notify you if it cannot find the file you
- specified. The example client configures JBoss DNA to sequence MP3 audio files, Java source files, or image files with one of
- the following extensions (technically, nodes that have names ending in the following):
- <code>jpg</code>, <code>jpeg</code>, <code>gif</code>, <code>bmp</code>, <code>pcx</code>, <code>png</code>,
- <code>iff</code>, <code>ras</code>, <code>pbm</code>, <code>pgm</code>, <code>ppm</code>, and <code>psd</code>.
- Files with other extensions in the repository path will be ignored. For your convenience, the example provides several
- files that will be sequenced (<code>caution.png</code>, <code>caution.jpg</code>, <code>caution.gif</code>, and
- <code>sample1.mp3</code>) and one image that will not be sequenced (<code>caution.pict</code>). Feel free to try other files.
- </para>
- <para>
- After you have specified the file you want to upload, the example application asks you where in the repository you'd like to
- place the file. (If you want to use the suggested location, just press <code>return</code>.) The client application
- uses the JCR API to upload the file to that location in the repository, creating any nodes (of type <code>nt:folder</code>)
- for any directories that don't exist, and creating a node (of type <code>nt:file</code>) for the file. And, per the JCR specification,
- the application creates a <code>jcr:content</code> node (of type <code>nt:resource</code>) under the file node.
- The file contents are placed on this <code>jcr:content</code> node in the <code>jcr:data</code> property. For example, if you specify
- <code>/a/b/caution.png</code>, the following structure will be created in the repository:</para>
- <programlisting><![CDATA[
-/a (nt:folder)
- /b (nt:folder)
- /caution.png (nt:file)
- /jcr:content (nt:resource)
- @jcr:data = {contents of the file}
- @jcr:mimeType = {mime type of the file}
- @jcr:lastModified = {now}
-]]></programlisting>
- <para>Other kinds of files are treated in a similar way.</para>
- <para>When the client uploads the file using the JCR API, DNA gets notified of the changes, consults the sequencers to see whether
- any of them are interested in the new or updated content, and if so runs those sequencers. The image sequencer processes image
- files for metadata, and any metadata found is stored under the <code>/images</code> branch of the repository. The MP3 sequencer
- processes MP3 audio files for metadata, and any metadata found is stored under the <code>/mp3s</code>
- branch of the repository. And metadata about Java classes are stored under the <code>/java</code> area of the repository.
- All of this happens asynchronously, so any DNA activity doesn't impede or slow down the client activities.
- </para>
- <para>So, after the file is uploaded, you can search the repository for the image metadata using the "s" menu option:
- <figure id="example-sequencer-search">
- <title>Searching for media using the example client</title>
- <graphic align="center" scale="100" fileref="example-sequencer-search.png"/>
- </figure>
- Here are the search results after the <code>sample1.mp3</code> audio file has been uploaded (to the <code>/a/b/sample1.mp3</code> location):
- <figure id="example-sequencer-search-with-mp3">
- <title>Searching for media using the example client</title>
- <graphic align="center" scale="100" fileref="example-sequencer-search-with-mp3.png"/>
- </figure>
- You can also display the sequencing statistics using the "d" menu option:
- <figure id="example-sequencer-statistics">
- <title>Sequencing statistics using the example client</title>
- <graphic align="center" scale="100" fileref="example-sequencer-statistics.png"/>
- </figure>
- These stats show how many nodes were sequenced, and how many nodes were skipped because they didn't apply to the sequencer's
- criteria.
- </para>
- <note>
- <para>There will probably be more nodes skipped than sequenced, since there are more <code>nt:folder</code> and <code>nt:resource</code>
- nodes than there are <code>nt:file</code> nodes with acceptable names.</para>
- </note>
- <para>You can repeat this process with other files. Any file that isn't an image or MP3 files (as recognized by the sequencing configurations
- that we'll describe later) will not be sequenced.</para>
+ <sect1 id="downloading_and_running_whats_next">
+ <title>What's next</title>
+ <para>In this chapter you downloaded, installed, and built the two example applications. In the next two chapters, we'll
+ run these examples and walk through the code.
+ </para>
</sect1>
- <sect1 id="running_repository_example">
- <title>Running the repository example</title>
- <para>The repository example consists of a client application that sets up two DNA repositories (named "Cars" and "Airplanes") and
- a federated repository ("Vehicles") that dynamically federates the information from the other two repositories.
- The client application allows you to interactively navigate each of these repositories just as you would navigate the
- directory structure on a file system.</para>
- <para>This collection of repositories is shown in the following figure:
- <figure id="example-repositories">
- <title>Repositories used in the example client</title>
- <graphic align="center" scale="100" fileref="example-repositories.png"/>
- </figure>
- Most of the repositories are in-memory repositories (using the In-Memory repository connector), but the federated "Vehicles" repository
- content is federated from the other repositories and cached into the "Cache" repository. This is shown in the following figure:
- <figure id="example-federated-repository">
- <title>Vehicles repository content is federated from the Cars, Airplanes and Configuration repositories</title>
- <graphic align="center" scale="100" fileref="example-federated-repository.png"/>
- </figure>
- </para>
- <para>
- To run the client application, go to the <code>examples/repository/target/dna-example-repositories-basic.dir/</code>
- directory and type <code>./run.sh</code>. You should see the command-line client and its menus in your terminal:
- <figure id="example-repositories-client">
- <title>Example Client</title>
- <graphic align="center" scale="100" fileref="example-repositories-client.png"/>
- </figure>
- From this menu, you can see the list of repositories, select one, and navigate through that repository in a manner similar
- to a *nix command-line shell (although the client itself uses the JCR API to interact with the repositories).
- Here are some of the commands you can use:</para>
- <table frame='all'>
- <title>Repository client commands to navigate a repository</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row><entry>Command</entry><entry>Description</entry></row>
- </thead>
- <tbody>
- <row><entry>pwd</entry><entry>Print the path of the current node (e.g., the "working directory")</entry></row>
- <row><entry>ls [<emphasis>path</emphasis>]</entry><entry>List the children and properties of the node at the supplied path,
- where "<emphasis>path</emphasis>" can be any relative path or absolute path. If "<emphasis>path</emphasis>" is not supplied,
- the current working node's path is used.</entry></row>
- <row><entry>cd <emphasis>path</emphasis></entry><entry>Change to the specified node, where "<emphasis>path</emphasis>"
- can be any relative path or absolute path. For example, "<code>cd alpha</code>" changes the current node to be a child named
- "<code>alpha</code>"; "<code>cd ..</code>" changes the current node to the parent node; "<code>cd /a/b</code>" changes
- the current node to be the "<code>/a/b</code>" node.</entry></row>
- <row><entry>exit</entry><entry>Exit this repository and return the list of repositories.</entry></row>
- </tbody>
- </tgroup>
- </table>
- <para>If you were to select the "Cars" repository and use some of the commands, you should see something similar to:
- <figure id="example-repositories-navigating">
- <title>Navigating the Cars repository</title>
- <graphic align="center" scale="100" fileref="example-repositories-navigating.png"/>
- </figure>
- </para>
- <para>You can also choose to navigate the "Vehicles" repository, which projects the "Cars" repository content under the
- <code>/Vehicles/Cars</code> node, the "Airplanes" content under the <code>/Vehicles/Airplanes</code> branch,
- and the "Configuration" content under <code>/dna:system</code>.
- </para>
- <para>Try using the client to walk the different repositories. And while this is a contrived application, it does demonstrate
- the use of JBoss DNA to federate repositories and provide access through JCR.</para>
- </sect1>
- <sect1 id="downloading_and_running_review">
- <title>Summarizing what we just did</title>
- <para>In this chapter you downloaded, installed, and built the two example applicationss. With the sequencer client, you could upload files into a
- JCR repository, while JBoss DNA automatically sequenced the image, MP3, or Java source files you uploaded, extracted the metadata from the
- files, and stored that metadata inside the repository. The repository client allowed you to walk through multiple repositories,
- including one whose content was federated from multiple other repositories.</para>
- <para>These example applications were very simplistic. In fact, running through the examples probably only took you a few minutes.
- So while these applications won't win any awards, they hopefully showed you the basics of what JBoss DNA can do.</para>
- <para>In the next two chapters, we'll venture into the code to get an understanding of how JBoss DNA actually works.
- The <link linkend="using_dna_for_sequencing">next chapter</link> reviews the sequencer application and talks about
- how you can use DNA sequencers in your own applications. Then in the <link linkend="using_dna_repositories">following chapter</link>
- we'll venture into the repositories example code to show how you can use DNA repositories, including federated repositories,
- in your own applications.</para>
- </sect1>
</chapter>
Deleted: trunk/docs/gettingstarted/src/main/docbook/en-US/content/future.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/future.xml 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/future.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="future">
- <title>Looking to the future</title>
- <para>
- What's next for JBoss DNA? Well, the sequencing system is just the beginning. With this release, the sequencing system
- is stable enough so that more <link linkend="sequencers">sequencers</link> can be developed and used within your own applications.
- We've also established the foundation for JBoss DNA repositories, including a number of <link linkend="repository-connectors">connectors</link>.
- We'll continue to expand our library of sequencers and connectors, as well as expand our support of JCR.
- Other components on our roadmap include a web user interface, a REST-ful server, and a view system that allows domain-specific
- views of information in the repository. These components are farther out on our roadmap, and at this time have not been
- targeted to a particular release.
- </para>
- <para>
- If you're interested in getting involved with the JBoss DNA project, consider picking up one of the sequencers on our
- <ulink url="http://jira.jboss.org/jira/browse/DNA?report=com.atlassian.jira.plugin.sy...">roadmap</ulink>.
- Or, check out <ulink url="http://jira.jboss.org/jira/secure/IssueNavigator.jspa?reset=true&mode...">JIRA</ulink>
- for the list of sequencers we've thought of. If you think of one that's not there, please add it to JIRA!
- </para>
-</chapter>
Modified: trunk/docs/gettingstarted/src/main/docbook/en-US/content/introduction.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/introduction.xml 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/introduction.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -24,7 +24,10 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
+%CustomDTD;
+]>
<chapter id="introduction">
<title>Introduction</title>
<para>There are a lot of ways for applications to store information persistently so that it can be accessed at a
@@ -85,26 +88,48 @@
and is being revised under <ulink url="http://www.jcp.org/en/jsr/detail?id=283">JSR-283</ulink>.
</para>
<para>
- The <emphasis>JBoss DNA project</emphasis>
- is building unified metadata repository system that is compliant with JCR. Nearly all of these capabilities are to be hidden
- below the JCR API and involve automated processing of the information in the repository. Thus, JBoss DNA can add value to
- existing repository implementations. For example, JCR repositories offer the ability to upload files into the repository and
- have the file content indexed for search purposes. JBoss DNA also defines a library for "sequencing" content - to extract
- meaningful information from that content and store it in the repository, where it can then be searched, accessed, and
- analyzed using the JCR API.
- </para>
- <para> JBoss DNA has other features as well. You can create federated repositories that dynamically merge the information
- from multiple databases, services, applications, and other JCR repositories. JBoss DNA also will allow you to
- create customized views based upon the type of data and the role of the user that is accessing the data. And yet another goal is
- to create a REST-ful API to allow the JCR content to be accessed easily by other applications written in other languages.
- </para>
- <para>
- The <link linkend="understanding_dna">next chapter</link> in this book goes into more detail about JBoss DNA and its architecture,
- the different components, what's available now, and what's coming in future releases.
- <link linkend="downloading_and_running">Chapter 3</link> then provides instructions for downloading and running the sequencer
- examples for the current release. <link linkend="using_dna">Chapter 4</link> walks through how to use JBoss DNA sequencers
- in your applications, while <link linkend="custom_sequencers">Chapter 5</link> shows how to use JBoss DNA repositories.
- <link linkend="custom_sequencers">Chapter 6</link> goes over how to create custom sequencers, and finally,
- <link linkend="future">Chapter 7</link> wraps things up with a discussion about the future of JBoss DNA.
- </para>
+ The JCR API provides a number of information services that are needed by many applications,
+ including: read and write access to information; the ability to structure information in a hierarchical and flexible manner that can adapt
+ and evolve over time; ability to work with unstructured content; ability to (transparently) handle large strings;
+ notifications of changes in the information; search and query; versioning of information; access control; integrity constraints;
+ participation within distributed transactions; explicit locking of content; and of course persistence.
+ </para>
+ <sect1 id="what_is_jboss_dna">
+ <title>JBoss DNA</title>
+ <para>
+ What makes JCR interesting, however, is that a JCR implementation provides all these features and capabilities regardless
+ of where or how that information is persisted or stored. <emphasis>This is in fact the main purpose of JBoss DNA:
+ provide a JCR implementation that provides access to content stored in many different kinds of systems.</emphasis>
+ A JBoss DNA repository isn't yet another silo of information, but rather it's a JCR view of the information you already have
+ in your environment: files systems, databases, other repositories, services, applications, etc. JBoss DNA can
+ help you understand the systems and information you already have.
+ </para>
+ <para>
+ Of course when you start providing a unified view of all this information, you start recognizing the need to store more
+ information, including metadata about and relationships between the existing content. JBoss DNA lets you do this, too.
+ And JBoss DNA even tries to help you discover more about the information you already have, especially the
+ information wrapped up in the kinds of files often found in enterprise systems: service definitions, policy files,
+ images, media, documents, presentations, application components, reusable libraries, configuration files,
+ application installations, databases schemas, management scripts, and so on. As files are loaded into the repository,
+ JBoss DNA can <emphasis>sequence</emphasis> these files to extract from their content meaningful information that
+ can be stored in the repository, where it can then be searched, accessed, and analyzed using the JCR API.
+ </para>
+ </sect1>
+ <sect1 id="introduction_whats_next">
+ <title>What's next</title>
+ <para>
+ As we'll see in the <link linkend="use_cases">next chapter</link>, the ability of JBoss DNA to
+ federate, integrate, and sequence information make JBoss DNA a powerful asset and tool.
+ Then <link linkend="using_dna">Chapter 3</link> will show that once a JBoss DNA repository is set up, application see
+ JBoss DNA just as another JCR <code>javax.jcr.Repository</code> instance and uses the standard JCR API to obtain a <code>javax.jcr.Session</code>
+ and work with the content.
+ </para>
+ <para>
+ <link linkend="downloading_and_running">Chapter 4</link> walks you through downloading
+ and building the JBoss DNA examples, while <link linkend="sequencer_example">Chapter 5</link>
+ and <link linkend="repository_example">Chapter 6</link> will run these very simple examples and walking through code.
+ <link linkend="conclusion">Chapter 7</link> wraps things up with a discussion about the future of JBoss DNA
+ and what you can do next to start using JBoss DNA in your own applications.
+ </para>
+ </sect1>
</chapter>
Modified: trunk/docs/gettingstarted/src/main/docbook/en-US/content/legal_notice.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/legal_notice.xml 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/legal_notice.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -24,7 +24,10 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-<!DOCTYPE legalnotice PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!DOCTYPE legalnotice PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
+%CustomDTD;
+]>
<legalnotice id="Legal_Notice">
<title>Legal Notice</title>
Modified: trunk/docs/gettingstarted/src/main/docbook/en-US/content/preface.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/preface.xml 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/preface.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -24,7 +24,10 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
+%CustomDTD;
+]>
<preface id="preface" revision="1">
<title>What this book covers</title>
<para>The goal of this book is to help you learn about JBoss DNA and how you can use it in your own applications to get the
Added: trunk/docs/gettingstarted/src/main/docbook/en-US/content/repository_example.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/repository_example.xml (rev 0)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/repository_example.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -0,0 +1,483 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="repository_example">
+ <title>The Repository Example</title>
+ <para>
+ <link linkend="downloading_and_running">Chapter 4</link> walked through the process of downloading and building the examples,
+ while the <link linkend="sequencer_example">previous chapter</link> showed how to run the sequencer example and walked
+ through the code. In this chapter, we'll run the repository example and walk through that example code to see what
+ it's doing.
+ </para>
+ <sect1 id="running_repository_example">
+ <title>Running the repository example</title>
+ <para>The repository example consists of a client application that sets up two DNA repositories (named "Cars" and "Airplanes") and
+ a federated repository ("Vehicles") that dynamically federates the information from the other two repositories.
+ The client application allows you to interactively navigate each of these repositories just as you would navigate the
+ directory structure on a file system.</para>
+ <para>This collection of repositories is shown in the following figure:
+ <figure id="example-repositories">
+ <title>Repositories used in the example client</title>
+ <graphic align="center" scale="100" fileref="example-repositories.png"/>
+ </figure>
+ Most of the repositories are in-memory repositories (using the In-Memory repository connector), but the federated "Vehicles" repository
+ content is federated from the other repositories and cached into the "Cache" repository. This is shown in the following figure:
+ <figure id="example-federated-repository">
+ <title>Vehicles repository content is federated from the Cars, Airplanes and Configuration repositories</title>
+ <graphic align="center" scale="100" fileref="example-federated-repository.png"/>
+ </figure>
+ </para>
+ <para>
+ To run the client application, go to the <code>examples/repository/target/dna-example-repositories-basic.dir/</code>
+ directory and type <code>./run.sh</code>. You should see the command-line client and its menus in your terminal:
+ <figure id="example-repositories-client">
+ <title>Example Client</title>
+ <graphic align="center" scale="100" fileref="example-repositories-client.png"/>
+ </figure>
+ From this menu, you can see the list of repositories, select one, and navigate through that repository in a manner similar
+ to a *nix command-line shell (although the client itself uses the JCR API to interact with the repositories).
+ Here are some of the commands you can use:</para>
+ <table frame='all'>
+ <title>Repository client commands to navigate a repository</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row><entry>Command</entry><entry>Description</entry></row>
+ </thead>
+ <tbody>
+ <row><entry>pwd</entry><entry>Print the path of the current node (e.g., the "working directory")</entry></row>
+ <row><entry>ls [<emphasis>path</emphasis>]</entry><entry>List the children and properties of the node at the supplied path,
+ where "<emphasis>path</emphasis>" can be any relative path or absolute path. If "<emphasis>path</emphasis>" is not supplied,
+ the current working node's path is used.</entry></row>
+ <row><entry>cd <emphasis>path</emphasis></entry><entry>Change to the specified node, where "<emphasis>path</emphasis>"
+ can be any relative path or absolute path. For example, "<code>cd alpha</code>" changes the current node to be a child named
+ "<code>alpha</code>"; "<code>cd ..</code>" changes the current node to the parent node; "<code>cd /a/b</code>" changes
+ the current node to be the "<code>/a/b</code>" node.</entry></row>
+ <row><entry>exit</entry><entry>Exit this repository and return the list of repositories.</entry></row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>If you were to select the "Cars" repository and use some of the commands, you should see something similar to:
+ <figure id="example-repositories-navigating">
+ <title>Navigating the Cars repository</title>
+ <graphic align="center" scale="100" fileref="example-repositories-navigating.png"/>
+ </figure>
+ </para>
+ <para>You can also choose to navigate the "Vehicles" repository, which projects the "Cars" repository content under the
+ <code>/Vehicles/Cars</code> node, the "Airplanes" content under the <code>/Vehicles/Airplanes</code> branch,
+ and the "Configuration" content under <code>/dna:system</code>.
+ </para>
+ <para>Try using the client to walk the different repositories. And while this is a contrived application, it does demonstrate
+ the use of JBoss DNA to federate repositories and provide access through JCR.</para>
+ </sect1>
+ <sect1 id="connectors">
+ <title>JBoss DNA connectors</title>
+ <para>As mentioned in the <link linkend="introduction">Introduction</link>, one of the capabilities of JBoss DNA is to provide access through
+ <ulink url="http://www.jcp.org/en/jsr/detail?id=170">JCR</ulink> to different kinds of repositories and storage systems.
+ Your applications work with the JCR API, but through JBoss DNA you're able to accesses the content from where the information
+ exists - not just a single purpose-built repository. This is fundamentally what makes JBoss DNA different.</para>
+ <para>How does JBoss DNA do this? At the heart of JBoss DNA and it's JCR implementation is a simple connector
+ system that is designed around creating and accessing graphs. The JBoss DNA JCR implementation actually just sits on
+ top of a single repository source, which it uses to access of the repositories content.
+ <figure id="dnajcr-and-connector">
+ <title>JBoss DNA's JCR implementation delegates to a repository source</title>
+ <graphic align="center" scale="100" fileref="dnajcr-and-connector.png"/>
+ </figure>
+ That single repository source could be an in-memory repository, a JBoss Cache instance, or a federated repository.
+ <figure id="dna-connectors-0.2">
+ <title>JBoss DNA can put JCR on top of multiple kinds of systems</title>
+ <graphic align="center" scale="100" fileref="dna-connectors-0.2.png"/>
+ </figure>
+ And the JBoss DNA project has plans to create other connectors, too. For instance, we're going to build a connector
+ to other JCR repositories. And another to a file system, so that the files and directories on an area of the file system
+ can be accessed through JCR. Of course, if we don't have a connector to suit your needs, you can write your own.
+ <figure id="dna-connectors-future">
+ <title>Future JBoss DNA connectors</title>
+ <graphic align="center" scale="100" fileref="dna-connectors-future.png"/>
+ </figure>
+ </para>
+ <note>
+ <para>You might be thinking that these connectors are interesting, but what do they really provide? Is it really useful
+ to use JCR to access a relational database rather than JDBC? Or, why access the files on a file system when there
+ are already mechanisms to do that?</para>
+ <para>Maybe putting JCR on top of a single system (like a JDBC database) isn't that interesting. What
+ <emphasis>is</emphasis> interesting, though, is accessing the information in multiple systems <emphasis>as if all that information were
+ in a single JCR repository</emphasis>. That's what the federated repository source is all about. The JBoss DNA connector
+ system just makes it possible to interact with all these systems in the same way.</para>
+ <para>Think of it this way: with JBoss DNA, you can use JCR to get to the schemas of multiple relational databases <emphasis>and</emphasis> the schemas
+ defined by DDL files in your SVN repository <emphasis>and</emphasis> the schemas defined by logical models stored on your file system.
+ </para>
+ </note>
+ <para>Before we go further, let's define some terminology regarding connectors.</para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ A <emphasis role="strong">connector</emphasis> is the runnable code packaged in one or more JAR files that
+ contains implementations of several interfaces (described below). A Java developer <emphasis>writes</emphasis>
+ a connector to a type of source, such as a particular database management system, LDAP directory, source code
+ management system, etc. It is then packaged into one or more JAR files (including dependent JARs) and deployed
+ for use in applications that use JBoss DNA repositories.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The description of a particular source system (e.g., the "Customer" database, or the company LDAP system)
+ is called a <emphasis role="strong">repository source</emphasis>. JBoss DNA defines a &RepositorySource; interface
+ that defines methods describing the behavior and supported features and a method for establishing connections.
+ A connector will have a class that implements this interface and that has JavaBean properties for
+ all of the connector-specific properties required to fully describe an instance of the system. Use of JavaBean
+ properties is not required, but it is highly recommended, as it enables reflective configuration and administration.
+ Applications that use JBoss DNA create an instance of the connector's &RepositorySource; implementation and set
+ the properties for the external source that the application wants to access with that connector.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A repository source instance is then used to establish <emphasis role="strong">connections</emphasis> to
+ that source. A connector provides an implementation of the &RepositoryConnection; interface, which
+ defines methods for interacting with the external system. In particular, the <code>execute(...)</code> method
+ takes an &ExecutionContext; instance and a &Request; object. The &ExectuionContext; object defines the
+ environment in which the processing is occurring, including information about the JAAS &Subject; and &LoginContext;.
+ The &Request; object describes the requested operations on the content, with different concrete subclasses
+ representing each type of activity. Examples of commands include (but not limited to) getting a node, moving a node, creating a node,
+ changing a node, and deleting a node. And, if the repository source is able to participate in JTA/JTS distributed transactions, then the
+ &RepositoryConnection; must implement the <code>getXaResource()</code> method by returning
+ a valid <code>javax.transaction.xa.XAResource</code> object that can be used by the transaction monitor.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>As an example, consider that we want JBoss DNA to give us access through JCR to the schema information contained in a
+ relational databases. We first have to develop a connector that allows us to interact with relational databases using JDBC.
+ That connector would contain a <code>JdbcRepositorySource</code> Java class that implements &RepositorySource;,
+ and that has all of the various JavaBean properties for setting the name of the driver class, URL, username, password,
+ and other properties. (Or we might have a JavaBean property that defines the JNDI name where we can find a JDBC
+ <code>DataSource</code> instance pointing to our JDBC database.)
+ </para>
+ <para>So with this very high-level summary, let's dive a little deeper and look at the repository example.</para>
+ </sect1>
+ <sect1 id="example_repository_application_review">
+ <title>Reviewing the example repository application</title>
+ <para>Recall that the example repository application consists of a client application that sets up a repository service and the
+ repositories defined in a configuration repository, allowing the user to pick a repository and interactively navigate
+ the selected repository. Several repositories are set up, including several in-memory repositories and one federated repository
+ that dynamically federates the content from the other repositories.</para>
+ <para>
+ The example is comprised of 2 classes and 1 interface, located in the <code>src/main/java</code> directory:</para>
+ <programlisting><![CDATA[
+ org/jboss/example/dna/repositories/ConsoleInput.java
+ /RepositoryClient.java
+ /UserInterface.java
+ ]]></programlisting>
+ <para><code>RepositoryClient</code> is the class that contains the main application. It uses an instance of the
+ <code>UserInterface</code> interface to methods that will be called at runtime to obtain information about the
+ files that are imported into the in-memory repositories and the JAAS <code>CallbackHandler</code> implementation
+ that will be used by JAAS to prompt the user for authentication information. Finally, the <code>ConsoleInput</code>
+ is an implementation of this that creates a text user interface, allowing the user to operate the client from the command-line.
+ We can easily create a graphical implementation of <code>UserInterface</code> at a later date, or we can also create a mock
+ implementation for testing purposes that simulates a user entering data. This allows us to check the behavior of the client
+ automatically using conventional JUnit test cases, as demonstrated by the code in the <code>src/test/java</code> directory:</para>
+ <programlisting><![CDATA[
+ org/jboss/example/dna/sequencers/RepositoryClientTest.java
+ /RepositoryClientUsingJcrTest.java
+ ]]></programlisting>
+ <para>If we look at the <code>RepositoryClient</code> code, there are a handful of methods that encapsulate the various activities.</para>
+ <note>
+ <para>Some of the code samples included in this book have had some of the error handling and comments removed so that
+ the code is more readable and concise.</para>
+ </note>
+ <para>The <code>main(String[] argv)</code> method is of course the method that is executed when the application is run. This code
+ creates the JBoss DNA configuration by loading it from a file.
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+// Set up the JAAS provider (IDTrust) and a policy file (which defines the "dna-jcr" login config name)
+IDTrustConfiguration idtrustConfig = new IDTrustConfiguration();
+try {
+ idtrustConfig.config("security/jaas.conf.xml");
+} catch (Exception ex) {
+ throw new IllegalStateException(ex);
+}
+
+// Now configure the repository client component ...
+RepositoryClient client = new RepositoryClient();
+for (String arg : args) {
+ arg = arg.trim();
+ if (arg.equals("--api=jcr")) client.setApi(Api.JCR);
+ if (arg.equals("--api=dna")) client.setApi(Api.DNA);
+ if (arg.equals("--jaas")) client.setJaasContextName(JAAS_LOGIN_CONTEXT_NAME);
+ if (arg.startsWith("--jaas=") && arg.length() > 7) client.setJaasContextName(arg.substring(7).trim());
+}
+// And have it use a ConsoleInput user interface ...
+client.setUserInterface(new ConsoleInput(client, args));
+ ]]></programlisting>
+ <para>
+ The first block sets up the JAAS provider to be the IDTrust library and a policy file that defines the "dna-jcr" JAAS configuration.
+ </para>
+ <para>
+ The second block of code instantiates the <code>RepositoryClient</code> and passes in some options determined from the command-line.
+ It then sets the user interface (which then executes its behavior, which we'll see below).
+ </para>
+ <para>
+ The <code>startRepositories()</code> method builds the <code>JcrEngine</code> component from the configuration, starts the engine,
+ and obtains the JCR <code>javax.jcr.Repository</code> instance that the client will use. Note that the client has not yet
+ obtained a <code>javax.jcr.Session</code> instance, since this will be done each time the client needs to access content from
+ the repository. (This is actually a common practice according to the JCR specification, since Sessions are intended to be
+ very lightweight.)
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+public void startRepositories() throws IOException, SAXException {
+ if (engine != null) return; // already started
+
+ // Load the configuration from a file, as provided by the user interface ...
+ JcrConfiguration configuration = new JcrConfiguration();
+ configuration.loadFrom(userInterface.getRepositoryConfiguration());
+
+ // Load the node types for each JCR repository, via a CND file. These could have been defined
+ // in the configuration file, but this approach is easy and allows us to define the node types
+ // using the CND format in one or multiple files.
+ String locationOfCndFiles = userInterface.getLocationOfCndFiles();
+ configuration.repository("aircraft repository").addNodeTypes(locationOfCndFiles + "/aircraft.cnd");
+ configuration.repository("car repository").addNodeTypes(locationOfCndFiles + "/cars.cnd");
+ configuration.repository("virtual").addNodeTypes(locationOfCndFiles + "/virtual.cnd");
+
+ // Now create the JCR engine ...
+ engine = configuration.build();
+ engine.start();
+
+ // For this example, we're using a couple of in-memory repositories (including one for the configuration repository).
+ // Normally, these would exist already and would simply be accessed. But in this example, we're going to
+ // populate these repositories here by importing from files. First do the configuration repository ...
+ String location = this.userInterface.getLocationOfRepositoryFiles();
+
+ // Now import the content for the two in-memory repositories ...
+ Graph cars = engine.getGraph("Cars");
+ cars.importXmlFrom(location + "/cars.xml").into("/");
+ Graph aircraft = engine.getGraph("Aircraft");
+ aircraft.importXmlFrom(location + "/aircraft.xml").into("/");
+}
+ ]]></programlisting>
+ <para>
+ This method does a number of different things. First, it checks to make sure the repositories are not already running; if so
+ the method just returns. Then, it creates a JBoss DNA <code>JcrConfiguration</code> instance and loads the configuration
+ from a file provided by the user interface. The method then loads the node types for each of the repositories; this could
+ have been done in the configuration, but it would have made the configuration file larger and more difficult to understand.
+ It then creates the <code>JcrEngine</code> from the configuration and starts it. Finally, it obtains the location of the
+ content files from the user interface, and imports them into the "Cars" and "Aircraft" repositories. Again, this is
+ done to keep the example simple.
+ </para>
+ <para>
+ The <code>shutdown()</code> method of the example then logs out and requests the <code>JcrEngine</code> instance shuts down and, since that may take
+ a few moments (if there are any ongoing operations or enqueued activities) awaits for it to complete the shutdown.
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+public void shutdown() throws InterruptedException, LoginException {
+ logout();
+ if (engine == null) return;
+ try {
+ // Tell the engine to shut down, and then wait up to 5 seconds for it to complete...
+ engine.shutdown();
+ engine.awaitTermination(5, TimeUnit.SECONDS);
+ } finally {
+ engine = null;
+ }
+}
+ ]]></programlisting>
+ <para>
+ A few of the other methods in the <code>RepositoryClient</code> class deal with the JAAS <code>LoginContext</code>.
+ When needed, the client will authenticate the user (by asking the user interface for a callback handler that will be called
+ when the authentication information is needed). The resulting authenticated <code>LoginContext</code> is wrapped
+ by a custom <code>javax.jcr.Credentials</code> implementation. As long as the <code>Credentials</code> implementation
+ has a <code>getLoginContext()</code> method that returns a <code>LoginContext</code> object, JBoss DNA's repository
+ implementation will use that context to create the <code>javax.jcr.Session</code>. (Of course, the <code>javax.jcr.SimpleCredentials</code>
+ can also be used to create a Session, and JBoss DNA will then attempt to use JAAS to authenticate the user given by the credentials.)
+ </para>
+ <para>
+ The <code>getNodeInfo(...)</code> method of the example is what is called when the properties and children of a particular node
+ are requested by the user interface. (In the console user interface, this happens when the user navigates the graph structure.)
+ There are really two different behaviors to this method, depending upon whether the JCR API is to be used or whether
+ the JBoss DNA Graph API is to be used. The portion that uses JCR is shown below:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+JcrRepository jcrRepository = engine.getRepository(sourceName);
+Session session = null;
+if (loginContext != null) {
+ // Could also use SimpleCredentials(username,password) too
+ Credentials credentials = new JaasCredentials(loginContext);
+ session = jcrRepository.login(credentials);
+} else {
+ session = jcrRepository.login();
+}
+try {
+ // Make the path relative to the root by removing the leading slash(es) ...
+ pathToNode = pathToNode.replaceAll("^/+", "");
+ // Get the node by path ...
+ Node root = session.getRootNode();
+ Node node = root;
+ if (pathToNode.length() != 0) {
+ if (!pathToNode.endsWith("]")) pathToNode = pathToNode + "[1]";
+ node = pathToNode.equals("") ? root : root.getNode(pathToNode);
+ }
+
+ // Now populate the properties and children ...
+ if (properties != null) {
+ for (PropertyIterator iter = node.getProperties(); iter.hasNext();) {
+ javax.jcr.Property property = iter.nextProperty();
+ Object[] values = null;
+ // Must call either 'getValue()' or 'getValues()' depending upon # of values
+ if (property.getDefinition().isMultiple()) {
+ Value[] jcrValues = property.getValues();
+ values = new String[jcrValues.length];
+ for (int i = 0; i < jcrValues.length; i++) {
+ values[i] = jcrValues[i].getString();
+ }
+ } else {
+ values = new Object[] {property.getValue().getString()};
+ }
+ properties.put(property.getName(), values);
+ }
+ }
+ if (children != null) {
+ // Figure out which children need same-name sibling indexes ...
+ Set<String> sameNameSiblings = new HashSet<String>();
+ for (NodeIterator iter = node.getNodes(); iter.hasNext();) {
+ javax.jcr.Node child = iter.nextNode();
+ if (child.getIndex() > 1) sameNameSiblings.add(child.getName());
+ }
+ for (NodeIterator iter = node.getNodes(); iter.hasNext();) {
+ javax.jcr.Node child = iter.nextNode();
+ String name = child.getName();
+ if (sameNameSiblings.contains(name)) name = name + "[" + child.getIndex() + "]";
+ children.add(name);
+ }
+ }
+} catch (javax.jcr.ItemNotFoundException e) {
+ return false;
+} catch (javax.jcr.PathNotFoundException e) {
+ return false;
+} finally {
+ if (session != null) session.logout();
+}
+ ]]></programlisting>
+ <para>
+ This code is literally just using the standard JCR API. First, it obtains a <code>javax.jcr.Session</code> instance
+ (using the available <code>LoginContext</code>), finds the desired <code>javax.jcr.Node</code>, copies the
+ properties and names of the children into collections supplied by the caller via method parameters, and
+ finally logs out of the session.
+ </para>
+ <para>
+ The JBoss DNA Graph API is actually an internal API used within the different components of JBoss DNA
+ (including the connector and sequencer frameworks), and provides low-level access to the exact same content.
+ Though we do not recommend using this API in your client applications, if you need to write a connector
+ or sequencer, you may need to know how to use the Graph API.
+ Here is the portion of the <code>getNodeInfo(...)</code> method that does the exact same operation as the JCR code
+ shown above:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+// Use the DNA Graph API to read the properties and children of the node ...
+ExecutionContext context = loginContext != null ? this.context.create(loginContext) : this.context;
+Graph graph = engine.getGraph(context, sourceName);
+graph.useWorkspace("default");
+org.jboss.dna.graph.Node node = graph.getNodeAt(pathToNode);
+
+if (properties != null) {
+ // Now copy the properties into the map provided as a method parameter ...
+ for (Property property : node.getProperties()) {
+ String name = property.getName().getString(context.getNamespaceRegistry());
+ properties.put(name, property.getValuesAsArray());
+ }
+}
+if (children != null) {
+ // And copy the names of the children into the list provided as a method parameter ...
+ for (Location child : node.getChildren()) {
+ String name = child.getPath().getLastSegment().getString(context.getNamespaceRegistry());
+ children.add(name);
+ }
+}
+ ]]></programlisting>
+ <para>
+ Note that this code is significantly shorter than the equivalent code based upon the JCR API.
+ This is in part because the Graph API doesn't have the notion of a stateful session. But some of it also is simply
+ because the Graph API design requires less code to do the same kinds of operations.
+ </para>
+ <para>None of the other methods in the <code>RepositoryClient</code> really do anything with JBoss DNA or JCR
+ <emphasis>per se</emphasis>. Instead, they really facilitate interaction with the user interface.
+ </para>
+ <para>If we look at the <code>ConsoleInput</code> constructor, it starts the repository and a thread
+ for the user interface. At this point, the constructor returns, but the main application continues under the user interface thread.
+ When the user requests to quit, the user interface thread also shuts down the JCR repository.</para>
+ <programlisting role="JAVA"><![CDATA[
+public ConsoleInput( SequencerClient client ) {
+ try {
+ client.startRepositories();
+
+ System.out.println(getMenu());
+ Thread eventThread = new Thread(new Runnable() {
+ private boolean quit = false;
+ public void run() {
+ try {
+ while (!quit) {
+ // Display the prompt and process the requested operation ...
+ }
+ } finally {
+ try {
+ // Terminate ...
+ client.shutdown();
+ } catch (Exception err) {
+ System.out.println("Error shutting down repository: "
+ + err.getLocalizedMessage());
+ err.printStackTrace(System.err);
+ }
+ }
+ }
+ });
+ eventThread.start();
+ } catch (Exception err) {
+ System.out.println("Error: " + err.getLocalizedMessage());
+ err.printStackTrace(System.err);
+ }
+}
+ ]]></programlisting>
+ <para>At this point, we've reviewed all of the interesting code in the example application related to JBoss DNA. However, feel free
+ to play with the application, trying different things.
+ </para>
+ </sect1>
+ <sect1 id="repository_example_whats_next">
+ <title>What's next</title>
+ <para>
+ This chapter walked through running the repository example and looked at the example code. This example allowed you to walk
+ through multiple repositories, including one whose content was federated from multiple other repositories.
+ This was a very simplistic example that only took a few minutes to run.
+ </para>
+ <para>
+ In the <link linkend="conclusion">next chapter</link> we'll wrap up by summarizing what we've learned about JBoss DNA
+ and provide information about where you can find out more about JBoss DNA.
+ </para>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/gettingstarted/src/main/docbook/en-US/content/repository_example.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/docs/gettingstarted/src/main/docbook/en-US/content/sequencer_example.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/sequencer_example.xml (rev 0)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/sequencer_example.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -0,0 +1,315 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="sequencer_example">
+ <title>The Sequencer Example</title>
+ <para>
+ The previous chapter walked through the process of downloading and building the examples.
+ This chapter will focus on the sequencer example, showing how to run the example and then walking through the code
+ to describe what it's doing.
+ </para>
+ <sect1 id="running_sequencer_example">
+ <title>Running the sequencing example</title>
+ <para>The sequencing example consists of a client application that sets up an in-memory JCR repository and that allows a user to
+ upload files into that repository. The client also sets up the DNA services with two sequencers so that if any of the
+ uploaded files are PNG, JPEG, GIF, BMP or other images, DNA will automatically extract the image's metadata (e.g., image
+ format, physical size, pixel density, etc.) and store that in the repository. Alternatively, if the uploaded file
+ is an MP3 audio file, DNA will extract some of the ID3 metadata (e.g., the author, title, album, year and comment)
+ and store that in the repository.</para>
+ <para>
+ To run the client application, go to the <code>examples/sequencers/target/dna-example-sequencers-basic.dir/</code>
+ directory and type <code>./run.sh</code>. You should see the command-line client and its menus in your terminal:
+ <figure id="xample-sequencer-cli-client">
+ <title>Example client</title>
+ <graphic align="center" scale="100" fileref="example-sequencer-client.png"/>
+ </figure>
+ From this menu, you can upload a file into the repository, search for media in the repository, print sequencing statistics,
+ or quit the application.</para>
+ <para>
+ The first step is to upload one of the example images. If you type 'u' and press return, you'll be prompted to supply the
+ path to the file you want to upload. Since the application is running from within the
+ <code>examples/sequencers/target/dna-example-sequencers-basic.dir/</code> directory, you can specify any of the files
+ in that directory without specifying the path:
+ <figure id="example-sequencer-upload">
+ <title>Uploading an image using the example client</title>
+ <graphic align="center" scale="100" fileref="example-sequencer-upload.png"/>
+ </figure>
+ You can specify any fully-qualified or relative path. The application will notify you if it cannot find the file you
+ specified. The example client configures JBoss DNA to sequence MP3 audio files, Java source files, or image files with one of
+ the following extensions (technically, nodes that have names ending in the following):
+ <code>jpg</code>, <code>jpeg</code>, <code>gif</code>, <code>bmp</code>, <code>pcx</code>, <code>png</code>,
+ <code>iff</code>, <code>ras</code>, <code>pbm</code>, <code>pgm</code>, <code>ppm</code>, and <code>psd</code>.
+ Files with other extensions in the repository path will be ignored. For your convenience, the example provides several
+ files that will be sequenced (<code>caution.png</code>, <code>caution.jpg</code>, <code>caution.gif</code>, and
+ <code>sample1.mp3</code>) and one image that will not be sequenced (<code>caution.pict</code>). Feel free to try other files.
+ </para>
+ <para>
+ After you have specified the file you want to upload, the example application asks you where in the repository you'd like to
+ place the file. (If you want to use the suggested location, just press <code>return</code>.) The client application
+ uses the JCR API to upload the file to that location in the repository, creating any nodes (of type <code>nt:folder</code>)
+ for any directories that don't exist, and creating a node (of type <code>nt:file</code>) for the file. And, per the JCR specification,
+ the application creates a <code>jcr:content</code> node (of type <code>nt:resource</code>) under the file node.
+ The file contents are placed on this <code>jcr:content</code> node in the <code>jcr:data</code> property. For example, if you specify
+ <code>/a/b/caution.png</code>, the following structure will be created in the repository:</para>
+ <programlisting><![CDATA[
+/a (nt:folder)
+ /b (nt:folder)
+ /caution.png (nt:file)
+ /jcr:content (nt:resource)
+ @jcr:data = {contents of the file}
+ @jcr:mimeType = {mime type of the file}
+ @jcr:lastModified = {now}
+]]></programlisting>
+ <para>Other kinds of files are treated in a similar way.</para>
+ <para>When the client uploads the file using the JCR API, DNA gets notified of the changes, consults the sequencers to see whether
+ any of them are interested in the new or updated content, and if so runs those sequencers. The image sequencer processes image
+ files for metadata, and any metadata found is stored under the <code>/images</code> branch of the repository. The MP3 sequencer
+ processes MP3 audio files for metadata, and any metadata found is stored under the <code>/mp3s</code>
+ branch of the repository. And metadata about Java classes are stored under the <code>/java</code> area of the repository.
+ All of this happens asynchronously, so any DNA activity doesn't impede or slow down the client activities.
+ </para>
+ <para>So, after the file is uploaded, you can search the repository for the image metadata using the "s" menu option:
+ <figure id="example-sequencer-search">
+ <title>Searching for media using the example client</title>
+ <graphic align="center" scale="100" fileref="example-sequencer-search.png"/>
+ </figure>
+ Here are the search results after the <code>sample1.mp3</code> audio file has been uploaded (to the <code>/a/b/sample1.mp3</code> location):
+ <figure id="example-sequencer-search-with-mp3">
+ <title>Searching for media using the example client</title>
+ <graphic align="center" scale="100" fileref="example-sequencer-search-with-mp3.png"/>
+ </figure>
+ You can also display the sequencing statistics using the "d" menu option:
+ <figure id="example-sequencer-statistics">
+ <title>Sequencing statistics using the example client</title>
+ <graphic align="center" scale="100" fileref="example-sequencer-statistics.png"/>
+ </figure>
+ These stats show how many nodes were sequenced, and how many nodes were skipped because they didn't apply to the sequencer's
+ criteria.
+ </para>
+ <note>
+ <para>There will probably be more nodes skipped than sequenced, since there are more <code>nt:folder</code> and <code>nt:resource</code>
+ nodes than there are <code>nt:file</code> nodes with acceptable names.</para>
+ </note>
+ <para>You can repeat this process with other files. Any file that isn't an image or MP3 files (as recognized by the sequencing configurations
+ that we'll describe later) will not be sequenced.</para>
+ </sect1>
+ <sect1 id="example_application_review">
+ <title>Reviewing the example application</title>
+ <para>Recall that the example application consists of a client application that sets up an in-memory JCR repository and
+ that allows a user to upload files into that repository. The client also sets up the DNA services with an image sequencer so
+ that if any of the uploaded files are PNG, JPEG, GIF, BMP or other images, DNA will automatically extract the image's
+ metadata (e.g., image format, physical size, pixel density, etc.) and store that in the repository. Or, if the client uploads
+ MP3 audio files, the title, author, album, year, and comment are extracted from the audio file and stored in the repository.</para>
+ <para>
+ The example is comprised of 5 classes and 1 interface, located in the <code>src/main/java</code> directory:</para>
+ <programlisting><![CDATA[
+ org/jboss/example/dna/sequencers/ConsoleInput.java
+ /ContentInfo.java
+ /JavaInfo.java
+ /MediaInfo.java
+ /SequencingClient.java
+ /UserInterface.java
+ ]]></programlisting>
+ <para><code>SequencingClient</code> is the class that contains the main application. <code>ContentInfo</code> is a simple class
+ that encapsulate metadata generated by the sequencers and accessed by this example application, and there are two subclasses:
+ <code>MediaInfo</code> encapsulates metadata about media (image and MP3) files, while <code>JavaInfo</code> is a subclass
+ encapsulating information about a Java class. The client accesses the content from the repository and represent the
+ information using instances of <code>ContentInfo</code> (and its subclasses) and then passing them to the <code>UserInterface</code>.
+ <code>UserInterface</code> is an interface with methods that will be called at runtime to
+ request data from the user. <code>ConsoleInput</code> is an implementation of this that creates a text user interface,
+ allowing the user to operate the client from the command-line. We can easily create a graphical implementation of
+ <code>UserInterface</code> at a later date. We can also create a mock implementation for testing purposes that simulates
+ a user entering data. This allows us to check the behavior of the client automatically using conventional JUnit test cases,
+ as demonstrated by the code in the <code>src/test/java</code> directory:</para>
+ <programlisting><![CDATA[
+ org/jboss/example/dna/sequencers/SequencingClientTest.java
+ /MockUserInterface.java
+ ]]></programlisting>
+ <para>If we look at the <code>SequencingClient</code> code, there are a handful of methods that encapsulate the various activities.</para>
+ <note>
+ <para>Some of the code samples included in this book have had some of the error handling and comments removed so that
+ the code is more readable and concise.</para>
+ </note>
+ <para>The <code>main(String[] argv)</code> method is of course the method that is executed when the application is run. This code
+ creates the JBoss DNA configuration using the programmatic style.
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+// Set up the JAAS provider (IDTrust) and a policy file (which defines the "dna-jcr" login config name)
+IDTrustConfiguration idtrustConfig = new IDTrustConfiguration();
+try {
+ idtrustConfig.config("security/jaas.conf.xml");
+} catch (Exception ex) {
+ throw new IllegalStateException(ex);
+}
+
+// Create the configuration.
+String repositoryId = "content";
+String workspaceName = "default";
+JcrConfiguration config = new JcrConfiguration();
+// Set up the in-memory source where we'll upload the content and where the sequenced output will be stored ...
+config.repositorySource("store")
+ .usingClass(InMemoryRepositorySource.class)
+ .setDescription("The repository for our content")
+ .setProperty("defaultWorkspaceName", workspaceName);
+// Set up the JCR repository to use the source ...
+config.repository(repositoryId)
+ .addNodeTypes("sequencing.cnd")
+ .setSource("store")
+ .setOption(JcrRepository.Option.JAAS_LOGIN_CONFIG_NAME, "dna-jcr");
+// Set up the image sequencer ...
+config.sequencer("Image Sequencer")
+ .usingClass("org.jboss.dna.sequencer.image.ImageMetadataSequencer")
+ .loadedFromClasspath()
+ .setDescription("Sequences image files to extract the characteristics of the image")
+ .sequencingFrom("//(*.(jpg|jpeg|gif|bmp|pcx|png|iff|ras|pbm|pgm|ppm|psd)[*])/jcr:content[@jcr:data]")
+ .andOutputtingTo("/images/$1");
+// Set up the MP3 sequencer ...
+config.sequencer("MP3 Sequencer")
+ .usingClass("org.jboss.dna.sequencer.mp3.Mp3MetadataSequencer")
+ .loadedFromClasspath()
+ .setDescription("Sequences mp3 files to extract the id3 tags of the audio file")
+ .sequencingFrom("//(*.mp3[*])/jcr:content[@jcr:data]")
+ .andOutputtingTo("/mp3s/$1");
+// Set up the Java source file sequencer ...
+config.sequencer("Java Sequencer")
+ .usingClass("org.jboss.dna.sequencer.java.JavaMetadataSequencer")
+ .loadedFromClasspath()
+ .setDescription("Sequences Java files to extract the AST structure of the Java source code")
+ .sequencingFrom("//(*.java[*])/jcr:content[@jcr:data]")
+ .andOutputtingTo("/java/$1");
+
+// Now start the client and tell it which repository and workspace to use ...
+SequencingClient client = new SequencingClient(config, repositoryId, workspaceName);
+client.setUserInterface(new ConsoleInput(client));
+ ]]></programlisting>
+ <para>
+ The first block sets up the JAAS provider to be the IDTrust library and a policy file that defines the "dna-jcr" JAAS configuration.
+ </para>
+ <para>
+ The second block of code configures the <code>JcrConfiguration</code> and sets up the "store" source, the "content" repository,
+ and three sequencers. Again, this is done via the programmatic style. An alternative would be to load the entire configuration
+ from a configuration file or from an existing configuration repository. (The repository example shown in the
+ <link linkend="repository_example">next chapter</link> shows how to load the configuration from a file.)
+ </para>
+ <para>
+ The third block simply instantiates the <code>SequencingClient</code> class, passing the configuration and the name of the repository
+ and workspace, and finally sets the user interface (which then executes its behavior, which we'll see below).
+ </para>
+ <para>
+ The <code>startRepository()</code> method builds the <code>JcrEngine</code> component from the configuration, starts the engine,
+ and obtains the JCR <code>javax.jcr.Repository</code> instance that the client will use. Note that the client has not yet
+ obtained a <code>javax.jcr.Session</code> instance, since this will be done each time the client needs to access content from
+ the repository. (This is actually a common practice according to the JCR specification, since Sessions are intended to be
+ very lightweight.)
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+public void startRepository() throws Exception {
+ if (this.repository == null) {
+ try {
+ // Start the DNA engine ...
+ this.engine = this.configuration.build();
+ this.engine.start();
+
+ // Now get the JCR repository instance ...
+ this.repository = this.engine.getRepository(repositoryName);
+ } catch (Exception e) {
+ this.repository = null;
+ throw e;
+ }
+ }
+}
+ ]]></programlisting>
+ <para>The <code>shutdownRepository()</code> method requests the <code>JcrEngine</code> instance shuts down and, since that may take
+ a few moments (if there are any ongoing operations or enqueued activities) awaits for it to complete the shutdown.
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+public void shutdownRepository() throws Exception {
+ if (this.repository != null) {
+ try {
+ this.engine.shutdown();
+ this.engine.awaitTermination(4, TimeUnit.SECONDS);
+ } finally {
+ this.repository = null;
+ }
+ }
+}
+ ]]></programlisting>
+ <para>None of the other methods really do anything with JBoss DNA <emphasis>per se</emphasis>. Instead, they merely work with the repository
+ using the JCR API.</para>
+ <para>If we look at the <code>ConsoleInput</code> constructor, it starts the repository and a thread
+ for the user interface. At this point, the constructor returns, but the main application continues under the user interface thread.
+ When the user requests to quit, the user interface thread also shuts down the JCR repository.</para>
+ <programlisting role="JAVA"><![CDATA[
+public ConsoleInput( SequencerClient client ) {
+ try {
+ client.startRepository();
+
+ System.out.println(getMenu());
+ Thread eventThread = new Thread(new Runnable() {
+ private boolean quit = false;
+ public void run() {
+ try {
+ while (!quit) {
+ // Display the prompt and process the requested operation ...
+ }
+ } finally {
+ try {
+ // Terminate ...
+ client.shutdownRepository();
+ } catch (Exception err) {
+ System.out.println("Error shutting down sequencing service and repository: "
+ + err.getLocalizedMessage());
+ err.printStackTrace(System.err);
+ }
+ }
+ }
+ });
+ eventThread.start();
+ } catch (Exception err) {
+ System.out.println("Error: " + err.getLocalizedMessage());
+ err.printStackTrace(System.err);
+ }
+}
+ ]]></programlisting>
+ <para>At this point, we've reviewed all of the interesting code in the example application related to JBoss DNA. However, feel free
+ to play with the application, trying different things.</para>
+ </sect1>
+ <sect1 id="using_dna_whats_next">
+ <title>What's next</title>
+ <para>
+ This chapter walked through running the sequencer example and looked at the example code. With the sequencer client, you could upload files into a
+ JCR repository, while JBoss DNA automatically sequenced the image, MP3, or Java source files you uploaded, extracted the metadata from the
+ files, and stored that metadata inside the repository.
+ </para>
+ <para>
+ In the <link linkend="repository_example">next chapter </link> we'll do the same for the repository example.
+ </para>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/gettingstarted/src/main/docbook/en-US/content/sequencer_example.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: trunk/docs/gettingstarted/src/main/docbook/en-US/content/understanding_dna.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/understanding_dna.xml 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/understanding_dna.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -1,576 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="understanding_dna">
- <title>Understanding JBoss DNA</title>
- <sect1 id="jboss_dna_overview">
- <title>Overview</title>
- <para>JBoss DNA is a repository and set of tools that make it easy to capture, version, analyze, and understand the
- fundamental building blocks of information. As models, service and process definitions, schemas, source code, and other
- artifacts are added to the repository, JBoss DNA "sequences" the makeup of these components and extracts their structure
- and interdependencies. The JBoss DNA web application will allow end users to access, visualize, and edit this information in
- the terminology and structure they are familiar with. Such domain-specific solutions can be easily created with little or
- no programming.</para>
- <para> JBoss DNA supports the Java Content Repository (JCR) standard and is able to provide a single integrated view of
- multiple repositories, external databases, services, and applications, ensuring that JBoss DNA has access to the latest
- and most reliable master data. For instance, DNA could provide in a single view valuable insight into the business
- processes and process-level services impacted by a change to in an intermediary web server operation defined via WSDL.
- Similarly, a user could quickly view and navigate the dependencies between the data source models and transformation
- information stored within a content repository, the code base stored within a version control system, and the database
- schemas used by an application.</para>
- </sect1>
- <sect1 id="architecture">
- <title>Architecture</title>
- <para>The planned architecture for JBoss DNA consists of several major components that will be built on top of standard APIs,
- including JCR, JDBC, JNDI and HTTP. The goal is to allow these components to be assembled as needed and add value on top
- of other DNA components or third-party systems that support these standard APIs. Not all of these components exist
- yet - at the moment we're focusing on completing our JCR-compliant implementation using our connector framework.</para>
- <mediaobject>
- <imageobject role="fo">
- <imagedata align="center" fileref="dna-architecture.png" />
- </imageobject>
- <imageobject role="html">
- <imagedata align="center" fileref="dna-architecture.png" />
- </imageobject>
- </mediaobject>
- <para>
- Let's go over each of these components, starting from the bottom of the diagram:
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">DNA Connectors</emphasis>
- are used to communicate with these external sources of information, whether there's one source (like a database) in
- which all of the content is stored, or information is being federated from multiple sources. The connector's
- job is to interact with the external source and map the source's information into the lower-level graph language used by
- JBoss DNA. Connectors also may optionally participate in distributed transactions by exposing an XAResource.
- In summary, then, the connector API isolates all of the other components from how the graph are persisted.
- We've built a number of connectors already, but we're always interested in adding more. Or, you could write your own,
- since we've designed the connector API to be as straightforward as possible.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Federation</emphasis>
- is actually a special repository connector that accesses information from multiple other sources via connectors,
- making all this information look like it is part of a single, unified repository. Because it is a connector,
- it can be used wherever connectors can be used. And because it uses connectors, the federation connector
- makes it possible to integrate a wide variety of external systems, like other JCR
- repositories, databases, applications, and services.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA JCR</emphasis>
- is an implementation of the JCR API that accesses the content from a single connector. Our implementation has come a long
- way, and is nearly Level 1 and Level 2 compliant. Finishing the remaining features, including search
- and query, are major objectives of our next release.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Sequencers</emphasis>
- are pluggable components that automatically process content (typically files) that are uploaded into the repository,
- looking for useful structure and information in that content. When a file is uploaded to the repository, JBoss DNA automatically
- figures out which sequencer(s) should be run, and then runs them. Each sequencer, then, extracts the meaningful information
- from the file's content and places that structure in the repository. Once this information is in
- the repository, it can be viewed, edited, analyzed, searched, and related to other content. DNA defines a Java
- interface that sequencers must implement. DNA sequencers operate upon any JCR-compliant repository.
- We have a number of sequencers, but plan on adding more over time. Like connectors, the Sequencer API makes it very
- simple to write sequencers for your own file types.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Analyses</emphasis>
- are similar to sequencers, except they process the graph structure rather than uploaded files. You can think of them
- as report generators, where they process some area of the repository and generate output. The output doesn't take the
- form of a document or file, but rather more graph content that is then stored in the repository, where it can be accessed
- and searched just like any other content. We're still figuring out how to best make analyzers easy to write and use,
- and have been focused on other aspects of the architecture. But we're planning on using analyzers for dependency,
- similarity, and statistical analyses.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Maven</emphasis>
- is a classloader library compatible with Maven 2 project dependencies. This allows the creation of Java ClassLoader
- instances using Maven 2 style paths, and all dependencies are transitively managed and included. This exists but is
- still immature.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- The remaining parts of the architecture haven't yet been started, but they service important purposes for a complete metadata
- repository system.
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">DNA Eclipse Plugins</emphasis>
- enable Eclipse users to access the contents of a JBoss DNA repository. This is a planned component that may be started soon.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA JDBC Driver</emphasis>
- provides a driver implementation, allowing JDBC-aware applications to connect to and use a JBoss DNA repository.
- This is a planned component on our roadmap.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Remote JCR</emphasis>
- is a client-side component for accessing remote JCR repositories.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Web Application</emphasis>
- is used by end users and domain experts to visualize, search, edit, change and tag the repository content. The web
- application uses views to define how different types of information are to be presented and edited in
- domain-specific ways. The goal is that this web application is easily customized and branded for inclusion into
- other solutions and application systems. The DNA Web Application operates upon any JCR-compliant repository,
- although it does rely upon the DNA analysis and templating services.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Publishing Server</emphasis>
- allows content to be downloaded, uploaded, and edited using the Atom Publishing Protocol. With the DNA Publishing
- Server, the content of the repository can easily be created, read, edited, and deleted using the standard HTTP
- operations of POST, GET, PUT, and DELETE (respectively). More and more tools are being created that support working
- with Atom Publishing servers. The DNA Publishing Server operates upon any JCR-compliant repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA WebDAV Server</emphasis>
- allows clients such as Microsoft Windows and Apple OS X to connect to, read, and edit the content in the repository
- using the WebDAV standard. WebDAV is an extension of HTTP, so web browsers are able to access the content
- served by a WebDAV compliant server. The DNA WebDAV Server operates upon any JCR-compliant repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Views</emphasis>
- are definitions of how types of information are to be presented in a user interface to allow for creation, reading,
- editing, and deletion of information. DNA view definitions consist of data stored in a JCR repository, and as such
- views can be easily added, changed or removed entirely by using the DNA Web Application, requiring no programming.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- Continue reading the rest of this chapter for more detail about the
- <link linkend="sequencers">sequencing framework</link> available in this release, or the <link linkend="federation">federation engine</link>
- and <link linkend="federation_connectors">connectors</link>. Or, skip to the <link linkend="downloading_and_running">examples</link>
- to see how to start using JBoss DNA &versionNumber; today.
- </para>
- </sect1>
- <sect1 id="sequencers">
- <title>Sequencing content</title>
- <para> The current JBoss DNA release contains a sequencing framework that is designed to sequence data (typically files)
- stored in a JCR repository to automatically extract meaningful and useful information. This additional information is then
- saved back into the repository, where it can be accessed and used.</para>
- <para> In other words, you can just upload various kinds of files into a JCR repository, and DNA automatically processes
- those files to extract meaningful structured information. For example, load DDL files into the repository, and let
- sequencers extract the structure and metadata for the database schema. Load Hibernate configuration files into the
- repository, and let sequencers extract the schema and mapping information. Load Java source into the repository, and let
- sequencers extract the class structure, JavaDoc, and annotations. Load a PNG, JPEG, or other image into the repository,
- and let sequencers extract the metadata from the image and save it in the repository. The same with XSDs, WSDL, WS
- policies, UML, MetaMatrix models, etc.</para>
- <para>
- JBoss DNA sequencers sit on top of existing JCR repositories (including federated repositories) - they basically extract
- more useful information from what's already stored in the repository. And they use the existing JCR event and versioning system. Each
- sequencer typically processes a single kind of file format or a single kind of content. </para>
- <para>The following sequencers are included in JBoss DNA:
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">Image sequencer</emphasis>
- - A sequencer that processes the binary content of an image file, extracts the metadata for the image, and then
- writes that image metadata to the repository. It gets the file format, image resolution, number of bits per pixel
- (and optionally number of images), comments and physical resolution from JPEG, GIF, BMP, PCX, PNG, IFF, RAS, PBM,
- PGM, PPM, and PSD files. (This sequencer may be improved in the future to also extract EXIF metadata from JPEG
- files; see <ulink url="http://jira.jboss.org/jira/browse/DNA-26">DNA-26</ulink>.)
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">MP3 sequencer</emphasis>
- - A sequencer that processes the contents of an MP3 audio file, extracts the metadata for the file, and then
- writes that image metadata to the repository. It gets the title, author, album, year, and comment.
- (This sequencer may be improved in the future to also extract other ID3 metadata from other audio file formats; see
- <ulink url="http://jira.jboss.org/jira/browse/DNA-66">DNA-66</ulink>.)
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">ZIP Archive Sequencer</emphasis>
- - Process ZIP archive files to extract (explode) the contents into the repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Java Source File Sequencer</emphasis>
- - Process Java source files to extract the class structure (including annotations) into the repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">XML File Sequencer</emphasis>
- - Process XML files to extract the structure into the repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Microsoft Office File Sequencer</emphasis>
- - Process Microsoft Office documents, spreadsheets, and presentation files to extract their basic structure.
- For example, the sequencer extracts the outline of a document, or the title and outline of a presentation.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">JCR Compact Node Definition (CND) File Sequencer</emphasis>
- - Process the CND files defined by JCR, extracting the various node types with their property definitions and child
- node definitions.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- As the community develops additional sequencers, they will also be included in JBoss DNA. Some of those that have been
- identified as being useful include:
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">Data Definition Language (DDL) Sequencer</emphasis>
- - Process various dialects of DDL, including that from Oracle, SQL Server, MySQL, PostgreSQL, and others. May need
- to be split up into a different sequencer for each dialect. This sequencer is being developed as part of a
- Google Summer of Code 2009 project. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-26">DNA-26</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">XML Schema Document (XSD) Sequencer</emphasis>
- - Process XSD files and extract the various elements, attributes, complex types, simple types, groups, and other
- information. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-32">DNA-32</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Web Service Definition Language (WSDL) Sequencer</emphasis>
- - Process WSDL files and extract the services, bindings, ports, operations, parameters, and other information. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-33">DNA-33</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Hibernate File Sequencer</emphasis>
- - Process Hibernate configuration (cfg.xml) and mapping (hbm.xml) files to extract the configuration and mapping
- information. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-61">DNA-61</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">XML Metadata Interchange (XMI) Sequencer</emphasis>
- - Process XMI documents that contain UML models or models using another metamodel, extracting the model structure
- into the repository. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-31">DNA-31</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Java Archive (JAR) Sequencer</emphasis>
- - Process JAR files to extract (explode) the contents into the classes and file resources. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-64">DNA-64</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Java Class File Sequencer</emphasis>
- - Process Java class files (bytecode) to extract the class structure (including annotations) into the repository.
- (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-62">DNA-62</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">PDF Sequencer</emphasis>
- - Process PDF files to extract the document metadata, including table of contents. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-50">DNA-50</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Maven 2 POM Sequencer</emphasis>
- - Process Maven 2 Project Object Model (POM) files to extract the project information, dependencies, plugins, and
- other content. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-24">DNA-24</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">MP3 and MP4 Sequencer</emphasis>
- - Process MP3 and MP4 audio files to extract the name of the song, artist, album, track number, and other metadata.
- (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-30">DNA-30</ulink>
- )
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- The
- <link linkend="using_dna">examples</link>
- in this book go into more detail about how sequencers are managed and used, and
- <link linkend="custom_sequencers">Chapter 5</link>
- goes into detail about how to write custom sequencers.
- </para>
- </sect1>
- <sect1 id="federation">
- <title>JCR and federated repositories</title>
- <para>There is a lot of information stored in many of different places: databases, repositories, SCM systems,
- registries, file systems, services, etc. The purpose of the federation engine is to allow applications to use the JCR API
- to access that information as if it were all stored in a single JCR repository, but to really leave the information where
- it is.</para>
- <para>Why not just copy or move the information into a JCR repository? Moving it is probably pretty difficult, since most
- likely existing applications rely upon that information being where it is. All of those applications
- would break or have to change. And copying the information means that we'd have to continually synchronize the changes.
- This not only is a lot of work, but it often creates issues with knowing which information is accurate.
- </para>
- <para>The JBoss DNA allows lets us leave the information where it is, yet provide access to that information to new applications through
- the JCR API. As the existing applications update the information in the original systems, applications using JBoss DNA also see
- these updates. JCR clients even get the benefit of using JCR observation to be notified of the changes. And if a JBoss DNA repository is
- configured to allow updates, client applications can change the information in the repository and JBoss DNA will propagate
- those changes down to the original source.</para>
- <sect2 id="repository-connectors">
- <title>Connecting to information sources</title>
- <para>
- JBoss DNA uses connectors to interact with different information sources to get at the content
- in those systems. We already have some connectors, including:</para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">In-Memory Connector</emphasis>
- - Uses a Map instance as a repository. This is a simple connector that works really well for small and transient graphs.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">JBoss Cache Connector</emphasis>
- - Uses a JBoss Cache instance as a repository. JBoss Cache is a powerful cache capable of persisting the information
- and being clustered for concurrent use by multiple processes.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Federation Connector</emphasis>
- - Creates a single repository by accessing and federating the information in multiple other repository sources.
- This is a powerful connector that is discussed in more detail in the <link linkend="federated_repositories">next section</link>.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">File System Connector</emphasis>
- - Expose the files and directories on a file system through JCR.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">JPA-based Storage Connector</emphasis>
- - Store and access information in a relational database through JPA. Also useful for persisting information in the federated
- repository not stored elsewhere.
- </para>
- </listitem>
- </itemizedlist>
- <para>We're working on a few other connectors:</para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">JDBC Metadata Connector</emphasis>
- - Connect to relational databases via JDBC and expose their schema as content in a repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">SVN Connector</emphasis>
- - Interact with Subversion software configuration management (SCM) repositories to expose the managed resources
- through JCR. Consider using the
- <ulink url="http://svnkit.com/">SVNkit</ulink>
- (dual license) library for an API into Subversion.
- </para>
- </listitem>
- </itemizedlist>
- <para>And even more connectors that are planned:</para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">JCR Repository Connector</emphasis>
- - Connect to and interact with other JCR repositories.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Maven 2 Repository Connector</emphasis>
- - Access and expose the contents of a Maven 2 repository (either on the local file system or via HTTP) through
- JCR.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">UDDI Connector</emphasis>
- - Interact with UDDI registries to integrate their content into a repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">CVS Connector</emphasis>
- - Interact with CVS software configuration management (SCM) repositories to expose the managed resources through
- JCR.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Distributed Database Connector</emphasis>
- - Store and access information in a
- <ulink url="http://www.hypertable.org/">Hypertable</ulink>
- or
- <ulink url="http://hadoop.apache.org/hbase/">HBase</ulink>
- distributed databases. Also useful for persisting information in the federated repository not stored elsewhere.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- If the connectors allow the information they contribute to be updated, they must provide an
- <code>XAResource</code>
- implementation that can be used with a Java Transaction Service. Connectors that provide read-only access need not
- provide an implementation.
- </para>
- <para>
- Also, connectors talk to
- <emphasis>sources</emphasis>
- of information, and it's quite likely that the same connector is used to talk to different sources. Each source contains
- the configuration details (e.g., connection information, location, properties, options, etc.) for working with that
- particular source, as well as a reference to the connector that should be used to establish connections to the source.
- And of course, sources can be added or removed without having to stop and restart the federated repository.
- </para>
- </sect2>
- <sect2 id="federated_repositories">
- <title>Federated repositories</title>
- <para> The federation connector works by effectively building up a single graph by querying each source and merging or
- unifying the responses. This information is cached, which improves performance, reduces the number of (potentially
- expensive) remote calls, reduces the load on the sources, and helps mitigate problems with source availability. As
- clients interact with the repository, this cache is consulted first. When the requested portion of the graph (or
- "subgraph") is contained completely in the cache, it is retuned immediately. However, if any part of the requested
- subgraph is not in the cache, each source is consulted for their contributions to that subgraph, and any results are
- cached.</para>
- <para> This basic flow makes it possible for the federated repository to build up a local cache of the integrated graph
- (or at least the portions that are used by clients). In fact, the federated repository caches information in a manner
- that is similar to that of the Domain Name System (DNS). As sources are consulted for their contributions, the source
- also specifies whether it is the authoritative source for this information (some sources that are themselves federated
- may not be the information's authority), whether the information may be modified, the time-to-live (TTL) value (the time
- after which the cached information should be refreshed), and the expiration time (the time after which the cached
- information is no longer valid). In effect, the source has complete control over how the information it contributes is
- cached and used.</para>
- <para>
- The federated repository also needs to incorporate
- <emphasis>negative caching</emphasis>
- , which is storage of the knowledge that something does not exist. Sources can be configured to contribute information
- only below certain paths (e.g.,
- <code>/A/B/C</code>
- ), and the federation engine can take advantage of this by never consulting that source for contributions to information
- on other paths. However, below that path, any negative responses must also be cached (with appropriate TTL and expiry
- parameters) to prevent the exclusion of that source (in case the source has information to contribute at a later time)
- or the frequent checking with the source.
- </para>
- </sect2>
- <sect2 id="federation_queries">
- <title>Searching and querying</title>
- <para> The JBoss DNA federated repository will support queries against the integrated and unified graph. In some
- situations the query can be determined to apply to a single source, but in most situations the query must be planned
- (and possibly rewritten) such that it can be pushed down to all the appropriate sources. Also, the cached results must
- be consulted prior to returning the query results, as the results from one source might have contributions from another
- source.</para>
- <para>Searching the whole federated repository is also important. This allows users to simply supply a handful of
- search terms, and to get results that are ranked based upon how close each result is to the search terms. (Searching is
- very different from querying, which involves specifying the exact semantics of what is to be searched and how the
- information is to be compared.) JBoss DNA will incorporate a search engine (e.g., likely to be Lucene) and will populate
- the engine's indexes using the federated content and the cached information. Notifications of changing information will
- be reflected in the indexes, but some sources may want to explicitly allow or disallow periodic crawling of their
- content.</para>
- </sect2>
- <sect2 id="federation_updates">
- <title>Updating content</title>
- <para>
- The JBoss DNA federated repositories also make it possible for client applications to make changes to the unified graph
- within the context of distributed transactions. According to the JCR API, client applications use the Java Transaction
- API (JTA) to control the boundaries of their transactions. Meanwhile, the federated repository uses a
- <ulink url="http://www.jboss.org/jbosstm/">distributed transaction service</ulink>
- to coordinate the XA resources provided by the connectors.
- </para>
- <para> It is quite possible that clients add properties to nodes in the unified graph, and that this information cannot be
- handled by the same underlying source that contributed to the node. In this case, the federated repository can be
- configured with a fallback source that will be used used to store this "extra" information.</para>
- <para>
- It is a goal that non-XA sources (i.e., sources that use connectors without XA resources) can participate in distributed
- transactions through the use of
- <emphasis>compensating transactions</emphasis>
- . Because the JBoss DNA federation engine implements the JCR observation system, it is capable of recording all of the
- changes made to the distributed graph (and those changes sent to each updatable source). Therefore, if a non-XA source
- is involved in a distributed transaction that must be rolled back, any changes made to non-XA sources can be undone. (Of
- course, this does not make the underlying source transactional: non-transactional sources still may expose the interim
- changes to other clients.)
- </para>
- </sect2>
- <sect2 id="federation_events">
- <title>Observing changes</title>
- <para> The JCR API supports observing a repository to receive notifications of additions, changes and deletions of nodes
- and properties. The JBoss DNA federated repository will support this API through two primary means.</para>
- <para> When the changes are made through the federated repository, the JBoss DNA federation engine is well aware of the
- set of changes that have been (or are being) made to the unified graph. These events are directly propagated to
- listeners.</para>
- <para> Sources have the ability to publish events, making it possible for the JBoss DNA federation engine and clients that
- have registered listeners to be notified of changes in the information managed by that source. These events are first
- processed by the federation engine and possibly altered based upon contributions from other sources. (The federation
- engine also uses these events to update or purge information in the cache, which may add to the event set.) The
- resulting (and possibly altered) event set is then sent to all client listeners.</para>
- </sect2>
- </sect1>
-</chapter>
Added: trunk/docs/gettingstarted/src/main/docbook/en-US/content/use_cases.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/use_cases.xml (rev 0)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/use_cases.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="use_cases">
+ <title>JBoss DNA Use Cases</title>
+ <para>There are lots of ways to use JBoss DNA in your own applications, but this chapter attempts to show some representative
+ scenarios that take advantage of JBoss DNA's support for the JCR API as well as the federation, integration, and sequencing
+ capabilities.
+ </para>
+ <sect1 id="service_repository">
+ <title>Service repository</title>
+ <para>
+ In a SOA environment, one important component is a service registry that provides versioned storage of all the artifacts
+ that describe the services, their capabilities/restrictions, and the policies that surround them. Service repositories
+ contain information that define the services and their message models, ownership, availability, security requirements/abilities, auditing,
+ funding, monitoring, provisioning, provenance, usage, discovery mechanism, configuration, documentation, relationships
+ to other services, classification taxonomies, ontologies, and many other important aspects.
+ </para>
+ <para>
+ A JCR repository provides an excellent starting point for a service repository. The ability to store a wide range of
+ content, ranging from structured information to documents, means that a JCR repository can offer the flexibility
+ to manage and organize the information while maintaining the ability to adapt the structure and schema as needs evolve
+ over time.
+ </para>
+ <para>
+ A service repository will contain lots of information represented in different forms, and it's important that the repository
+ make it easy for users to quickly find what they need. Organization of the information (probably in multiple hierarchies and with tags)
+ is important, but more important is the ability for users to use simple searching (or more advanced queries) to return ranked
+ results that match the criteria. For search to be effective, it is important that the repository understand the different
+ kinds of artifacts that are uploaded and the information they contain.
+ </para>
+ <para>
+ JCR repositories are naturally searchable and queryable, but also can be used to integrate a taxonomy (or folksonomic tags)
+ with the content, allowing the same content to be presented in different hierarchical classifications.
+ But JBoss DNA capabilities also offer a great advantage, since any file that is uploaded can be automatically sequenced and processed
+ to extract information that's meaningful and useful but often locked up within the file. For example, when a WSDL file is uploaded,
+ the appropriate sequencer(s) process the file and extract and stores in the repository the structured information describing the types,
+ message structures, operations, port types, bindings, and services found within the WSDL file.
+ When an XML Schema Document is uploaded, JBoss DNA can do the same for the schema's complex and simple types, element and attribute
+ declarations, model groups, namespaces, imports, includes, annotations, etc. And JBoss DNA can do the same for the various policy files,
+ resource declarations, documentation, presentations, ontologies, etc.
+ </para>
+ <para>
+ It is also desirable that the service registry can provide accurate and up-to-date information about where the services are deployed
+ and their current health. The best way to do this would be to access this information directly from the other components of the SOA,
+ such as the Enterprise Service Bus and the management/monitoring system. JBoss DNA connectors might allow the service registry
+ to access an ESB to discover which services are deployed, which are running, and automatically annotate the services in the registry
+ with this dynamic information. In fact, the service registry could cache this information to provide a safe and low-impact mechanism
+ for obtaining this information to other applications without having each application hit the ESB.
+ </para>
+ <para>
+ Integration with a management system can be done in a similar manner. A JBoss DNA connector could access the management system
+ to discover the servers and enable auto-discovery of the services, and "tag" the services deployments with the lifecycle phase
+ (dev, test, production, etc.).
+ </para>
+ <para>
+ By using JBoss DNA, a service repository could manage the wide range of artifacts required in a SOA or web-oriented architecture,
+ yet be able to present a unified view of all service information.
+ </para>
+ </sect1>
+ <sect1 id="data_source_management">
+ <title>Manage data sources and services</title>
+ <para>
+ Many enterprise environments include numerous databases and data services, yet there is often no single place where all
+ these different assets are described or related. A data source/service repository could provide information about the
+ many databases running within the enterprise as well as their documentation, schema history, availability, usage policies,
+ current users of the data (including applications, ETL processes, reporting), geographic deployments and synchronization,
+ and the provenance of the data.
+ </para>
+ <para>
+ Some of this information may actually be defined or controlled within the data sources themselves or within other systems.
+ For example, the DDL scripts used to migrate the database schemas are (hopefully) stored in a version control system,
+ and the databases themselves have the ability to describe their current schemas. Using JBoss DNA, the repository could
+ use a connector to the version control system to expose the scripts, as well as connectors to the databases to expose
+ (and cache) the current schema of the databases. The data repository would then be able to allow users to search over
+ this information without even touching the underlying systems.
+ </para>
+ <para>
+ However, the power of a data repository is really the ability to capture the relationships that otherwise were only captured
+ in people's heads or trapped in documents spread throughout the network. A data repository can capture the policies that
+ dictate how each data source should be used (which are for development purposes, or QA/testing purposes, or which are production,
+ and how are they all related), and it can integrate with management systems to provide information about
+ availability and deployment. As web services are created to provide service-based access to the data in databases,
+ the repository can be used to maintain the relationships between these <emphasis>data services</emphasis> and the underlying sources.
+ Similarly, the repository can track how the databases are used by applications, ETL processes, and reports.
+ </para>
+ </sect1>
+ <sect1 id="configuration_repository">
+ <title>Configuration repository</title>
+ <para>
+ Many applications and libraries have configuration files that allow the users (or developers) to dictate the setup and behavior.
+ Often this involves multiple files in a specific structure on the file system. But invalid or inopportune changes to these files
+ sometimes corrupt the environment, but creating a more robust configuration management system is often way beyond the desired
+ effort.
+ </para>
+ <para>
+ An embedded JBoss DNA repository can provide a more formal and flexible configuration system with little effort. JCR's
+ event system allows the system to be notified when the configuration changes, and versioning can help guarantee the ability
+ to revert back to a previous (valid) configuration. JBoss DNA connectors can be used to integrate the files on the file system
+ into the configuration system, keeping it natural for those wanting to view and change the configuration via the files.
+ JBoss DNA sequencers can even process the configuration files to extract a more structured view of the system.
+ And because JBoss DNA can used with a minimal footprint, it provides the ability to manage and version the configuration
+ with little overhead.
+ </para>
+ <para>
+ JBoss DNA can even be used to centralize the configuration definition for a clustered or distributed system. In this mode,
+ the configuration is managed in a central repository that is remotely accessible by the application. When a process is started,
+ it examines the repository and reads the content containing its configuration. The application can monitor the configuration for
+ changes so that it can modify itself and its components.
+ For larger deployments, a central "enterprise configuration" repository can house the configuration of different kinds of systems,
+ and can even be managed and manipulated through JCR.
+ </para>
+ <para>
+ As we'll see in the <link linkend="using_dna">next chapter</link>, this is actually the way in which JBoss DNA manages
+ its own configuration. In the embedded case, the configuration repository is simply a local (in-memory) repository that
+ is populated by the configuration file (or programmatic API). In a clustered mode, the repository is centralized. But either
+ way, to JBoss DNA the configuration is always defined in a repository.
+ </para>
+ </sect1>
+ <sect1 id="use_case_whats_next">
+ <title>What's next</title>
+ <para>
+ The scenarios described in this chapter are representative of some of the ways in which JBoss DNA can be used, and hopefully
+ give you ideas about how you can leverage JBoss DNA in your application or library.
+ </para>
+ <para>
+ In the <link linkend="using_dna">next chapter</link>, we'll show how you can set up JBoss DNA and use it via the standard JCR API.
+ </para>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/gettingstarted/src/main/docbook/en-US/content/use_cases.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna.xml (rev 0)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -0,0 +1,371 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss DNA (http://www.jboss.org/dna)
+ ~
+ ~ See the COPYRIGHT.txt file distributed with this work for information
+ ~ regarding copyright ownership. Some portions may be licensed
+ ~ to Red Hat, Inc. under one or more contributor license agreements.
+ ~ See the AUTHORS.txt file in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ ~ is licensed to you under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ JBoss DNA is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd " [
+<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="using_dna">
+ <title>Using JBoss DNA</title>
+ <para>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 <code>JcrEngine</code>. After that, you obtain the
+ <code>javax.jcr.Repository</code> instance for a named repository and just use the standard JCR API throughout your
+ application.
+ </para>
+ <sect1 id="jcr_engine">
+ <title>JBoss DNA's JcrEngine</title>
+ <para>
+ JBoss DNA encapsulates everything necessary to run one or more JCR repositories into a single &JcrEngine; instance.
+ This includes all underlying repository sources, the pools of connections to the sources, the sequencers,
+ the MIME type detector(s), and the &Repository; implementations.
+ </para>
+ <para>
+ Obtaining a &JcrEngine; instance is very easy - assuming that you have a valid &JcrConfiguration; instance. We'll see
+ how to get one of those in a little bit, but if you have one then all you have to do is build and start the engine:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+JcrEngine engine = config.build();
+engine.start();
+ ]]></programlisting>
+ <para>
+ Obtaining a JCR &Repository; instance is a matter of simply asking the engine for it by the name defined in the configuration:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+javax.jcr.Repository repository = engine.getRepository("Name of repository");
+ ]]></programlisting>
+ <para>
+ At this point, your application can proceed by working with the JCR API.
+ </para>
+ <para>
+ And, once you're finished with the &JcrEngine;, you should shut it down:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+engine.shutdown();
+engine.awaitTermination(3,TimeUnit.SECONDS); // optional
+ ]]></programlisting>
+ <para>
+ When the <code>shutdown()</code> method is called, the &Repository; instances managed by the engine are marked as being shut down,
+ and they will not be able to create new &Session;s. However, any existing &Session;s or ongoing operations (e.g., event notifications)
+ present at the time of the <code>shutdown()</code> call will be allowed to finish.
+ In essence, <code>shutdown()</code> is a <emphasis>graceful</emphasis> request, and since it may take some time to complete,
+ you can wait until the shutdown has completed by simply calling <code>awaitTermination(...)</code> as shown above.
+ This method will block until the engine has indeed shutdown or until the supplied time duration has passed (whichever comes first).
+ And, yes, you can call the <code>awaitTermination(...)</code> method repeatedly if needed.
+ </para>
+ </sect1>
+ <sect1 id="jcr_configuration">
+ <title>JcrConfiguration</title>
+ <para>
+ The previous section assumed the existence of a &JcrConfiguration;. It's not really that creating an instance is all that difficult.
+ In fact, there's only one no-argument constructor, so actually creating the instance is a piece of cake. What can be a little more challenging,
+ though, is setting up the &JcrConfiguration; instance, which must define the following components:
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="strong"><code>Repository sources</code></emphasis> are the POJO objects that each describe a particular
+ location where content is stored. Each repository source object is an instance of a JBoss DNA connector, and is configured
+ with the properties that particular source. JBoss DNA'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. </para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>Repositories</code></emphasis> define the JCR repositories that are available. Each
+ repository has a unique name that is used to obtain the &Repository; instance from the &JcrEngine;'s <code>getRepository(String)</code>
+ method, but each repository definition also can include the predefined namespaces (other than those automatically defined by
+ JBoss DNA), various options, and the node types that are to be available in the repository without explicit registration
+ through the JCR API.</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>Sequencers</code></emphasis> 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.</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>MIME type detectors</code></emphasis> 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. JBoss DNA 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.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ There really are three options:
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="strong"><code>Load from a file</code></emphasis> is conceptually the easiest and requires the least amount
+ of Java code, but it now requires a configuration file.</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>Load from a configuration repository</code></emphasis> is not much more complicated than loading
+ from a file, but it does allow multiple &JcrEngine; instances (usually in different processes perhaps on different machines)
+ to easily access their (shared) configuration. And technically, loading the configuration from a file really just creates an
+ &InMemoryRepositorySource;, imports the configuration file into that source, and then proceeds with this approach.</para>
+ </listitem>
+ <listitem>
+ <para><emphasis role="strong"><code>Programmatic configuration</code></emphasis> is always possible, even if the configuration is loaded
+ from a file or repository. Using the &JcrConfiguration;'s API, you can define (or update or remove) all of the definitions that make
+ up a configuration.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Each of these approaches has their obvious advantages, so the choice of which one to use is entirely up to you.
+ </para>
+ <sect2 id="loading_from_file">
+ <title>Loading from a configuration file</title>
+ <para>
+ Loading the JBoss DNA configuration from a file is actually very simple:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = new JcrConfiguration();
+configuration.loadFrom(file);
+ ]]></programlisting>
+ <para>
+ where the <code>file</code> parameter can actually be a &File; instance, a &URL; to the file, an &InputStream;
+ containing the contents of the file, or even a &String; containing the contents of the file.
+ </para>
+ <note>
+ <para>The <code>loadFrom(...)</code> method can be called any number of times, but each time it is called it completely wipes
+ out any current notion of the configuration and replaces it with the configuration found in the file.
+ </para>
+ </note>
+ <para>
+ There is an optional second parameter that defines the &Path; within the configuration file identifying the parent node of the various
+ configuration nodes. If not specified, it assumes "/". This makes it possible for the configuration content to be
+ located at a different location in the hierarchical structure. (This is not often required, but when it is required
+ this second parameter is very useful.)
+ </para>
+ <para>
+ 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):
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration xmlns="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <!--
+ Define the JCR repositories
+ -->
+ <dna:repositories>
+ <!--
+ Define a JCR repository that accesses the 'Cars' source directly.
+ This of course is optional, since we could access the same content through 'vehicles'.
+ -->
+ <dna:repository jcr:name="car repository" dna:source="Cars">
+ <options jcr:primaryType="dna:options"/>
+ <jaasLoginConfigName jcr:primaryType="dna:option" dna:value="dna-jcr"/>
+ </options>
+ </dna:repository>
+ </dna:repositories>
+ <!--
+ Define the sources for the content. These sources are directly accessible using the DNA-specific Graph API.
+ -->
+ <dna:sources jcr:primaryType="nt:unstructured">
+ <dna:source jcr:name="Cars" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" dna:retryLimit="3" dna:defaultWorkspaceName="workspace1"/>
+ <dna:source jcr:name="Aircraft" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource">
+ <!-- Define the name of the workspace used by default. Optional, but convenient. -->
+ <defaultWorkspaceName>workspace2</defaultWorkspaceName>
+ </dna:source>
+ </dna:sources>
+ <!--
+ Define the sequencers. This is an optional section. For this example, we're not using any sequencers.
+ -->
+ <dna:sequencers>
+ <!--dna:sequencer jcr:name="Image Sequencer" dna:classname="org.jboss.dna.sequencer.image.ImageMetadataSequencer">
+ <dna:description>Image metadata sequencer</dna:description>
+ <dna:pathExpression>/foo/source => /foo/target</dna:pathExpression>
+ <dna:pathExpression>/bar/source => /bar/target</dna:pathExpression>
+ </dna:sequencer-->
+ </dna:sequencers>
+ <dna:mimeTypeDetectors>
+ <dna:mimeTypeDetector jcr:name="Detector" dna:description="Standard extension-based MIME type detector"/>
+ </dna:mimeTypeDetectors>
+</configuration>
+ ]]></programlisting>
+ </sect2>
+ <sect2 id="loading_from_repository">
+ <title>Loading from a configuration repository</title>
+ <para>
+ Loading the JBoss DNA configuration from an existing repository is also pretty straightforward. Simply create and configure the
+ &RepositorySource; instance to point to the desired repository, and then call the <code>loadFrom(&RepositorySource; source)</code>
+ method:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+RepositorySource configSource = ...
+JcrConfiguration config = new JcrConfiguration();
+configuration.loadFrom(configSource);
+ ]]></programlisting>
+ <para>
+ This really is a more advanced way to define your configuration, so we won't go into how you configure a &RepositorySource;.
+ For more information, consult the &ReferenceGuide;.
+ </para>
+ <note>
+ <para>The <code>loadFrom(...)</code> method can be called any number of times, but each time it is called it completely wipes
+ out any current notion of the configuration and replaces it with the configuration found in the file.
+ </para>
+ </note>
+ <para>
+ There is an optional second parameter that defines the name of the workspace in the supplied source where the configuration content
+ can be found. It is not needed if the workspace is the source's default workspace.
+ There is an optional third parameter that defines the &Path; within the configuration repository identifying the parent node of the various
+ configuration nodes. If not specified, it assumes "/". This makes it possible for the configuration content to be
+ located at a different location in the hierarchical structure. (This is not often required, but when it is required
+ this second parameter is very useful.)
+ </para>
+ </sect2>
+ <sect2 id="programmatic_configuration">
+ <title>Programmatic configuration</title>
+ <para>
+ Defining the configuration programmatically is not terribly complicated, and it for obvious reasons results in more verbose Java code.
+ But this approach is very useful and often the easiest approach when the configuration must change or is a reflection of other
+ dynamic information.
+ </para>
+ <para>
+ The &JcrConfiguration; class was designed to have an easy-to-use API that makes it easy to configure each of the different kinds of
+ components, especially when using an IDE with code completion. Here are several examples:
+ </para>
+ <sect3 id="programmatically_configuring_sources">
+ <title>Repository sources</title>
+ <para>Each repository source definition must include the name of the &RepositorySource; class as well as each bean property
+ that should be set on the object:
+ </para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+config.repositorySource("source A")
+ .usingClass(InMemoryRepositorySource.class)
+ .setDescription("The repository for our content")
+ .setProperty("defaultWorkspaceName", workspaceName);
+ ]]></programlisting>
+ <para>
+ This example defines an in-memory source with the name "source A", a description, and a single "defaultWorkspaceName" bean property.
+ Different &RepositorySource; implementations will the bean properties that are required and optional.
+ Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
+ the classpath or from a specific classpath).
+ </para>
+ <note>
+ <para>Each time <code>repositorySource(String)</code> is called, it will either load the existing definition with the supplied
+ name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
+ on the result of <code>repositorySource(String)</code>.
+ The set of existing definitions can be accessed with the <code>repositorySources()</code> method.
+ </para>
+ </note>
+ </sect3>
+ <sect3 id="programmatically_configuring_repositories">
+ <title>Repositories</title>
+ <para>Each repository must be defined to use a named repository source, but all other aspects (e.g., namespaces, node types, options)
+ are optional.</para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+config.repository("repository A")
+ .addNodeTypes("myCustomNodeTypes.cnd")
+ .setSource("source 1")
+ .registerNamespace("acme","http://www.example.com/acme")
+ .setOption(JcrRepository.Option.JAAS_LOGIN_CONFIG_NAME, "dna-jcr");
+ ]]></programlisting>
+ <para>
+ This example defines a repository that uses the "source 1" repository source (which could be a federated source, an in-memory source,
+ a database store, or any other source). Additionally, this example adds the node types in the "myCustomNodeTypes.cnd" file as those
+ that will be made available when the repository is accessed. It also defines the "http://www.example.com/acme" namespace,
+ and finally sets the "JAAS_LOGIN_CONFIG_NAME" option to define the name of the JAAS login configuration that should be used by
+ the JBoss DNA repository.
+ </para>
+ <note>
+ <para>Each time <code>repository(String)</code> is called, it will either load the existing definition with the supplied
+ name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
+ on the result of <code>repository(String)</code>.
+ The set of existing definitions can be accessed with the <code>repositories()</code> method.
+ </para>
+ </note>
+ </sect3>
+ <sect3 id="programmatically_configuring_sequencers">
+ <title>Sequencers</title>
+ <para>Each defined sequencer must specify the name of the &StreamSequencer; implementation class as well as the path expressions
+ defining which nodes should be sequenced and the output paths defining where the sequencer output should be placed (often as a function
+ of the input path expression).</para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+config.sequencer("Image Sequencer")
+ .usingClass("org.jboss.dna.sequencer.image.ImageMetadataSequencer")
+ .loadedFromClasspath()
+ .setDescription("Sequences image files to extract the characteristics of the image")
+ .sequencingFrom("//(*.(jpg|jpeg|gif|bmp|pcx|png|iff|ras|pbm|pgm|ppm|psd)[*])/jcr:content[@jcr:data]")
+ .andOutputtingTo("/images/$1");
+ ]]></programlisting>
+ <para>
+ This shows an example of a sequencer definition named "Image Sequencer" that uses the &ImageMetadataSequencer; class
+ (loaded from the classpath), that is to sequence the "jcr:data" property on any new or changed nodes that are named
+ "jcr:content" below a parent node with a name ending in ".jpg", ".jpeg", ".gif", ".bmp", ".pcx", ".iff", ".ras",
+ ".pbm", ".pgm", ".ppm" or ".psd". The output of the sequencing operation should be placed at the "/images/$1" node,
+ where the "$1" value is captured as the name of the parent node. (The capture groups work the same was as regular expressions;
+ see the &ReferenceGuide; for more details.)
+ Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
+ the classpath or from a specific classpath).
+ </para>
+ <note>
+ <para>Each time <code>sequencer(String)</code> is called, it will either load the existing definition with the supplied
+ name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
+ on the result of <code>sequencer(String)</code>.
+ The set of existing definitions can be accessed with the <code>sequencers()</code> method.
+ </para>
+ </note>
+ </sect3>
+ <sect3 id="programmatically_configuring_mime_type_detectors">
+ <title>MIME type detectors</title>
+ <para>Each defined MIME type detector must specify the name of the &MimeTypeDetector; implementation class as well as any
+ other bean properties required by the implementation.</para>
+ <programlisting role="JAVA"><![CDATA[
+JcrConfiguration config = ...
+config.mimeTypeDetector("Extension Detector")
+ .usingClass(org.jboss.dna.graph.mimetype.ExtensionBasedMimeTypeDetector.class);
+ ]]></programlisting>
+ <para>
+ Of course, the class can be specified as Class reference or a string (followed by whether the class should be loaded from
+ the classpath or from a specific classpath).
+ </para>
+ <note>
+ <para>Each time <code>mimeTypeDetector(String)</code> is called, it will either load the existing definition with the supplied
+ name or will create a new definition if one does not already exist. To remove a definition, simply call <code>remove()</code>
+ on the result of <code>mimeTypeDetector(String)</code>.
+ The set of existing definitions can be accessed with the <code>mimeTypeDetectors()</code> method.
+ </para>
+ </note>
+ </sect3>
+ </sect2>
+ </sect1>
+ <sect1 id="using_dna_whats_next">
+ <title>What's next</title>
+ <para>
+ This chapter outline how you configure JBoss DNA, how you then access a <code>javax.jcr.Repository</code> instance,
+ and use the standard JCR API to interact with the repository. The
+ <link linkend="downloading_and_running">next chapter </link> walks you through downloading
+ and running the JBoss DNA examples.
+ </para>
+ </sect1>
+</chapter>
Property changes on: trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna_for_sequencing.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna_for_sequencing.xml 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna_for_sequencing.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -1,558 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="using_dna_for_sequencing">
- <title>Using JBoss DNA for Sequencing</title>
- <para>As we've mentioned before, JBoss DNA is able to work with existing JCR repositories. Your client applications
- make changes to the information in those repositories, and JBoss DNA automatically uses its sequencers to extract
- additional information from the uploaded files.</para>
- <note>
- <para>Configuring JBoss DNA services is a bit more manual than is ideal. As you'll see, JBoss DNA uses dependency
- injection to allow a great deal of flexibility in how it can be configured and customized. But this flexibility
- makes it more difficult for you to use. We understand this, and will soon provide a much easier way to set up
- and manage JBoss DNA. Current plans are to use the <ulink url="http://www.jboss.org/jbossmc">JBoss Microcontainer</ulink>
- along with a configuration repository.</para>
- </note>
- <sect1 id="sequencing_service">
- <title>Configuring the Sequencing Service</title>
- <para>The JBoss DNA <emphasis>sequencing service</emphasis> is the component that manages the <emphasis>sequencers</emphasis>,
- reacting to changes in JCR repositories and then running the appropriate sequencers.
- This involves processing the changes on a node, determining which (if any) sequencers should be run on that node,
- and for each sequencer constructing the execution environment, calling the sequencer, and saving the information
- generated by the sequencer.</para>
- <para>To set up the sequencing service, an instance is created, and dependent components are injected into
- the object. This includes among other things:
- <itemizedlist>
- <listitem>
- <para>An <emphasis>execution context</emphasis> that defines the context in which the service runs, including
- a factory for JCR sessions given names of the repository and workspace. This factory must be configured,
- and is how JBoss DNA knows about your JCR repositories and how to connect to them. More on this a bit later.</para>
- </listitem>
- <listitem>
- <para>An <code>java.util.concurrent.ExecutorService</code> used to execute the sequencing activites. If none
- is supplied, a new single-threaded executor is created by calling <code>Executors.newSingleThreadExecutor()</code>.
- (This can easily be changed by subclassing and overriding the <code>SequencerService.createDefaultExecutorService()</code> method.)</para>
- </listitem>
- <listitem>
- <para>Filters for sequencers and events. By default, all sequencers are considered for "node added", "property added"
- and "property changed" events.</para>
- </listitem>
- </itemizedlist>
- </para>
- <para>As mentioned above, the <code>JcrExecutionContext</code> provides access to a <code>SessionFactory</code> that is used
- by JBoss DNA to establish sessions to your JCR repositories. Two implementations are available:
- <itemizedlist>
- <listitem>
- <para>The <code>JndiSessionFactory</code> looks up JCR <code>Repository</code> instances in JNDI using
- names that are supplied when creating sessions. This implementation also has methods to set the
- JCR <code>Credentials</code> for a given workspace name.</para>
- </listitem>
- <listitem>
- <para>The <code>SimpleSessionFactory</code> has methods to register the JCR <code>Repository</code> instances
- with names, as well as methods to set the JCR <code>Credentials</code> for a given workspace name.</para>
- </listitem>
- </itemizedlist>
- You can use the <code>SimpleExecutionContext</code> implementation of <code>ExecutionContext</code> and supply
- a <code>SessionFactory</code> instance, or you can provide your own implementation.</para>
- <para>Here's an example of how to instantiate and configure the SequencingService:</para>
- <programlisting role="JAVA"><![CDATA[
-SimpleSessionFactory sessionFactory = new SimpleSessionFactory();
-sessionFactory.registerRepository("Repository", this.repository);
-Credentials credentials = new SimpleCredentials("jsmith", "secret".toCharArray());
-sessionFactory.registerCredentials("Repository/Workspace1", credentials);
-JcrExecutionContext context = new JcrExecutionContext(sessionFactory,"Repository/Workspace1");
-
-// Create the sequencing service, passing in the execution context ...
-SequencingService sequencingService = new SequencingService();
-sequencingService.setExecutionContext(context);
- ]]></programlisting>
- <para>After the sequencing service is created and configured, it must be started. The SequencingService
- has an <emphasis>administration object</emphasis> (that is an instance of <code>ServiceAdministrator</code>)
- with <code>start()</code>, <code>pause()</code>, and <code>shutdown()</code> methods. The latter method will
- close the queue for sequencing, but will allow sequencing operations already running to complete normally.
- To wait until all sequencing operations have completed, simply call the <code>awaitTermination</code> method
- and pass it the maximum amount of time you want to wait.</para>
- <programlisting role="JAVA"><![CDATA[sequencingService.getAdministrator().start();
-]]></programlisting>
- <para>The sequencing service must also be configured with the sequencers that it will use. This is done using the
- <code>addSequencer(SequencerConfig)</code> method and passing a <code>SequencerConfig</code> instance that
- you create. Here's the code that defines 3 sequencer configurations: 1 that places image metadata into
- "<code><![CDATA[/images/<filename>]]></code>", another that places MP3 metadata into "<code><![CDATA[/mp3s/<filename>]]></code>",
- and a third that places a structure that represents the classes, methods, and attributes found within Java source into
- "<code><![CDATA[/java/<filename>]]></code>".</para>
- <programlisting role="JAVA"><![CDATA[
-String name = "Image Sequencer";
-String desc = "Sequences image files to extract the characteristics of the image";
-String classname = "org.jboss.dna.sequencer.image.ImageMetadataSequencer";
-String[] classpath = null; // Use the current classpath
-String[] pathExpressions = {"//(*.(jpg|jpeg|gif|bmp|pcx|png)[*])/jcr:content[@jcr:data] => /images/$1"};
-SequencerConfig imageSequencerConfig = new SequencerConfig(name, desc, classname,
- classpath, pathExpressions);
-sequencingService.addSequencer(imageSequencerConfig);
-
-name = "MP3 Sequencer";
-desc = "Sequences MP3 files to extract the ID3 tags from the audio file";
-classname = "org.jboss.dna.sequencer.mp3.Mp3MetadataSequencer";
-pathExpressions = {"//(*.mp3[*])/jcr:content[@jcr:data] => /mp3s/$1"};
-SequencerConfig mp3SequencerConfig = new SequencerConfig(name, desc, classname,
- classpath, pathExpressions);
-sequencingService.addSequencer(mp3SequencerConfig);
-
-name = "Java Sequencer";
-desc = "Sequences java files to extract the characteristics of the Java source";
-classname = "org.jboss.dna.sequencer.java.JavaMetadataSequencer";
-pathExpressions = {"//(*.java[*])/jcr:content[@jcr:data] => /java/$1"};
-SequencerConfig javaSequencerConfig = new SequencerConfig(name, desc, classname,
- classpath, pathExpressions);
-this.sequencingService.addSequencer(javaSequencerConfig);
- ]]></programlisting>
- <para>Each configuration defines several things, including the name, description, and sequencer implementation class.
- The configuration also defines the classpath information, which can be passed to the <code>ExecutionContext</code> to get
- a Java classloader with which the sequencer class can be loaded. (If no classpath information is provided, as is done
- in the code above, the application class loader is used.) The configuration also specifies the path expressions that
- identify the nodes that should be sequenced with the sequencer and where to store the output generated by the sequencer.
- Path expressions are pretty straightforward but are quite powerful, so before we go any further with the example,
- let's dive into path expressions in more detail.</para>
- <sect2 id="path_expressions">
- <title>Path Expressions</title>
- <para>Path expressions consist of two parts: a selection criteria (or an input path) and an output path:</para>
- <programlisting><![CDATA[ inputPath => outputPath ]]></programlisting>
- <para>The <emphasis>inputPath</emphasis> part defines an expression for the path of a node that is to be sequenced.
- Input paths consist of '<code>/</code>' separated segments, where each segment represents a pattern for a single node's
- name (including the same-name-sibling indexes) and '<code>@</code>' signifies a property name.</para>
- <para>Let's first look at some simple examples:</para>
- <table frame='all'>
- <title>Simple Input Path Examples</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Input Path</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row><entry>/a/b</entry><entry>Match node "<code>b</code>" that is a child of the top level node "<code>a</code>". Neither node
- may have any same-name-sibilings.</entry></row>
- <row><entry>/a/*</entry><entry>Match any child node of the top level node "<code>a</code>".</entry></row>
- <row><entry>/a/*.txt</entry><entry>Match any child node of the top level node "<code>a</code>" that also has a name ending in "<code>.txt</code>".</entry></row>
- <row><entry>/a/*.txt</entry><entry>Match any child node of the top level node "<code>a</code>" that also has a name ending in "<code>.txt</code>".</entry></row>
- <row><entry>/a/b@c</entry><entry>Match the property "<code>c</code>" of node "<code>/a/b</code>".</entry></row>
- <row><entry>/a/b[2]</entry><entry>The second child named "<code>b</code>" below the top level node "<code>a</code>".</entry></row>
- <row><entry>/a/b[2,3,4]</entry><entry>The second, third or fourth child named "<code>b</code>" below the top level node "<code>a</code>".</entry></row>
- <row><entry>/a/b[*]</entry><entry>Any (and every) child named "<code>b</code>" below the top level node "<code>a</code>".</entry></row>
- <row><entry>//a/b</entry><entry>Any node named "<code>b</code>" that exists below a node named "<code>a</code>", regardless
- of where node "<code>a</code>" occurs. Again, neither node may have any same-name-sibilings.</entry></row>
- </tbody>
- </tgroup>
- </table>
- <para>With these simple examples, you can probably discern the most important rules. First, the '<code>*</code>' is a wildcard character
- that matches any character or sequence of characters in a node's name (or index if appearing in between square brackets), and
- can be used in conjunction with other characters (e.g., "<code>*.txt</code>").</para>
- <para>Second, square brackets (i.e., '<code>[</code>' and '<code>]</code>') are used to match a node's same-name-sibiling index.
- You can put a single non-negative number or a comma-separated list of non-negative numbers. Use '0' to match a node that has no
- same-name-sibilings, or any positive number to match the specific same-name-sibling.</para>
- <para>Third, combining two delimiters (e.g., "<code>//</code>") matches any sequence of nodes, regardless of what their names are
- or how many nodes. Often used with other patterns to identify nodes at any level matching other patterns.
- Three or more sequential slash characters are treated as two.</para>
- <para>Many input paths can be created using just these simple rules. However, input paths can be more complicated. Here are some
- more examples:</para>
- <table frame='all'>
- <title>More Complex Input Path Examples</title>
- <tgroup cols='2' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Input Path</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row><entry>/a/(b|c|d)</entry><entry>Match children of the top level node "<code>a</code>" that are named "<code>a</code>",
- "<code>b</code>" or "<code>c</code>". None of the nodes may have same-name-sibling indexes.</entry></row>
- <row><entry>/a/b[c/d]</entry><entry>Match node "<code>b</code>" child of the top level node "<code>a</code>", when node
- "<code>b</code>" has a child named "<code>c</code>", and "<code>c</code>" has a child named "<code>d</code>".
- Node "<code>b</code>" is the selected node, while nodes "<code>b</code>" and "<code>b</code>" are used as criteria but are not
- selected.</entry></row>
- <row><entry>/a(/(b|c|d|)/e)[f/g/@something]</entry><entry>Match node "<code>/a/b/e</code>", "<code>/a/c/e</code>", "<code>/a/d/e</code>",
- or "<code>/a/e</code>" when they also have a child "<code>f</code>" that itself has a child "<code>g</code>" with property
- "<code>something</code>". None of the nodes may have same-name-sibling indexes.</entry></row>
- </tbody>
- </tgroup>
- </table>
- <para>These examples show a few more advanced rules. Parentheses (i.e., '<code>(</code>' and '<code>)</code>') can be used
- to define a set of options for names, as shown in the first and third rules. Whatever part of the selected node's path
- appears between the parentheses is captured for use within the output path. Thus, the first input path in the previous table
- would match node "<code>/a/b</code>", and "b" would be captured and could be used within the output path using "<code>$1</code>",
- where the number used in the output path identifies the parentheses.</para>
- <para>Square brackets can also be used to specify criteria on a node's properties or children. Whatever appears in between the square
- brackets does not appear in the selected node.</para>
- <para>Let's go back to the previous code fragment and look at the first path expression:</para>
- <programlisting><![CDATA[ //(*.(jpg|jpeg|gif|bmp|pcx|png)[*])/jcr:content[@jcr:data] => /images/$1 ]]></programlisting>
- <para>This matches a node named "<code>jcr:content</code>" with property "<code>jcr:data</code>" but no siblings with the same name,
- and that is a child of a node whose name ends with "<code>.jpg</code>", "<code>.jpeg</code>", "<code>.gif</code>", "<code>.bmp</code>", "<code>.pcx</code>",
- or "<code>.png</code>" that may have any same-name-sibling index. These nodes can appear at any level in the repository.
- Note how the input path capture the filename (the segment containing the file extension), including any same-name-sibling index.
- This filename is then used in the output path, which is where the sequenced content is placed.</para>
- </sect2>
- <sect2 id="path_expressions_in_example">
- <title>Path Expressions Used in the Example</title>
- <para>Now that we've covered path expressions, let's go back to the three sequencer configuration in the example.
- Here they are again, with a description of what each path means:</para>
- <table frame='all'>
- <title>Path Expressions for the 3 Sequencers</title>
- <tgroup cols='3' align='left' colsep='1' rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <thead>
- <row>
- <entry>Input Path</entry>
- <entry>Output Path</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><![CDATA[//(*.(jpg|jpeg|gif|bmp|pcx|png)[*])/jcr:content[@jcr:data]]]></entry>
- <entry><![CDATA[/images/$1]]></entry>
- <entry>Any node with a name ending in "<code>.jpg</code>", "<code>.jpeg</code>", "<code>.gif</code>", "<code>.bmp</code>",
- "<code>.pcx</code>", or "<code>.png</code>", whether or not it has a same-name-sibling index, but that has a child named
- "<code>jcr:content</code>" with "<code>jcr:data</code>" property. The node name representing the filename (including any
- same-name-sibling index) is captured, and used to place the output in "<code><![CDATA[/images/<filename>]]></code>".</entry>
- </row>
- <row>
- <entry><![CDATA[//(*.mp3[*])/jcr:content[@jcr:data]]]></entry>
- <entry><![CDATA[/mp3s/$1]]></entry>
- <entry>Any node with a name ending in "<code>.mp3</code>", whether or not it has a same-name-sibling index, but that has a child named
- "<code>jcr:content</code>" with "<code>jcr:data</code>" property. The node name representing the filename (including any
- same-name-sibling index) is captured, and used to place the output in "<code><![CDATA[/mp3s/<filename>]]></code>".</entry>
- </row>
- <row>
- <entry><![CDATA[//(*.java[*])/jcr:content[@jcr:data]]]></entry>
- <entry><![CDATA[/java/$1]]></entry>
- <entry>Any node with a name ending in "<code>.java</code>", whether or not it has a same-name-sibling index, but that has a child named
- "<code>jcr:content</code>" with "<code>jcr:data</code>" property. The node name representing the filename (including any
- same-name-sibling index) is captured, and used to place the output in "<code><![CDATA[/java/<filename>]]></code>".</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>After these sequencer configurations are defined and added to the <code>SequencingService</code>,
- the service is now ready to start reacting to changes in the repository and automatically looking for nodes to sequence.
- But we first need to wire the service into the repository to receive those change events.
- This is accomplished using the <code>ObservationService</code>
- described in the <link linkend="observation_service">next section</link>.</para>
- </sect2>
- </sect1>
- <sect1 id="observation_service">
- <title>Configuring the Observation Service</title>
- <para>The JBoss DNA <code>ObservationService</code> is responsible for listening to one or more JCR repositories
- and multiplexing the events to its listeners. Unlike JCR events, this framework embeds in the events the
- name of the repository and workspace that can be passed to a <code>SessionFactory</code> to obtain a session
- to the repository in which the change occurred. This simple design makes it very easy for JBoss DNA to
- concurrently work with multiple JCR repositories.</para>
- <para>Configuring an observation service is pretty easy, especially if you reuse the same <code>SessionFactory</code>
- supplied to the sequencing service. Here's an example:</para>
- <programlisting role="JAVA"><![CDATA[
- this.observationService = new ObservationService(sessionFactory);
- this.observationService.getAdministrator().start();
- ]]></programlisting>
- <note>
- <para>Both <code>ObservationService</code> and <code>SequencingService</code> implement
- <code>AdministeredService</code>, which has a <code>ServiceAdministrator</code> used to start, pause, and shutdown the
- service. In other words, the lifecycle of the services are managed in the same way.</para>
- </note>
- <para>After the observation service is started, listeners can be added. The <code>SequencingService</code> implements the required
- interface, and so it may be registered directly:</para>
- <programlisting role="JAVA"><![CDATA[
- observationService.addListener(sequencingService);
- ]]></programlisting>
- <para>Finally, the observation service must be wired to monitor one of your JCR repositories. This is done with
- one of the <code>monitor(...)</code> methods:</para>
- <programlisting role="JAVA"><![CDATA[
- int eventTypes = Event.NODE_ADDED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED;
- observationService.monitor("Main Repository/Workspace1", eventTypes);
- ]]></programlisting>
- <para>At this point, the observation service is listening to a JCR repository and forwarding the appropriate events
- to the sequencing service, which will asynchronously process the changes and sequence the information added to or changed in the repository.
- </para>
- </sect1>
- <sect1 id="shutting_down">
- <title>Shutting down JBoss DNA services</title>
- <para>The JBoss DNA services are utilizing resources and threads that must be released before your application is ready to shut down.
- The safe way to do this is to simply obtain the <code>ServiceAdministrator</code> for each service (via the <code>getServiceAdministrator()</code> method)
- and call <code>shutdown()</code>. As previously mentioned, the shutdown method will simply prevent new work from being processed
- and will not wait for existing work to be completed. If you want to wait until the service completes all its work, you must wait
- until the service terminates. Here's an example that shows how this is done:</para>
- <programlisting role="JAVA"><![CDATA[
-// Shut down the service and wait until it's all shut down ...
-sequencingService.getAdministrator().shutdown();
-sequencingService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
-
-// Shut down the observation service ...
-observationService.getAdministrator().shutdown();
-observationService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
- ]]></programlisting>
- <para>At this point, we've covered how to configure and use the JBoss DNA services in your application.
- The next chapter goes back to the <link linkend="downloading_and_running">sample application</link> to show how all
- these pieces fit together.</para>
- </sect1>
- <sect1 id="example_application_review">
- <title>Reviewing the example application</title>
- <para>Recall that the example application consists of a client application that sets up an in-memory JCR repository and
- that allows a user to upload files into that repository. The client also sets up the DNA services with an image sequencer so
- that if any of the uploaded files are PNG, JPEG, GIF, BMP or other images, DNA will automatically extract the image's
- metadata (e.g., image format, physical size, pixel density, etc.) and store that in the repository. Or, if the client uploads
- MP3 audio files, the title, author, album, year, and comment are extracted from the audio file and stored in the repository.</para>
- <para>
- The example is comprised of 5 classes and 1 interface, located in the <code>src/main/java</code> directory:</para>
- <programlisting><![CDATA[
- org/jboss/example/dna/sequencers/ConsoleInput.java
- /ContentInfo.java
- /JavaInfo.java
- /MediaInfo.java
- /SequencingClient.java
- /UserInterface.java
- ]]></programlisting>
- <para><code>SequencingClient</code> is the class that contains the main application. <code>ContentInfo</code> is a simple class
- that encapsulate metadata generated by the sequencers and accessed by this example application, and there are two subclasses:
- <code>MediaInfo</code> encapsulates metadata about media (image and MP3) files, while <code>JavaInfo</code> is a subclass
- encapsulating information about a Java class. The client accesses the content from the repository and represent the
- information using instances of <code>ContentInfo</code> (and its subclasses) and then passing them to the <code>UserInterface</code>.
- <code>UserInterface</code> is an interface with methods that will be called at runtime to
- request data from the user. <code>ConsoleInput</code> is an implementation of this that creates a text user interface,
- allowing the user to operate the client from the command-line. We can easily create a graphical implementation of
- <code>UserInterface</code> at a later date. We can also create a mock implementation for testing purposes that simulates
- a user entering data. This allows us to check the behavior of the client automatically using conventional JUnit test cases,
- as demonstrated by the code in the <code>src/test/java</code> directory:</para>
- <programlisting><![CDATA[
- org/jboss/example/dna/sequencers/SequencingClientTest.java
- /MockUserInterface.java
- ]]></programlisting>
- <para>If we look at the <code>SequencingClient</code> code, there are a handful of methods that encapsulate the various activities.</para>
- <note>
- <para>Some of the code samples included in this book have had some of the error handling and comments removed so that
- the samples are more readable and concise.</para>
- </note>
- <para>The <code>startRepository()</code> method starts up an in-memory Jackrabbit JCR repository. The bulk of this method is simply
- gathering and passing the information required by Jackrabbit. Because Jackrabbit's <code>TransientRepository</code>
- implementation shuts down after the last session is closed, the application maintains a session to ensure that the
- repository remains open throughout the application's lifetime. And finally, the node type needed by the image sequencer is
- registered with Jackrabbit.</para>
- <programlisting role="JAVA"><![CDATA[
-public void startRepository() throws Exception {
- if (this.repository == null) {
- try {
-
- // Load the Jackrabbit configuration ...
- File configFile = new File(this.jackrabbitConfigPath);
- String pathToConfig = configFile.getAbsolutePath();
-
- // Find the directory where the Jackrabbit repository data will be stored ...
- File workingDirectory = new File(this.workingDirectory);
- String workingDirectoryPath = workingDirectory.getAbsolutePath();
-
- // Get the Jackrabbit custom node definition (CND) file ...
- URL cndFile = Thread.currentThread().getContextClassLoader().getResource("jackrabbitNodeTypes.cnd");
-
- // Create the Jackrabbit repository instance and establish a session to keep the repository alive ...
- this.repository = new TransientRepository(pathToConfig, workingDirectoryPath);
- if (this.username != null) {
- Credentials credentials = new SimpleCredentials(this.username, this.password);
- this.keepAliveSession = this.repository.login(credentials, this.workspaceName);
- } else {
- this.keepAliveSession = this.repository.login();
- }
-
- try {
- // Register the node types (only valid the first time) ...
- Workspace workspace = this.keepAliveSession.getWorkspace();
- JackrabbitNodeTypeManager mgr = (JackrabbitNodeTypeManager)workspace.getNodeTypeManager();
- mgr.registerNodeTypes(cndFile.openStream(), JackrabbitNodeTypeManager.TEXT_X_JCR_CND);
- } catch (RepositoryException e) {
- if (!e.getMessage().contains("already exists")) throw e;
- }
-
- } catch (Exception e) {
- this.repository = null;
- this.keepAliveSession = null;
- throw e;
- }
- }
-}
- ]]></programlisting>
- <para>As you can see, this method really has nothing to do with JBoss DNA, other than setting up a JCR repository that JBoss
- DNA will use.</para>
- <para>The <code>shutdownRepository()</code> method shuts down the Jackrabbit transient repository by closing the "keep-alive session".
- Again, this method really does nothing specifically with JBoss DNA, but is needed to manage the JCR repository that JBoss DNA uses.</para>
- <programlisting role="JAVA"><![CDATA[
-public void shutdownRepository() throws Exception {
- if (this.repository != null) {
- try {
- this.keepAliveSession.logout();
- } finally {
- this.repository = null;
- this.keepAliveSession = null;
- }
- }
-}
- ]]></programlisting>
- <para>The <code>startDnaServices()</code> method first starts the JCR repository (if it was not already started), and proceeds
- to create and configure the <code>SequencingService</code> as described <link linkend="sequencing_service">earlier</link>.
- This involes setting up the <code>SessionFactory</code> and <code>ExecutionContext</code>, creating the
- <code>SequencingService</code> instance, and configuring the image sequencer. The method then continues by setting up the
- <code>ObservationService</code> as described <link linkend="observation_service">earlier</link> and starting the service.</para>
- <programlisting role="JAVA"><![CDATA[
-public void startDnaServices() throws Exception {
- if (this.repository == null) this.startRepository();
- if (this.sequencingService == null) {
-
- SimpleSessionFactory sessionFactory = new SimpleSessionFactory();
- sessionFactory.registerRepository(this.repositoryName, this.repository);
- if (this.username != null) {
- Credentials credentials = new SimpleCredentials(this.username, this.password);
- sessionFactory.registerCredentials(this.repositoryName + "/" + this.workspaceName, credentials);
- }
- this.executionContext = new JcrExecutionContext(sessionFactory, repositoryWorkspaceName);
-
- // Create the sequencing service, passing in the execution context ...
- this.sequencingService = new SequencingService();
- this.sequencingService.setExecutionContext(executionContext);
-
- // Configure the sequencers.
- String name = "Image Sequencer";
- String desc = "Sequences image files to extract the characteristics of the image";
- String classname = "org.jboss.dna.sequencer.images.ImageMetadataSequencer";
- String[] classpath = null; // Use the current classpath
- String[] pathExpressions = {"//(*.(jpg|jpeg|gif|bmp|pcx|png|iff|ras|pbm|pgm|ppm|psd))[*]/jcr:content[@jcr:data] => /images/$1"};
- SequencerConfig imageSequencerConfig = new SequencerConfig(name, desc, classname, classpath, pathExpressions);
- this.sequencingService.addSequencer(imageSequencerConfig);
-
- // Set up the MP3 sequencer ...
- name = "Mp3 Sequencer";
- desc = "Sequences mp3 files to extract the id3 tags of the audio file";
- classname = "org.jboss.dna.sequencer.mp3.Mp3MetadataSequencer";
- pathExpressions = {"//(*.mp3)[*]/jcr:content[@jcr:data] => /mp3s/$1"};
- SequencerConfig mp3SequencerConfig = new SequencerConfig(name, desc, classname, classpath, pathExpressions);
- this.sequencingService.addSequencer(mp3SequencerConfig);
-
- name = "Java Sequencer";
- desc = "Sequences java files to extract the characteristics of the Java source";
- classname = "org.jboss.dna.sequencer.java.JavaMetadataSequencer";
- pathExpressions = {"//(*.java[*])/jcr:content[@jcr:data] => /java/$1"};
- SequencerConfig javaSequencerConfig = new SequencerConfig(name, desc, classname,classpath, pathExpressions);
- this.sequencingService.addSequencer(javaSequencerConfig);
-
- // Use the DNA observation service to listen to the JCR repository (or multiple ones), and
- // then register the sequencing service as a listener to this observation service...
- this.observationService = new ObservationService(this.executionContext.getSessionFactory());
- this.observationService.getAdministrator().start();
- this.observationService.addListener(this.sequencingService);
- this.observationService.monitor(this.repositoryName + "/" + this.workspaceName, Event.NODE_ADDED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED);
- }
- // Start up the sequencing service ...
- this.sequencingService.getAdministrator().start();
-}
- ]]></programlisting>
- <para>The <code>shutdownDnaServices()</code> method is pretty straightforward: it just calls shutdown on each of the services
- and waits until they terminate.</para>
- <programlisting role="JAVA"><![CDATA[
-public void shutdownDnaServices() throws Exception {
- if (this.sequencingService == null) return;
-
- // Shut down the service and wait until it's all shut down ...
- this.sequencingService.getAdministrator().shutdown();
- this.sequencingService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
-
- // Shut down the observation service ...
- this.observationService.getAdministrator().shutdown();
- this.observationService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
-}
- ]]></programlisting>
- <para>None of the other methods really do anything with JBoss DNA <emphasis>per se</emphasis>. Instead, they merely work with the repository
- using the JCR API.</para>
- <para>The <code>main</code> method of the <code>SequencingClient</code> class creates a <code>SequencingClient</code> instance,
- and passes a new <code>ConsoleInput</code> instance:</para>
- <programlisting role="JAVA"><![CDATA[
-public static void main( String[] args ) throws Exception {
- SequencingClient client = new SequencingClient();
- client.setRepositoryInformation("repo", "default", "jsmith", "secret".toCharArray());
- client.setUserInterface(new ConsoleInput(client));
-}
- ]]></programlisting>
- <para>If we look at the <code>ConsoleInput</code> constructor, it starts the repository, the DNA services, and a thread
- for the user interface. At this point, the constructor returns, but the main application continues under the user interface thread.
- When the user requests to quit, the user interface thread also shuts down the DNA services and JCR repository.</para>
- <programlisting role="JAVA"><![CDATA[
-public ConsoleInput( SequencerClient client ) {
- try {
- client.startRepository();
- client.startDnaServices();
-
- System.out.println(getMenu());
- Thread eventThread = new Thread(new Runnable() {
- private boolean quit = false;
- public void run() {
- try {
- while (!quit) {
- // Display the prompt and process the requested operation ...
- }
- } finally {
- try {
- // Terminate ...
- client.shutdownDnaServices();
- client.shutdownRepository();
- } catch (Exception err) {
- System.out.println("Error shutting down sequencing service and repository: "
- + err.getLocalizedMessage());
- err.printStackTrace(System.err);
- }
- }
- }
- });
- eventThread.start();
- } catch (Exception err) {
- System.out.println("Error: " + err.getLocalizedMessage());
- err.printStackTrace(System.err);
- }
-}
- ]]></programlisting>
- <para>At this point, we've reviewed all of the interesting code in the example application. However, feel free
- to play with the application, trying different things.</para>
- </sect1>
- <sect1 id="using_dna_review">
- <title>Summarizing what we just did</title>
- <para>In this chapter we covered the different JBoss DNA components used for automatically sequencing a variety of
- types of information, and how those components can be used in your application.
- Specifically, we described how the <code>SequencingService</code> and <code>ObservationService</code> can
- be configured and used. And we ended the chapter by reviewing the example application, which not only uses
- JBoss DNA, but also the repository via the JCR API.</para>
- </sect1>
-</chapter>
Deleted: trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna_repositories.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna_repositories.xml 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/using_dna_repositories.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -1,273 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ JBoss DNA (http://www.jboss.org/dna)
- ~
- ~ See the COPYRIGHT.txt file distributed with this work for information
- ~ regarding copyright ownership. Some portions may be licensed
- ~ to Red Hat, Inc. under one or more contributor license agreements.
- ~ See the AUTHORS.txt file in the distribution for a full listing of
- ~ individual contributors.
- ~
- ~ JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- ~ is licensed to you under the terms of the GNU Lesser General Public License as
- ~ published by the Free Software Foundation; either version 2.1 of
- ~ the License, or (at your option) any later version.
- ~
- ~ JBoss DNA is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="using_dna_repositories">
- <title>Using JBoss DNA Repositories</title>
- <para>One of the capabilities of JBoss DNA is to provide access through
- <ulink url="http://www.jcp.org/en/jsr/detail?id=170">JCR</ulink> to different kinds of repositories and storage systems.
- Your applications work with the JCR API, but through JBoss DNA you're able to accesses the content from where the information
- exists - not just a single purpose-built repository. This is fundamentally what makes JBoss DNA different.</para>
- <para>How does JBoss DNA do this? At the heart of JBoss DNA and it's JCR implementation is a simple connector
- system that is designed around creating and accessing graphs. The JBoss DNA JCR implementation actually just sits on
- top of a single repository source, which it uses to access of the repositories content.
- <figure id="dnajcr-and-connector">
- <title>JBoss DNA's JCR implementation delegates to a repository source</title>
- <graphic align="center" scale="100" fileref="dnajcr-and-connector.png"/>
- </figure>
- That single repository source could be an in-memory repository, a JBoss Cache instance, or a federated repository.
- <figure id="dna-connectors-0.2">
- <title>JBoss DNA can put JCR on top of multiple kinds of systems</title>
- <graphic align="center" scale="100" fileref="dna-connectors-0.2.png"/>
- </figure>
- And the JBoss DNA project has plans to create other connectors, too. For instance, we're going to build a connector
- to other JCR repositories. And another to a file system, so that the files and directories on an area of the file system
- can be accessed through JCR. Of course, if we don't have a connector to suit your needs, you can write your own.
- <figure id="dna-connectors-future">
- <title>Future JBoss DNA connectors</title>
- <graphic align="center" scale="100" fileref="dna-connectors-future.png"/>
- </figure>
- </para>
- <note>
- <para>You might be thinking that these connectors are interesting, but what do they really provide? Is it really useful
- to use JCR to access a relational database rather than JDBC? Or, why access the files on a file system when there
- are already mechanisms to do that?</para>
- <para>Maybe putting JCR on top of a single system (like a JDBC database) isn't that interesting. What
- <emphasis>is</emphasis> interesting, though, is accessing the information in multiple systems <emphasis>as if all that information were
- in a single JCR repository</emphasis>. That's what the federated repository source is all about. The JBoss DNA connector
- system just makes it possible to interact with all these systems in the same way.</para>
- <para>Think of it this way: with JBoss DNA, you can use JCR to get to the schemas of multiple relational databases <emphasis>and</emphasis> the schemas
- defined by DDL files in your SVN repository <emphasis>and</emphasis> the schemas defined by logical models stored on your file system.
- </para>
- </note>
- <para>So with this very high-level summary, let's dive a little deeper and look at how to configure and use JBoss DNA and JCR.</para>
- <sect1 id="repository_service">
- <title>Configuring the Repository Service</title>
- <para>The JBoss DNA <emphasis>repository service</emphasis> is the component that manages the <emphasis>repositories</emphasis>
- and connections to them. The service reads its configuration from a <code>RepositorySource</code> instance (i.e., the
- "configuration repository") and automatically sets up the repositories given the <code>RepositorySource</code> instances
- found in the configuration repository.</para>
- <note>
- <para>Configuring JBoss DNA services is more manual and complex than we want. As you'll see, JBoss DNA uses dependency
- injection to allow a great deal of flexibility in how it can be configured and customized. But this flexibility
- makes it more difficult for you to use. We understand this, and will soon provide a much easier way to set up
- and manage JBoss DNA. Current plans are to use the <ulink url="http://www.jboss.org/jbossmc">JBoss Microcontainer</ulink>
- along with a configuration repository that makes it very easy to set up and manage JBoss DNA, whether it's used in
- a simple application or a cluster of processes.</para>
- </note>
- <para>To set up the repository service, we need to first set up a few other objects:
- <itemizedlist>
- <listitem>
- <para>An <emphasis>execution contexts</emphasis>. Execution contexts define the context (or environment)
- in which the service runs and in which operations against repositories are performed. <code>ExecutionContext</code>
- instances can be created using JAAS application contexts, meaning that they contain the information about the subject
- that the software represents. Execution contexts also provide access to the all of the factories and utilities
- used throughout the services and components, and it is through this mechanism that you can inject your own behavior.
- For example, if your application already had a notion of namespaces, you could create an execution context that
- uses your own <code>NamespaceRegistry</code> implementation (which would use the namespaces defined in your application).</para>
- </listitem>
- <listitem>
- <para>A <emphasis>repository library</emphasis> that manages the list of <code>RepositorySource</code> instances.
- The library makes sure to inject the environments into each repository source, and it provides for each source
- a configurable pool of connections.</para>
- </listitem>
- <listitem>
- <para>A <emphasis>configuration repository</emphasis> that contains descriptions of all of the repository sources
- as well as any information those sources need. Because this is a regular repository, this could be a simple
- repository with content loaded from an XML file (as in this example). Or it could be a shared
- central repository with information about all of the JBoss DNA processes across your company.</para>
- </listitem>
- </itemizedlist>
- With these components in place, we can then instantiate the <code>RepositoryService</code> and start it (using its
- <code>ServiceAdministrator</code>). During startup, the service reads the configuration repository and loads any
- defined <code>RepositorySource</code> instances into the repository library, using the class loader factory
- (available in the <code>ExecutionContext</code>) to obtain.
- </para>
- <para>Here's sample code that shows how to set up and start the repository service. You can see something similar
- in the example application in the <code>startRepositories()</code> method of the <code>org.jboss.example.dna.repository.RepositoryClient</code> class.</para>
- <programlisting role="JAVA"><![CDATA[
- // Create the execution context that we'll use for the services. If we'd want to use JAAS, we'd
- // create the context by supplying LoginContext, AccessControlContext, or even Subject with
- // CallbackHandlers. But this example doesn't use JAAS in this example.
- ExecutionContext context = new ExecutionContext();
-
- // Create the library for the RepositorySource instances ...
- RepositoryLibrary sources = new RepositoryLibrary(context);
-
- // Load into the source manager the repository source for the configuration repository ...
- InMemoryRepositorySource configSource = new InMemoryRepositorySource();
- configSource.setName("Configuration");
- sources.addSource(configSource);
-
- // Now instantiate the Repository Service ...
- RepositoryService service = new RepositoryService(sources, configSource.getName(), context);
- service.getAdministrator().start();
- ]]></programlisting>
- <para>After startup completes, the repositories are ready to be used. The client application obtains the list of repositories
- and presents them to the user. When the user selects one, the client application starts navigating that repository
- starting at its root node (e.g., the "/" path). As you type a command to list the contents of the current node or to
- "change directories" to a different node, the client application obtains the information for the node using a simple
- procedure:
- <orderedlist>
- <listitem>
- <para>Get a connection to the repository.</para>
- </listitem>
- <listitem>
- <para>Using the connection, find the current node and read its properties and children, putting the information
- into a simple Java plain old Java object (POJO).</para>
- </listitem>
- <listitem>
- <para>Close the connection to the repository (in a finally block to ensure it always happens).</para>
- </listitem>
- </orderedlist>
- </para>
- <sect2 id="using_jcr_with_dna">
- <title>Using JCR to read repository</title>
- <para>If we want to perform these steps using JCR, a JCR <code>Session</code> represents our connection.
- So after we create a <code>JcrRepository</code> instance pointing to our repository library, we can
- then login to obtain a JCR session:</para>
- <programlisting role="JAVA"><![CDATA[
- JcrRepository jcrRepository = new JcrRepository(context, sources);
- Session session = jcrRepository.login(sourceName);
- ]]></programlisting>
- <para>Now, the above code doesn't do any authentication; it essentially trusts the caller has the appropriate privileges.
- Normally, your application will need to authenticate the user, so let's look at how that's done.</para>
- <para>JBoss DNA uses the <ulink url="http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/tutorials/General...">Java
- Authentication and Authorization Service (JAAS)</ulink>, making it possible to use any existing JAAS security provider.
- There are numerous JAAS providers, but one of the best open-source implementations is
- <ulink url="http://www.jboss.org/jbosssecurity/">JBoss Security</ulink>, which can authenticate using LDAP, certificates,
- the operating system, and federated single-sign-on (among others).
- </para>
- <para>
- The JCR API defines a <code>Credentials</code> marker interface, an instance of which can be passed to the
- <code>Session.login(...)</code> method. Rather than provide a concrete implementation of this interface, JBoss DNA
- allows you to pass any implementation of <code>Credentials</code> that also has one of the following methods:
- <itemizedlist>
- <listitem>
- <para><code>getLoginContext()</code> that returns a <code>javax.security.auth.login.LoginContext</code> instance.</para>
- </listitem>
- <listitem>
- <para><code>getAccessControlContext()</code> that returns a <code>java.security.AccessControlContext</code> instance.</para>
- </listitem>
- </itemizedlist>
- This way, your application can obtain the JAAS <code>LoginContext</code> or <code>AccessControlContext</code> however it wants,
- and then merely passes that into DNA through the JCR <code>Credentials</code>. No interfaces or classes specific to JBoss DNA are required.
- </para>
- <para>The following code shows how this is done, using an anonymous inner class for the <code>Credentials</code> implementation.</para>
- <programlisting role="JAVA"><![CDATA[
- CallbackHandler callbackHandler = // as needed by your app, according to JAAS
- final LoginContext loginContext = new LoginContext("MyAppContextName",callbackHandler);
- Credentials credentials = new Credentials() {
- public LoginContext getLoginContext() { return loginContext; }
- };
- JcrRepository jcrRepository = new JcrRepository(context, sources);
- Session session = jcrRepository.login(credentials, sourceName);
- ]]></programlisting>
- <para>Once you have a JCR session, you can then use it to find the node of interest and access the necessary information. All of this
- code will use only the JCR API - there's nothing specific to JBoss DNA's implementation. And remember, when you're finished with
- the session, be sure to logout (usually in a <code>finally</code> block):</para>
- <programlisting role="JAVA"><![CDATA[
- if (session != null) session.logout();
- ]]></programlisting>
- <para>Like many people recommend with JCR, you can create either long-lived or short-lived JCR <code>Session</code>s. The
- JBoss DNA implementation of JCR was designed to efficiently do either.</para>
- </sect2>
- <!--
- <sect2 id="using_dna_repositories_with_dna_api">
- <title>Using JBoss DNA's API to read repository</title>
- <para>Although we recommend using JCR, JBoss DNA has an internal command-based API that completely side-steps JCR and provides
- very simple graph-based operations. For more information, see the <code>RepositoryClient</code> class in the example.</para>
- <note>
- <para>This API is likely to undergo changes in the next few releases, and using it at this time is not suggested.</para>
- </note>
- </sect2>
- -->
- </sect1>
- <sect1 id="shutting_down_repository_service">
- <title>Shutting down the Repository Service</title>
- <para>In the first part of this chapter, we saw how to instantiate, configure, and start the <code>RepositoryService</code>.
- We then saw how to use JCR to access the repository service by creating JCR <code>Session</code>s, and how to log out of those
- sessions when no longer needed.</para>
- <para>In this short section we'll see how to shut down the <code>RepositoryService</code> and <code>RepositoryLibrary</code>
- when you're finished with all of the repositories. It's a simple but important step, since this closes all outstanding
- connections that may be sitting unused in the library's connection pools.</para>
- <para>Shutting down these components is very straightforward: get the <code>ServiceAdministrator</code> on each, and call <code>shutdown()</code>.</para>
- <programlisting role="JAVA"><![CDATA[
- // Shut down the repository service ...
- repositoryService.getAdministrator().shutdown();
-
- // Shut down the manager of the RepositorySource instances, waiting until all connections are closed
- sources.getAdministrator().shutdown();
- sources.getAdministrator().awaitTermination(1, TimeUnit.SECONDS);
- ]]></programlisting>
- <para>The <code>shutdown()</code> method attempts to close all open and unused resources (such as open and unused connections in the pool).
- No more connections can be created, and any connections that are currently in use are not closed but allowed to be used and closed normally.
- When the last connection is used, the service then transitions to a <emphasis>terminated</emphasis> state, which you can wait for using
- the <code>awaitTermination(int,TimeUnit)</code> method.</para>
- <para>If you want to shutdown the services immediately, then you could call <code>shutdownNow()</code>, which blocks while it attempts to immediately
- close all connections - <emphasis>even those currently in use</emphasis>. So, while you generally want to use <code>shutdown()</code>,
- it is good to be aware that this <code>shutdownNow()</code> method does exist.</para>
- </sect1>
- <sect1 id="example_repository_application_review">
- <title>Reviewing the example repository application</title>
- <para>Recall that the example repository application consists of a client application that sets up a repository service and the
- repositories defined in a configuration repository, allowing the user to pick a repository and interactively navigate
- the selected repository. Several repositories are set up, including several in-memory repositories and one federated repository
- that dynamically federates the content from the other repositories.</para>
- <para>
- The example is comprised of 2 classes and 1 interface, located in the <code>src/main/java</code> directory:</para>
- <programlisting><![CDATA[
- org/jboss/example/dna/repositories/ConsoleInput.java
- /RepositoryClient.java
- /UserInterface.java
- ]]></programlisting>
- <para><code>RepositoryClient</code> is the class that contains the main application. It uses an instance of the
- <code>UserInterface</code> interface to methods that will be called at runtime to obtain information about the
- files that are imported into the in-memory repositories and the JAAS <code>CallbackHandler</code> implementation
- that will be used by JAAS to prompt the user for authentication information. Finally, the <code>ConsoleInput</code>
- is an implementation of this that creates a text user interface, allowing the user to operate the client from the command-line.
- We can easily create a graphical implementation of <code>UserInterface</code> at a later date, or we can also create a mock
- implementation for testing purposes that simulates a user entering data. This allows us to check the behavior of the client
- automatically using conventional JUnit test cases, as demonstrated by the code in the <code>src/test/java</code> directory:</para>
- <programlisting><![CDATA[
- org/jboss/example/dna/sequencers/RepositoryClientTest.java
- /RepositoryClientUsingJcrTest.java
- ]]></programlisting>
- <para>
- The code we presented earlier in this chapter represent the bulk of the JBoss DNA and JCR-specific code used in the
- <code>RepositoryClient</code>, so we won't cover it in any more detail here. Please refer to the sample client code
- if you want to see more.
- </para>
- </sect1>
- <sect1 id="using_dna_repositories_review">
- <title>Summarizing what we just did</title>
- <para>In this chapter we covered the different JBoss DNA components used for accessing repositories through JCR, including
- repositories that federate their content from the content of other repositories. Specifically, we described how the
- <code>RepositoryService</code> and <code>JcrRepository</code> can be configured and used.
- </para>
- </sect1>
-</chapter>
-
Added: trunk/docs/gettingstarted/src/main/docbook/en-US/custom.dtd
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/custom.dtd (rev 0)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/custom.dtd 2009-06-07 22:33:45 UTC (rev 989)
@@ -0,0 +1,138 @@
+<!ENTITY versionNumber "0.5">
+<!ENTITY copyrightYears "2008-2009">
+<!ENTITY copyrightHolder "Red Hat, Inc.">
+
+<!-- Frequently used URLs -->
+
+<!ENTITY Home "http://www.jboss.org/dna/">
+<!ENTITY Downloads "&Home;downloads.html">
+<!ENTITY Community "&Home;community.html">
+<!ENTITY DocHome "http://www.jboss.org/file-access/default/members/dna/freezone/">
+<!ENTITY API "&DocHome;docs/&versionNumber;/apidocs/org/jboss/dna/">
+<!ENTITY JIRA "http://jira.jboss.org/jira/browse/DNA">
+<!ENTITY Roadmap "&JIRA;?report=com.atlassian.jira.plugin.system.project:roadmap-panel">
+<!ENTITY Subversion "http://anonsvn.jboss.org/repos/dna/">
+<!ENTITY Fisheye "http://fisheye.jboss.org/browse/DNA/">
+<!ENTITY SecureSubversion "https://svn.jboss.org/repos/dna/">
+<!ENTITY Forums "http://www.jboss.com/index.html?module=bb&op=viewforum&f=272">
+<!ENTITY JSR170 "http://www.jcp.org/en/jsr/detail?id=170">
+<!ENTITY JSR283 "http://www.jcp.org/en/jsr/detail?id=283">
+<!ENTITY JSR203 "http://www.jcp.org/en/jsr/detail?id=203">
+<!ENTITY MailTo "mailto:dna-users@jboss.org">
+<!ENTITY Wikipedia "http://en.wikipedia.org/wiki/">
+<!ENTITY JBossMaven "http://repository.jboss.com/maven2/">
+
+<!ENTITY Java "http://java.sun.com/j2se/1.5.0/docs/api/">
+
+<!ENTITY GettingStarted "<ulink url='&DocHome;docs/&versionNumber;/manuals/gettingstarted/html/index.html'>Getting Started</ulink>">
+<!ENTITY ReferenceGuide "<ulink url='&DocHome;docs/&versionNumber;/manuals/reference/html/index.html'>Getting Started</ulink>">
+
+<!-- Types in JRE -->
+
+<!ENTITY String "<ulink url='&Java;java/lang/String.html'><interface>String</interface></ulink>">
+<!ENTITY File "<ulink url='&Java;java/io/File.html'><classname>File</classname></ulink>">
+<!ENTITY URL "<ulink url='&Java;java/net/URL.html'><classname>URL</classname></ulink>">
+<!ENTITY URI "<ulink url='&Java;java/net/URL.html'><classname>URI</classname></ulink>">
+<!ENTITY InputStream "<ulink url='&Java;java/io/InputStream.html'><interface>InputStream</interface></ulink>">
+<!ENTITY IOException "<ulink url='&Java;java/io/IOException.html'><classname>IOException</classname></ulink>">
+<!ENTITY ClassLoader "<ulink url='&Java;java/lang/ClassLoader.html'><interface>ClassLoader</interface></ulink>">
+<!ENTITY AccessControlContext "<ulink url='&Java;java/security/AccessController.html'><classname>AccessControlContext</classname></ulink>">
+<!ENTITY LoginContext "<ulink url='&Java;javax/security/auth/login/LoginContext.html'><classname>LoginContext</classname></ulink>">
+<!ENTITY Subject "<ulink url='&Java;javax/security/auth/Subject.html'><classname>Subject</classname></ulink>">
+<!ENTITY CallbackHandler "<ulink url='&Java;javax/security/auth/callback/CallbackHandler.html'><interface>CallbackHandler</interface></ulink>">
+<!ENTITY ExecutorService "<ulink url='&Java;java/util/concurrent/ExecutorService.html'><interface>ExecutorService</interface></ulink>">
+<!ENTITY TimeUnit "<ulink url='&Java;java/util/concurrent/TimeUnit.html'><interface>TimeUnit</interface></ulink>">
+<!ENTITY UUID "<ulink url='&Java;java/util/UUID.html'><classname>UUID</classname></ulink>">
+<!ENTITY DataSource "<ulink url='&Java;javax/sql/DataSource.html'><classname>DataSource</classname></ulink>">
+
+
+<!-- Types in JCR API -->
+
+<!ENTITY Repository "<interface>Repository</interface>">
+<!ENTITY Session "<interface>Session</interface>">
+<!ENTITY Credentials "<interface>Credentials</interface>">
+<!ENTITY SimpleCredentials "<interface>SimpleCredentials</interface>">
+
+<!-- Types in dna-common -->
+
+<!ENTITY Logger "<ulink url='&API;common/util/Logger.html'><interface>Logger</interface></ulink>">
+<!ENTITY ClassLoaderFactory "<ulink url='&API;common/component/ClassLoaderFactory.html'><interface>ClassLoaderFactory</interface></ulink>">
+<!ENTITY StandardClassLoaderFactory "<ulink url='&API;common/component/StandardClassLoaderFactory.html'><classname>StandardClassLoaderFactory</classname></ulink>">
+
+<!-- Types in dna-graph -->
+
+<!ENTITY Graph "<ulink url='&API;graph/Graph.html'><classname>Graph</classname></ulink>">
+<!ENTITY GraphBatch "<ulink url='&API;graph/Graph.Batch.html'><classname>Graph.Batch</classname></ulink>">
+<!ENTITY Subgraph "<ulink url='&API;graph/Subgraph.html'><interface>Subgraph</interface></ulink>">
+<!ENTITY Node "<ulink url='&API;graph/Node.html'><interface>Node</interface></ulink>">
+<!ENTITY Workspace "<ulink url='&API;graph/Workspace.html'><interface>Workspace</interface></ulink>">
+<!ENTITY Results "<ulink url='&API;graph/Results.html'><interface>Results</interface></ulink>">
+<!ENTITY Location "<ulink url='&API;graph/Location.html'><classname>Location</classname></ulink>">
+<!ENTITY ExecutionContext "<ulink url='&API;graph/ExecutionContext.html'><classname>ExecutionContext</classname></ulink>">
+<!ENTITY Name "<ulink url='&API;graph/property/Name.html'><interface>Name</interface></ulink>">
+<!ENTITY Path "<ulink url='&API;graph/property/Path.html'><interface>Path</interface></ulink>">
+<!ENTITY PathSegment "<ulink url='&API;graph/property/Path.Segment.html'><interface>Path.Segment</interface></ulink>">
+<!ENTITY Property "<ulink url='&API;graph/property/Property.html'><interface>Property</interface></ulink>">
+<!ENTITY ValueFactories "<ulink url='&API;graph/property/ValueFactories.html'><interface>ValueFactories</interface></ulink>">
+<!ENTITY NamespaceRegistry "<ulink url='&API;graph/property/NamespaceRegistry.html'><interface>NamespaceRegistry</interface></ulink>">
+<!ENTITY PropertyFactory "<ulink url='&API;graph/property/PropertyFactory.html'><interface>PropertyFactory</interface></ulink>">
+<!ENTITY PathNotFoundException "<ulink url='&API;graph/property/PathNotFoundException.html'><classname>PathNotFoundException</classname></ulink>">
+<!ENTITY RepositorySource "<ulink url='&API;graph/connector/RepositorySource.html'><interface>RepositorySource</interface></ulink>">
+<!ENTITY RepositoryConnection "<ulink url='&API;graph/connector/RepositoryConnection.html'><interface>RepositoryConnection</interface></ulink>">
+<!ENTITY RepositoryConnectionFactory "<ulink url='&API;graph/connector/RepositoryConnectionFactory.html'><interface>RepositoryConnectionFactory</interface></ulink>">
+<!ENTITY RepositorySourceListener "<ulink url='&API;graph/connector/RepositorySourceListener.html'><interface>RepositorySourceListener</interface></ulink>">
+<!ENTITY RepositorySourceCapabilities "<ulink url='&API;graph/connector/RepositorySourceCapabilities.html'><classname>RepositorySourceCapabilities</classname></ulink>">
+<!ENTITY InMemoryRepository "<ulink url='&API;graph/connector/inmemory/InMemoryRepository.html'><classname>InMemoryRepository</classname></ulink>">
+<!ENTITY InMemoryRepositorySource "<ulink url='&API;graph/connector/inmemory/InMemoryRepositorySource.html'><classname>InMemoryRepositorySource</classname></ulink>">
+<!ENTITY FederatedRepository "<ulink url='&API;graph/connector/federation/FederatedRepository.html'><classname>FederatedRepository</classname></ulink>">
+<!ENTITY FederatedRepositorySource "<ulink url='&API;graph/connector/federation/FederatedRepositorySource.html'><classname>FederatedRepositorySource</classname></ulink>">
+<!ENTITY Projection "<ulink url='&API;graph/connector/federation/Projection.html'><classname>Projection</classname></ulink>">
+<!ENTITY CachePolicy "<ulink url='&API;graph/cache/CachePolicy.html'><interface>CachePolicy</interface></ulink>">
+<!ENTITY Request "<ulink url='&API;graph/request/Request.html'><classname>Request</classname></ulink>">
+<!ENTITY CompositeRequest "<ulink url='&API;graph/request/CompositeRequest.html'><classname>CompositeRequest</classname></ulink>">
+<!ENTITY ReadNodeRequest "<ulink url='&API;graph/request/ReadNodeRequest.html'><classname>ReadNodeRequest</classname></ulink>">
+<!ENTITY CopyBranchRequest "<ulink url='&API;graph/request/CopyBranchRequest.html'><classname>CopyBranchRequest</classname></ulink>">
+<!ENTITY InvalidRequestException "<ulink url='&API;graph/request/InvalidRequestException.html'><classname>InvalidRequestException</classname></ulink>">
+<!ENTITY InvalidWorkspaceException "<ulink url='&API;graph/request/InvalidWorkspaceException.html'><classname>InvalidWorkspaceException</classname></ulink>">
+<!ENTITY UnsupportedRequestException "<ulink url='&API;graph/request/UnsupportedRequestException.html'><classname>UnsupportedRequestException</classname></ulink>">
+<!ENTITY RequestProcessor "<ulink url='&API;graph/request/processor/RequestProcessor.html'><classname>RequestProcessor</classname></ulink>">
+<!ENTITY StreamSequencer "<ulink url='&API;graph/sequencer/StreamSequencer.html'><interface>StreamSequencer</interface></ulink>">
+<!ENTITY SequencerOutput "<ulink url='&API;graph/sequencer/SequencerOutput.html'><interface>SequencerOutput</interface></ulink>">
+<!ENTITY SequencerContext "<ulink url='&API;graph/sequencer/SequencerContext.html'><interface>SequencerContext</interface></ulink>">
+<!ENTITY MimeTypeDetector "<ulink url='&API;graph/mimetype/MimeTypeDetector.html'><interface>MimeTypeDetector</interface></ulink>">
+<!ENTITY MockSequencerOutput "<ulink url='&API;graph/sequencer/MockSequencerOutput.html'><interface>MockSequencerOutput</interface></ulink>">
+<!ENTITY MockSequencerContext "<ulink url='&API;graph/sequencer/MockSequencerContext.html'><interface>MockSequencerContext</interface></ulink>">
+
+<!-- Types in dna-repository -->
+
+<!ENTITY DnaEngine "<ulink url='&API;repository/DnaEngine.html'><classname>DnaEngine</classname></ulink>">
+<!ENTITY DnaConfiguration "<ulink url='&API;repository/DnaConfiguration.html'><classname>DnaConfiguration</classname></ulink>">
+<!ENTITY RepositoryLibrary "<ulink url='&API;repository/RepositoryLibrary.html'><classname>RepositoryLibrary</classname></ulink>">
+<!ENTITY RepositoryService "<ulink url='&API;repository/RepositoryService.html'><classname>RepositoryService</classname></ulink>">
+<!ENTITY ServiceAdministrator "<ulink url='&API;repository/service/ServiceAdministrator.html'><interface>ServiceAdministrator</interface></ulink>">
+<!ENTITY SequencingService "<ulink url='&API;repository/sequencer/SequencingService.html'><classname>SequencingService</classname></ulink>">
+<!ENTITY SequencerConfig "<ulink url='&API;repository/sequencer/SequencerConfig.html'><classname>SequencerConfig</classname></ulink>">
+<!ENTITY SessionFactory "<ulink url='&API;repository/util/SessionFactory.html'><interface>SessionFactory</interface></ulink>">
+<!ENTITY JndiSessionFactory "<ulink url='&API;repository/util/JndiSessionFactory.html'><classname>JndiSessionFactory</classname></ulink>">
+<!ENTITY SimpleSessionFactory "<ulink url='&API;repository/util/SimpleSessionFactory.html'><classname>SimpleSessionFactory</classname></ulink>">
+<!ENTITY JcrExecutionContext "<ulink url='&API;repository/util/JcrExecutionContext.html'><interface>JcrExecutionContext</interface></ulink>">
+<!ENTITY MimeType "<ulink url='&API;repository/mimetype/MimeType.html'><classname>MimeType</classname></ulink>">
+<!ENTITY MimeTypeDetectorConfig "<ulink url='&API;repository/mimetype/MimeTypeDetectorConfig.html'><interface>MimeTypeDetectorConfig</interface></ulink>">
+
+
+<!-- Types in dna-jcr -->
+
+<!ENTITY JcrEngine "<ulink url='&API;jcr/JcrEngine.html'><classname>JcrEngine</classname></ulink>">
+<!ENTITY JcrConfiguration "<ulink url='&API;jcr/JcrConfiguration.html'><classname>JcrConfiguration</classname></ulink>">
+<!ENTITY JcrRepository "<ulink url='&API;jcr/JcrRepository.html'><classname>JcrRepository</classname></ulink>">
+<!ENTITY JcrSession "<ulink url='&API;jcr/JcrSession.html'><classname>JcrSession</classname></ulink>">
+
+<!-- Types in extensions/ -->
+
+<!ENTITY JBossCacheRepository "<ulink url='&API;connector/jbosscache/JBossCacheRepository.html'><classname>JBossCacheRepository</classname></ulink>">
+<!ENTITY JBossCacheSource "<ulink url='&API;connector/jbosscache/JBossCacheSource.html'><classname>JBossCacheSource</classname></ulink>">
+<!ENTITY ImageMetadataSequencer "<ulink url='&API;sequencer/image/ImageMetadataSequencer.html'><classname>ImageMetadataSequencer</classname></ulink>">
+<!ENTITY ImageMetadata "<ulink url='&API;sequencer/image/ImageMetadata.html'><classname>ImageMetadata</classname></ulink>">
+<!ENTITY ImageSequencerI18n "<ulink url='&API;sequencer/image/ImageSequencerI18n.html'><classname>ImageSequencerI18n</classname></ulink>">
+<!ENTITY ApertureMimeTypeDetector "<ulink url='&API;mimetype/aperture/ApertureMimeTypeDetector.html'><classname>ApertureMimeTypeDetector</classname></ulink>">
+
Modified: trunk/docs/gettingstarted/src/main/docbook/en-US/master.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/master.xml 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/master.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -25,9 +25,8 @@
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-<!ENTITY versionNumber "0.4">
-<!ENTITY copyrightYear "2008-2009">
-<!ENTITY copyrightHolder "Red Hat, Inc.">
+<!ENTITY % CustomDTD SYSTEM "custom.dtd">
+%CustomDTD;
]>
<book lang="en">
<bookinfo>
@@ -35,7 +34,7 @@
<subtitle>Getting Started Guide</subtitle>
<releaseinfo>&versionNumber;</releaseinfo>
<productnumber>&versionNumber;</productnumber>
- <issuenum>4</issuenum>
+ <issuenum>5</issuenum>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="dna-logo.png" align="center"/>
@@ -53,10 +52,10 @@
</bookinfo>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/preface.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/introduction.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/understanding_dna.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/use_cases.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/using_dna.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/downloading_and_running.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/using_dna_for_sequencing.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/using_dna_repositories.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/custom_sequencers.xml"/>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/future.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/sequencer_example.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/repository_example.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/conclusion.xml"/>
</book>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml 2009-06-07 15:05:15 UTC (rev 988)
+++ trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml 2009-06-07 22:33:45 UTC (rev 989)
@@ -225,14 +225,20 @@
<para>This profile informs Maven of the two JBoss repositories (<ulink url="http://repository.jboss.org/maven2">snapshots</ulink>
and <ulink url="http://snapshots.jboss.org/maven2">releases</ulink>) that contain all of the JARs for JBoss DNA and all dependent libraries.
</para>
+ <para>While you're adding <code>$MAVEN_HOME/bin</code> to your path, you should also set the <code>$MAVEN_OPTS</code> environment variable
+ to "<code>-Xmx256m</code>". If you don't do this, you'll likely see an <code>java.lang.OutOfMemoryError</code> sometime during a full
+ build.
<note>
<para>
- It is a policy of the project that the <emphasis>source code and JARs</emphasis> for <emphasis>all</emphasis> dependencies
- <emphasis>must</emphasis> be loaded into the JBoss repository. This is so that the project can always be built
- and that all source code is always available.
+ The JBoss Maven repository provides a central location for not only the artifacts produced by the JBoss.org projects (well, at least those
+ that use Maven), but also is where those projects can place the artifacts that they depend on. JBoss DNA has a policy that
+ the <emphasis>source code and JARs</emphasis> for <emphasis>all</emphasis> dependencies <emphasis>must</emphasis> be loaded into the
+ JBoss Maven repository. It may be a little bit more work for the developers, but it does help ensure that developers have easy
+ access to the source and that the project (and dependencies) can always be rebuilt when needed.
</para>
<para>
- For more information about the JBoss Maven repository, see the <ulink url="http://wiki.jboss.org/wiki/Maven">JBoss.org Wiki</ulink>.
+ For more information about the JBoss Maven repository, including instructions for adding source and JAR artifacts,
+ see the <ulink url="http://wiki.jboss.org/wiki/Maven">JBoss.org Wiki</ulink>.
</para>
</note>
<para>
16 years, 6 months
DNA SVN: r988 - in trunk/extensions: dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model and 2 other directories.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-06-07 11:05:15 -0400 (Sun, 07 Jun 2009)
New Revision: 988
Added:
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/package-info.java
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/package-info.java
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/package-info.java
Modified:
trunk/extensions/dna-web-jcr-rest-war/src/test/java/org/jboss/dna/web/jcr/rest/JcrResourcesTest.java
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/DnaJcrDeployer.java
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/JcrResources.java
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/RepositoryFactory.java
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/ServletSecurityContext.java
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryEntry.java
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryResources.java
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceEntry.java
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceResources.java
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/DnaJcrRepositoryProvider.java
trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/RepositoryProvider.java
Log:
DNA-318 Provide documentation/examples/tutorial explaining use of RESTful API
Bolstered Javadoc in dna-web-jcr-rest subproject as a precursor to putting comparable information into the Getting Started and Reference Guide documents.
Modified: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/DnaJcrDeployer.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/DnaJcrDeployer.java 2009-06-07 00:20:55 UTC (rev 987)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/DnaJcrDeployer.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -1,23 +1,58 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
package org.jboss.dna.web.jcr.rest;
+
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
+import org.jboss.dna.web.jcr.rest.spi.RepositoryProvider;
+import net.jcip.annotations.NotThreadSafe;
-
+/**
+ * Servlet context listener that is responsible for {@link RepositoryFactory#initialize(javax.servlet.ServletContext) initializing}
+ * the {@link RepositoryFactory repository factory}.
+ * <p>
+ * This class is not thread safe, but in practice this does not matter as the servlet container must ensure that only
+ * a single instance of this exists per web context and that it is only called in a single-threaded manner.
+ * </p>
+ * @see RepositoryFactory
+ */
+@NotThreadSafe
public class DnaJcrDeployer implements ServletContextListener {
- public static final String DEFAULT_JNDI_NAME = "java:comp/env/org/jboss/dna/Engine";
-
- public static final String SYSTEM_PROPERTY_JNDI_NAME = "org.jboss.dna.dnaEngineJndiName";
-
- public static final String INIT_PARAMETER_JNDI_NAME = "org.jboss.dna.dnaEngineJndiName";
-
+ /**
+ * Alerts the repository factory that the web application is shutting down
+ * @see RepositoryFactory#shutdown()
+ * @see RepositoryProvider#shutdown()
+ */
public void contextDestroyed( ServletContextEvent event ) {
RepositoryFactory.shutdown();
}
/**
- * Mounts a DNA engine
+ * Initializes the repository factory
+ * @see RepositoryFactory#initialize(javax.servlet.ServletContext)
*/
public void contextInitialized( ServletContextEvent event ) {
RepositoryFactory.initialize(event.getServletContext());
Modified: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/JcrResources.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/JcrResources.java 2009-06-07 00:20:55 UTC (rev 987)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/JcrResources.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -55,6 +55,7 @@
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
+import net.jcip.annotations.Immutable;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
@@ -108,6 +109,7 @@
* </tr>
* </table>
*/
+@Immutable
@Path( "/" )
public class JcrResources {
Modified: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/RepositoryFactory.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/RepositoryFactory.java 2009-06-07 00:20:55 UTC (rev 987)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/RepositoryFactory.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -1,3 +1,26 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
package org.jboss.dna.web.jcr.rest;
import java.util.Collection;
@@ -5,10 +28,33 @@
import javax.jcr.Session;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.web.jcr.rest.spi.RepositoryProvider;
+/**
+ * Factory that provides implementations of the {@link RepositoryProvider repository provider SPI} by wrapping a
+ * {@link RepositoryProvider}.
+ * <p>
+ * The repository factory implements a lifecycle for the repository providers. It is first {@link #initialize(ServletContext)
+ * initialized} by {@link DnaJcrDeployer}, a servlet context listener that must be configured in the DNA JCR REST web
+ * configuration (web.xml). The repository factory looks in the context for a parameter with the name of {@link #PROVIDER_KEY}.
+ * This is assumed to be the FQN of the {@link RepositoryProvider repository provider}, which the factory will then instantiate.
+ * </p>
+ * <p>
+ * The repository factory is then able to respond to multiple requests to {@link #getJcrRepositoryNames() list the repository
+ * names} and {@link #getSession(HttpServletRequest, String, String) return active JCR sessions} until the {@link #shutdown()
+ * shutdown method} is called.
+ * </p>
+ * <p>
+ * The {@link #shutdown() shutdown method} is a simple proxy to the {@link RepositoryProvider#shutdown()} repository provider's
+ * shutdown method}.
+ * </p>
+ */
+@ThreadSafe
public class RepositoryFactory {
+ /** The FQN of the repository provider class. Currently set to {@value} . */
public static final String PROVIDER_KEY = "org.jboss.dna.web.jcr.rest.REPOSITORY_PROVIDER";
private static RepositoryProvider provider;
@@ -17,13 +63,20 @@
}
+ /**
+ * Initializes the repository factory. For more details, please see the {@link RepositoryFactory class-level documentation}.
+ *
+ * @param context the servlet context; may not be null
+ * @see RepositoryFactory
+ */
static void initialize( ServletContext context ) {
+ CheckArg.isNotNull(context, "context");
String className = context.getInitParameter(PROVIDER_KEY);
try {
Class<? extends RepositoryProvider> providerClass = Class.forName(className).asSubclass(RepositoryProvider.class);
provider = providerClass.newInstance();
-
+
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
@@ -31,7 +84,9 @@
provider.startup(context);
}
- public static Session getSession( HttpServletRequest request, String repositoryName, String workspaceName) throws RepositoryException {
+ public static Session getSession( HttpServletRequest request,
+ String repositoryName,
+ String workspaceName ) throws RepositoryException {
return provider.getSession(request, repositoryName, workspaceName);
}
Modified: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/ServletSecurityContext.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/ServletSecurityContext.java 2009-06-07 00:20:55 UTC (rev 987)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/ServletSecurityContext.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -1,13 +1,42 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
package org.jboss.dna.web.jcr.rest;
import javax.servlet.http.HttpServletRequest;
+import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.SecurityContext;
/**
* Servlet-based {@link SecurityContext security context} that assumes servlet-based authentication and provides authorization
* through the {@link HttpServletRequest#isUserInRole(String) servlet role-checking mechanism}.
+ * <p>
+ * This security context is really only valid for the life of the {@link HttpServletRequest servlet request} and should
+ * only be used to support longer-lasting session scopes with great care. *
+ * </p>
*/
+@ThreadSafe
public class ServletSecurityContext implements SecurityContext {
private final String userName;
Modified: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryEntry.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryEntry.java 2009-06-07 00:20:55 UTC (rev 987)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryEntry.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -1,3 +1,26 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
package org.jboss.dna.web.jcr.rest.model;
import javax.xml.bind.annotation.XmlElement;
Modified: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryResources.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryResources.java 2009-06-07 00:20:55 UTC (rev 987)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryResources.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -1,3 +1,26 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
package org.jboss.dna.web.jcr.rest.model;
import javax.xml.bind.annotation.XmlElement;
Modified: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceEntry.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceEntry.java 2009-06-07 00:20:55 UTC (rev 987)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceEntry.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -1,3 +1,26 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
package org.jboss.dna.web.jcr.rest.model;
import javax.xml.bind.annotation.XmlElement;
Modified: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceResources.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceResources.java 2009-06-07 00:20:55 UTC (rev 987)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceResources.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -1,3 +1,26 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
package org.jboss.dna.web.jcr.rest.model;
import javax.xml.bind.annotation.XmlElement;
Added: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/package-info.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/package-info.java (rev 0)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/package-info.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -0,0 +1,28 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * Models for the DNA interface to faciliate serving basic information as XML or JSON in the future.
+ */
+package org.jboss.dna.web.jcr.rest.model;
+
Property changes on: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/package-info.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/package-info.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/package-info.java (rev 0)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/package-info.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -0,0 +1,36 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * This package contains the core components for the DNA REST server implementation.
+ * <p>
+ * The key classes are:
+ * <ul>
+ * <li>{@link JcrResources} - the class that handles requests for valid URIs</li>
+ * <li>{@link JcrApplication} - the JAX-RS application class that indicates that JcrResources should be used to handle URIs</li>
+ * <li>{@link RepositoryFactory} - the interface to the DNA JCR SPI</li>
+ * </ul>
+ * </p>
+ */
+package org.jboss.dna.web.jcr.rest;
+
Property changes on: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/package-info.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/DnaJcrRepositoryProvider.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/DnaJcrRepositoryProvider.java 2009-06-07 00:20:55 UTC (rev 987)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/DnaJcrRepositoryProvider.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -1,3 +1,26 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
package org.jboss.dna.web.jcr.rest.spi;
import java.io.IOException;
@@ -9,6 +32,7 @@
import javax.jcr.Session;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
+import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.jcr.JcrConfiguration;
import org.jboss.dna.jcr.JcrEngine;
import org.jboss.dna.jcr.SecurityContextCredentials;
@@ -17,6 +41,18 @@
import org.jboss.resteasy.spi.UnauthorizedException;
import org.xml.sax.SAXException;
+/**
+ * Repository provider backed by the DNA JCR implementation.
+ * <p>
+ * The provider instantiates a {@link JcrEngine} that is {@link JcrConfiguration#loadFrom(InputStream) configured from} the file
+ * in the location specified by the servlet context parameter {@code org.jboss.dna.web.jcr.rest.CONFIG_FILE}. This location must
+ * be accessible by the classloader for this class.
+ * </p>
+ *
+ * @see RepositoryProvider
+ * @see Class#getResourceAsStream(String)
+ */
+@ThreadSafe
public class DnaJcrRepositoryProvider implements RepositoryProvider {
public static final String CONFIG_FILE = "org.jboss.dna.web.jcr.rest.CONFIG_FILE";
@@ -36,7 +72,7 @@
public void startup( ServletContext context ) {
String configFile = context.getInitParameter(CONFIG_FILE);
-
+
try {
InputStream configFileInputStream = getClass().getResourceAsStream(configFile);
jcrEngine = new JcrConfiguration().loadFrom(configFileInputStream).build();
@@ -62,26 +98,26 @@
* @return an active session with the given workspace in the named repository
* @throws RepositoryException if any other error occurs
*/
- public Session getSession( HttpServletRequest request,
- String repositoryName,
- String workspaceName ) throws RepositoryException {
+ public Session getSession( HttpServletRequest request,
+ String repositoryName,
+ String workspaceName ) throws RepositoryException {
assert request != null;
- assert request.getUserPrincipal() != null: "Request must be authorized";
+ assert request.getUserPrincipal() != null : "Request must be authorized";
// Sanity check in case assertions are disabled
if (request.getUserPrincipal() == null) {
throw new UnauthorizedException("Client is not authorized");
}
-
+
Repository repository;
-
+
try {
repository = getRepository(repositoryName);
-
+
} catch (RepositoryException re) {
throw new NotFoundException(re.getMessage(), re);
}
-
+
return repository.login(new SecurityContextCredentials(new ServletSecurityContext(request)), workspaceName);
}
Modified: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/RepositoryProvider.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/RepositoryProvider.java 2009-06-07 00:20:55 UTC (rev 987)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/RepositoryProvider.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -1,3 +1,26 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
package org.jboss.dna.web.jcr.rest.spi;
import java.util.Set;
@@ -7,13 +30,18 @@
import javax.servlet.http.HttpServletRequest;
/**
- * Interface for any class that provides access to one or more local JCR repositories. Repository providers must provide a public,
- * no-argument constructor.
+ * Interface for any class that provides access to one or more local JCR repositories.
+ * <p>
+ * Repository providers must provide a public, no-argument constructor and be thread-safe.
+ * </p>
*/
public interface RepositoryProvider {
/**
* Returns an active session for the given workspace name in the named repository.
+ * <p>
+ * JCR implementations that do not support multiple repositories on the same server can ignore the repositoryName parameter.
+ * </p>
*
* @param request the servlet request; may not be null or unauthenticated
* @param repositoryName the name of the repository in which the session is created
@@ -21,27 +49,32 @@
* @return an active session with the given workspace in the named repository
* @throws RepositoryException if any other error occurs
*/
- public Session getSession( HttpServletRequest request,
- String repositoryName,
- String workspaceName ) throws RepositoryException;
-
+ public Session getSession( HttpServletRequest request,
+ String repositoryName,
+ String workspaceName ) throws RepositoryException;
+
/**
* Returns the available repository names
+ * <p>
+ * JCR implementations that do not support multiple repositories on the same server should provide a singleton set containing
+ * some default repository name.
+ * </p>
*
- * @return the available repository names; may not be null
+ * @return the available repository names; may not be null or empty
*/
Set<String> getJcrRepositoryNames();
/**
- * Signals the repository provider that it should initialize itself based on the provided {@link ServletContext servlet context}
- * and begin accepting connections.
+ * Signals the repository provider that it should initialize itself based on the provided {@link ServletContext servlet
+ * context} and begin accepting connections.
*
* @param context the servlet context for the REST servlet
*/
- void startup(ServletContext context);
+ void startup( ServletContext context );
+
/**
- * Signals the repository provider that it should complete any pending transactions, shutdown, and release
- * any external resource held.
+ * Signals the repository provider that it should complete any pending transactions, shutdown, and release any external
+ * resource held.
*/
void shutdown();
Added: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/package-info.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/package-info.java (rev 0)
+++ trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/package-info.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -0,0 +1,42 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * Service provider interface (SPI) for the JCR implementation that backs the DNA JCR REST server.
+ * <p>
+ * Service providers must provide a thread-safe implementation of the {@link RepositoryProvider} interface
+ * which is then bundled in the server WAR. The REST server can be configured to use the provider by specifying
+ * the fully-qualified name (FQN) of the custom repository provider class in the {@code org.jboss.dna.web.jcr.rest.REPOSITORY_PROVIDER} context parameter
+ * in the web configuration file (web.xml).
+ * </p>
+ * <p>
+ * Custom repository providers for JCR implementations that do not support hosting multiple repositories in the same server
+ * can context can ignore the {@code repositoryName} parameter for {@link RepositoryProvider#getSession(javax.servlet.http.HttpServletRequest, String, String)},
+ * but must always return a non-empty, non-null set containing some default repository name from {@link RepositoryProvider#getJcrRepositoryNames()}.
+ * </p>
+ *
+ * @see org.jboss.dna.web.jcr.rest.RepositoryFactory
+ * @see org.jboss.dna.web.jcr.rest.spi.RepositoryProvider
+ */
+package org.jboss.dna.web.jcr.rest.spi;
+
Property changes on: trunk/extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/package-info.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/extensions/dna-web-jcr-rest-war/src/test/java/org/jboss/dna/web/jcr/rest/JcrResourcesTest.java
===================================================================
--- trunk/extensions/dna-web-jcr-rest-war/src/test/java/org/jboss/dna/web/jcr/rest/JcrResourcesTest.java 2009-06-07 00:20:55 UTC (rev 987)
+++ trunk/extensions/dna-web-jcr-rest-war/src/test/java/org/jboss/dna/web/jcr/rest/JcrResourcesTest.java 2009-06-07 15:05:15 UTC (rev 988)
@@ -42,6 +42,12 @@
import org.junit.Before;
import org.junit.Test;
+/**
+ * Test of the DNA JCR REST resource. Note that this test case uses a very low-level API to construct
+ * requests and deconstruct the responses. Users are encouraged to use a higher-level library to communicate
+ * with the REST server (e.g., Apache HTTP Commons).
+ *
+ */
public class JcrResourcesTest {
private static final String SERVER_CONTEXT = "/resources";
16 years, 6 months
DNA SVN: r987 - trunk/dna-jcr/src/test/java/org/jboss/dna/jcr.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-06-06 20:20:55 -0400 (Sat, 06 Jun 2009)
New Revision: 987
Modified:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java
Log:
Tried to fix cast error that does not appear in Java 1.6
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java 2009-06-07 00:08:51 UTC (rev 986)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java 2009-06-07 00:20:55 UTC (rev 987)
@@ -186,6 +186,7 @@
repository.login();
}
+ @SuppressWarnings("cast")
@Test
public void shouldAllowLoginWithNoCredentialsInPrivilegedBlock() throws Exception {
LoginContext login = new LoginContext("dna-jcr", new UserPasswordCallbackHandler("superuser", "superuser".toCharArray()));
@@ -193,11 +194,10 @@
Subject subject = login.getSubject();
- Session session = Subject.doAsPrivileged(subject, new PrivilegedExceptionAction<Session>() {
+ Session session = (Session) Subject.doAsPrivileged(subject, new PrivilegedExceptionAction<Session>() {
- @SuppressWarnings("cast")
public Session run() throws Exception {
- return (Session) repository.login();
+ return repository.login();
}
}, AccessController.getContext());
16 years, 6 months