DNA SVN: r870 - in trunk: docs/gettingstarted/src/main/docbook/en-US and 3 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-30 18:11:02 -0400 (Thu, 30 Apr 2009)
New Revision: 870
Modified:
trunk/docs/gettingstarted/src/main/docbook/en-US/content/custom_sequencers.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/understanding_dna.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/master.xml
trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml
trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml
trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml
trunk/docs/reference/src/main/docbook/en-US/content/testing.xml
trunk/docs/reference/src/main/docbook/en-US/custom.dtd
trunk/docs/reference/src/main/docbook/en-US/master.xml
trunk/pom.xml
Log:
DNA-385 Documentation Updates for 0.4
Reviewed and edited both documents to bring everything up to the current state of the code. Most parts were still accurate, but there were a number of places there were minor changes and quite a few sections that needed more work.
Pending errors or other changes/suggestions, the docs are complete and accurate for this release.
Modified: 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-04-30 18:18:49 UTC (rev 869)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/custom_sequencers.xml 2009-04-30 22:11:02 UTC (rev 870)
@@ -73,12 +73,12 @@
<dependency>
<groupId>org.jboss.dna</groupId>
<artifactId>dna-common</artifactId>
- <version>0.1</version>
+ <version>0.4</version>
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
<artifactId>dna-graph</artifactId>
- <version>0.1</version>
+ <version>0.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
@@ -122,7 +122,7 @@
<dependency>
<groupId>org.jboss.dna</groupId>
<artifactId>dna-repository</artifactId>
- <version>0.1</version>
+ <version>0.4</version>
<scope>test</scope>
</dependency>
<!-- Java Content Repository API -->
@@ -136,7 +136,7 @@
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-api</artifactId>
- <version>1.3.3</version>
+ <version>1.4</version>
<scope>test</scope>
<!-- Exclude these since they are included in JDK 1.5 -->
<exclusions>
@@ -153,7 +153,7 @@
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-core</artifactId>
- <version>1.3.3</version>
+ <version>1.4.5</version>
<scope>test</scope>
<!-- Exclude these since they are included in JDK 1.5 -->
<exclusions>
Modified: 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-04-30 18:18:49 UTC (rev 869)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/understanding_dna.xml 2009-04-30 22:11:02 UTC (rev 870)
@@ -45,9 +45,10 @@
</sect1>
<sect1 id="architecture">
<title>Architecture</title>
- <para>The architecture for JBoss DNA consists of several major components that will be built on top of standard APIs,
+ <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.</para>
+ 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" />
@@ -57,18 +58,87 @@
</imageobject>
</mediaobject>
<para>
- As shown in the diagram above, the major components are (starting at the top):
+ 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 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 graph. 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
+ with in the 0.4 release, 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.
+ 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>
@@ -106,74 +176,19 @@
</listitem>
<listitem>
<para>
- <emphasis role="strong">DNA Sequencers</emphasis>
- are pluggable components that make it possible for content to be uploaded to the repository and automatically
- processed to extract meaningful structure and place 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.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Analyses</emphasis>
- are pluggable components that analyze content and the relationships between content to generate reports or to answer
- queries. DNA will include some standard analyzers, like dependency analysis and similarity analysis, that are
- commonly needed by many different solutions. DNA analyzers operate 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>
- <listitem>
- <para>
- <emphasis role="strong">DNA Repositories</emphasis>
- is an implementation of the JCR API that builds the content within the repository by accessing and integrating
- information from one or more sources.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Federation</emphasis>
- is a special repository connector that accesses information from multiple sources and makes it accessible
- as if it were a single repository. DNA Federation allows the integration of external systems, like other JCR
- repositories, databases, applications, and services.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Connectors</emphasis>
- are used to communicate with these external sources of information. In the federation engine, each source is able to
- contribute node structure and node properties to any part of the federated graph, although typically many connectors
- will contribute most of their information to isolated subgraphs. The result is that integration from a wide range of
- systems can be integrated and accessed through the DNA Web Application, DNA Publishing Server, and DNA WebDAV
- Server. Connectors also may optionally participate in distributed transactions by exposing an XAResource.
- </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.
- </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>
- that will be the focus of the next release. Or, skip to the
- <link linkend="downloading_and_running">examples</link>
- to see how to start using JBoss DNA &versionNumber;
- today.
+ <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">
@@ -190,7 +205,7 @@
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 versioning system. Each
+ 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>
@@ -201,9 +216,7 @@
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>
- .)
+ files; see <ulink url="http://jira.jboss.org/jira/browse/DNA-26">DNA-26</ulink>.)
</para>
</listitem>
<listitem>
@@ -212,10 +225,41 @@
- 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-26</ulink>
- .)
+ <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>
@@ -224,6 +268,16 @@
<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
@@ -259,14 +313,6 @@
</listitem>
<listitem>
<para>
- <emphasis role="strong">ZIP Archive Sequencer</emphasis>
- - Process ZIP archive files to extract (explode) the contents into the repository. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-63">DNA-63</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>
@@ -284,14 +330,6 @@
</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. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-51">DNA-51</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>
@@ -309,15 +347,6 @@
</listitem>
<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. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-26">DNA-26</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
@@ -342,7 +371,7 @@
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
+ 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>
@@ -500,11 +529,6 @@
(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>
- <note>
- <para> It is hoped that the MetaMatrix query engine can be used for this purpose after it is open-sourced. This engine
- implements sophisticated query planning and optimization techniques for working efficiently with multiple sources.
- </para>
- </note>
<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
Modified: trunk/docs/gettingstarted/src/main/docbook/en-US/master.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/master.xml 2009-04-30 18:18:49 UTC (rev 869)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/master.xml 2009-04-30 22:11:02 UTC (rev 870)
@@ -25,9 +25,9 @@
~ 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.3">
-<!ENTITY copyrightYear "2008">
-<!ENTITY copyrightHolder "Red Hat Middleware, LLC.">
+<!ENTITY versionNumber "0.4">
+<!ENTITY copyrightYear "2008-2009">
+<!ENTITY copyrightHolder "Red Hat, Inc.">
]>
<book lang="en">
<bookinfo>
@@ -35,7 +35,7 @@
<subtitle>Getting Started Guide</subtitle>
<releaseinfo>&versionNumber;</releaseinfo>
<productnumber>&versionNumber;</productnumber>
- <issuenum>1</issuenum>
+ <issuenum>4</issuenum>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="dna-logo.png" align="center"/>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml 2009-04-30 18:18:49 UTC (rev 869)
+++ trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml 2009-04-30 22:11:02 UTC (rev 870)
@@ -170,7 +170,7 @@
</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
+ is building unified metadata repository system that will be 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
Modified: trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml 2009-04-30 18:18:49 UTC (rev 869)
+++ trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml 2009-04-30 22:11:02 UTC (rev 870)
@@ -101,6 +101,15 @@
</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,
Modified: trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml 2009-04-30 18:18:49 UTC (rev 869)
+++ trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml 2009-04-30 22:11:02 UTC (rev 870)
@@ -167,6 +167,24 @@
<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>
@@ -309,6 +327,11 @@
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>
@@ -373,6 +396,19 @@
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>
@@ -422,22 +458,25 @@
cache and federated sources. This graph structure that is expected at this location is as follows:
</para>
<programlisting><![CDATA[<!-- Define the federation configuration. -->
-<dna:federation xmlns:dna="http://www.jboss.org/dna"
+<dna:federatedRepository xmlns:dna="http://www.jboss.org/dna"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
dna:timeToCache="100000" >
- <!-- Define how the content in the 'Cache' source is to map to the federated cache -->
- <dna:cache>
- <dna:projection jcr:name="Cache" dna:projectionRules="/ => /" />
- </dna:cache>
- <!-- 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: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:federation>
+ </dna:projections>
+ </dna:workspace>
+ </dna:workspaces>
+</dna:federatedRepository>
]]></programlisting>
<note>
<para>
@@ -488,6 +527,11 @@
&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>
@@ -601,7 +645,7 @@
<dependency>
<groupId>org.jboss.dna</groupId>
<artifactId>dna-graph</artifactId>
- <version>0.3</version>
+ <version>0.4</version>
</dependency>
]]></programlisting>
<para>
@@ -616,14 +660,14 @@
<dependency>
<groupId>org.jboss.dna</groupId>
<artifactId>dna-graph</artifactId>
- <version>0.3</version>
+ <version>0.4</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
<artifactId>dna-common</artifactId>
- <version>0.3</version>
+ <version>0.4</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
@@ -907,7 +951,7 @@
information, although the connector should still perform as expected when requests have incomplete locations.
</para>
<table frame='all'>
- <title>Types of Requests</title>
+ <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*"/>
@@ -921,62 +965,76 @@
<row>
<entry>ReadNodeRequest</entry>
<entry>
- A request to read from the source a node's properties and children.
+ 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.
+ 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 source all of the properties of a node.
+ 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.
+ 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 source a single property of a node.
+ 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.
+ 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 source all of the children of a node.
+ 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.
+ 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 source a block of children of a node, starting with the n<superscript>th</superscript> children.
+ 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.
+ 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 source a block of children of a node, starting with the children that immediately follow
+ 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
@@ -984,7 +1042,8 @@
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.
+ 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>
@@ -997,7 +1056,8 @@
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.
+ 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>
@@ -1009,7 +1069,8 @@
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.
+ 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>
@@ -1018,7 +1079,8 @@
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.
+ 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>
@@ -1027,7 +1089,8 @@
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.
+ 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>
@@ -1036,19 +1099,23 @@
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.
+ 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.
+ 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>
@@ -1059,7 +1126,8 @@
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.
+ 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>
@@ -1068,7 +1136,8 @@
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.
+ 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>
@@ -1082,6 +1151,60 @@
</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;.
@@ -1101,10 +1224,10 @@
</para>
<note>
<para>
- In many cases, the default implementations of the <code>process(...)</code> methods are <emphasis>sufficient</emphasis>
- but probably not efficient or optimum. If that is the case, simply provide your own methods that perform the request
- in a manner that is efficient for your source. However, if performance is not a big issue, all of the concrete methods
- will provide the correct behavior. And remember, you can always provide better implementations later.
+ 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>
@@ -1116,7 +1239,11 @@
public void execute( final &ExecutionContext; context,
final &Request; request ) throws RepositorySourceException {
RequestProcessor processor = new RequestProcessor(context);
- processor.process(request);
+ 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.
@@ -1191,8 +1318,67 @@
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 returns a map of properties (keyed by property name)
+ 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>
@@ -1268,6 +1454,7 @@
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>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/testing.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/testing.xml 2009-04-30 18:18:49 UTC (rev 869)
+++ trunk/docs/reference/src/main/docbook/en-US/content/testing.xml 2009-04-30 22:11:02 UTC (rev 870)
@@ -129,4 +129,24 @@
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/custom.dtd
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/custom.dtd 2009-04-30 18:18:49 UTC (rev 869)
+++ trunk/docs/reference/src/main/docbook/en-US/custom.dtd 2009-04-30 22:11:02 UTC (rev 870)
@@ -1,4 +1,4 @@
-<!ENTITY versionNumber "0.3">
+<!ENTITY versionNumber "0.4">
<!ENTITY copyrightYears "2008-2009">
<!ENTITY copyrightHolder "Red Hat, Inc.">
@@ -50,7 +50,7 @@
<!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/ClassLoaderFactory.html'><classname>StandardClassLoaderFactory</classname></ulink>">
+<!ENTITY StandardClassLoaderFactory "<ulink url='&API;common/component/StandardClassLoaderFactory.html'><classname>StandardClassLoaderFactory</classname></ulink>">
<!-- Types in dna-graph -->
@@ -58,6 +58,7 @@
<!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>">
@@ -74,13 +75,16 @@
<!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 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 CachePolicy "<ulink url='&API;graph/cache/CachePolicy.html'><interface>CachePolicy</interface></ulink>">
-<!ENTITY Request "<ulink url='&API;graph/request/Requests.html'><classname>Request</classname></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>">
Modified: trunk/docs/reference/src/main/docbook/en-US/master.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/master.xml 2009-04-30 18:18:49 UTC (rev 869)
+++ trunk/docs/reference/src/main/docbook/en-US/master.xml 2009-04-30 22:11:02 UTC (rev 870)
@@ -34,7 +34,7 @@
<subtitle>Reference Guide</subtitle>
<releaseinfo>&versionNumber;</releaseinfo>
<productnumber>&versionNumber;</productnumber>
- <issuenum>1</issuenum>
+ <issuenum>4</issuenum>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="dna-logo.png" align="center"/>
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2009-04-30 18:18:49 UTC (rev 869)
+++ trunk/pom.xml 2009-04-30 22:11:02 UTC (rev 870)
@@ -403,6 +403,11 @@
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
+ <artifactId>dna-jcr-tck</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
<artifactId>dna-connector-federation</artifactId>
<version>${pom.version}</version>
</dependency>
@@ -413,9 +418,59 @@
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
+ <artifactId>dna-connector-store-jpa</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-connector-filesystem</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-connector-svn</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
<artifactId>dna-mimetype-detector-aperture</artifactId>
<version>${pom.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-sequencer-cnd</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-sequencer-images</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-sequencer-java</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-sequencer-mp3</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-sequencer-msoffice</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-sequencer-xml</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-sequencer-zip</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
<!--
Time and Date
-->
16 years, 7 months
DNA SVN: r868 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/io and 6 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-30 12:15:59 -0400 (Thu, 30 Apr 2009)
New Revision: 868
Added:
trunk/dna-graph/src/test/resources/xmlHandler/docWithNestedProperties.xml
Modified:
trunk/dna-graph/pom.xml
trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/Destination.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphBatchDestination.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/io/GraphImporterTest.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java
trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/CndSequencer.java
Log:
DNA-378 XML Graph Importer should support importing multi-valued properties
Applied the patch, which adds support for multi-valued properties as child elements (intermixed with child elements for nodes).
Modified: trunk/dna-graph/pom.xml
===================================================================
--- trunk/dna-graph/pom.xml 2009-04-30 15:31:52 UTC (rev 867)
+++ trunk/dna-graph/pom.xml 2009-04-30 16:15:59 UTC (rev 868)
@@ -32,6 +32,11 @@
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.google.code.google-collections</groupId>
+ <artifactId>google-collect</artifactId>
+ <version>snapshot-20080530</version>
+ </dependency>
<!--
Testing (note the scope)
-->
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/Destination.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/Destination.java 2009-04-30 15:31:52 UTC (rev 867)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/Destination.java 2009-04-30 16:15:59 UTC (rev 868)
@@ -66,6 +66,15 @@
Property... additionalProperties );
/**
+ * Sets the given properties on the node at the supplied path. The path will be absolute.
+ *
+ * @param path the absolute path of the node
+ * @param properties the remaining properties for the node
+ */
+ public void setProperties( Path path,
+ Property... properties );
+
+ /**
* Signal to this destination that any enqueued create requests should be submitted. Usually this happens at the end of the
* document parsing, but an implementer must allow for it to be called multiple times and anytime during parsing.
*/
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphBatchDestination.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphBatchDestination.java 2009-04-30 15:31:52 UTC (rev 867)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/io/GraphBatchDestination.java 2009-04-30 16:15:59 UTC (rev 868)
@@ -117,6 +117,18 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.io.Destination#setProperties(org.jboss.dna.graph.property.Path, org.jboss.dna.graph.property.Property[])
+ */
+ public void setProperties( Path path,
+ Property... properties ) {
+ if (properties == null) return;
+
+ batch.set(properties).on(path);
+ }
+
+ /**
+ * {@inheritDoc}
*
* @see org.jboss.dna.graph.io.Destination#submit()
*/
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-04-30 15:31:52 UTC (rev 867)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-04-30 16:15:59 UTC (rev 868)
@@ -94,7 +94,7 @@
return newRequest;
}
// We have at least one other request, so add the pending request ...
- add(newRequest);
+ addPending();
++number;
} else {
// There is no pending request ...
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java 2009-04-30 15:31:52 UTC (rev 867)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java 2009-04-30 16:15:59 UTC (rev 868)
@@ -24,6 +24,9 @@
package org.jboss.dna.graph.xml;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -45,6 +48,8 @@
import org.jboss.dna.graph.property.basic.LocalNamespaceRegistry;
import org.xml.sax.Attributes;
import org.xml.sax.ext.DefaultHandler2;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
/**
* A {@link DefaultHandler2} specialization that responds to XML content events by creating the corresponding content in the
@@ -162,6 +167,20 @@
protected final Object[] propertyValues = new Object[1];
/**
+ * Character buffer to aggregate nested character data
+ *
+ * @see ElementEntry
+ */
+ private StringBuilder characterDataBuffer = new StringBuilder();
+
+ /**
+ * Stack of pending {@link ElementEntry element entries} from the root of the imported content to the current node.
+ *
+ * @see ElementEntry
+ */
+ private final LinkedList<ElementEntry> elementStack = new LinkedList<ElementEntry>();
+
+ /**
* Create a handler that creates content in the supplied graph
*
* @param destination the destination where the content should be sent.graph in which the content should be placed
@@ -310,6 +329,16 @@
assert localName != null;
Name nodeName = null;
+ ElementEntry element;
+ if (!elementStack.isEmpty()) {
+ // Add the parent
+ elementStack.peek().addAsNode();
+ element = new ElementEntry(elementStack.peek(), currentPath, null);
+ } else {
+ element = new ElementEntry(null, currentPath, null);
+ }
+ elementStack.addFirst(element);
+
properties.clear();
Object typePropertyValue = null;
// Convert each of the attributes to a property ...
@@ -333,6 +362,7 @@
// Check to see if this is an attribute that represents the node name (which may be null) ...
if (nodeName == null && attributeName.equals(nameAttribute)) {
nodeName = nameFactory.create(attributes.getValue(i)); // don't use a decoder
+ element.setName(nodeName);
continue;
}
if (typePropertyValue == null && attributeName.equals(typeAttribute)) {
@@ -340,13 +370,13 @@
continue;
}
// Create a property for this attribute ...
- Property property = createProperty(attributeName, attributes.getValue(i));
- properties.add(property);
+ element.addProperty(attributeName, attributes.getValue(i));
}
// Create the node name if required ...
if (nodeName == null) {
// No attribute defines the node name ...
nodeName = nameFactory.create(uri, localName, decoder);
+ element.setName(nodeName);
} else {
if (typePropertyValue == null) typePropertyValue = nameFactory.create(uri, localName, decoder);
}
@@ -354,15 +384,12 @@
// A attribute defines the node name. Set the type property, if required
if (typePropertyValue == null) typePropertyValue = typeAttributeValue;
if (typePropertyValue != null) {
- propertyValues[0] = typePropertyValue;
- Property property = propertyFactory.create(typeAttribute, propertyValues);
- properties.add(property);
+ element.addProperty(typeAttribute, typePropertyValue);
}
}
+
// Update the current path ...
- currentPath = pathFactory.create(currentPath, nodeName);
- // Create the node, and note that we don't care about same-name siblings (as the graph will correct them) ...
- destination.create(currentPath, properties);
+ currentPath = element.path();
}
/**
@@ -374,6 +401,15 @@
public void endElement( String uri,
String localName,
String name ) {
+
+ String s = characterDataBuffer.toString().trim();
+ if (s.length() > 0) {
+ elementStack.removeFirst().addAsPropertySetTo(s);
+ } else if (!elementStack.isEmpty()) {
+ elementStack.removeFirst().submit();
+ }
+ characterDataBuffer = new StringBuilder();
+
// Nothing to do but to change the current path to be the parent ...
currentPath = currentPath.getParent();
}
@@ -381,6 +417,19 @@
/**
* {@inheritDoc}
*
+ * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
+ */
+ @Override
+ public void characters( char[] ch,
+ int start,
+ int length ) {
+ // Have to add this to a buffer as one logical set of character data can cause this method to fire multiple times
+ characterDataBuffer.append(ch, start, length);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.xml.sax.helpers.DefaultHandler#endDocument()
*/
@Override
@@ -402,8 +451,118 @@
protected Property createProperty( Name propertyName,
Object value ) {
propertyValues[0] = value;
- Property result = propertyFactory.create(propertyName, propertyValues);
- return result;
+ return propertyFactory.create(propertyName, propertyValues);
}
+ /**
+ * Create a property with the given name and values, obtained from an attribute name and value in the XML content.
+ * <p>
+ * By default, this method creates a property by directly using the values as the values of the property.
+ * </p>
+ *
+ * @param propertyName the name of the property; never null
+ * @param values the attribute values
+ * @return the property; may not be null
+ */
+ protected Property createProperty( Name propertyName,
+ Collection<Object> values ) {
+ return propertyFactory.create(propertyName, values);
+ }
+
+ /**
+ * Possible states for an {@link ElementEntry} instance. All element entries start in state {@code TBD} and then transition to
+ * one of the terminating states, {@code NODE} or {@code PROPERTY} when {@link ElementEntry#addAsNode()} or
+ * {@link ElementEntry#addAsPropertySetTo(Object)} is invoked.
+ */
+ protected enum ElementEntryState {
+ NODE,
+ PROPERTY,
+ TBD
+ }
+
+ /**
+ * Element entries hold references to the data of "pending" elements. "Pending" elements are elements which have been
+ * encountered through a {@link XmlHandler#startElement(String, String, String, Attributes)} event but have not yet been fully
+ * committed to the {@link XmlHandler#destination}.
+ * <p>
+ * As the current import semantics allow elements with nested character data to be imported as properties, it is not always
+ * possible to determine whether the element represents a node or a property from within the {@code startElement} method.
+ * Therefore, {@code ElementEntries} are initially created in an {@link ElementEntryState#TBD unknown state} and submitted to
+ * the {@code destination} when it can be positively determined that the entry represents a property (if nested character data
+ * is encountered) or a node (if a child node is detected or the {@link XmlHandler#endElement(String, String, String)} method
+ * is invoked prior to encountering nested character data).
+ * </p>
+ * <p>
+ * As DNA does not currently support a way to add a value to an existing property through the Graph API, {@code
+ * ElementEntries} also contain a {@link Multimap} of property names to values. The node's properties are aggregated and only
+ * submitted to the {@code destination} when the {@link XmlHandler#endElement(String, String, String)} event fires.
+ * </p>
+ */
+ private class ElementEntry {
+
+ private ElementEntry parent;
+ // Stored separately since the root node has no parent ElementEntry but does have a path
+ private Path pathToParent;
+ private Path pathToThisNode;
+ private Name name;
+ private Multimap<Name, Object> properties;
+ private ElementEntryState state;
+
+ protected ElementEntry( ElementEntry parent,
+ Path pathToParent,
+ Name name ) {
+ this.parent = parent;
+ this.pathToParent = pathToParent;
+ this.name = name;
+ this.state = ElementEntryState.TBD;
+ properties = new LinkedHashMultimap<Name, Object>();
+ }
+
+ protected void setName( Name name ) {
+ this.name = name;
+ pathToThisNode = pathFactory.create(pathToParent, name);
+ }
+
+ protected void addProperty( Name propertyName,
+ Object propertyValue ) {
+ assert state != ElementEntryState.PROPERTY;
+ properties.put(propertyName, propertyValue);
+ }
+
+ protected void addAsNode() {
+ assert state != ElementEntryState.PROPERTY;
+ if (state == ElementEntryState.NODE) return;
+
+ state = ElementEntryState.NODE;
+ destination.create(pathFactory.create(pathToParent, name), Collections.<Property>emptyList());
+ }
+
+ protected void addAsPropertySetTo( Object value ) {
+ assert state != ElementEntryState.NODE;
+ state = ElementEntryState.PROPERTY;
+ parent.addProperty(name, value);
+ }
+
+ protected final Path path() {
+ return pathToThisNode;
+ }
+
+ protected void submit() {
+ if (state == ElementEntryState.PROPERTY) return;
+
+ if (state == ElementEntryState.NODE && properties.size() == 0) return;
+ Property[] propertiesToAdd = new Property[properties.size()];
+ int i = 0;
+ for (Name name : properties.keySet()) {
+ propertiesToAdd[i++] = createProperty(name, properties.get(name));
+ }
+
+ if (state == ElementEntryState.TBD) {
+ // Merge the add and the create
+ destination.create(pathToThisNode, Arrays.asList(propertiesToAdd));
+ } else {
+ destination.setProperties(pathToThisNode, propertiesToAdd);
+ }
+ }
+ }
}
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/io/GraphImporterTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/io/GraphImporterTest.java 2009-04-30 15:31:52 UTC (rev 867)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/io/GraphImporterTest.java 2009-04-30 16:15:59 UTC (rev 868)
@@ -26,6 +26,7 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.stub;
import java.io.File;
import java.net.URI;
@@ -51,6 +52,8 @@
import org.jboss.dna.graph.request.CompositeRequest;
import org.jboss.dna.graph.request.CreateNodeRequest;
import org.jboss.dna.graph.request.Request;
+import org.jboss.dna.graph.request.SetPropertyRequest;
+import org.jboss.dna.graph.request.UpdatePropertiesRequest;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
import org.junit.Before;
import org.junit.Test;
@@ -98,8 +101,8 @@
assertThat(lastExecutedRequest, is(instanceOf(CompositeRequest.class)));
Iterator<Request> iter = ((CompositeRequest)lastExecutedRequest).iterator();
// assertCreateNode(iter, "/a/b/", "jcr:primaryType={http://www.jboss.org/dna/xml/1.0}document");
- assertCreateNode(iter, "/a/b/dna:system[1]", "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured");
- assertCreateNode(iter, "/a/b/dna:system[1]/dna:sources[1]", "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured");
+ assertCreateNode(iter, "/a/b/dna:system[1]");
+ assertCreateNode(iter, "/a/b/dna:system[1]/dna:sources[1]");
assertCreateNode(iter,
"/a/b/dna:system[1]/dna:sources[1]/sourceA[1]",
"repositoryName=repositoryA",
@@ -111,6 +114,8 @@
"repositoryName=repositoryB",
"jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured",
"dna:classname=org.jboss.dna.connector.inmemory.InMemoryRepositorySource");
+ assertCreateProperties(iter, "/a/b/dna:system[1]/dna:sources[1]", "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured");
+ assertCreateProperties(iter, "/a/b/dna:system[1]", "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured");
assertThat(iter.hasNext(), is(false));
}
@@ -124,8 +129,60 @@
Path parentPath = createNode.under().getPath();
assertThat(parentPath, is(expectedPath.getParent()));
assertThat(createNode.named(), is(expectedPath.getLastSegment().getName()));
+
+ if (properties.length > 0) {
+ Map<Name, Property> propertiesByName = new HashMap<Name, Property>();
+ for (Property prop : createNode.properties()) {
+ propertiesByName.put(prop.getName(), prop);
+ }
+ for (String propertyStr : properties) {
+ if (propertyStr == "any properties") {
+ propertiesByName.clear();
+ break;
+ }
+ Matcher matcher = Pattern.compile("([^=]+)=(.*)").matcher(propertyStr);
+ if (!matcher.matches()) continue;
+ System.out.println("Property: " + propertyStr + " ==> " + matcher);
+ Name propertyName = context.getValueFactories().getNameFactory().create(matcher.group(1));
+ System.out.println("Property name: " + matcher.group(1));
+ String value = matcher.group(2); // doesn't handle multiple values!!
+ if (value.trim().length() == 0) value = null;
+ Property actual = propertiesByName.remove(propertyName);
+ Property expectedProperty = context.getPropertyFactory().create(propertyName, value);
+ assertThat("missing property " + propertyName, actual, is(expectedProperty));
+ }
+ if (!propertiesByName.isEmpty()) {
+ System.out.println("Properties for " + path + "\n" + propertiesByName);
+ }
+ assertThat(propertiesByName.isEmpty(), is(true));
+ }
+ }
+
+ public void assertCreateProperties( Iterator<Request> iterator,
+ String path,
+ String... properties ) {
+ Request nextCommand = iterator.next();
+
+ if (nextCommand instanceof UpdatePropertiesRequest) {
+ assertUpdateProperties((UpdatePropertiesRequest) nextCommand, path, properties);
+ }
+ else if (nextCommand instanceof SetPropertyRequest) {
+ assertSetProperty((SetPropertyRequest) nextCommand, path, properties);
+ }
+ else {
+ fail("Invalid next request type: " + nextCommand.getClass().getName());
+ }
+
+ }
+ public void assertUpdateProperties( UpdatePropertiesRequest createNode,
+ String path,
+ String... properties ) {
+ Path expectedPath = context.getValueFactories().getPathFactory().create(path);
+ Path parentPath = createNode.changedLocation().getPath().getParent();
+ assertThat(parentPath, is(expectedPath.getParent()));
+ assertThat(createNode.changedLocation().getPath().getLastSegment().getName(), is(expectedPath.getLastSegment().getName()));
Map<Name, Property> propertiesByName = new HashMap<Name, Property>();
- for (Property prop : createNode.properties()) {
+ for (Property prop : createNode.properties().values()) {
propertiesByName.put(prop.getName(), prop);
}
for (String propertyStr : properties) {
@@ -150,6 +207,40 @@
assertThat(propertiesByName.isEmpty(), is(true));
}
+ public void assertSetProperty( SetPropertyRequest createNode,
+ String path,
+ String... properties ) {
+ Path expectedPath = context.getValueFactories().getPathFactory().create(path);
+ Path parentPath = createNode.changedLocation().getPath().getParent();
+ assertThat(parentPath, is(expectedPath.getParent()));
+ assertThat(createNode.changedLocation().getPath().getLastSegment().getName(), is(expectedPath.getLastSegment().getName()));
+ Map<Name, Property> propertiesByName = new HashMap<Name, Property>();
+ Property prop = createNode.property();
+ propertiesByName.put(prop.getName(), prop);
+
+ for (String propertyStr : properties) {
+ if (propertyStr == "any properties") {
+ propertiesByName.clear();
+ break;
+ }
+ Matcher matcher = Pattern.compile("([^=]+)=(.*)").matcher(propertyStr);
+ if (!matcher.matches()) continue;
+ System.out.println("Property: " + propertyStr + " ==> " + matcher);
+ Name propertyName = context.getValueFactories().getNameFactory().create(matcher.group(1));
+ System.out.println("Property name: " + matcher.group(1));
+ String value = matcher.group(2); // doesn't handle multiple values!!
+ if (value.trim().length() == 0) value = null;
+ Property actual = propertiesByName.remove(propertyName);
+ Property expectedProperty = context.getPropertyFactory().create(propertyName, value);
+ assertThat("missing property " + propertyName, actual, is(expectedProperty));
+ }
+ if (!propertiesByName.isEmpty()) {
+ System.out.println("Properties for " + path + "\n" + propertiesByName);
+ }
+ assertThat(propertiesByName.isEmpty(), is(true));
+ }
+
+
protected class MockRepositoryConnection implements RepositoryConnection {
public void close() {
}
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java 2009-04-30 15:31:52 UTC (rev 867)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java 2009-04-30 16:15:59 UTC (rev 868)
@@ -146,7 +146,11 @@
@Test
public void shouldParseXmlDocumentWithoutNamespaces() throws IOException, SAXException {
+ System.out.println("\n");
+ System.out.flush();
parse("xmlHandler/docWithoutNamespaces.xml");
+ System.out.println("\n");
+ System.out.flush();
// Check the generated content; note that the attribute name doesn't match, so the nodes don't get special names
assertNode("Cars");
assertNode("Cars/Hybrid");
@@ -350,14 +354,18 @@
parse("xmlHandler/docWithoutNamespaces.xml");
// Check the generated content; note that the attribute name doesn't match, so the nodes don't get special names
String unstructPrimaryType = "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured";
- assertNode("Cars", unstructPrimaryType);
- assertNode("Cars/Hybrid", unstructPrimaryType);
+ assertNode("Cars");
+ assertNode("Cars/Hybrid");
assertNode("Cars/Hybrid/car", unstructPrimaryType, "name=Toyota Prius", "maker=Toyota", "model=Prius");
assertNode("Cars/Hybrid/car", unstructPrimaryType, "name=Toyota Highlander", "maker=Toyota", "model=Highlander");
assertNode("Cars/Hybrid/car", unstructPrimaryType, "name=Nissan Altima", "maker=Nissan", "model=Altima");
- assertNode("Cars/Sports", unstructPrimaryType);
+ assertProperties("Cars/Hybrid", unstructPrimaryType);
+ assertNode("Cars/Sports");
assertNode("Cars/Sports/car", unstructPrimaryType, "name=Aston Martin DB9", "maker=Aston Martin", "model=DB9");
assertNode("Cars/Sports/car", unstructPrimaryType, "name=Infiniti G37", "maker=Infiniti", "model=G37");
+ assertProperties("Cars/Sports", unstructPrimaryType);
+ assertProperties("Cars", unstructPrimaryType);
+
}
@Test
@@ -371,21 +379,94 @@
// Check the generated content; note that the attribute name doesn't match, so the nodes don't get special names
String unstructPrimaryType = "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured";
String carPrimaryType = "jcr:primaryType={http://default.namespace.com}car";
- assertNode("c:Cars", unstructPrimaryType);
- assertNode("c:Cars/c:Hybrid", unstructPrimaryType);
+ assertNode("c:Cars");
+ assertNode("c:Cars/c:Hybrid");
assertNode("c:Cars/c:Hybrid/c:Toyota Prius", carPrimaryType, "c:maker=Toyota", "c:model=Prius");
assertNode("c:Cars/c:Hybrid/c:Toyota Highlander", carPrimaryType, "c:maker=Toyota", "c:model=Highlander");
assertNode("c:Cars/c:Hybrid/c:Nissan Altima", carPrimaryType, "c:maker=Nissan", "c:model=Altima");
- assertNode("c:Cars/c:Sports", unstructPrimaryType);
+ assertProperties("c:Cars/c:Hybrid", unstructPrimaryType);
+ assertNode("c:Cars/c:Sports");
assertNode("c:Cars/c:Sports/c:Aston Martin DB9", carPrimaryType, "c:maker=Aston Martin", "c:model=DB9");
assertNode("c:Cars/c:Sports/c:Infiniti G37", carPrimaryType, "c:maker=Infiniti", "c:model=G37");
+ assertProperties("c:Cars/c:Sports", unstructPrimaryType);
+ assertProperties("c:Cars", unstructPrimaryType);
}
+ @Test
+ public void shouldParseXmlDocumentWithNestedPropertiesShouldPlaceContentUnderRootNode() throws IOException, SAXException {
+ context.getNamespaceRegistry().register("jcr", "http://www.jcp.org/jcr/1.0");
+ handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
+ parse("xmlHandler/docWithNestedProperties.xml");
+ // Check the generated content; note that the attribute name DOES match, so the nodes names come from "jcr:name" attribute
+ assertNode("Cars");
+ assertNode("Cars/Hybrid");
+ assertNode("Cars/Hybrid/car", "name=Toyota Prius", "maker=Toyota", "model=Prius");
+ assertNode("Cars/Hybrid/car", "name=Toyota Highlander", "maker=Toyota", "model=Highlander");
+ assertNode("Cars/Hybrid/car");
+ assertProperties("Cars/Hybrid/car", "name=Nissan Altima", "maker=Nissan", "model=Altima");
+ assertNode("Cars/Sports");
+ assertNode("Cars/Sports/car", "name=Aston Martin DB9", "maker=Aston Martin", "model=DB9");
+ assertNode("Cars/Sports/car");
+ assertNode("Cars/Sports/car/driver", "name=Tony Stewart");
+ assertProperties("Cars/Sports/car", "name=Infiniti G37", "maker=Infiniti", "model=G37", "category=Turbocharged=My Sedan");
+ assertNode("Cars/Sports/car");
+ assertNode("Cars/Sports/car/jcr:xmltext", "jcr:xmlcharacters=This is my text ");
+ assertNode("Cars/Sports/car/jcr:xmltext", "jcr:xmlcharacters=that should be merged");
+ assertProperties("Cars/Sports/car", "name=Infiniti G37", "maker=Infiniti", "model=G37");
+ }
+
protected void assertNode( String path,
String... properties ) {
// Create the expected path ...
PathFactory factory = context.getValueFactories().getPathFactory();
Path expectedPath = parentPath != null ? factory.create(parentPath, path) : factory.create("/" + path);
+ // Now get the next request and compare the expected and actual ...
+ CreateNodeRequest request = requests.remove();
+ Path parentPath = request.under().getPath();
+ assertThat(parentPath, is(expectedPath.getParent()));
+ assertThat(request.named(), is(expectedPath.getLastSegment().getName()));
+
+ if (properties.length != 0) {
+ // Create the list of properties ...
+ Map<Name, Property> expectedProperties = new HashMap<Name, Property>();
+ for (String propertyString : properties) {
+ String[] strings = propertyString.split("=");
+ if (strings.length < 2) continue;
+ Name name = context.getValueFactories().getNameFactory().create(strings[0]);
+ Object[] values = new Object[strings.length - 1];
+ for (int i = 1; i != strings.length; ++i) {
+ values[i - 1] = strings[i];
+ }
+ Property property = context.getPropertyFactory().create(name, values);
+ expectedProperties.put(name, property);
+ }
+
+ for (Property actual : request.properties()) {
+ Property expected = expectedProperties.remove(actual.getName());
+ assertThat("unexpected property: " + actual, expected, is(notNullValue()));
+ assertThat(actual, is(expected));
+ }
+ if (!expectedProperties.isEmpty()) {
+ StringBuilder msg = new StringBuilder("missing actual properties: ");
+ boolean isFirst = true;
+ for (Property expected : expectedProperties.values()) {
+ if (!isFirst) msg.append(", ");
+ else isFirst = false;
+ msg.append(expected.getName());
+ }
+ msg.append(" on node ").append(request.under());
+ System.out.println("Found properties: " + request.properties());
+ assertThat(msg.toString(), expectedProperties.isEmpty(), is(true));
+ }
+ }
+ }
+
+ protected void assertProperties( String path,
+ String... properties ) {
+ // Create the expected path ...
+ PathFactory factory = context.getValueFactories().getPathFactory();
+ Path expectedPath = parentPath != null ? factory.create(parentPath, path) : factory.create("/" + path);
// Create the list of properties ...
Map<Name, Property> expectedProperties = new HashMap<Name, Property>();
for (String propertyString : properties) {
@@ -399,12 +480,13 @@
Property property = context.getPropertyFactory().create(name, values);
expectedProperties.put(name, property);
}
- // Now get the next request and compare the expected and actual ...
- CreateNodeRequest request = requests.remove();
- Path parentPath = request.under().getPath();
+
+ CreateNodeRequest propertyRequest = requests.remove();
+ Path parentPath = propertyRequest.under().getPath();
assertThat(parentPath, is(expectedPath.getParent()));
- assertThat(request.named(), is(expectedPath.getLastSegment().getName()));
- for (Property actual : request.properties()) {
+ assertThat(propertyRequest.named(), is(expectedPath.getLastSegment().getName()));
+
+ for (Property actual : propertyRequest.properties()) {
Property expected = expectedProperties.remove(actual.getName());
assertThat("unexpected property: " + actual, expected, is(notNullValue()));
assertThat(actual, is(expected));
@@ -417,6 +499,8 @@
else isFirst = false;
msg.append(expected.getName());
}
+ msg.append(" on node ").append(propertyRequest.under());
+ System.out.println("Found properties: " + propertyRequest.properties());
assertThat(msg.toString(), expectedProperties.isEmpty(), is(true));
}
}
@@ -481,6 +565,21 @@
}
}
+ public void setProperties( Path path,
+ Property... properties ) {
+ if (properties.length == 0) {
+ return;
+ }
+ else if (properties.length == 1) {
+ create(path, properties[0]);
+ }
+ else {
+ Property[] additionalProperties = new Property[properties.length - 1];
+ System.arraycopy(properties, 1, additionalProperties, 0, properties.length - 1);
+ create(path, properties[0], additionalProperties);
+ }
+ }
+
@SuppressWarnings( "synthetic-access" )
public ExecutionContext getExecutionContext() {
return XmlHandlerTest.this.context;
Added: trunk/dna-graph/src/test/resources/xmlHandler/docWithNestedProperties.xml
===================================================================
--- trunk/dna-graph/src/test/resources/xmlHandler/docWithNestedProperties.xml (rev 0)
+++ trunk/dna-graph/src/test/resources/xmlHandler/docWithNestedProperties.xml 2009-04-30 16:15:59 UTC (rev 868)
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Cars xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <Hybrid>
+ <car name="Toyota Prius" maker="Toyota" model="Prius"/>
+ <car name="Toyota Highlander" maker="Toyota" model="Highlander"/>
+ <car name="Nissan Altima">
+ <property jcr:name="maker">Nissan</property>
+ <model>Altima</model>
+ </car>
+ </Hybrid>
+ <Sports>
+ <car name="Aston Martin DB9" maker="Aston Martin" model="DB9"/>
+ <car name="Infiniti G37">
+ <maker>Infiniti</maker>
+ <category>Turbocharged</category>
+ <driver name="Tony Stewart" />
+ <property jcr:name="model">G37</property>
+ <category>My <![CDATA[Sedan]]></category>
+ </car>
+ <car name="Infiniti G37" maker="Infiniti" model="G37">
+ <unstructured jcr:name="jcr:xmltext" jcr:xmlcharacters="This is my text " />
+ <unstructured jcr:name="jcr:xmltext" jcr:xmlcharacters="that should be merged" />
+ </car>
+ </Sports>
+</Cars>
\ No newline at end of file
Property changes on: trunk/dna-graph/src/test/resources/xmlHandler/docWithNestedProperties.xml
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/CndSequencer.java
===================================================================
--- trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/CndSequencer.java 2009-04-30 15:31:52 UTC (rev 867)
+++ trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/CndSequencer.java 2009-04-30 16:15:59 UTC (rev 868)
@@ -111,6 +111,19 @@
/**
* {@inheritDoc}
*
+ * @see org.jboss.dna.graph.io.Destination#setProperties(org.jboss.dna.graph.property.Path,
+ * org.jboss.dna.graph.property.Property[])
+ */
+ public void setProperties( Path path,
+ Property... properties ) {
+ for (Property property : properties) {
+ output.setProperty(path, property.getName(), property.getValues());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.jboss.dna.graph.io.Destination#submit()
*/
public void submit() {
16 years, 7 months
DNA SVN: r867 - in trunk: dna-jcr/src/main/resources/org/jboss/dna/jcr and 2 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-30 11:31:52 -0400 (Thu, 30 Apr 2009)
New Revision: 867
Added:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrConfiguration.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEngine.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/Configurator.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java
Removed:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEmptyNodeIterator.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEmptyPropertyIterator.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMixLexicon.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNtLexicon.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSingleValueProperty.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSvLexicon.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrValue.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/OnParentVersionBehavior.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SelfClosingInputStream.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java
Log:
DNA-58 Create repository configuration and component
Refactored the DnaConfiguration class to use more interfaces and to move those interfaces (and reusable implementations) into a Configurator class that uses generics. DnaConfiguration instantiates a configurator, but also implements some of the high-level interfaces by delegating them to the wrapped configurator instance. This allows DnaConfiguration to appear to be doing the configurating, but in reality it is the wrapped builder that is doing it. Also, DnaConfiguration (or other components) can choose which "aspects" of configuration it is to expose by inheriting controlling which higher-level interfaces are implemented. Since delegation is used, this works very well.
This is a more complicated design, but it is far more extensible and reusable. A JcrConfiguration class was also created that works in the same way as DnaConfiguration, except that it uses a different type parameter (so all the interfaces return JcrConfiguration). It thus gets to reuse all of the Configurator logic. However, JcrConfiguration doesn't implement all of the "aspects", essentially hiding certain services (e.g., sequencers, since they don't yet work with our implementation).
This change also made a few minor corrections to the JavaDoc and visibility modifiers on the classes in the 'org.jboss.dna.jcr' package.
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrConfiguration.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrConfiguration.java (rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrConfiguration.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ *
+ * 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.jcr;
+
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.mimetype.MimeTypeDetector;
+import org.jboss.dna.repository.Configurator;
+import org.jboss.dna.repository.DnaConfiguration;
+import org.jboss.dna.repository.DnaConfigurationException;
+import org.jboss.dna.repository.Configurator.ChooseClass;
+import org.jboss.dna.repository.Configurator.ConfigRepositoryDetails;
+import org.jboss.dna.repository.Configurator.MimeTypeDetectorDetails;
+import org.jboss.dna.repository.Configurator.RepositoryDetails;
+
+/**
+ * A configuration builder for a {@link JcrEngine}. This class is an internal domain-specific language (DSL),
+ * and is designed to be used in a traditional way or in a method-chained manner:
+ * <pre>
+ * configuration.addRepository("Source1").usingClass(InMemoryRepositorySource.class).describedAs("description");
+ * configuration.addMimeTypeDetector("detector")
+ * .usingClass(ExtensionBasedMimeTypeDetector.class)
+ * .describedAs("default detector");
+ * configuration.addSequencer("MicrosoftDocs")
+ * .usingClass("org.jboss.dna.sequencer.msoffice.MSOfficeMetadataSequencer")
+ * .loadedFromClasspath()
+ * .named("Microsoft Document sequencer")
+ * .describedAs("Our primary sequencer for all .doc files")
+ * .sequencingFrom("/public//(*.(doc|xml|ppt)[*]/jcr:content[@jcr:data]")
+ * .andOutputtingTo("/documents/$1");
+ * configuration.save();
+ * </pre>
+ */
+public class JcrConfiguration
+ implements Configurator.Initializer<JcrConfiguration>, /*Configurator.SequencerConfigurator<JcrConfiguration>,*/
+ Configurator.RepositoryConfigurator<JcrConfiguration>, Configurator.MimeDetectorConfigurator<JcrConfiguration>,
+ Configurator.Builder<JcrEngine> {
+
+ private final DnaConfiguration.Builder<JcrConfiguration> builder;
+
+ /**
+ * Create a new configuration for DNA.
+ */
+ public JcrConfiguration() {
+ this(new ExecutionContext());
+ }
+
+ /**
+ * Specify a new {@link ExecutionContext} that should be used for this DNA instance.
+ *
+ * @param context the new context, or null if a default-constructed execution context should be used
+ * @throws IllegalArgumentException if the supplied context reference is null
+ */
+ public JcrConfiguration( ExecutionContext context ) {
+ this.builder = new DnaConfiguration.Builder<JcrConfiguration>(context, this);
+ }
+
+ /**
+ * Get the execution context used by this configurator.
+ *
+ * @return the execution context; never null
+ */
+ public final ExecutionContext getExecutionContext() {
+ return builder.getExecutionContext();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.Initializer#withConfigurationRepository()
+ */
+ public ChooseClass<RepositorySource, ConfigRepositoryDetails<JcrConfiguration>> withConfigurationRepository() {
+ return builder.withConfigurationRepository();
+ }
+
+// /**
+// * {@inheritDoc}
+// *
+// * @see org.jboss.dna.repository.Configurator.SequencerConfigurator#addSequencer(java.lang.String)
+// */
+// public ChooseClass<Sequencer, SequencerDetails<JcrConfiguration>> addSequencer( String id ) {
+// CheckArg.isNotEmpty(id, "id");
+// return builder.addSequencer(id);
+// }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.RepositoryConfigurator#addRepository(java.lang.String)
+ */
+ public ChooseClass<RepositorySource, RepositoryDetails<JcrConfiguration>> addRepository( String id ) {
+ CheckArg.isNotEmpty(id, "id");
+ return builder.addRepository(id);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.RepositoryConfigurator#addRepository(org.jboss.dna.graph.connector.RepositorySource)
+ */
+ public JcrConfiguration addRepository( RepositorySource source ) {
+ CheckArg.isNotNull(source, "source");
+ CheckArg.isNotEmpty(source.getName(), "source.getName()");
+ return builder.addRepository(source);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.MimeDetectorConfigurator#addMimeTypeDetector(java.lang.String)
+ */
+ public ChooseClass<MimeTypeDetector, MimeTypeDetectorDetails<JcrConfiguration>> addMimeTypeDetector( String id ) {
+ CheckArg.isNotEmpty(id, "id");
+ return builder.addMimeTypeDetector(id);
+ }
+
+ /**
+ * Save any changes that have been made so far to the configuration. This method does nothing if no changes have been made.
+ *
+ * @return this configuration object for method chaining purposes; never null
+ */
+ public JcrConfiguration save() {
+ return builder.save();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.Builder#build()
+ */
+ public JcrEngine build() throws DnaConfigurationException {
+ save();
+ return new JcrEngine(builder.buildDnaEngine());
+ }
+}
Property changes on: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrConfiguration.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEmptyNodeIterator.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEmptyNodeIterator.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEmptyNodeIterator.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -31,7 +31,7 @@
/**
*
*/
-public class JcrEmptyNodeIterator implements NodeIterator {
+class JcrEmptyNodeIterator implements NodeIterator {
/**
* {@inheritDoc}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEmptyPropertyIterator.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEmptyPropertyIterator.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEmptyPropertyIterator.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -31,7 +31,7 @@
/**
*
*/
-public class JcrEmptyPropertyIterator implements PropertyIterator {
+class JcrEmptyPropertyIterator implements PropertyIterator {
/**
* {@inheritDoc}
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEngine.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEngine.java (rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEngine.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ *
+ * 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.jcr;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.jcr.JcrRepository.Options;
+import org.jboss.dna.repository.DnaEngine;
+import org.jboss.dna.repository.RepositoryService;
+import org.jboss.dna.repository.observation.ObservationService;
+import org.jboss.dna.repository.sequencer.SequencingService;
+
+/**
+ * The basic component that encapsulates the JBoss DNA services, including the {@link Repository} instances.
+ */
+public class JcrEngine {
+
+ private final DnaEngine dnaEngine;
+ private final Map<String, JcrRepository> repositories;
+ private final Lock repositoriesLock;
+
+ JcrEngine( DnaEngine dnaEngine ) {
+ this.dnaEngine = dnaEngine;
+ this.repositories = new HashMap<String, JcrRepository>();
+ this.repositoriesLock = new ReentrantLock();
+ }
+
+ /**
+ * Get the problems that were encountered when setting up this engine from the configuration.
+ *
+ * @return the problems, which may be empty but will never be null
+ */
+ public Problems getProblems() {
+ return dnaEngine.getProblems();
+ }
+
+ /**
+ * Get the execution context for this engine. This context can be used to create additional (perhaps narrowed) contexts.
+ *
+ * @return the engine's execution context; never null
+ */
+ public final ExecutionContext getExecutionContext() {
+ return dnaEngine.getExecutionContext();
+ }
+
+ /**
+ * Get the RepositorySource with the supplied name.
+ *
+ * @param repositoryName the name of the repository (or repository source)
+ * @return the named repository source, or null if there is no such repository
+ */
+ protected final RepositorySource getRepositorySource( String repositoryName ) {
+ return dnaEngine.getRepositorySource(repositoryName);
+ }
+
+ protected final RepositoryConnectionFactory getRepositoryConnectionFactory() {
+ return dnaEngine.getRepositoryConnectionFactory();
+ }
+
+ protected final RepositoryService getRepositoryService() {
+ return dnaEngine.getRepositoryService();
+ }
+
+ protected final ObservationService getObservationService() {
+ return dnaEngine.getObservationService();
+ }
+
+ protected final SequencingService getSequencingService() {
+ return dnaEngine.getSequencingService();
+ }
+
+ /**
+ * Get the {@link Repository} implementation for the named repository.
+ *
+ * @param repositoryName the name of the repository, which corresponds to the name of a configured {@link RepositorySource}
+ * @return the named repository instance
+ * @throws IllegalArgumentException if the repository name is null, blank or invalid
+ * @throws RepositoryException if there is no repository with the specified name
+ */
+ public final Repository getRepository( String repositoryName ) throws RepositoryException {
+ CheckArg.isNotEmpty(repositoryName, "repositoryName");
+ try {
+ repositoriesLock.lock();
+ JcrRepository repository = repositories.get(repositoryName);
+ if (repository == null) {
+ if (getRepositorySource(repositoryName) == null) {
+ // The repository name is not a valid repository ...
+ String msg = JcrI18n.repositoryDoesNotExist.text(repositoryName);
+ throw new RepositoryException(msg);
+ }
+ repository = doCreateJcrRepository(repositoryName);
+ repositories.put(repositoryName, repository);
+ }
+ return repository;
+ } finally {
+ repositoriesLock.unlock();
+ }
+ }
+
+ protected JcrRepository doCreateJcrRepository( String repositoryName ) {
+ RepositoryConnectionFactory connectionFactory = getRepositoryConnectionFactory();
+ Map<String, String> descriptors = null;
+ Map<Options, String> options = Collections.singletonMap(Options.PROJECT_NODE_TYPES, "false");
+ return new JcrRepository(getExecutionContext(), connectionFactory, repositoryName, descriptors, options);
+ }
+
+ /*
+ * Lifecycle methods
+ */
+
+ public void start() {
+ dnaEngine.start();
+ }
+
+ public void shutdown() {
+ dnaEngine.shutdown();
+ }
+}
Property changes on: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEngine.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -43,6 +43,7 @@
public static I18n permissionDenied;
public static I18n repositoryMustBeConfigured;
public static I18n sourceInUse;
+ public static I18n repositoryDoesNotExist;
public static I18n noNamespaceWithPrefix;
public static I18n noNamespaceWithUri;
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -27,9 +27,9 @@
import org.jboss.dna.graph.property.basic.BasicName;
/**
- * @author Randall Hauch
+ * Lexicon of names from the standard JCR "<code>http://www.jcp.org/jcr/1.0</code>" namespace.
*/
-class JcrLexicon extends org.jboss.dna.graph.JcrLexicon {
+public class JcrLexicon extends org.jboss.dna.graph.JcrLexicon {
public static final Name BASE_VERSION = new BasicName(Namespace.URI, "baseVersion");
public static final Name CONTENT = new BasicName(Namespace.URI, "content");
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMixLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMixLexicon.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMixLexicon.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -1,5 +1,31 @@
+/*
+ * 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.jcr;
+/**
+ * Lexicon of names from the standard JCR "<code>http://www.jcp.org/jcr/mix/1.0</code>" namespace.
+ */
public class JcrMixLexicon extends org.jboss.dna.graph.JcrMixLexicon {
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -40,7 +40,7 @@
import org.jboss.dna.graph.property.Property;
/**
- * @author jverhaeg
+ *
*/
@NotThreadSafe
final class JcrMultiValueProperty extends AbstractJcrProperty {
@@ -222,7 +222,7 @@
} else {
jcrValues = EMPTY_VALUES;
}
-
+
cache.getEditorFor(propertyId.getNodeId()).setProperty(propertyId.getPropertyName(), jcrValues, PropertyType.STRING);
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -30,7 +30,7 @@
import net.jcip.annotations.NotThreadSafe;
/**
- * @author jverhaeg
+ *
*/
@NotThreadSafe
final class JcrNode extends AbstractJcrNode {
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNtLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNtLexicon.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNtLexicon.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -26,6 +26,9 @@
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.basic.BasicName;
+/**
+ * Lexicon of names from the standard JCR "<code>http://www.jcp.org/jcr/nt/1.0</code>" namespace.
+ */
public class JcrNtLexicon extends org.jboss.dna.graph.JcrNtLexicon {
public static final Name FROZEN_NODE = new BasicName(Namespace.URI, "frozenNode");
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSingleValueProperty.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSingleValueProperty.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSingleValueProperty.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -39,7 +39,7 @@
import org.jboss.dna.graph.property.ValueFactories;
/**
- * @author jverhaeg
+ *
*/
final class JcrSingleValueProperty extends AbstractJcrProperty {
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSvLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSvLexicon.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSvLexicon.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -27,7 +27,7 @@
import org.jboss.dna.graph.property.basic.BasicName;
/**
- *
+ * Lexicon of names from the standard JCR "<code>http://www.jcp.org/jcr/sv/1.0</code>" namespace.
*/
public class JcrSvLexicon {
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrValue.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrValue.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrValue.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -45,7 +45,7 @@
import org.jboss.dna.graph.property.ValueFactories;
/**
- * @author jverhaeg
+ *
*/
@NotThreadSafe
final class JcrValue implements Value {
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -68,8 +68,7 @@
import org.xml.sax.helpers.XMLReaderFactory;
/**
- * @author John Verhaeg
- * @author Randall Hauch
+ *
*/
@NotThreadSafe
final class JcrWorkspace implements Workspace {
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -1,201 +0,0 @@
-/*
- * 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.
- *
- * 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.jcr;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.NameFactory;
-import org.jboss.dna.graph.property.ValueFormatException;
-
-/**
- * An immutable identifier for a node definition. Although instances can be serialized, the node definitions are often stored
- * within the graph as {@link #getString() string values} on a property. These string values can later be
- * {@link #fromString(String, NameFactory) parsed} to reconstruct the identifier. Note that this string representation does not
- * use namespace prefixes, so they are long-lasting and durable.
- * <p>
- * What distinguishes one property definition from another is not well documented in the JSR-170 specification. The closest this
- * version of the spec gets is Section 6.7.15, but that merely says that more than one property definition can have the same name.
- * The proposed draft of the JSR-283 specification does clarify this more: Section 4.7.15 says :
- * </p>
- * <p>
- * <quote>"Similarly, a node type may have two or more child node definitions with identical name attributes as long as they are
- * distinguishable by the required primary types attribute (the value returned by
- * NodeDefinition.getRequiredPrimaryTypes)."</quote>
- * </p>
- * <p>
- * This class is {@link Serializable} and designed to be used as a key in a {@link HashMap}.
- * </p>
- */
-@Immutable
-public final class NodeDefinitionId implements Serializable {
-
- /**
- * Current version is {@value} .
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * The string-form of the name that can be used to represent a residual property definition.
- */
- public static final String ANY_NAME = JcrNodeType.RESIDUAL_ITEM_NAME;
-
- private final Name nodeTypeName;
- private final Name childDefinitionName;
- private final Name[] requiredPrimaryTypes;
- /**
- * A cached string representation, which is used for {@link #equals(Object)} and {@link #hashCode()} among other things.
- */
- private final String stringRepresentation;
-
- /**
- * Create an identifier for a node definition.
- *
- * @param nodeTypeName the name of the node type on which this child node definition is defined; may not be null
- * @param childDefinitionName the name of the child node definition, which may be a {@link #ANY_NAME residual child
- * definition}; may not be null
- * @param requiredPrimaryTypes the names of the required primary types for the child node definition
- */
- public NodeDefinitionId( Name nodeTypeName,
- Name childDefinitionName,
- Name[] requiredPrimaryTypes ) {
- assert nodeTypeName != null;
- assert childDefinitionName != null;
- this.nodeTypeName = nodeTypeName;
- this.childDefinitionName = childDefinitionName;
- this.requiredPrimaryTypes = requiredPrimaryTypes;
- StringBuilder sb = new StringBuilder(this.nodeTypeName.getString());
- sb.append('/').append(this.childDefinitionName.getString());
- for (Name requiredPrimaryType : requiredPrimaryTypes) {
- sb.append('/');
- sb.append(requiredPrimaryType.getString());
- }
- this.stringRepresentation = sb.toString();
- }
-
- /**
- * Get the name of the node type on which the child node definition is defined.
- *
- * @return the node type's name; never null
- */
- public Name getNodeTypeName() {
- return nodeTypeName;
- }
-
- /**
- * Get the name of the child definition.
- *
- * @return the child definition's name; never null
- */
- public Name getChildDefinitionName() {
- return childDefinitionName;
- }
-
- /**
- * @return requiredPrimaryTypes
- */
- public Name[] getRequiredPrimaryTypes() {
- Name[] copy = new Name[requiredPrimaryTypes.length];
- System.arraycopy(requiredPrimaryTypes, 0, copy, 0, requiredPrimaryTypes.length);
- return copy;
- }
-
- /**
- * Determine whether this node definition defines any named child.
- *
- * @return true if this node definition allows children with any name, or false if this definition requires a particular child
- * name
- */
- public boolean allowsAnyChildName() {
- return childDefinitionName.getLocalName().equals(ANY_NAME) && childDefinitionName.getNamespaceUri().length() == 0;
- }
-
- /**
- * Get the string form of this identifier. This form can be persisted, since it does not rely upon namespace prefixes.
- *
- * @return the string form
- */
- public String getString() {
- return this.stringRepresentation;
- }
-
- /**
- * Parse the supplied string for of an identifer, and return the object form for that identifier.
- *
- * @param definition the {@link #getString() string form of the identifier}; may not be null
- * @param factory the factory that should be used to create Name objects; may not be null
- * @return the object form of the identifier; never null
- * @throws ValueFormatException if the definition is not the valid format
- */
- public static NodeDefinitionId fromString( String definition,
- NameFactory factory ) {
- String[] parts = definition.split("/");
- String nodeTypeNameString = parts[0];
- String childDefinitionNameString = parts[1];
- Name[] requiredPrimaryTypes = new Name[parts.length - 2];
- for (int i = 2, j = 0; i != parts.length; ++i, ++j) {
- requiredPrimaryTypes[j] = factory.create(parts[i]);
- }
- Name nodeTypeName = factory.create(nodeTypeNameString);
- Name childDefinitionName = factory.create(childDefinitionNameString);
- return new NodeDefinitionId(nodeTypeName, childDefinitionName, requiredPrimaryTypes);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- return stringRepresentation.hashCode();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals( Object obj ) {
- if (obj == this) return true;
- if (obj instanceof NodeDefinitionId) {
- NodeDefinitionId that = (NodeDefinitionId)obj;
- return this.stringRepresentation.equals(that.stringRepresentation);
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return this.stringRepresentation;
- }
-
-}
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java (rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/NodeDefinitionId.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ *
+ * 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.jcr;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NameFactory;
+import org.jboss.dna.graph.property.ValueFormatException;
+
+/**
+ * An immutable identifier for a node definition. Although instances can be serialized, the node definitions are often stored
+ * within the graph as {@link #getString() string values} on a property. These string values can later be
+ * {@link #fromString(String, NameFactory) parsed} to reconstruct the identifier. Note that this string representation does not
+ * use namespace prefixes, so they are long-lasting and durable.
+ * <p>
+ * What distinguishes one property definition from another is not well documented in the JSR-170 specification. The closest this
+ * version of the spec gets is Section 6.7.15, but that merely says that more than one property definition can have the same name.
+ * The proposed draft of the JSR-283 specification does clarify this more: Section 4.7.15 says :
+ * </p>
+ * <p>
+ * <quote>"Similarly, a node type may have two or more child node definitions with identical name attributes as long as they are
+ * distinguishable by the required primary types attribute (the value returned by
+ * NodeDefinition.getRequiredPrimaryTypes)."</quote>
+ * </p>
+ * <p>
+ * This class is {@link Serializable} and designed to be used as a key in a {@link HashMap}.
+ * </p>
+ */
+@Immutable
+public final class NodeDefinitionId implements Serializable {
+
+ /**
+ * Current version is {@value} .
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The string-form of the name that can be used to represent a residual property definition.
+ */
+ public static final String ANY_NAME = JcrNodeType.RESIDUAL_ITEM_NAME;
+
+ private final Name nodeTypeName;
+ private final Name childDefinitionName;
+ private final Name[] requiredPrimaryTypes;
+ /**
+ * A cached string representation, which is used for {@link #equals(Object)} and {@link #hashCode()} among other things.
+ */
+ private final String stringRepresentation;
+
+ /**
+ * Create an identifier for a node definition.
+ *
+ * @param nodeTypeName the name of the node type on which this child node definition is defined; may not be null
+ * @param childDefinitionName the name of the child node definition, which may be a {@link #ANY_NAME residual child
+ * definition}; may not be null
+ * @param requiredPrimaryTypes the names of the required primary types for the child node definition
+ */
+ public NodeDefinitionId( Name nodeTypeName,
+ Name childDefinitionName,
+ Name[] requiredPrimaryTypes ) {
+ assert nodeTypeName != null;
+ assert childDefinitionName != null;
+ this.nodeTypeName = nodeTypeName;
+ this.childDefinitionName = childDefinitionName;
+ this.requiredPrimaryTypes = requiredPrimaryTypes;
+ StringBuilder sb = new StringBuilder(this.nodeTypeName.getString());
+ sb.append('/').append(this.childDefinitionName.getString());
+ for (Name requiredPrimaryType : requiredPrimaryTypes) {
+ sb.append('/');
+ sb.append(requiredPrimaryType.getString());
+ }
+ this.stringRepresentation = sb.toString();
+ }
+
+ /**
+ * Get the name of the node type on which the child node definition is defined.
+ *
+ * @return the node type's name; never null
+ */
+ public Name getNodeTypeName() {
+ return nodeTypeName;
+ }
+
+ /**
+ * Get the name of the child definition.
+ *
+ * @return the child definition's name; never null
+ */
+ public Name getChildDefinitionName() {
+ return childDefinitionName;
+ }
+
+ /**
+ * @return requiredPrimaryTypes
+ */
+ public Name[] getRequiredPrimaryTypes() {
+ Name[] copy = new Name[requiredPrimaryTypes.length];
+ System.arraycopy(requiredPrimaryTypes, 0, copy, 0, requiredPrimaryTypes.length);
+ return copy;
+ }
+
+ /**
+ * Determine whether this node definition defines any named child.
+ *
+ * @return true if this node definition allows children with any name, or false if this definition requires a particular child
+ * name
+ */
+ public boolean allowsAnyChildName() {
+ return childDefinitionName.getLocalName().equals(ANY_NAME) && childDefinitionName.getNamespaceUri().length() == 0;
+ }
+
+ /**
+ * Get the string form of this identifier. This form can be persisted, since it does not rely upon namespace prefixes.
+ *
+ * @return the string form
+ */
+ public String getString() {
+ return this.stringRepresentation;
+ }
+
+ /**
+ * Parse the supplied string for of an identifer, and return the object form for that identifier.
+ *
+ * @param definition the {@link #getString() string form of the identifier}; may not be null
+ * @param factory the factory that should be used to create Name objects; may not be null
+ * @return the object form of the identifier; never null
+ * @throws ValueFormatException if the definition is not the valid format
+ */
+ public static NodeDefinitionId fromString( String definition,
+ NameFactory factory ) {
+ String[] parts = definition.split("/");
+ String nodeTypeNameString = parts[0];
+ String childDefinitionNameString = parts[1];
+ Name[] requiredPrimaryTypes = new Name[parts.length - 2];
+ for (int i = 2, j = 0; i != parts.length; ++i, ++j) {
+ requiredPrimaryTypes[j] = factory.create(parts[i]);
+ }
+ Name nodeTypeName = factory.create(nodeTypeNameString);
+ Name childDefinitionName = factory.create(childDefinitionNameString);
+ return new NodeDefinitionId(nodeTypeName, childDefinitionName, requiredPrimaryTypes);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return stringRepresentation.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof NodeDefinitionId) {
+ NodeDefinitionId that = (NodeDefinitionId)obj;
+ return this.stringRepresentation.equals(that.stringRepresentation);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.stringRepresentation;
+ }
+
+}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/OnParentVersionBehavior.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/OnParentVersionBehavior.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/OnParentVersionBehavior.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -28,7 +28,7 @@
/**
* Enumeration of possible behaviors for on-parent-version setting of properties and child nodes in JCR specification.
*/
-public enum OnParentVersionBehavior {
+enum OnParentVersionBehavior {
/** @see OnParentVersionAction#ABORT */
ABORT(OnParentVersionAction.ABORT, OnParentVersionAction.ACTIONNAME_ABORT),
/** @see OnParentVersionAction#COMPUTE */
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -1,216 +0,0 @@
-/*
- * 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.
- *
- * 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.jcr;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import javax.jcr.PropertyType;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.NameFactory;
-import org.jboss.dna.graph.property.ValueFormatException;
-
-/**
- * An immutable identifier for a property definition. Although instances can be serialized, the property definitions are often
- * stored within the graph as {@link #getString() string values} on a property. These string values can later be
- * {@link #fromString(String, NameFactory) parsed} to reconstruct the identifier. Note that this string representation does not
- * use namespace prefixes, so they are long-lasting and durable.
- * <p>
- * What distinguishes one property definition from another is not well documented in the JSR-170 specification. The closest this
- * version of the spec gets is Section 6.7.15, but that merely says that more than one property definition can have the same name.
- * The proposed draft of the JSR-283 specification does clarify this more: Section 4.7.15 says :
- * </p>
- * <p>
- * <quote>"A node type may have two or more property definitions with identical name attributes (the value returned by
- * ItemDefinition.getName) as long as the definitions are otherwise distinguishable by either the required type attribute (the
- * value returned by PropertyDefinition.getRequiredType) or the multiple attribute (the value returned by
- * PropertyDefinition.isMultiple)."</quote>
- * </p>
- * <p>
- * This class is {@link Serializable} and designed to be used as a key in a {@link HashMap}.
- * </p>
- */
-@Immutable
-public final class PropertyDefinitionId implements Serializable {
-
- /**
- * Current version is {@value} .
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * The string-form of the name that can be used to represent a residual property definition.
- */
- public static final String ANY_NAME = JcrNodeType.RESIDUAL_ITEM_NAME;
-
- private final Name nodeTypeName;
- private final Name propertyDefinitionName;
- private final int propertyType;
- private final boolean allowsMultiple;
- /**
- * A cached string representation, which is used for {@link #equals(Object)} and {@link #hashCode()} among other things.
- */
- private final String stringRepresentation;
-
- /**
- * Create a new identifier for a property definition.
- *
- * @param nodeTypeName the name of the node type; may not be null
- * @param propertyDefinitionName the name of the property definition, which may be a {@link #ANY_NAME residual property}; may
- * not be null
- * @param propertyType the required property type for the definition; must be a valid {@link PropertyType} value
- * @param allowsMultiple true if the property definition should allow multiple values, or false if it is a single-value
- * property definition
- */
- public PropertyDefinitionId( Name nodeTypeName,
- Name propertyDefinitionName,
- int propertyType,
- boolean allowsMultiple ) {
- this.nodeTypeName = nodeTypeName;
- this.propertyDefinitionName = propertyDefinitionName;
- this.propertyType = propertyType;
- this.allowsMultiple = allowsMultiple;
- this.stringRepresentation = this.nodeTypeName.getString() + '/' + this.propertyDefinitionName.getString() + '/'
- + PropertyType.nameFromValue(propertyType) + '/' + (allowsMultiple ? '*' : '1');
- }
-
- /**
- * Get the name of the node type on which the property definition is defined
- *
- * @return the node type's name; may not be null
- */
- public Name getNodeTypeName() {
- return nodeTypeName;
- }
-
- /**
- * Get the name of the property definition.
- *
- * @return the property definition's name; never null
- */
- public Name getPropertyDefinitionName() {
- return propertyDefinitionName;
- }
-
- /**
- * Get the required property type
- *
- * @return the property type; always a valid {@link PropertyType} value
- */
- public int getPropertyType() {
- return propertyType;
- }
-
- /**
- * Return whether the property definition allows multiple values.
- *
- * @return true if the property definition allows multiple values, or false if it is a single-value property definition
- */
- public boolean allowsMultiple() {
- return allowsMultiple;
- }
-
- /**
- * Determine whether this property definition allows properties with any name.
- *
- * @return true if this node definition allows properties with any name, or false if this definition requires a particular
- * property name
- */
- public boolean allowsAnyChildName() {
- return propertyDefinitionName.getLocalName().equals(ANY_NAME) && propertyDefinitionName.getNamespaceUri().length() == 0;
- }
-
- /**
- * Get the string form of this identifier. This form can be persisted, since it does not rely upon namespace prefixes.
- *
- * @return the string form
- */
- public String getString() {
- return this.stringRepresentation;
- }
-
- /**
- * Parse the supplied string for of an identifer, and return the object form for that identifier.
- *
- * @param definition the {@link #getString() string form of the identifier}; may not be null
- * @param factory the factory that should be used to create Name objects; may not be null
- * @return the object form of the identifier; never null
- * @throws ValueFormatException if the definition is not the valid format
- */
- public static PropertyDefinitionId fromString( String definition,
- NameFactory factory ) {
- String[] parts = definition.split("/");
- String nodeTypeNameString = parts[0];
- String propertyDefinitionNameString = parts[1];
- Name nodeTypeName = factory.create(nodeTypeNameString);
- Name propertyDefinitionName = factory.create(propertyDefinitionNameString);
- int propertyType = PropertyType.valueFromName(parts[2]);
- boolean allowsMultiple = parts[3].charAt(0) == '*';
- return new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, propertyType, allowsMultiple);
- }
-
- public PropertyDefinitionId asSingleValued() {
- return new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, propertyType, false);
- }
-
- public PropertyDefinitionId asMultiValued() {
- return new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, propertyType, true);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- return this.stringRepresentation.hashCode();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals( Object obj ) {
- if (obj == this) return true;
- if (obj instanceof PropertyDefinitionId) {
- PropertyDefinitionId that = (PropertyDefinitionId)obj;
- return this.stringRepresentation.equals(that.stringRepresentation);
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return this.stringRepresentation;
- }
-
-}
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java (rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -0,0 +1,216 @@
+/*
+ * 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.
+ *
+ * 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.jcr;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import javax.jcr.PropertyType;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NameFactory;
+import org.jboss.dna.graph.property.ValueFormatException;
+
+/**
+ * An immutable identifier for a property definition. Although instances can be serialized, the property definitions are often
+ * stored within the graph as {@link #getString() string values} on a property. These string values can later be
+ * {@link #fromString(String, NameFactory) parsed} to reconstruct the identifier. Note that this string representation does not
+ * use namespace prefixes, so they are long-lasting and durable.
+ * <p>
+ * What distinguishes one property definition from another is not well documented in the JSR-170 specification. The closest this
+ * version of the spec gets is Section 6.7.15, but that merely says that more than one property definition can have the same name.
+ * The proposed draft of the JSR-283 specification does clarify this more: Section 4.7.15 says :
+ * </p>
+ * <p>
+ * <quote>"A node type may have two or more property definitions with identical name attributes (the value returned by
+ * ItemDefinition.getName) as long as the definitions are otherwise distinguishable by either the required type attribute (the
+ * value returned by PropertyDefinition.getRequiredType) or the multiple attribute (the value returned by
+ * PropertyDefinition.isMultiple)."</quote>
+ * </p>
+ * <p>
+ * This class is {@link Serializable} and designed to be used as a key in a {@link HashMap}.
+ * </p>
+ */
+@Immutable
+public final class PropertyDefinitionId implements Serializable {
+
+ /**
+ * Current version is {@value} .
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The string-form of the name that can be used to represent a residual property definition.
+ */
+ public static final String ANY_NAME = JcrNodeType.RESIDUAL_ITEM_NAME;
+
+ private final Name nodeTypeName;
+ private final Name propertyDefinitionName;
+ private final int propertyType;
+ private final boolean allowsMultiple;
+ /**
+ * A cached string representation, which is used for {@link #equals(Object)} and {@link #hashCode()} among other things.
+ */
+ private final String stringRepresentation;
+
+ /**
+ * Create a new identifier for a property definition.
+ *
+ * @param nodeTypeName the name of the node type; may not be null
+ * @param propertyDefinitionName the name of the property definition, which may be a {@link #ANY_NAME residual property}; may
+ * not be null
+ * @param propertyType the required property type for the definition; must be a valid {@link PropertyType} value
+ * @param allowsMultiple true if the property definition should allow multiple values, or false if it is a single-value
+ * property definition
+ */
+ public PropertyDefinitionId( Name nodeTypeName,
+ Name propertyDefinitionName,
+ int propertyType,
+ boolean allowsMultiple ) {
+ this.nodeTypeName = nodeTypeName;
+ this.propertyDefinitionName = propertyDefinitionName;
+ this.propertyType = propertyType;
+ this.allowsMultiple = allowsMultiple;
+ this.stringRepresentation = this.nodeTypeName.getString() + '/' + this.propertyDefinitionName.getString() + '/'
+ + PropertyType.nameFromValue(propertyType) + '/' + (allowsMultiple ? '*' : '1');
+ }
+
+ /**
+ * Get the name of the node type on which the property definition is defined
+ *
+ * @return the node type's name; may not be null
+ */
+ public Name getNodeTypeName() {
+ return nodeTypeName;
+ }
+
+ /**
+ * Get the name of the property definition.
+ *
+ * @return the property definition's name; never null
+ */
+ public Name getPropertyDefinitionName() {
+ return propertyDefinitionName;
+ }
+
+ /**
+ * Get the required property type
+ *
+ * @return the property type; always a valid {@link PropertyType} value
+ */
+ public int getPropertyType() {
+ return propertyType;
+ }
+
+ /**
+ * Return whether the property definition allows multiple values.
+ *
+ * @return true if the property definition allows multiple values, or false if it is a single-value property definition
+ */
+ public boolean allowsMultiple() {
+ return allowsMultiple;
+ }
+
+ /**
+ * Determine whether this property definition allows properties with any name.
+ *
+ * @return true if this node definition allows properties with any name, or false if this definition requires a particular
+ * property name
+ */
+ public boolean allowsAnyChildName() {
+ return propertyDefinitionName.getLocalName().equals(ANY_NAME) && propertyDefinitionName.getNamespaceUri().length() == 0;
+ }
+
+ /**
+ * Get the string form of this identifier. This form can be persisted, since it does not rely upon namespace prefixes.
+ *
+ * @return the string form
+ */
+ public String getString() {
+ return this.stringRepresentation;
+ }
+
+ /**
+ * Parse the supplied string for of an identifer, and return the object form for that identifier.
+ *
+ * @param definition the {@link #getString() string form of the identifier}; may not be null
+ * @param factory the factory that should be used to create Name objects; may not be null
+ * @return the object form of the identifier; never null
+ * @throws ValueFormatException if the definition is not the valid format
+ */
+ public static PropertyDefinitionId fromString( String definition,
+ NameFactory factory ) {
+ String[] parts = definition.split("/");
+ String nodeTypeNameString = parts[0];
+ String propertyDefinitionNameString = parts[1];
+ Name nodeTypeName = factory.create(nodeTypeNameString);
+ Name propertyDefinitionName = factory.create(propertyDefinitionNameString);
+ int propertyType = PropertyType.valueFromName(parts[2]);
+ boolean allowsMultiple = parts[3].charAt(0) == '*';
+ return new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, propertyType, allowsMultiple);
+ }
+
+ public PropertyDefinitionId asSingleValued() {
+ return new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, propertyType, false);
+ }
+
+ public PropertyDefinitionId asMultiValued() {
+ return new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, propertyType, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return this.stringRepresentation.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof PropertyDefinitionId) {
+ PropertyDefinitionId that = (PropertyDefinitionId)obj;
+ return this.stringRepresentation.equals(that.stringRepresentation);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.stringRepresentation;
+ }
+
+}
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -1,111 +0,0 @@
-/*
- * 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.
- *
- * 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.jcr;
-
-import java.util.UUID;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.common.util.HashCode;
-import org.jboss.dna.graph.property.Name;
-
-/**
- * An immutable identifier for a property, often used to reference information a property held within the {@link SessionCache}.
- */
-@Immutable
-public final class PropertyId {
-
- private final UUID nodeId;
- private final Name propertyName;
- private final int hc;
-
- /**
- * Create a new property identifier.
- *
- * @param nodeId the UUID of the node that owns the property being reference; may not be null
- * @param propertyName the name of the property being referenced; may not be null
- */
- public PropertyId( UUID nodeId,
- Name propertyName ) {
- assert nodeId != null;
- assert propertyName != null;
- this.nodeId = nodeId;
- this.propertyName = propertyName;
- this.hc = HashCode.compute(this.nodeId, this.propertyName);
- }
-
- /**
- * Get the UUID of the node that owns the property.
- *
- * @return the node's UUID; never null
- */
- public UUID getNodeId() {
- return nodeId;
- }
-
- /**
- * Get the name of the property.
- *
- * @return the property name; never null
- */
- public Name getPropertyName() {
- return propertyName;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- return hc;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals( Object obj ) {
- if (obj == this) return true;
- if (obj instanceof PropertyId) {
- PropertyId that = (PropertyId)obj;
- if (this.hc != that.hc) return false;
- if (!this.nodeId.equals(that.nodeId)) return false;
- return this.propertyName.equals(that.propertyName);
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return this.nodeId.toString() + '@' + this.propertyName.toString();
- }
-
-}
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java (rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ *
+ * 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.jcr;
+
+import java.util.UUID;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.Name;
+
+/**
+ * An immutable identifier for a property, often used to reference information a property held within the {@link SessionCache}.
+ */
+@Immutable
+public final class PropertyId {
+
+ private final UUID nodeId;
+ private final Name propertyName;
+ private final int hc;
+
+ /**
+ * Create a new property identifier.
+ *
+ * @param nodeId the UUID of the node that owns the property being reference; may not be null
+ * @param propertyName the name of the property being referenced; may not be null
+ */
+ public PropertyId( UUID nodeId,
+ Name propertyName ) {
+ assert nodeId != null;
+ assert propertyName != null;
+ this.nodeId = nodeId;
+ this.propertyName = propertyName;
+ this.hc = HashCode.compute(this.nodeId, this.propertyName);
+ }
+
+ /**
+ * Get the UUID of the node that owns the property.
+ *
+ * @return the node's UUID; never null
+ */
+ public UUID getNodeId() {
+ return nodeId;
+ }
+
+ /**
+ * Get the name of the property.
+ *
+ * @return the property name; never null
+ */
+ public Name getPropertyName() {
+ return propertyName;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof PropertyId) {
+ PropertyId that = (PropertyId)obj;
+ if (this.hc != that.hc) return false;
+ if (!this.nodeId.equals(that.nodeId)) return false;
+ return this.propertyName.equals(that.propertyName);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.nodeId.toString() + '@' + this.propertyName.toString();
+ }
+
+}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SelfClosingInputStream.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SelfClosingInputStream.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SelfClosingInputStream.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -40,7 +40,7 @@
* </p>
*/
@NotThreadSafe
-public class SelfClosingInputStream extends InputStream {
+class SelfClosingInputStream extends InputStream {
private final Binary binary;
private final InputStream stream;
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -121,7 +121,7 @@
* </p>
*/
@ThreadSafe
-public class SessionCache {
+class SessionCache {
/**
* Hidden flag that controls whether properties that appear on DNA nodes but not allowed by the node type or mixins should be
Modified: trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
===================================================================
--- trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-04-30 15:31:52 UTC (rev 867)
@@ -32,7 +32,8 @@
pathNotFoundRelativeTo = No item exists at path {0} relative to {1} in workspace "{2}"
permissionDenied = Permission denied to perform actions "{1}" on path {0}.
repositoryMustBeConfigured = DNA repositories must be configured with either a repository source factory or a repository source.
-sourceInUse = All sessions must end before a new repository source can be set.
+sourceInUse = All sessions must end before a new repository source can be set
+repositoryDoesNotExist = There is no repository named "{0}"
noNamespaceWithPrefix = There is no namespace with prefix "{0}"
noNamespaceWithUri = There is no namespace with URI "{0}"
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/Configurator.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/Configurator.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/Configurator.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -0,0 +1,1051 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * 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.
+ *
+ * This software 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.repository;
+
+import java.util.ArrayList;
+import java.util.List;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.component.ClassLoaderFactory;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.text.Inflector;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.Reflection;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+import org.jboss.dna.graph.mimetype.MimeTypeDetector;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathExpression;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.ValueFormatException;
+import org.jboss.dna.graph.property.basic.RootPath;
+import org.jboss.dna.repository.sequencer.Sequencer;
+
+/**
+ * @param <BuilderType>
+ */
+public abstract class Configurator<BuilderType> {
+
+ /**
+ * Interface used to configure a sequencer.
+ *
+ * @param <ReturnType> the type of interface to return after the sequencer's configuration is completed
+ */
+ public interface SequencerConfigurator<ReturnType> {
+
+ /**
+ * Add a new {@link Sequencer sequencer} to this configuration. The new sequencer will have the supplied name, and if the
+ * name of an existing sequencer is used, this will replace the existing sequencer configuration.
+ *
+ * @param id the identifier of the new sequencer
+ * @return the interface for choosing the class, which returns the interface used to configure the sequencer; never null
+ * @throws IllegalArgumentException if the sequencer name is null, empty, or otherwise invalid
+ */
+ public ChooseClass<Sequencer, SequencerDetails<ReturnType>> addSequencer( final String id );
+ }
+
+ /**
+ * Interface used to initialize the configurator to use a specific repository containing configuration information.
+ *
+ * @param <ReturnType> the configurator type returned after the configuration repository is defined
+ */
+ public interface Initializer<ReturnType> {
+ /**
+ * Specify that this configuration should use a particular {@link RepositorySource} for its configuration repository. By
+ * default each configuration uses an internal transient repository for its configuration, but using this method will make
+ * the configuration use a different repository (that is perhaps shared with other processes).
+ *
+ * @return the interface for choosing the class, which returns the interface used to configure the repository source that
+ * will be used for the configuration repository; never null
+ */
+ public ChooseClass<RepositorySource, ConfigRepositoryDetails<ReturnType>> withConfigurationRepository();
+ }
+
+ /**
+ * Interface used to configure a repository source.
+ *
+ * @param <ReturnType> the type of interface to return after the repository source's configuration is completed
+ */
+ public interface RepositoryConfigurator<ReturnType> {
+ /**
+ * Add a new {@link RepositorySource repository} for this configuration. The new repository will have the supplied name,
+ * and if the name of an existing repository is used, this will replace the existing repository configuration.
+ *
+ * @param id the id of the new repository that is to be added
+ * @return the interface for choosing the class, which returns the interface used to configure the repository source;
+ * never null
+ * @throws IllegalArgumentException if the repository name is null, empty, or otherwise invalid
+ * @see #addRepository(RepositorySource)
+ */
+ public ChooseClass<RepositorySource, RepositoryDetails<ReturnType>> addRepository( final String id );
+
+ /**
+ * Add a new {@link RepositorySource repository} for this configuration. The new repository will have the supplied name,
+ * and if the name of an existing repository is used, this will replace the existing repository configuration.
+ *
+ * @param source the {@link RepositorySource} instance that should be used
+ * @return this configuration object, for method-chaining purposes
+ * @throws IllegalArgumentException if the repository source reference is null
+ * @see #addRepository(String)
+ */
+ public ReturnType addRepository( RepositorySource source );
+ }
+
+ /**
+ * Interface used to configure a MIME type detector.
+ *
+ * @param <ReturnType> the type of interface to return after the detector's configuration is completed
+ */
+ public interface MimeDetectorConfigurator<ReturnType> {
+ /**
+ * Add a new {@link MimeTypeDetector MIME type detector} to this configuration. The new detector will have the supplied
+ * name, and if the name of an existing detector is used, this will replace the existing detector configuration.
+ *
+ * @param id the id of the new detector
+ * @return the interface for choosing the class, which returns the interface used to configure the detector; never null
+ * @throws IllegalArgumentException if the detector name is null, empty, or otherwise invalid
+ */
+ public ChooseClass<MimeTypeDetector, MimeTypeDetectorDetails<ReturnType>> addMimeTypeDetector( final String id );
+ }
+
+ /**
+ * Interface used to build the configured component.
+ *
+ * @param <ReturnType> the type of component that this configuration builds
+ */
+ public interface Builder<ReturnType> {
+ /**
+ * Complete this configuration and create the corresponding engine.
+ *
+ * @return the new engine configured by this instance
+ * @throws DnaConfigurationException if the engine cannot be created from this configuration.
+ */
+ public ReturnType build() throws DnaConfigurationException;
+ }
+
+ /**
+ * Interface used to configure a {@link RepositorySource repository}.
+ *
+ * @param <ReturnType>
+ */
+ public interface RepositoryDetails<ReturnType>
+ extends SetName<RepositoryDetails<ReturnType>>, SetDescription<RepositoryDetails<ReturnType>>,
+ SetProperties<RepositoryDetails<ReturnType>>, And<ReturnType> {
+ }
+
+ /**
+ * Interface used to define the configuration repository.
+ *
+ * @param <ReturnType>
+ */
+ public interface ConfigRepositoryDetails<ReturnType>
+ extends SetDescription<ConfigRepositoryDetails<ReturnType>>, SetProperties<ConfigRepositoryDetails<ReturnType>>,
+ And<ReturnType> {
+ /**
+ * Specify the path under which the configuration content is to be found. This path is assumed to be "/" by default.
+ *
+ * @param path the path to the configuration content in the configuration source; may not be null
+ * @return this instance for method chaining purposes; never null
+ */
+ public ConfigRepositoryDetails<ReturnType> under( String path );
+ }
+
+ /**
+ * Interface used to configure a {@link Sequencer sequencer}.
+ *
+ * @param <ReturnType>
+ */
+ public interface SequencerDetails<ReturnType>
+ extends SetName<SequencerDetails<ReturnType>>, SetDescription<SequencerDetails<ReturnType>>, And<ReturnType> {
+
+ /**
+ * Specify the input {@link PathExpression path expression} represented as a string, which determines when this sequencer
+ * will be executed.
+ *
+ * @param inputPathExpression the path expression for nodes that, when they change, will be passed as an input to the
+ * sequencer
+ * @return the interface used to specify the output path expression; never null
+ */
+ PathExpressionOutput<ReturnType> sequencingFrom( String inputPathExpression );
+
+ /**
+ * Specify the input {@link PathExpression path expression}, which determines when this sequencer will be executed.
+ *
+ * @param inputPathExpression the path expression for nodes that, when they change, will be passed as an input to the
+ * sequencer
+ * @return the interface used to continue specifying the configuration of the sequencer
+ */
+ SequencerDetails<ReturnType> sequencingFrom( PathExpression inputPathExpression );
+ }
+
+ /**
+ * Interface used to specify the output path expression for a
+ * {@link Configurator.SequencerDetails#sequencingFrom(PathExpression) sequencer configuration}.
+ *
+ * @param <ReturnType>
+ */
+ public interface PathExpressionOutput<ReturnType> {
+ /**
+ * Specify the output {@link PathExpression path expression}, which determines where this sequencer's output will be
+ * placed.
+ *
+ * @param outputExpression the path expression for the location(s) where output generated by the sequencer is to be placed
+ * @return the interface used to continue specifying the configuration of the sequencer
+ */
+ SequencerDetails<ReturnType> andOutputtingTo( String outputExpression );
+ }
+
+ /**
+ * Interface used to configure a {@link MimeTypeDetector MIME type detector}.
+ *
+ * @param <ReturnType>
+ */
+ public interface MimeTypeDetectorDetails<ReturnType>
+ extends SetName<MimeTypeDetectorDetails<ReturnType>>, SetDescription<MimeTypeDetectorDetails<ReturnType>>,
+ SetProperties<MimeTypeDetectorDetails<ReturnType>>, And<ReturnType> {
+ }
+
+ /**
+ * Interface for configuring the JavaBean-style properties of an object.
+ *
+ * @param <ReturnType> the interface returned after the property has been set.
+ * @author Randall Hauch
+ */
+ public interface SetProperties<ReturnType> {
+ /**
+ * Specify the name of the JavaBean-style property that is to be set. The value may be set using the interface returned by
+ * this method.
+ *
+ * @param beanPropertyName the name of the JavaBean-style property (e.g., "retryLimit")
+ * @return the interface used to set the value for the property; never null
+ */
+ PropertySetter<ReturnType> with( String beanPropertyName );
+ }
+
+ /**
+ * The interface used to set the value for a JavaBean-style property.
+ *
+ * @param <ReturnType> the interface returned from these methods
+ * @author Randall Hauch
+ * @see Configurator.SetProperties#with(String)
+ */
+ public interface PropertySetter<ReturnType> {
+ /**
+ * Set the property value to an integer.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( int value );
+
+ /**
+ * Set the property value to a long number.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( long value );
+
+ /**
+ * Set the property value to a short.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( short value );
+
+ /**
+ * Set the property value to a boolean.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( boolean value );
+
+ /**
+ * Set the property value to a float.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( float value );
+
+ /**
+ * Set the property value to a double.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( double value );
+
+ /**
+ * Set the property value to a string.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( String value );
+
+ /**
+ * Set the property value to an object.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( Object value );
+ }
+
+ /**
+ * The interface used to configure the class used for a component.
+ *
+ * @param <ComponentClassType> the class or interface that the component is to implement
+ * @param <ReturnType> the interface returned from these methods
+ */
+ public interface ChooseClass<ComponentClassType, ReturnType> {
+
+ /**
+ * Specify the name of the class that should be instantiated for the instance. The classpath information will need to be
+ * defined using the returned interface.
+ *
+ * @param classname the name of the class that should be instantiated
+ * @return the interface used to define the classpath information; never null
+ * @throws IllegalArgumentException if the class name is null, empty, blank, or not a valid class name
+ */
+ LoadedFrom<ReturnType> usingClass( String classname );
+
+ /**
+ * Specify the class that should be instantiated for the instance. Because the class is already available to this class
+ * loader, there is no need to specify the classloader information.
+ *
+ * @param clazz the class that should be instantiated
+ * @return the next component to continue configuration; never null
+ * @throws DnaConfigurationException if the class could not be accessed and instantiated (if needed)
+ * @throws IllegalArgumentException if the class reference is null
+ */
+ ReturnType usingClass( Class<? extends ComponentClassType> clazz );
+ }
+
+ /**
+ * The interface used to set a description on a component.
+ *
+ * @param <ReturnType> the interface returned from these methods
+ */
+ public interface SetDescription<ReturnType> {
+ /**
+ * Specify the description of this component.
+ *
+ * @param description the description; may be null or empty
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType describedAs( String description );
+ }
+
+ /**
+ * The interface used to set a human readable name on a component.
+ *
+ * @param <ReturnType> the interface returned from these methods
+ */
+ public interface SetName<ReturnType> {
+ /**
+ * Specify the human-readable name for this component.
+ *
+ * @param description the description; may be null or empty
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType named( String description );
+ }
+
+ /**
+ * Interface for specifying from where the component's class is to be loaded.
+ *
+ * @param <ReturnType> the interface returned from these methods
+ */
+ public interface LoadedFrom<ReturnType> {
+ /**
+ * Specify the names of the classloaders that form the classpath for the component, from which the component's class (and
+ * its dependencies) can be loaded. The names correspond to the names supplied to the
+ * {@link ExecutionContext#getClassLoader(String...)} methods.
+ *
+ * @param classPathNames the names for the classloaders, as passed to the {@link ClassLoaderFactory} implementation (e.g.,
+ * the {@link ExecutionContext}).
+ * @return the next component to continue configuration; never null
+ * @see #loadedFromClasspath()
+ * @see ExecutionContext#getClassLoader(String...)
+ */
+ ReturnType loadedFrom( String... classPathNames );
+
+ /**
+ * Specify that the component (and its dependencies) will be found on the current (or
+ * {@link Thread#getContextClassLoader() current context}) classloader.
+ *
+ * @return the next component to continue configuration; never null
+ * @see #loadedFrom(String...)
+ * @see ExecutionContext#getClassLoader(String...)
+ */
+ ReturnType loadedFromClasspath();
+ }
+
+ /**
+ * Continue with another aspect of configuration.
+ *
+ * @param <ReturnType>
+ */
+ public interface And<ReturnType> {
+
+ /**
+ * Return a reference to the next configuration interface for additional operations.
+ *
+ * @return a reference to the next configuration interface
+ */
+ ReturnType and();
+ }
+
+ protected final BuilderType builder;
+ protected final ExecutionContext context;
+ protected ConfigurationRepository configurationSource;
+ private Graph graph;
+ private Graph.Batch batch;
+
+ /**
+ * Specify a new {@link ExecutionContext} that should be used for this DNA instance.
+ *
+ * @param context the new context, or null if a default-constructed execution context should be used
+ * @param builder the builder
+ * @throws IllegalArgumentException if the supplied context reference is null
+ */
+ protected Configurator( ExecutionContext context,
+ BuilderType builder ) {
+ CheckArg.isNotNull(context, "context");
+ CheckArg.isNotNull(builder, "builder");
+ this.context = context;
+ this.builder = builder;
+
+ // Set up the default configuration repository ...
+ this.configurationSource = createDefaultConfigurationSource();
+ }
+
+ /**
+ * Method that is used to set up the default configuration repository source. By default, this method sets up the
+ * {@link InMemoryRepositorySource} loaded from the classpath.
+ *
+ * @return the default repository source
+ */
+ protected ConfigurationRepository createDefaultConfigurationSource() {
+ InMemoryRepositorySource defaultSource = new InMemoryRepositorySource();
+ defaultSource.setName("Configuration");
+ ConfigurationRepository result = new ConfigurationRepository(defaultSource, "Configuration Repository", null);
+ return result;
+ }
+
+ /**
+ * Get the execution context used by this configurator.
+ *
+ * @return the execution context; never null
+ */
+ public final ExecutionContext getExecutionContext() {
+ return this.context;
+ }
+
+ protected final PathFactory pathFactory() {
+ return getExecutionContext().getValueFactories().getPathFactory();
+ }
+
+ /**
+ * Get the graph containing the configuration information.
+ *
+ * @return the configuration repository graph; never null
+ * @see #graph()
+ */
+ protected final Graph graph() {
+ if (this.graph == null) {
+ this.graph = Graph.create(configurationSource.getRepositorySource(), context);
+ }
+ return this.graph;
+ }
+
+ /**
+ * Get the graph batch that can be used to change the configuration, where the changes are enqueued until {@link #save()
+ * saved}.
+ *
+ * @return the latest batch for changes to the configuration repository; never null
+ * @see #graph()
+ */
+ protected final Graph.Batch configuration() {
+ if (this.batch == null) {
+ this.batch = graph().batch();
+ }
+ return this.batch;
+ }
+
+ /**
+ * Save any changes that have been made so far to the configuration. This method does nothing if no changes have been made.
+ *
+ * @return this configuration object for method chaining purposes; never null
+ */
+ public BuilderType save() {
+ if (this.batch != null) {
+ this.batch.execute();
+ this.batch = this.graph.batch();
+ }
+ return this.builder;
+ }
+
+ protected abstract Name nameFor( String name );
+
+ protected Path createOrReplaceNode( Path parentPath,
+ String id ) {
+ Path path = pathFactory().create(parentPath, id);
+ configuration().create(path).with(DnaLexicon.READABLE_NAME, id).and();
+ return path;
+ }
+
+ protected void recordBeanPropertiesInGraph( Path path,
+ Object javaBean ) {
+ Reflection reflector = new Reflection(javaBean.getClass());
+ for (String propertyName : reflector.findGetterPropertyNames()) {
+ Object value;
+ try {
+ value = reflector.invokeGetterMethodOnTarget(propertyName, javaBean);
+ if (value == null) continue;
+ propertyName = Inflector.getInstance().lowerCamelCase(propertyName);
+ configuration().set(nameFor(propertyName)).to(value).on(path);
+ } catch (ValueFormatException err) {
+ throw err;
+ } catch (Throwable err) {
+ // Unable to call getter and set property
+ }
+ }
+ }
+
+ protected class ConfigurationRepositoryClassChooser<ReturnType>
+ implements ChooseClass<RepositorySource, ConfigRepositoryDetails<ReturnType>> {
+
+ private final ReturnType returnObject;
+
+ protected ConfigurationRepositoryClassChooser( ReturnType returnObject ) {
+ assert returnObject != null;
+ this.returnObject = returnObject;
+ }
+
+ public LoadedFrom<ConfigRepositoryDetails<ReturnType>> usingClass( final String className ) {
+ return new LoadedFrom<ConfigRepositoryDetails<ReturnType>>() {
+ @SuppressWarnings( "unchecked" )
+ public ConfigRepositoryDetails loadedFrom( String... classpath ) {
+ ClassLoader classLoader = getExecutionContext().getClassLoader(classpath);
+ Class<? extends RepositorySource> clazz = null;
+ try {
+ clazz = (Class<? extends RepositorySource>)classLoader.loadClass(className);
+ } catch (ClassNotFoundException err) {
+ throw new DnaConfigurationException(RepositoryI18n.unableToLoadClassUsingClasspath.text(className,
+ classpath));
+ }
+ return usingClass(clazz);
+ }
+
+ @SuppressWarnings( "unchecked" )
+ public ConfigRepositoryDetails loadedFromClasspath() {
+ Class<? extends RepositorySource> clazz = null;
+ try {
+ clazz = (Class<? extends RepositorySource>)Class.forName(className);
+ } catch (ClassNotFoundException err) {
+ throw new DnaConfigurationException(RepositoryI18n.unableToLoadClass.text(className));
+ }
+ return usingClass(clazz);
+ }
+ };
+ }
+
+ public ConfigRepositoryDetails<ReturnType> usingClass( Class<? extends RepositorySource> repositorySource ) {
+ try {
+ Configurator.this.configurationSource = new ConfigurationRepository(repositorySource.newInstance());
+ } catch (InstantiationException err) {
+ I18n msg = RepositoryI18n.errorCreatingInstanceOfClass;
+ throw new DnaConfigurationException(msg.text(repositorySource.getName(), err.getLocalizedMessage()), err);
+ } catch (IllegalAccessException err) {
+ I18n msg = RepositoryI18n.errorCreatingInstanceOfClass;
+ throw new DnaConfigurationException(msg.text(repositorySource.getName(), err.getLocalizedMessage()), err);
+ }
+ return new ConfigurationSourceDetails<ReturnType>(returnObject);
+ }
+ }
+
+ protected class ConfigurationSourceDetails<ReturnType> implements ConfigRepositoryDetails<ReturnType> {
+ private final ReturnType returnObject;
+
+ protected ConfigurationSourceDetails( ReturnType returnObject ) {
+ assert returnObject != null;
+ this.returnObject = returnObject;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SetDescription#describedAs(java.lang.String)
+ */
+ public ConfigRepositoryDetails<ReturnType> describedAs( String description ) {
+ Configurator.this.configurationSource = Configurator.this.configurationSource.with(description);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SetProperties#with(java.lang.String)
+ */
+ public PropertySetter<ConfigRepositoryDetails<ReturnType>> with( String propertyName ) {
+ return new BeanPropertySetter<ConfigRepositoryDetails<ReturnType>>(
+ Configurator.this.configurationSource.getRepositorySource(),
+ propertyName, this);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.ConfigRepositoryDetails#under(java.lang.String)
+ */
+ public ConfigRepositoryDetails<ReturnType> under( String path ) {
+ CheckArg.isNotNull(path, "path");
+ Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(path);
+ Configurator.this.configurationSource = Configurator.this.configurationSource.with(newPath);
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.And#and()
+ */
+ public ReturnType and() {
+ return returnObject;
+ }
+ }
+
+ /**
+ * Reusable implementation of {@link Configurator.ChooseClass} that can be used to obtain the name of a class and how its
+ * class loader is defined.
+ *
+ * @param <ComponentClass> the type of the component that is being chosen
+ * @param <ReturnType> the interface that should be returned when the class name and classpath have been chosen.
+ */
+ protected class ClassChooser<ComponentClass, ReturnType> implements Configurator.ChooseClass<ComponentClass, ReturnType> {
+ protected final Path pathOfComponentNode;
+ protected final ReturnType returnObject;
+
+ protected ClassChooser( Path pathOfComponentNode,
+ ReturnType returnObject ) {
+ assert pathOfComponentNode != null;
+ assert returnObject != null;
+ this.pathOfComponentNode = pathOfComponentNode;
+ this.returnObject = returnObject;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see Configurator.ChooseClass#usingClass(java.lang.String)
+ */
+ public Configurator.LoadedFrom<ReturnType> usingClass( final String classname ) {
+ CheckArg.isNotEmpty(classname, "classname");
+ configuration().set(DnaLexicon.CLASSNAME).to(classname).on(pathOfComponentNode);
+ return new Configurator.LoadedFrom<ReturnType>() {
+ public ReturnType loadedFromClasspath() {
+ return returnObject;
+ }
+
+ public ReturnType loadedFrom( String... classpath ) {
+ CheckArg.isNotEmpty(classpath, "classpath");
+ if (classpath.length == 1 && classpath[0] != null) {
+ configuration().set(DnaLexicon.CLASSPATH).to(classpath[0]).on(pathOfComponentNode);
+ } else {
+ Object[] remaining = new String[classpath.length - 1];
+ System.arraycopy(classpath, 1, remaining, 0, remaining.length);
+ configuration().set(DnaLexicon.CLASSPATH).to(classpath[0], remaining).on(pathOfComponentNode);
+ }
+ return returnObject;
+ }
+ };
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see Configurator.ChooseClass#usingClass(java.lang.Class)
+ */
+ public ReturnType usingClass( Class<? extends ComponentClass> clazz ) {
+ CheckArg.isNotNull(clazz, "clazz");
+ return usingClass(clazz.getName()).loadedFromClasspath();
+ }
+ }
+
+ /**
+ * Reusable implementation of {@link Configurator.PropertySetter} that sets the JavaBean-style property using reflection.
+ *
+ * @param <ReturnType>
+ */
+ protected class BeanPropertySetter<ReturnType> implements Configurator.PropertySetter<ReturnType> {
+ private final Object javaBean;
+ private final String beanPropertyName;
+ private final ReturnType returnObject;
+
+ protected BeanPropertySetter( Object javaBean,
+ String beanPropertyName,
+ ReturnType returnObject ) {
+ assert javaBean != null;
+ assert beanPropertyName != null;
+ assert returnObject != null;
+ this.javaBean = javaBean;
+ this.beanPropertyName = beanPropertyName;
+ this.returnObject = returnObject;
+ }
+
+ public ReturnType setTo( boolean value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( int value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( long value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( short value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( float value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( double value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( String value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( Object value ) {
+ // Set the JavaBean-style property on the RepositorySource instance ...
+ Reflection reflection = new Reflection(javaBean.getClass());
+ try {
+ reflection.invokeSetterMethodOnTarget(beanPropertyName, javaBean, value);
+ } catch (Throwable err) {
+ I18n msg = RepositoryI18n.errorSettingJavaBeanPropertyOnInstanceOfClass;
+ throw new DnaConfigurationException(msg.text(beanPropertyName, javaBean.getClass(), err.getMessage()), err);
+ }
+ return returnObject;
+ }
+ }
+
+ /**
+ * Reusable implementation of {@link Configurator.PropertySetter} that sets the property on the specified node in the
+ * configuration graph.
+ *
+ * @param <ReturnType>
+ */
+ protected class GraphPropertySetter<ReturnType> implements Configurator.PropertySetter<ReturnType> {
+ private final Path path;
+ private final String beanPropertyName;
+ private final ReturnType returnObject;
+
+ protected GraphPropertySetter( Path path,
+ String beanPropertyName,
+ ReturnType returnObject ) {
+ assert path != null;
+ assert beanPropertyName != null;
+ assert returnObject != null;
+ this.path = path;
+ this.beanPropertyName = Inflector.getInstance().lowerCamelCase(beanPropertyName);
+ this.returnObject = returnObject;
+ }
+
+ public ReturnType setTo( boolean value ) {
+ configuration().set(nameFor(beanPropertyName)).to(value).on(path);
+ return returnObject;
+ }
+
+ public ReturnType setTo( int value ) {
+ configuration().set(nameFor(beanPropertyName)).to(value).on(path);
+ return returnObject;
+ }
+
+ public ReturnType setTo( long value ) {
+ configuration().set(nameFor(beanPropertyName)).to(value).on(path);
+ return returnObject;
+ }
+
+ public ReturnType setTo( short value ) {
+ configuration().set(nameFor(beanPropertyName)).to(value).on(path);
+ return returnObject;
+ }
+
+ public ReturnType setTo( float value ) {
+ configuration().set(nameFor(beanPropertyName)).to(value).on(path);
+ return returnObject;
+ }
+
+ public ReturnType setTo( double value ) {
+ configuration().set(nameFor(beanPropertyName)).to(value).on(path);
+ return returnObject;
+ }
+
+ public ReturnType setTo( String value ) {
+ configuration().set(nameFor(beanPropertyName)).to(value).on(path);
+ return returnObject;
+ }
+
+ public ReturnType setTo( Object value ) {
+ configuration().set(nameFor(beanPropertyName)).to(value).on(path);
+ return returnObject;
+ }
+ }
+
+ protected class GraphRepositoryDetails<ReturnType> implements RepositoryDetails<ReturnType> {
+ private final Path path;
+ private final ReturnType returnObject;
+
+ protected GraphRepositoryDetails( Path path,
+ ReturnType returnObject ) {
+ assert path != null;
+ assert returnObject != null;
+ this.path = path;
+ this.returnObject = returnObject;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SetName#named(java.lang.String)
+ */
+ public RepositoryDetails<ReturnType> named( String name ) {
+ configuration().set(DnaLexicon.READABLE_NAME).to(name).on(path);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SetDescription#describedAs(java.lang.String)
+ */
+ public RepositoryDetails<ReturnType> describedAs( String description ) {
+ configuration().set(DnaLexicon.DESCRIPTION).to(description).on(path);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SetProperties#with(java.lang.String)
+ */
+ public PropertySetter<RepositoryDetails<ReturnType>> with( String propertyName ) {
+ return new GraphPropertySetter<RepositoryDetails<ReturnType>>(path, propertyName, this);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.And#and()
+ */
+ public ReturnType and() {
+ return returnObject;
+ }
+ }
+
+ protected class GraphSequencerDetails<ReturnType> implements SequencerDetails<ReturnType> {
+ private final Path path;
+ private final List<String> compiledExpressions = new ArrayList<String>();
+ private final ReturnType returnObject;
+
+ protected GraphSequencerDetails( Path path,
+ ReturnType returnObject ) {
+ assert path != null;
+ assert returnObject != null;
+ this.path = path;
+ this.returnObject = returnObject;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SequencerDetails#sequencingFrom(java.lang.String)
+ */
+ public PathExpressionOutput<ReturnType> sequencingFrom( final String from ) {
+ CheckArg.isNotEmpty(from, "from");
+ return new PathExpressionOutput<ReturnType>() {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.PathExpressionOutput#andOutputtingTo(java.lang.String)
+ */
+ public SequencerDetails<ReturnType> andOutputtingTo( String into ) {
+ CheckArg.isNotEmpty(into, "into");
+ return sequencingFrom(PathExpression.compile(from + " => " + into));
+ }
+ };
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SetName#named(java.lang.String)
+ */
+ public SequencerDetails<ReturnType> named( String name ) {
+ configuration().set(DnaLexicon.READABLE_NAME).to(name).on(path);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SequencerDetails#sequencingFrom(org.jboss.dna.graph.property.PathExpression)
+ */
+ public SequencerDetails<ReturnType> sequencingFrom( PathExpression expression ) {
+ CheckArg.isNotNull(expression, "expression");
+ String compiledExpression = expression.getExpression();
+ if (!compiledExpressions.contains(compiledExpression)) compiledExpressions.add(compiledExpression);
+ configuration().set(DnaLexicon.PATH_EXPRESSIONS).on(path).to(compiledExpressions);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SetDescription#describedAs(java.lang.String)
+ */
+ public SequencerDetails<ReturnType> describedAs( String description ) {
+ configuration().set(DnaLexicon.DESCRIPTION).to(description).on(path);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.And#and()
+ */
+ public ReturnType and() {
+ return returnObject;
+ }
+ }
+
+ protected class GraphMimeTypeDetectorDetails<ReturnType> implements MimeTypeDetectorDetails<ReturnType> {
+ private final Path path;
+ private final ReturnType returnObject;
+
+ protected GraphMimeTypeDetectorDetails( Path path,
+ ReturnType returnObject ) {
+ assert path != null;
+ assert returnObject != null;
+ this.path = path;
+ this.returnObject = returnObject;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SetName#named(java.lang.String)
+ */
+ public MimeTypeDetectorDetails<ReturnType> named( String name ) {
+ configuration().set(DnaLexicon.READABLE_NAME).to(name).on(path);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SetProperties#with(java.lang.String)
+ */
+ public PropertySetter<MimeTypeDetectorDetails<ReturnType>> with( String propertyName ) {
+ return new GraphPropertySetter<MimeTypeDetectorDetails<ReturnType>>(path, propertyName, this);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SetDescription#describedAs(java.lang.String)
+ */
+ public MimeTypeDetectorDetails<ReturnType> describedAs( String description ) {
+ configuration().set(DnaLexicon.DESCRIPTION).to(description).on(path);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.And#and()
+ */
+ public ReturnType and() {
+ return returnObject;
+ }
+ }
+
+ @Immutable
+ public static class ConfigurationRepository {
+ private final RepositorySource source;
+ private final String description;
+ private final Path path;
+
+ protected ConfigurationRepository( RepositorySource source ) {
+ this(source, null, null);
+ }
+
+ protected ConfigurationRepository( RepositorySource source,
+ String description,
+ Path path ) {
+ this.source = source;
+ this.description = description != null ? description : "";
+ this.path = path != null ? path : RootPath.INSTANCE;
+ }
+
+ /**
+ * @return source
+ */
+ public RepositorySource getRepositorySource() {
+ return source;
+ }
+
+ /**
+ * @return description
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * @return path
+ */
+ public Path getPath() {
+ return path;
+ }
+
+ public ConfigurationRepository with( String description ) {
+ return new ConfigurationRepository(source, description, path);
+ }
+
+ public ConfigurationRepository with( Path path ) {
+ return new ConfigurationRepository(source, description, path);
+ }
+ }
+}
Property changes on: trunk/dna-repository/src/main/java/org/jboss/dna/repository/Configurator.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Deleted: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -1,1074 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * 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.
- *
- * This software 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.repository;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.common.component.ClassLoaderFactory;
-import org.jboss.dna.common.i18n.I18n;
-import org.jboss.dna.common.text.Inflector;
-import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.common.util.Reflection;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Graph;
-import org.jboss.dna.graph.Node;
-import org.jboss.dna.graph.connector.RepositorySource;
-import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
-import org.jboss.dna.graph.mimetype.MimeTypeDetector;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.PathExpression;
-import org.jboss.dna.graph.property.PathFactory;
-import org.jboss.dna.graph.property.ValueFormatException;
-import org.jboss.dna.graph.property.basic.RootPath;
-import org.jboss.dna.repository.sequencer.Sequencer;
-
-/**
- */
-@Immutable
-public class DnaConfiguration {
-
- protected static final Map<String, Name> NAMES_TO_MAP;
- static {
- Map<String, Name> names = new HashMap<String, Name>();
- names.put(DnaLexicon.READABLE_NAME.getLocalName(), DnaLexicon.READABLE_NAME);
- names.put(DnaLexicon.DESCRIPTION.getLocalName(), DnaLexicon.DESCRIPTION);
- names.put(DnaLexicon.DEFAULT_CACHE_POLICY.getLocalName(), DnaLexicon.DEFAULT_CACHE_POLICY);
- names.put(DnaLexicon.RETRY_LIMIT.getLocalName(), DnaLexicon.RETRY_LIMIT);
- names.put(DnaLexicon.PATH_EXPRESSIONS.getLocalName(), DnaLexicon.PATH_EXPRESSIONS);
- names.put(DnaLexicon.CLASSNAME.getLocalName(), DnaLexicon.CLASSNAME);
- names.put(DnaLexicon.CLASSPATH.getLocalName(), DnaLexicon.CLASSPATH);
- NAMES_TO_MAP = Collections.unmodifiableMap(names);
- }
-
- @Immutable
- protected class ConfigurationRepository {
- private final RepositorySource source;
- private final String description;
- private final Path path;
-
- protected ConfigurationRepository( RepositorySource source ) {
- this(source, null, null);
- }
-
- protected ConfigurationRepository( RepositorySource source,
- String description,
- Path path ) {
- this.source = source;
- this.description = description != null ? description : "";
- this.path = path != null ? path : RootPath.INSTANCE;
- }
-
- /**
- * @return source
- */
- public RepositorySource getRepositorySource() {
- return source;
- }
-
- /**
- * @return description
- */
- public String getDescription() {
- return description;
- }
-
- /**
- * @return path
- */
- public Path getPath() {
- return path;
- }
-
- public ConfigurationRepository with( String description ) {
- return new ConfigurationRepository(source, description, path);
- }
-
- public ConfigurationRepository with( Path path ) {
- return new ConfigurationRepository(source, description, path);
- }
- }
-
- private final ExecutionContext context;
- protected ConfigurationRepository configurationSource;
- private Path sourcesPath;
- private Path sequencersPath;
- private Path detectorsPath;
- private Graph graph;
- private Graph.Batch batch;
-
- /**
- * Create a new configuration for DNA.
- */
- public DnaConfiguration() {
- this(new ExecutionContext());
- }
-
- /**
- * Specify a new {@link ExecutionContext} that should be used for this DNA instance.
- *
- * @param context the new context, or null if a default-constructed execution context should be used
- * @throws IllegalArgumentException if the supplied context reference is null
- */
- public DnaConfiguration( ExecutionContext context ) {
- CheckArg.isNotNull(context, "context");
- this.context = context;
-
- // Set up the default configuration repository ...
- this.configurationSource = createDefaultConfigurationSource();
- }
-
- /**
- * Method that is used to set up the default configuration repository source. By default, this method sets up the
- * {@link InMemoryRepositorySource} loaded from the classpath.
- *
- * @return the default repository source
- */
- protected ConfigurationRepository createDefaultConfigurationSource() {
- InMemoryRepositorySource defaultSource = new InMemoryRepositorySource();
- defaultSource.setName("Configuration");
- ConfigurationRepository result = new ConfigurationRepository(defaultSource, "Configuration Repository", null);
- return result;
- }
-
- protected final ExecutionContext context() {
- return this.context;
- }
-
- protected final PathFactory pathFactory() {
- return context().getValueFactories().getPathFactory();
- }
-
- /**
- * Get the graph containing the configuration information. This should be called only after the
- * {@link #withConfigurationRepository() configuration repository} is set up.
- *
- * @return the configuration repository graph; never null
- * @see #graph()
- */
- protected final Graph graph() {
- if (this.graph == null) {
- this.graph = Graph.create(configurationSource.getRepositorySource(), context);
- }
- return this.graph;
- }
-
- /**
- * Get the graph batch that can be used to change the configuration, where the changes are enqueued until {@link #save()
- * saved}. This should be called only after the {@link #withConfigurationRepository() configuration repository} is set up.
- *
- * @return the latest batch for changes to the configuration repository; never null
- * @see #graph()
- */
- protected final Graph.Batch configuration() {
- if (this.batch == null) {
- this.batch = graph().batch();
- }
- return this.batch;
- }
-
- /**
- * Save any changes that have been made so far to the configuration. This method does nothing if no changes have been made.
- *
- * @return this configuration object for method chaining purposes; never null
- */
- public DnaConfiguration save() {
- if (this.batch != null) {
- this.batch.execute();
- this.batch = this.graph.batch();
- }
- return this;
- }
-
- /**
- * Specify that this configuration should use a particular {@link RepositorySource} for its configuration repository. By
- * default each configuration uses an internal transient repository for its configuration, but using this method will make the
- * configuration use a different repository (that is perhaps shared with other processes).
- *
- * @return the interface for choosing the class, which returns the interface used to configure the repository source that will
- * be used for the configuration repository; never null
- */
- public ChooseClass<RepositorySource, ConfigRepositoryDetails> withConfigurationRepository() {
- // The config repository is different, since it has to load immediately ...
- return new ChooseClass<RepositorySource, ConfigRepositoryDetails>() {
- public LoadedFrom<ConfigRepositoryDetails> usingClass( final String className ) {
- return new LoadedFrom<ConfigRepositoryDetails>() {
- @SuppressWarnings( "unchecked" )
- public ConfigRepositoryDetails loadedFrom( String... classpath ) {
- ClassLoader classLoader = context().getClassLoader(classpath);
- Class<? extends RepositorySource> clazz = null;
- try {
- clazz = (Class<? extends RepositorySource>)classLoader.loadClass(className);
- } catch (ClassNotFoundException err) {
- throw new DnaConfigurationException(RepositoryI18n.unableToLoadClassUsingClasspath.text(className,
- classpath));
- }
- return usingClass(clazz);
- }
-
- @SuppressWarnings( "unchecked" )
- public ConfigRepositoryDetails loadedFromClasspath() {
- Class<? extends RepositorySource> clazz = null;
- try {
- clazz = (Class<? extends RepositorySource>)Class.forName(className);
- } catch (ClassNotFoundException err) {
- throw new DnaConfigurationException(RepositoryI18n.unableToLoadClass.text(className));
- }
- return usingClass(clazz);
- }
- };
- }
-
- public ConfigRepositoryDetails usingClass( Class<? extends RepositorySource> repositorySource ) {
- try {
- DnaConfiguration.this.configurationSource = new ConfigurationRepository(repositorySource.newInstance());
- } catch (InstantiationException err) {
- I18n msg = RepositoryI18n.errorCreatingInstanceOfClass;
- throw new DnaConfigurationException(msg.text(repositorySource.getName(), err.getLocalizedMessage()), err);
- } catch (IllegalAccessException err) {
- I18n msg = RepositoryI18n.errorCreatingInstanceOfClass;
- throw new DnaConfigurationException(msg.text(repositorySource.getName(), err.getLocalizedMessage()), err);
- }
- return new ConfigurationSourceDetails();
- }
- };
- }
-
- /**
- * Add a new {@link RepositorySource repository} for this configuration. The new repository will have the supplied name, and
- * if the name of an existing repository is used, this will replace the existing repository configuration.
- *
- * @param id the id of the new repository that is to be added
- * @return the interface for choosing the class, which returns the interface used to configure the repository source; never
- * null
- * @throws IllegalArgumentException if the repository name is null, empty, or otherwise invalid
- * @see #addRepository(RepositorySource)
- */
- public ChooseClass<RepositorySource, RepositoryDetails> addRepository( final String id ) {
- CheckArg.isNotEmpty(id, "id");
- // Now create the "dna:source" node with the supplied id ...
- Path sourcePath = pathFactory().create(sourcesPath(), id);
- configuration().create(sourcePath).with(DnaLexicon.READABLE_NAME, id).and();
- return new ClassChooser<RepositorySource, RepositoryDetails>(sourcePath, new GraphRepositoryDetails(sourcePath));
- }
-
- /**
- * Add a new {@link RepositorySource repository} for this configuration. The new repository will have the supplied name, and
- * if the name of an existing repository is used, this will replace the existing repository configuration.
- *
- * @param source the {@link RepositorySource} instance that should be used
- * @return this configuration object, for method-chaining purposes
- * @throws IllegalArgumentException if the repository source reference is null
- * @see #addRepository(String)
- */
- public DnaConfiguration addRepository( RepositorySource source ) {
- CheckArg.isNotNull(source, "source");
- CheckArg.isNotEmpty(source.getName(), "source.getName()");
- String name = source.getName();
- RepositoryDetails details = addRepository(source.getName()).usingClass(source.getClass().getName()).loadedFromClasspath();
- // Record all of the bean properties ...
- Path sourcePath = pathFactory().create(sourcesPath(), name);
- Reflection reflector = new Reflection(source.getClass());
- for (String propertyName : reflector.findGetterPropertyNames()) {
- Object value;
- try {
- value = reflector.invokeGetterMethodOnTarget(propertyName, source);
- if (value == null) continue;
- propertyName = Inflector.getInstance().lowerCamelCase(propertyName);
- if (NAMES_TO_MAP.containsKey(propertyName)) {
- configuration().set(NAMES_TO_MAP.get(propertyName)).to(value).on(sourcePath);
- } else {
- configuration().set(propertyName).to(value).on(sourcePath);
- }
- } catch (ValueFormatException err) {
- throw err;
- } catch (Throwable err) {
- // Unable to call getter and set property
- }
- }
- return details.and();
- }
-
- /**
- * Add a new {@link Sequencer sequencer} to this configuration. The new sequencer will have the supplied name, and if the name
- * of an existing sequencer is used, this will replace the existing sequencer configuration.
- *
- * @param id the identifier of the new sequencer
- * @return the interface for choosing the class, which returns the interface used to configure the sequencer; never null
- * @throws IllegalArgumentException if the sequencer name is null, empty, or otherwise invalid
- */
- public ChooseClass<Sequencer, SequencerDetails> addSequencer( final String id ) {
- CheckArg.isNotEmpty(id, "id");
- // Now create the "dna:sequencer" node with the supplied id ...
- Path sequencerPath = pathFactory().create(sequencersPath(), id);
- configuration().create(sequencerPath).with(DnaLexicon.READABLE_NAME, id).and();
- return new ClassChooser<Sequencer, SequencerDetails>(sequencerPath, new GraphSequencerDetails(sequencerPath));
- }
-
- /**
- * Add a new {@link MimeTypeDetector MIME type detector} to this configuration. The new detector will have the supplied name,
- * and if the name of an existing detector is used, this will replace the existing detector configuration.
- *
- * @param id the id of the new detector
- * @return the interface for choosing the class, which returns the interface used to configure the detector; never null
- * @throws IllegalArgumentException if the detector name is null, empty, or otherwise invalid
- */
- public ChooseClass<MimeTypeDetector, MimeTypeDetectorDetails> addMimeTypeDetector( final String id ) {
- CheckArg.isNotEmpty(id, "id");
- // Now create the "dna:sequencer" node with the supplied id ...
- Path detectorPath = pathFactory().create(detectorsPath(), id);
- configuration().create(detectorPath).with(DnaLexicon.READABLE_NAME, id).and();
- return new ClassChooser<MimeTypeDetector, MimeTypeDetectorDetails>(detectorPath,
- new GraphMimeTypeDetectorDetails(detectorPath));
- }
-
- /**
- * Complete this configuration and create the corresponding engine.
- *
- * @return the new engine configured by this instance
- * @throws DnaConfigurationException if the engine cannot be created from this configuration.
- */
- public DnaEngine build() throws DnaConfigurationException {
- save();
- return new DnaEngine(this);
- }
-
- protected Path sourcesPath() {
- // Make sure the "dna:sources" node is there
- if (sourcesPath == null) {
- Path path = pathFactory().create(this.configurationSource.getPath(), DnaLexicon.SOURCES);
- Node node = graph().createIfMissing(path).andReturn();
- this.sourcesPath = node.getLocation().getPath();
- }
- return this.sourcesPath;
- }
-
- protected Path sequencersPath() {
- // Make sure the "dna:sequencers" node is there
- if (sequencersPath == null) {
- Path path = pathFactory().create(this.configurationSource.getPath(), DnaLexicon.SEQUENCERS);
- Node node = graph().createIfMissing(path).andReturn();
- this.sequencersPath = node.getLocation().getPath();
- }
- return this.sequencersPath;
- }
-
- protected Path detectorsPath() {
- // Make sure the "dna:mimeTypeDetectors" node is there
- if (detectorsPath == null) {
- Path path = pathFactory().create(this.configurationSource.getPath(), DnaLexicon.MIME_TYPE_DETECTORS);
- Node node = graph().createIfMissing(path).andReturn();
- this.detectorsPath = node.getLocation().getPath();
- }
- return this.detectorsPath;
- }
-
- /**
- * Interface used to configure a {@link RepositorySource repository}.
- */
- public interface RepositoryDetails
- extends SetName<RepositoryDetails>, SetDescription<RepositoryDetails>, SetProperties<RepositoryDetails>,
- ConfigurationBuilder {
- }
-
- public interface ConfigRepositoryDetails
- extends SetDescription<ConfigRepositoryDetails>, SetProperties<ConfigRepositoryDetails>, ConfigurationBuilder {
- /**
- * Specify the path under which the configuration content is to be found. This path is assumed to be "/" by default.
- *
- * @param path the path to the configuration content in the configuration source; may not be null
- * @return this instance for method chaining purposes; never null
- */
- public ConfigRepositoryDetails under( String path );
- }
-
- /**
- * Interface used to configure a {@link Sequencer sequencer}.
- */
- public interface SequencerDetails extends SetName<SequencerDetails>, SetDescription<SequencerDetails>, ConfigurationBuilder {
-
- /**
- * Specify the input {@link PathExpression path expression} represented as a string, which determines when this sequencer
- * will be executed.
- *
- * @param inputPathExpression the path expression for nodes that, when they change, will be passed as an input to the
- * sequencer
- * @return the interface used to specify the output path expression; never null
- */
- PathExpressionOutput sequencingFrom( String inputPathExpression );
-
- /**
- * Specify the input {@link PathExpression path expression}, which determines when this sequencer will be executed.
- *
- * @param inputPathExpression the path expression for nodes that, when they change, will be passed as an input to the
- * sequencer
- * @return the interface used to continue specifying the configuration of the sequencer
- */
- SequencerDetails sequencingFrom( PathExpression inputPathExpression );
- }
-
- /**
- * Interface used to specify the output path expression for a {@link SequencerDetails#sequencingFrom(PathExpression) sequencer
- * configuration}.
- */
- public interface PathExpressionOutput {
- /**
- * Specify the output {@link PathExpression path expression}, which determines where this sequencer's output will be
- * placed.
- *
- * @param outputExpression the path expression for the location(s) where output generated by the sequencer is to be placed
- * @return the interface used to continue specifying the configuration of the sequencer
- */
- SequencerDetails andOutputtingTo( String outputExpression );
- }
-
- /**
- * Interface used to configure a {@link MimeTypeDetector MIME type detector}.
- */
- public interface MimeTypeDetectorDetails
- extends SetName<MimeTypeDetectorDetails>, SetDescription<MimeTypeDetectorDetails>,
- SetProperties<MimeTypeDetectorDetails>, ConfigurationBuilder {
- }
-
- /**
- * Interface for configuring the JavaBean-style properties of an object.
- *
- * @param <ReturnType> the interface returned after the property has been set.
- * @author Randall Hauch
- */
- public interface SetProperties<ReturnType> {
- /**
- * Specify the name of the JavaBean-style property that is to be set. The value may be set using the interface returned by
- * this method.
- *
- * @param beanPropertyName the name of the JavaBean-style property (e.g., "retryLimit")
- * @return the interface used to set the value for the property; never null
- */
- PropertySetter<ReturnType> with( String beanPropertyName );
- }
-
- /**
- * The interface used to set the value for a JavaBean-style property.
- *
- * @param <ReturnType> the interface returned from these methods
- * @author Randall Hauch
- * @see SetProperties#with(String)
- */
- public interface PropertySetter<ReturnType> {
- /**
- * Set the property value to an integer.
- *
- * @param value the new value for the property
- * @return the next component to continue configuration; never null
- */
- ReturnType setTo( int value );
-
- /**
- * Set the property value to a long number.
- *
- * @param value the new value for the property
- * @return the next component to continue configuration; never null
- */
- ReturnType setTo( long value );
-
- /**
- * Set the property value to a short.
- *
- * @param value the new value for the property
- * @return the next component to continue configuration; never null
- */
- ReturnType setTo( short value );
-
- /**
- * Set the property value to a boolean.
- *
- * @param value the new value for the property
- * @return the next component to continue configuration; never null
- */
- ReturnType setTo( boolean value );
-
- /**
- * Set the property value to a float.
- *
- * @param value the new value for the property
- * @return the next component to continue configuration; never null
- */
- ReturnType setTo( float value );
-
- /**
- * Set the property value to a double.
- *
- * @param value the new value for the property
- * @return the next component to continue configuration; never null
- */
- ReturnType setTo( double value );
-
- /**
- * Set the property value to a string.
- *
- * @param value the new value for the property
- * @return the next component to continue configuration; never null
- */
- ReturnType setTo( String value );
-
- /**
- * Set the property value to an object.
- *
- * @param value the new value for the property
- * @return the next component to continue configuration; never null
- */
- ReturnType setTo( Object value );
- }
-
- /**
- * The interface used to configure the class used for a component.
- *
- * @param <ComponentClassType> the class or interface that the component is to implement
- * @param <ReturnType> the interface returned from these methods
- */
- public interface ChooseClass<ComponentClassType, ReturnType> {
-
- /**
- * Specify the name of the class that should be instantiated for the instance. The classpath information will need to be
- * defined using the returned interface.
- *
- * @param classname the name of the class that should be instantiated
- * @return the interface used to define the classpath information; never null
- * @throws IllegalArgumentException if the class name is null, empty, blank, or not a valid class name
- */
- LoadedFrom<ReturnType> usingClass( String classname );
-
- /**
- * Specify the class that should be instantiated for the instance. Because the class is already available to this class
- * loader, there is no need to specify the classloader information.
- *
- * @param clazz the class that should be instantiated
- * @return the next component to continue configuration; never null
- * @throws DnaConfigurationException if the class could not be accessed and instantiated (if needed)
- * @throws IllegalArgumentException if the class reference is null
- */
- ReturnType usingClass( Class<? extends ComponentClassType> clazz );
- }
-
- /**
- * The interface used to set a description on a component.
- *
- * @param <ReturnType> the interface returned from these methods
- */
- public interface SetDescription<ReturnType> {
- /**
- * Specify the description of this component.
- *
- * @param description the description; may be null or empty
- * @return the next component to continue configuration; never null
- */
- ReturnType describedAs( String description );
- }
-
- /**
- * The interface used to set a human readable name on a component.
- *
- * @param <ReturnType> the interface returned from these methods
- */
- public interface SetName<ReturnType> {
- /**
- * Specify the human-readable name for this component.
- *
- * @param description the description; may be null or empty
- * @return the next component to continue configuration; never null
- */
- ReturnType named( String description );
- }
-
- /**
- * Interface for specifying from where the component's class is to be loaded.
- *
- * @param <ReturnType> the interface returned from these methods
- */
- public interface LoadedFrom<ReturnType> {
- /**
- * Specify the names of the classloaders that form the classpath for the component, from which the component's class (and
- * its dependencies) can be loaded. The names correspond to the names supplied to the
- * {@link ExecutionContext#getClassLoader(String...)} methods.
- *
- * @param classPathNames the names for the classloaders, as passed to the {@link ClassLoaderFactory} implementation (e.g.,
- * the {@link ExecutionContext}).
- * @return the next component to continue configuration; never null
- * @see #loadedFromClasspath()
- * @see ExecutionContext#getClassLoader(String...)
- */
- ReturnType loadedFrom( String... classPathNames );
-
- /**
- * Specify that the component (and its dependencies) will be found on the current (or
- * {@link Thread#getContextClassLoader() current context}) classloader.
- *
- * @return the next component to continue configuration; never null
- * @see #loadedFrom(String...)
- * @see ExecutionContext#getClassLoader(String...)
- */
- ReturnType loadedFromClasspath();
- }
-
- /**
- * Interface for classes that can return a reference to their DNA configuration.
- */
- public interface ConfigurationBuilder {
-
- /**
- * Return a reference to the enclosing configuration so that it can be built or further configured.
- *
- * @return a reference to the enclosing configuration
- */
- DnaConfiguration and();
- }
-
- protected class ConfigurationSourceDetails implements ConfigRepositoryDetails {
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
- */
- public ConfigRepositoryDetails describedAs( String description ) {
- DnaConfiguration.this.configurationSource = DnaConfiguration.this.configurationSource.with(description);
- return this;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SetProperties#with(java.lang.String)
- */
- public PropertySetter<ConfigRepositoryDetails> with( String propertyName ) {
- return new BeanPropertySetter<ConfigRepositoryDetails>(
- DnaConfiguration.this.configurationSource.getRepositorySource(),
- propertyName, this);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.ConfigRepositoryDetails#under(java.lang.String)
- */
- public ConfigRepositoryDetails under( String path ) {
- CheckArg.isNotNull(path, "path");
- Path newPath = context().getValueFactories().getPathFactory().create(path);
- DnaConfiguration.this.configurationSource = DnaConfiguration.this.configurationSource.with(newPath);
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.ConfigurationBuilder#and()
- */
- public DnaConfiguration and() {
- return DnaConfiguration.this;
- }
- }
-
- protected class GraphRepositoryDetails implements RepositoryDetails {
- private final Path path;
-
- protected GraphRepositoryDetails( Path path ) {
- assert path != null;
- this.path = path;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SetName#named(java.lang.String)
- */
- public RepositoryDetails named( String name ) {
- configuration().set(DnaLexicon.READABLE_NAME).to(name).on(path);
- return this;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
- */
- public RepositoryDetails describedAs( String description ) {
- configuration().set(DnaLexicon.DESCRIPTION).to(description).on(path);
- return this;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SetProperties#with(java.lang.String)
- */
- public PropertySetter<RepositoryDetails> with( String propertyName ) {
- return new GraphPropertySetter<RepositoryDetails>(path, propertyName, this);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.ConfigurationBuilder#and()
- */
- public DnaConfiguration and() {
- return DnaConfiguration.this;
- }
- }
-
- protected class GraphSequencerDetails implements SequencerDetails {
- private final Path path;
- private final List<String> compiledExpressions = new ArrayList<String>();
-
- protected GraphSequencerDetails( Path path ) {
- assert path != null;
- this.path = path;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SequencerDetails#sequencingFrom(java.lang.String)
- */
- public PathExpressionOutput sequencingFrom( final String from ) {
- CheckArg.isNotEmpty(from, "from");
- return new PathExpressionOutput() {
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.PathExpressionOutput#andOutputtingTo(java.lang.String)
- */
- public SequencerDetails andOutputtingTo( String into ) {
- CheckArg.isNotEmpty(into, "into");
- return sequencingFrom(PathExpression.compile(from + " => " + into));
- }
- };
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SetName#named(java.lang.String)
- */
- public SequencerDetails named( String name ) {
- configuration().set(DnaLexicon.READABLE_NAME).to(name).on(path);
- return this;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SequencerDetails#sequencingFrom(org.jboss.dna.graph.property.PathExpression)
- */
- public SequencerDetails sequencingFrom( PathExpression expression ) {
- CheckArg.isNotNull(expression, "expression");
- String compiledExpression = expression.getExpression();
- if (!compiledExpressions.contains(compiledExpression)) compiledExpressions.add(compiledExpression);
- configuration().set(DnaLexicon.PATH_EXPRESSIONS).on(path).to(compiledExpressions);
- return this;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
- */
- public SequencerDetails describedAs( String description ) {
- configuration().set(DnaLexicon.DESCRIPTION).to(description).on(path);
- return this;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.ConfigurationBuilder#and()
- */
- public DnaConfiguration and() {
- return DnaConfiguration.this;
- }
- }
-
- protected class GraphMimeTypeDetectorDetails implements MimeTypeDetectorDetails {
- private final Path path;
-
- protected GraphMimeTypeDetectorDetails( Path path ) {
- assert path != null;
- this.path = path;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SetName#named(java.lang.String)
- */
- public MimeTypeDetectorDetails named( String name ) {
- configuration().set(DnaLexicon.READABLE_NAME).to(name).on(path);
- return this;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SetProperties#with(java.lang.String)
- */
- public PropertySetter<MimeTypeDetectorDetails> with( String propertyName ) {
- return new GraphPropertySetter<MimeTypeDetectorDetails>(path, propertyName, this);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
- */
- public MimeTypeDetectorDetails describedAs( String description ) {
- configuration().set(DnaLexicon.DESCRIPTION).to(description).on(path);
- return this;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.ConfigurationBuilder#and()
- */
- public DnaConfiguration and() {
- return DnaConfiguration.this;
- }
- }
-
- /**
- * Abstract implementation of {@link ChooseClass} that has a single abstract method to obtain the interface that should be
- * returned when the class name and classpath have been selected.
- *
- * @param <ComponentClass> the type of the component that is being chosen
- * @param <ReturnType> the interface that should be returned when the class name and classpath have been chosen.
- * @author Randall Hauch
- */
- protected class ClassChooser<ComponentClass, ReturnType> implements ChooseClass<ComponentClass, ReturnType> {
- protected final Path pathOfComponentNode;
- protected final ReturnType returnObject;
-
- protected ClassChooser( Path pathOfComponentNode,
- ReturnType returnObject ) {
- assert pathOfComponentNode != null;
- assert returnObject != null;
- this.pathOfComponentNode = pathOfComponentNode;
- this.returnObject = returnObject;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.ChooseClass#usingClass(java.lang.String)
- */
- public LoadedFrom<ReturnType> usingClass( final String classname ) {
- CheckArg.isNotEmpty(classname, "classname");
- configuration().set(DnaLexicon.CLASSNAME).to(classname).on(pathOfComponentNode);
- return new LoadedFrom<ReturnType>() {
- public ReturnType loadedFromClasspath() {
- return returnObject;
- }
-
- public ReturnType loadedFrom( String... classpath ) {
- CheckArg.isNotEmpty(classpath, "classpath");
- if (classpath.length == 1 && classpath[0] != null) {
- configuration().set(DnaLexicon.CLASSPATH).to(classpath[0]).on(pathOfComponentNode);
- } else {
- Object[] remaining = new String[classpath.length - 1];
- System.arraycopy(classpath, 1, remaining, 0, remaining.length);
- configuration().set(DnaLexicon.CLASSPATH).to(classpath[0], remaining).on(pathOfComponentNode);
- }
- return returnObject;
- }
- };
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.ChooseClass#usingClass(java.lang.Class)
- */
- public ReturnType usingClass( Class<? extends ComponentClass> clazz ) {
- CheckArg.isNotNull(clazz, "clazz");
- return usingClass(clazz.getName()).loadedFromClasspath();
- }
- }
-
- /**
- * Reusable implementation of {@link PropertySetter} that sets the JavaBean-style property using reflection.
- *
- * @param <ReturnType>
- * @author Randall Hauch
- */
- protected class BeanPropertySetter<ReturnType> implements PropertySetter<ReturnType> {
- private final Object javaBean;
- private final String beanPropertyName;
- private final ReturnType returnObject;
-
- protected BeanPropertySetter( Object javaBean,
- String beanPropertyName,
- ReturnType returnObject ) {
- assert javaBean != null;
- assert beanPropertyName != null;
- assert returnObject != null;
- this.javaBean = javaBean;
- this.beanPropertyName = beanPropertyName;
- this.returnObject = returnObject;
- }
-
- public ReturnType setTo( boolean value ) {
- return setTo((Object)value);
- }
-
- public ReturnType setTo( int value ) {
- return setTo((Object)value);
- }
-
- public ReturnType setTo( long value ) {
- return setTo((Object)value);
- }
-
- public ReturnType setTo( short value ) {
- return setTo((Object)value);
- }
-
- public ReturnType setTo( float value ) {
- return setTo((Object)value);
- }
-
- public ReturnType setTo( double value ) {
- return setTo((Object)value);
- }
-
- public ReturnType setTo( String value ) {
- return setTo((Object)value);
- }
-
- public ReturnType setTo( Object value ) {
- // Set the JavaBean-style property on the RepositorySource instance ...
- Reflection reflection = new Reflection(javaBean.getClass());
- try {
- reflection.invokeSetterMethodOnTarget(beanPropertyName, javaBean, value);
- } catch (Throwable err) {
- I18n msg = RepositoryI18n.errorSettingJavaBeanPropertyOnInstanceOfClass;
- throw new DnaConfigurationException(msg.text(beanPropertyName, javaBean.getClass(), err.getMessage()), err);
- }
- return returnObject;
- }
- }
-
- /**
- * Reusable implementation of {@link PropertySetter} that sets the property on the specified node in the configuration graph.
- *
- * @param <ReturnType>
- * @author Randall Hauch
- */
- protected class GraphPropertySetter<ReturnType> implements PropertySetter<ReturnType> {
- private final Path path;
- private final String beanPropertyName;
- private final ReturnType returnObject;
-
- protected GraphPropertySetter( Path path,
- String beanPropertyName,
- ReturnType returnObject ) {
- assert path != null;
- assert beanPropertyName != null;
- assert returnObject != null;
- this.path = path;
- this.beanPropertyName = Inflector.getInstance().lowerCamelCase(beanPropertyName);
- this.returnObject = returnObject;
- }
-
- public ReturnType setTo( boolean value ) {
- if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
- configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
- } else {
- configuration().set(beanPropertyName).to(value).on(path);
- }
- return returnObject;
- }
-
- public ReturnType setTo( int value ) {
- if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
- configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
- } else {
- configuration().set(beanPropertyName).to(value).on(path);
- }
- return returnObject;
- }
-
- public ReturnType setTo( long value ) {
- if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
- configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
- } else {
- configuration().set(beanPropertyName).to(value).on(path);
- }
- return returnObject;
- }
-
- public ReturnType setTo( short value ) {
- if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
- configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
- } else {
- configuration().set(beanPropertyName).to(value).on(path);
- }
- return returnObject;
- }
-
- public ReturnType setTo( float value ) {
- if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
- configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
- } else {
- configuration().set(beanPropertyName).to(value).on(path);
- }
- return returnObject;
- }
-
- public ReturnType setTo( double value ) {
- if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
- configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
- } else {
- configuration().set(beanPropertyName).to(value).on(path);
- }
- return returnObject;
- }
-
- public ReturnType setTo( String value ) {
- if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
- configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
- } else {
- configuration().set(beanPropertyName).to(value).on(path);
- }
- return returnObject;
- }
-
- public ReturnType setTo( Object value ) {
- if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
- configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
- } else {
- configuration().set(beanPropertyName).to(value).on(path);
- }
- return returnObject;
- }
- }
-}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -0,0 +1,302 @@
+/*
+ * 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.
+ *
+ * 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.repository;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Node;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.mimetype.MimeTypeDetector;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.repository.Configurator.ChooseClass;
+import org.jboss.dna.repository.Configurator.ConfigRepositoryDetails;
+import org.jboss.dna.repository.Configurator.ConfigurationRepository;
+import org.jboss.dna.repository.Configurator.MimeTypeDetectorDetails;
+import org.jboss.dna.repository.Configurator.RepositoryDetails;
+import org.jboss.dna.repository.Configurator.SequencerDetails;
+import org.jboss.dna.repository.sequencer.Sequencer;
+
+/**
+ *
+ */
+public class DnaConfiguration
+ implements Configurator.Initializer<DnaConfiguration>, Configurator.SequencerConfigurator<DnaConfiguration>,
+ Configurator.RepositoryConfigurator<DnaConfiguration>, Configurator.MimeDetectorConfigurator<DnaConfiguration>,
+ Configurator.Builder<DnaEngine> {
+
+ protected static final Map<String, Name> NAMES_TO_MAP;
+ static {
+ Map<String, Name> names = new HashMap<String, Name>();
+ names.put(DnaLexicon.READABLE_NAME.getLocalName(), DnaLexicon.READABLE_NAME);
+ names.put(DnaLexicon.DESCRIPTION.getLocalName(), DnaLexicon.DESCRIPTION);
+ names.put(DnaLexicon.DEFAULT_CACHE_POLICY.getLocalName(), DnaLexicon.DEFAULT_CACHE_POLICY);
+ names.put(DnaLexicon.RETRY_LIMIT.getLocalName(), DnaLexicon.RETRY_LIMIT);
+ names.put(DnaLexicon.PATH_EXPRESSIONS.getLocalName(), DnaLexicon.PATH_EXPRESSIONS);
+ names.put(DnaLexicon.CLASSNAME.getLocalName(), DnaLexicon.CLASSNAME);
+ names.put(DnaLexicon.CLASSPATH.getLocalName(), DnaLexicon.CLASSPATH);
+ NAMES_TO_MAP = Collections.unmodifiableMap(names);
+ }
+
+ private final Builder<DnaConfiguration> builder;
+
+ /**
+ * Create a new configuration for DNA.
+ */
+ public DnaConfiguration() {
+ this(new ExecutionContext());
+ }
+
+ /**
+ * Specify a new {@link ExecutionContext} that should be used for this DNA instance.
+ *
+ * @param context the new context, or null if a default-constructed execution context should be used
+ * @throws IllegalArgumentException if the supplied context reference is null
+ */
+ public DnaConfiguration( ExecutionContext context ) {
+ this.builder = new Builder<DnaConfiguration>(context, this);
+ }
+
+ /**
+ * Get the execution context used by this configurator.
+ *
+ * @return the execution context; never null
+ */
+ public final ExecutionContext getExecutionContext() {
+ return builder.getExecutionContext();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.Initializer#withConfigurationRepository()
+ */
+ public ChooseClass<RepositorySource, ConfigRepositoryDetails<DnaConfiguration>> withConfigurationRepository() {
+ return builder.withConfigurationRepository();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.RepositoryConfigurator#addRepository(java.lang.String)
+ */
+ public ChooseClass<RepositorySource, RepositoryDetails<DnaConfiguration>> addRepository( String id ) {
+ return builder.addRepository(id);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.RepositoryConfigurator#addRepository(org.jboss.dna.graph.connector.RepositorySource)
+ */
+ public DnaConfiguration addRepository( RepositorySource source ) {
+ return builder.addRepository(source);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SequencerConfigurator#addSequencer(java.lang.String)
+ */
+ public ChooseClass<Sequencer, SequencerDetails<DnaConfiguration>> addSequencer( String id ) {
+ return builder.addSequencer(id);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.MimeDetectorConfigurator#addMimeTypeDetector(java.lang.String)
+ */
+ public ChooseClass<MimeTypeDetector, MimeTypeDetectorDetails<DnaConfiguration>> addMimeTypeDetector( String id ) {
+ return builder.addMimeTypeDetector(id);
+ }
+
+ /**
+ * Save any changes that have been made so far to the configuration. This method does nothing if no changes have been made.
+ *
+ * @return this configuration object for method chaining purposes; never null
+ */
+ public DnaConfiguration save() {
+ return builder.save();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.Builder#build()
+ */
+ public DnaEngine build() throws DnaConfigurationException {
+ save();
+ return new DnaEngine(builder.getExecutionContext(), builder.configurationSource);
+ }
+
+ protected Graph graph() {
+ return builder.graph();
+ }
+
+ protected ConfigurationRepository configurationRepository() {
+ return builder.configurationSource;
+ }
+
+ public static class Builder<ReturnType> extends Configurator<ReturnType>
+ implements Configurator.Initializer<ReturnType>, Configurator.SequencerConfigurator<ReturnType>,
+ Configurator.RepositoryConfigurator<ReturnType>, Configurator.MimeDetectorConfigurator<ReturnType> {
+
+ private Path sourcesPath;
+ private Path sequencersPath;
+ private Path detectorsPath;
+
+ /**
+ * Specify a new {@link ExecutionContext} that should be used for this DNA instance.
+ *
+ * @param context the new context, or null if a default-constructed execution context should be used
+ * @param builder the builder object returned from all the methods
+ * @throws IllegalArgumentException if the supplied context reference is null
+ */
+ public Builder( ExecutionContext context,
+ ReturnType builder ) {
+ super(context, builder);
+ }
+
+ public DnaEngine buildDnaEngine() {
+ return new DnaEngine(context, configurationSource);
+ }
+
+ public ConfigurationRepository getConfigurationRepository() {
+ return configurationSource;
+ }
+
+ protected Path sourcesPath() {
+ // Make sure the "dna:sources" node is there
+ if (sourcesPath == null) {
+ Path path = pathFactory().create(this.configurationSource.getPath(), DnaLexicon.SOURCES);
+ Node node = graph().createIfMissing(path).andReturn();
+ this.sourcesPath = node.getLocation().getPath();
+ }
+ return this.sourcesPath;
+ }
+
+ protected Path sequencersPath() {
+ // Make sure the "dna:sequencers" node is there
+ if (sequencersPath == null) {
+ Path path = pathFactory().create(this.configurationSource.getPath(), DnaLexicon.SEQUENCERS);
+ Node node = graph().createIfMissing(path).andReturn();
+ this.sequencersPath = node.getLocation().getPath();
+ }
+ return this.sequencersPath;
+ }
+
+ protected Path detectorsPath() {
+ // Make sure the "dna:mimeTypeDetectors" node is there
+ if (detectorsPath == null) {
+ Path path = pathFactory().create(this.configurationSource.getPath(), DnaLexicon.MIME_TYPE_DETECTORS);
+ Node node = graph().createIfMissing(path).andReturn();
+ this.detectorsPath = node.getLocation().getPath();
+ }
+ return this.detectorsPath;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.Initializer#withConfigurationRepository()
+ */
+ public ChooseClass<RepositorySource, ConfigRepositoryDetails<ReturnType>> withConfigurationRepository() {
+ return new ConfigurationRepositoryClassChooser<ReturnType>(builder);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.SequencerConfigurator#addSequencer(java.lang.String)
+ */
+ public ChooseClass<Sequencer, SequencerDetails<ReturnType>> addSequencer( String id ) {
+ CheckArg.isNotEmpty(id, "id");
+ // Now create the "dna:sequencer" node with the supplied id ...
+ Path path = createOrReplaceNode(sequencersPath(), id);
+ SequencerDetails<ReturnType> details = new GraphSequencerDetails<ReturnType>(path, builder);
+ return new ClassChooser<Sequencer, SequencerDetails<ReturnType>>(path, details);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.RepositoryConfigurator#addRepository(java.lang.String)
+ */
+ public ChooseClass<RepositorySource, RepositoryDetails<ReturnType>> addRepository( String id ) {
+ CheckArg.isNotEmpty(id, "id");
+ // Now create the "dna:source" node with the supplied id ...
+ Path path = createOrReplaceNode(sourcesPath(), id);
+ RepositoryDetails<ReturnType> details = new GraphRepositoryDetails<ReturnType>(path, builder);
+ return new ClassChooser<RepositorySource, RepositoryDetails<ReturnType>>(path, details);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.RepositoryConfigurator#addRepository(org.jboss.dna.graph.connector.RepositorySource)
+ */
+ public ReturnType addRepository( RepositorySource source ) {
+ CheckArg.isNotNull(source, "source");
+ CheckArg.isNotEmpty(source.getName(), "source.getName()");
+ String name = source.getName();
+ RepositoryDetails<ReturnType> details = addRepository(source.getName()).usingClass(source.getClass().getName())
+ .loadedFromClasspath();
+ // Record all of the bean properties ...
+ Path sourcePath = pathFactory().create(sourcesPath(), name);
+ recordBeanPropertiesInGraph(sourcePath, source);
+ return details.and();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator.MimeDetectorConfigurator#addMimeTypeDetector(java.lang.String)
+ */
+ public ChooseClass<MimeTypeDetector, MimeTypeDetectorDetails<ReturnType>> addMimeTypeDetector( String id ) {
+ CheckArg.isNotEmpty(id, "id");
+ // Now create the "dna:sequencer" node with the supplied id ...
+ Path detectorPath = createOrReplaceNode(detectorsPath(), id);
+ MimeTypeDetectorDetails<ReturnType> details = new GraphMimeTypeDetectorDetails<ReturnType>(detectorPath, builder);
+ return new ClassChooser<MimeTypeDetector, MimeTypeDetectorDetails<ReturnType>>(detectorPath, details);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.Configurator#nameFor(java.lang.String)
+ */
+ @Override
+ protected Name nameFor( String name ) {
+ Name result = NAMES_TO_MAP.get(name);
+ if (result == null) result = context.getValueFactories().getNameFactory().create(name);
+ return result;
+ }
+ }
+
+}
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -70,7 +70,7 @@
public static final String CONFIGURATION_REPOSITORY_NAME = "dna:configuration";
- private final DnaConfiguration.ConfigurationRepository configuration;
+ private final Configurator.ConfigurationRepository configuration;
private final ConfigurationScanner scanner;
private final Problems problems;
private final ExecutionContext context;
@@ -84,14 +84,15 @@
private final RepositoryConnectionFactory connectionFactory;
- DnaEngine( DnaConfiguration configuration ) {
+ DnaEngine( ExecutionContext context,
+ Configurator.ConfigurationRepository configuration ) {
this.problems = new SimpleProblems();
// Use the configuration's context ...
- this.context = configuration.context();
+ this.context = context;
// And set up the scanner ...
- this.configuration = configuration.configurationSource;
+ this.configuration = configuration;
this.scanner = new ConfigurationScanner(this.problems, this.context, this.configuration);
// Add the configuration source to the repository library ...
@@ -211,11 +212,11 @@
protected class ConfigurationScanner {
private final Problems problems;
private final ExecutionContext context;
- private final DnaConfiguration.ConfigurationRepository configurationRepository;
+ private final Configurator.ConfigurationRepository configurationRepository;
protected ConfigurationScanner( Problems problems,
ExecutionContext context,
- DnaConfiguration.ConfigurationRepository configurationRepository ) {
+ Configurator.ConfigurationRepository configurationRepository ) {
this.problems = problems;
this.context = context;
this.configurationRepository = configurationRepository;
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java 2009-04-30 04:32:26 UTC (rev 866)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java 2009-04-30 15:31:52 UTC (rev 867)
@@ -85,8 +85,8 @@
.and()
.save();
assertThat(config, is(notNullValue()));
- assertThat(config.configurationSource.getRepositorySource(), is(instanceOf(InMemoryRepositorySource.class)));
- InMemoryRepositorySource source = (InMemoryRepositorySource)config.configurationSource.getRepositorySource();
+ assertThat(config.configurationRepository().getRepositorySource(), is(instanceOf(InMemoryRepositorySource.class)));
+ InMemoryRepositorySource source = (InMemoryRepositorySource)config.configurationRepository().getRepositorySource();
assertThat(source.getName(), is("repository name"));
assertThat(source.getRetryLimit(), is(5));
}
@@ -287,7 +287,8 @@
.usingClass(ExtensionBasedMimeTypeDetector.class)
.describedAs("default detector");
configuration.addSequencer("sequencerA")
- .usingClass(MockSequencerA.class)
+ .usingClass(MockSequencerA.class.getName())
+ .loadedFromClasspath()
.named("The (Main) Sequencer")
.describedAs("Mock Sequencer A")
.sequencingFrom("/foo/source")
16 years, 7 months
DNA SVN: r866 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory and 14 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-30 00:32:26 -0400 (Thu, 30 Apr 2009)
New Revision: 866
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CopyBranchRequest.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CreateNodeRequest.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/MixinTest.java
trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
trunk/docs/examples/gettingstarted/repositories/src/main/resources/aircraft.xml
trunk/docs/examples/gettingstarted/repositories/src/main/resources/cars.xml
trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java
trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientUsingJcrTest.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedWorkspace.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java
trunk/extensions/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatingRequestProcessorTest.java
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java
trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties
trunk/pom.xml
Log:
DNA-387 Federation connector does not support updates, which are required when using with the JCR implementation
Added support for writes in limited scenarios (when the nodes being changed are within a single projection), and addressed a couple of issues related to the handling of UUIDs in the federation connector. Added more unit tests, verifying the behavior is correct. Also corrected a few errors in CopyBranchRequest, MoveBranchRequest, and CreateNodeRequest. Finally, the repository examples (from the Getting Started document) were corrected to use our JCR implementation.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -263,7 +263,13 @@
InMemoryNode node ) {
assert context != null;
assert node != null;
- assert getRoot().equals(node) != true;
+ if (getRoot().equals(node)) {
+ nodesByUuid.clear();
+ // Create the root node ...
+ InMemoryNode root = new InMemoryNode(rootNodeUuid);
+ nodesByUuid.put(root.getUuid(), root);
+ return;
+ }
InMemoryNode parent = node.getParent();
assert parent != null;
parent.getChildren().remove(node);
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -35,6 +35,7 @@
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.GraphI18n;
+import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
@@ -150,7 +151,7 @@
}
UUID uuid = null;
for (Property property : request.properties()) {
- if (property.getName().equals(DnaLexicon.UUID)) {
+ if (property.getName().equals(DnaLexicon.UUID) || property.getName().equals(JcrLexicon.UUID)) {
uuid = getExecutionContext().getValueFactories().getUuidFactory().create(property.getValues().next());
break;
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CopyBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CopyBranchRequest.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CopyBranchRequest.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -223,6 +223,7 @@
if (into.hasPath() && !intoLocation.getPath().getParent().equals(into.getPath())) {
throw new IllegalArgumentException(GraphI18n.actualLocationIsNotChildOfInputLocation.text(intoLocation, into));
}
+ this.actualFromLocation = fromLocation;
this.actualIntoLocation = intoLocation;
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CreateNodeRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CreateNodeRequest.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CreateNodeRequest.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -168,12 +168,6 @@
for (Property property : properties) {
if (property != null) props.add(property);
}
- // Add in the location properties ...
- if (under.hasIdProperties()) {
- for (Property property : under.getIdProperties()) {
- if (property != null) props.add(property);
- }
- }
this.properties = Collections.unmodifiableList(props);
}
@@ -207,12 +201,6 @@
Property property = properties.next();
if (property != null) props.add(property);
}
- // Add in the location properties ...
- if (under.hasIdProperties()) {
- for (Property property : under.getIdProperties()) {
- if (property != null) props.add(property);
- }
- }
this.properties = Collections.unmodifiableList(props);
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -237,6 +237,7 @@
if (!actualNewName.equals(expectedNewName)) {
throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(newLocation, into));
}
+ this.actualOldLocation = oldLocation;
this.actualNewLocation = newLocation;
}
@@ -265,9 +266,8 @@
*/
public boolean changes( String workspace,
Path path ) {
- return this.workspaceName.equals(workspace)
- && (into.hasPath() && into.getPath().isAtOrBelow(path)
- || from.hasPath() && from.getPath().isAtOrBelow(path));
+ return this.workspaceName.equals(workspace)
+ && (into.hasPath() && into.getPath().isAtOrBelow(path) || from.hasPath() && from.getPath().isAtOrBelow(path));
}
/**
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -94,9 +94,11 @@
assertThat(workspace.getRoot().getUuid(), is(rootUuid));
}
- @Test( expected = AssertionError.class )
- public void shouldNotAllowRootToBeRemoved() {
+ @Test
+ public void shouldAllowRootToBeRemoved() {
workspace.removeNode(context, workspace.getRoot());
+ assertThat(workspace.getRoot().getChildren().size(), is(0));
+ assertThat(workspace.getRoot().getProperties().size(), is(0));
}
@Test( expected = AssertionError.class )
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -141,10 +141,15 @@
context);
namespaceGraph.useWorkspace(workspaceName);
- Name uriProperty = DnaLexicon.NAMESPACE_URI;
+ // Make sure the "/jcr:system" node exists ...
PathFactory pathFactory = context.getValueFactories().getPathFactory();
Path root = pathFactory.createRootPath();
- Path namespacesPath = context.getValueFactories().getPathFactory().create(root, JcrLexicon.SYSTEM, DnaLexicon.NAMESPACES);
+ Path systemPath = pathFactory.create(root, JcrLexicon.SYSTEM);
+ Property systemPrimaryType = context.getPropertyFactory().create(JcrLexicon.PRIMARY_TYPE, DnaLexicon.SYSTEM);
+ namespaceGraph.createIfMissing(systemPath, systemPrimaryType);
+
+ Name uriProperty = DnaLexicon.NAMESPACE_URI;
+ Path namespacesPath = pathFactory.create(systemPath, DnaLexicon.NAMESPACES);
PropertyFactory propertyFactory = context.getPropertyFactory();
Property namespaceType = propertyFactory.create(JcrLexicon.PRIMARY_TYPE, DnaLexicon.NAMESPACE);
org.jboss.dna.graph.property.NamespaceRegistry persistentRegistry = new GraphNamespaceRegistry(namespaceGraph,
@@ -168,9 +173,7 @@
this.queryManager = new JcrQueryManager(this.session);
if (Boolean.valueOf(repository.getOptions().get(Options.PROJECT_NODE_TYPES))) {
- Path parentOfTypeNodes = context.getValueFactories().getPathFactory().create(root,
- JcrLexicon.SYSTEM,
- JcrLexicon.NODE_TYPES);
+ Path parentOfTypeNodes = context.getValueFactories().getPathFactory().create(systemPath, JcrLexicon.NODE_TYPES);
repoTypeManager.projectOnto(this.graph, parentOfTypeNodes);
}
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/MixinTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/MixinTest.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/MixinTest.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -115,10 +115,6 @@
// Set up the initial content ...
graph = Graph.create(source, context);
- // Make sure the path to the namespaces exists ...
- graph.create("/jcr:system"); // .and().create("/jcr:system/dna:namespaces");
- graph.set("jcr:primaryType").on("/jcr:system").to(DnaLexicon.SYSTEM);
-
// Stub out the connection factory ...
connectionFactory = new RepositoryConnectionFactory() {
/**
@@ -318,7 +314,9 @@
public void shouldAllowAdditionIfResidualChildNodeDoesNotConflict() throws Exception {
graph.create("/a").and().create("/a/" + CHILD_NODE_B);
graph.set(JcrLexicon.PRIMARY_TYPE.getString(registry)).on("/a").to(JcrNtLexicon.UNSTRUCTURED.getString(registry));
- graph.set(JcrLexicon.PRIMARY_TYPE.getString(registry)).on("/a/" + CHILD_NODE_B).to(JcrNtLexicon.UNSTRUCTURED.getString(registry));
+ graph.set(JcrLexicon.PRIMARY_TYPE.getString(registry))
+ .on("/a/" + CHILD_NODE_B)
+ .to(JcrNtLexicon.UNSTRUCTURED.getString(registry));
Node rootNode = session.getRootNode();
Node nodeA = rootNode.getNode("a");
@@ -672,4 +670,4 @@
}
-}
\ No newline at end of file
+}
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-04-29 14:31:49 UTC (rev 865)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -138,6 +138,7 @@
// Load into the source manager the repository source for the configuration repository ...
InMemoryRepositorySource configSource = new InMemoryRepositorySource();
configSource.setName("Configuration");
+ configSource.setDefaultWorkspaceName("default");
sources.addSource(configSource);
// For this example, we're using a couple of in-memory repositories (including one for the configuration repository).
@@ -145,7 +146,7 @@
// populate these repositories here by importing from files. First do the configuration repository ...
String location = this.userInterface.getLocationOfRepositoryFiles();
Graph config = Graph.create("Configuration", sources, context);
- config.createWorkspace().named("default");
+ config.useWorkspace("default");
config.importXmlFrom(location + "/configRepository.xml").into("/");
// Now instantiate the Repository Service ...
@@ -295,6 +296,8 @@
children.add(name);
}
}
+ } catch (javax.jcr.ItemNotFoundException e) {
+ return false;
} catch (javax.jcr.PathNotFoundException e) {
return false;
} finally {
Modified: trunk/docs/examples/gettingstarted/repositories/src/main/resources/aircraft.xml
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/main/resources/aircraft.xml 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/resources/aircraft.xml 2009-04-30 04:32:26 UTC (rev 866)
@@ -24,31 +24,31 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-<Aircraft xmlns:jcr="http://www.jcp.org/jcr/1.0">
+<Aircraft xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0">
<Business>
- <aircraft jcr:name="Gulfstream V" maker="Gulfstream" model="G-V" introduced="1995" range="5800nm" cruiseSpeed="488kt" crew="2" emptyWeight="46200lb" url="http://en.wikipedia.org/wiki/Gulfstream_V"/>
- <aircraft jcr:name="Learjet 45" maker="Learjet" model="LJ45" introduced="1995" numberBuilt="264+" crew="2" emptyWeight="13695lb" range="2120nm" cruiseSpeed="457kt" url="http://en.wikipedia.org/wiki/Learjet_45"/>
+ <nt:unstructured jcr:name="Gulfstream V" maker="Gulfstream" model="G-V" introduced="1995" range="5800nm" cruiseSpeed="488kt" crew="2" emptyWeight="46200lb" url="http://en.wikipedia.org/wiki/Gulfstream_V"/>
+ <nt:unstructured jcr:name="Learjet 45" maker="Learjet" model="LJ45" introduced="1995" numberBuilt="264+" crew="2" emptyWeight="13695lb" range="2120nm" cruiseSpeed="457kt" url="http://en.wikipedia.org/wiki/Learjet_45"/>
</Business>
<Commercial>
- <aircraft jcr:name="Boeing 777" maker="Boeing" model="777-200LR" introduced="1995" numberBuilt="731+" maxRange="7500nm" emptyWeight="326000lb" cruiseSpeed="560mph" url="http://en.wikipedia.org/wiki/Boeing_777"/>
- <aircraft jcr:name="Boeing 767" maker="Boeing" model="767-200" introduced="1982" numberBuilt="966+" maxRange="3950nm" emptyWeight="176650lb" cruiseSpeed="530mph" url="http://en.wikipedia.org/wiki/Boeing_767"/>
- <aircraft jcr:name="Boeing 787" maker="Boeing" model="787-3" introduced="2009" range="3050nm" emptyWeight="223000lb" cruiseSpeed="561mph" url="http://en.wikipedia.org/wiki/Boeing_787"/>
- <aircraft jcr:name="Boeing 757" maker="Boeing" model="757-200" introduced="1983" numberBuilt="1050" range="3900nm" maxWeight="255000lb" cruiseSpeed="530mph" url="http://en.wikipedia.org/wiki/Boeing_757"/>
- <aircraft jcr:name="Airbus A380" maker="Airbus" model="A380-800" introduced="2007" numberBuilt="18" range="8200nm" maxWeight="1235000lb" cruiseSpeed="647mph" url="http://en.wikipedia.org/wiki/Airbus_a380"/>
- <aircraft jcr:name="Airbus A340" maker="Airbus" model="A340-200" introduced="1993" numberBuilt="354" range="8000nm" maxWeight="606300lb" cruiseSpeed="557mph" url="http://en.wikipedia.org/wiki/Airbus_A-340"/>
- <aircraft jcr:name="Airbus A310" maker="Airbus" model="A310-200" introduced="1983" numberBuilt="255" cruiseSpeed="850km/h" emptyWeight="176312lb" range="3670nm" url="http://en.wikipedia.org/wiki/Airbus_A-310"/>
- <aircraft jcr:name="Embraer RJ-175" maker="Embraer" model="ERJ170-200" introduced="2004" range="3334km" cruiseSpeed="481kt" emptyWeight="21810kg" url="http://en.wikipedia.org/wiki/EMBRAER_170"/>
+ <nt:unstructured jcr:name="Boeing 777" maker="Boeing" model="777-200LR" introduced="1995" numberBuilt="731+" maxRange="7500nm" emptyWeight="326000lb" cruiseSpeed="560mph" url="http://en.wikipedia.org/wiki/Boeing_777"/>
+ <nt:unstructured jcr:name="Boeing 767" maker="Boeing" model="767-200" introduced="1982" numberBuilt="966+" maxRange="3950nm" emptyWeight="176650lb" cruiseSpeed="530mph" url="http://en.wikipedia.org/wiki/Boeing_767"/>
+ <nt:unstructured jcr:name="Boeing 787" maker="Boeing" model="787-3" introduced="2009" range="3050nm" emptyWeight="223000lb" cruiseSpeed="561mph" url="http://en.wikipedia.org/wiki/Boeing_787"/>
+ <nt:unstructured jcr:name="Boeing 757" maker="Boeing" model="757-200" introduced="1983" numberBuilt="1050" range="3900nm" maxWeight="255000lb" cruiseSpeed="530mph" url="http://en.wikipedia.org/wiki/Boeing_757"/>
+ <nt:unstructured jcr:name="Airbus A380" maker="Airbus" model="A380-800" introduced="2007" numberBuilt="18" range="8200nm" maxWeight="1235000lb" cruiseSpeed="647mph" url="http://en.wikipedia.org/wiki/Airbus_a380"/>
+ <nt:unstructured jcr:name="Airbus A340" maker="Airbus" model="A340-200" introduced="1993" numberBuilt="354" range="8000nm" maxWeight="606300lb" cruiseSpeed="557mph" url="http://en.wikipedia.org/wiki/Airbus_A-340"/>
+ <nt:unstructured jcr:name="Airbus A310" maker="Airbus" model="A310-200" introduced="1983" numberBuilt="255" cruiseSpeed="850km/h" emptyWeight="176312lb" range="3670nm" url="http://en.wikipedia.org/wiki/Airbus_A-310"/>
+ <nt:unstructured jcr:name="Embraer RJ-175" maker="Embraer" model="ERJ170-200" introduced="2004" range="3334km" cruiseSpeed="481kt" emptyWeight="21810kg" url="http://en.wikipedia.org/wiki/EMBRAER_170"/>
</Commercial>
<Vintage>
- <aircraft jcr:name="Fokker Trimotor" maker="Fokker" model="F.VII" introduced="1925" cruiseSpeed="170km/h" emptyWeight="3050kg" crew="2" url="http://en.wikipedia.org/wiki/Fokker_trimotor"/>
- <aircraft jcr:name="P-38 Lightning" maker="Lockheed" model="P-38" designedBy="Kelly Johnson" introduced="1941" numberBuilt="10037" rateOfClimb="4750ft/min" range="1300mi" emptyWeight="12780lb" crew="1" url="http://en.wikipedia.org/wiki/P-38_Lightning"/>
- <aircraft jcr:name="A6M Zero" maker="Mitsubishi" model="A6M" designedBy="Jiro Horikoshi" introduced="1940" numberBuilt="11000" crew="1" emptyWeight="3704lb" serviceCeiling="33000ft" maxSpeed="331mph" range="1929mi" rateOfClimb="3100ft/min" url="http://en.wikipedia.org/wiki/A6M_Zero"/>
- <aircraft jcr:name="Bf 109" maker="Messerschmitt" model="Bf 109" introduced="1937" url="http://en.wikipedia.org/wiki/BF_109"/>
- <aircraft jcr:name="Wright Flyer" maker="Wright Brothers" introduced="1903" range="852ft" maxSpeed="30mph" emptyWeight="605lb" crew="1"/>
+ <nt:unstructured jcr:name="Fokker Trimotor" maker="Fokker" model="F.VII" introduced="1925" cruiseSpeed="170km/h" emptyWeight="3050kg" crew="2" url="http://en.wikipedia.org/wiki/Fokker_trimotor"/>
+ <nt:unstructured jcr:name="P-38 Lightning" maker="Lockheed" model="P-38" designedBy="Kelly Johnson" introduced="1941" numberBuilt="10037" rateOfClimb="4750ft/min" range="1300mi" emptyWeight="12780lb" crew="1" url="http://en.wikipedia.org/wiki/P-38_Lightning"/>
+ <nt:unstructured jcr:name="A6M Zero" maker="Mitsubishi" model="A6M" designedBy="Jiro Horikoshi" introduced="1940" numberBuilt="11000" crew="1" emptyWeight="3704lb" serviceCeiling="33000ft" maxSpeed="331mph" range="1929mi" rateOfClimb="3100ft/min" url="http://en.wikipedia.org/wiki/A6M_Zero"/>
+ <nt:unstructured jcr:name="Bf 109" maker="Messerschmitt" model="Bf 109" introduced="1937" url="http://en.wikipedia.org/wiki/BF_109"/>
+ <nt:unstructured jcr:name="Wright Flyer" maker="Wright Brothers" introduced="1903" range="852ft" maxSpeed="30mph" emptyWeight="605lb" crew="1"/>
</Vintage>
<Homebuilt>
- <aircraft jcr:name="Long-EZ" maker="Rutan Aircraft Factory" model="61" emptyWeight="760lb" fuelCapacity="200L" maxSpeed="185kt" since="1976" range="1200nm" url="http://en.wikipedia.org/wiki/Rutan_Long-EZ"/>
- <aircraft jcr:name="Cirrus VK-30" maker="Cirrus Design" model="VK-30" emptyWeight="2400lb" maxLoad="1200lb" maxSpeed="250mph" rateOfClimb="1500ft/min" range="1300mi" url="http://en.wikipedia.org/wiki/Cirrus_VK-30"/>
- <aircraft jcr:name="Van's RV-4" maker="Van's Aircraft" model="RV-4" introduced="1980" emptyWeight="905lb" maxLoad="500lb" maxSpeed="200mph" rateOfClimb="2450ft/min" range="725mi" url="http://en.wikipedia.org/wiki/Van%27s_Aircraft_RV-4"/>
+ <nt:unstructured jcr:name="Long-EZ" maker="Rutan Aircraft Factory" model="61" emptyWeight="760lb" fuelCapacity="200L" maxSpeed="185kt" since="1976" range="1200nm" url="http://en.wikipedia.org/wiki/Rutan_Long-EZ"/>
+ <nt:unstructured jcr:name="Cirrus VK-30" maker="Cirrus Design" model="VK-30" emptyWeight="2400lb" maxLoad="1200lb" maxSpeed="250mph" rateOfClimb="1500ft/min" range="1300mi" url="http://en.wikipedia.org/wiki/Cirrus_VK-30"/>
+ <nt:unstructured jcr:name="Van's RV-4" maker="Van's Aircraft" model="RV-4" introduced="1980" emptyWeight="905lb" maxLoad="500lb" maxSpeed="200mph" rateOfClimb="2450ft/min" range="725mi" url="http://en.wikipedia.org/wiki/Van%27s_Aircraft_RV-4"/>
</Homebuilt>
</Aircraft>
\ No newline at end of file
Modified: trunk/docs/examples/gettingstarted/repositories/src/main/resources/cars.xml
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/main/resources/cars.xml 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/resources/cars.xml 2009-04-30 04:32:26 UTC (rev 866)
@@ -24,25 +24,25 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-<Cars xmlns:jcr="http://www.jcp.org/jcr/1.0">
+<Cars xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0">
<Hybrid>
- <car jcr:name="Toyota Prius" maker="Toyota" model="Prius" year="2008" msrp="$21,500" userRating="4.2" valueRating="5" mpgCity="48" mpgHighway="45"/>
- <car jcr:name="Toyota Highlander" maker="Toyota" model="Highlander" year="2008" msrp="$34,200" userRating="4" valueRating="5" mpgCity="27" mpgHighway="25"/>
- <car jcr:name="Nissan Altima" maker="Nissan" model="Altima" year="2008" msrp="$18,260" mpgCity="23" mpgHighway="32"/>
+ <nt:unstructured jcr:name="Toyota Prius" maker="Toyota" model="Prius" year="2008" msrp="$21,500" userRating="4.2" valueRating="5" mpgCity="48" mpgHighway="45"/>
+ <nt:unstructured jcr:name="Toyota Highlander" maker="Toyota" model="Highlander" year="2008" msrp="$34,200" userRating="4" valueRating="5" mpgCity="27" mpgHighway="25"/>
+ <nt:unstructured jcr:name="Nissan Altima" maker="Nissan" model="Altima" year="2008" msrp="$18,260" mpgCity="23" mpgHighway="32"/>
</Hybrid>
<Sports>
- <car jcr:name="Aston Martin DB9" maker="Aston Martin" model="DB9" year="2008" msrp="$171,600" userRating="5" mpgCity="12" mpgHighway="19" lengthInInches="185.5" wheelbaseInInches="108.0" engine="5,935 cc 5.9 liters V 12"/>
- <car jcr:name="Infiniti G37" maker="Infiniti" model="G37" year="2008" msrp="$34,900" userRating="3.5" valueRating="4" mpgCity="18" mpgHighway="24" />
+ <nt:unstructured jcr:name="Aston Martin DB9" maker="Aston Martin" model="DB9" year="2008" msrp="$171,600" userRating="5" mpgCity="12" mpgHighway="19" lengthInInches="185.5" wheelbaseInInches="108.0" engine="5,935 cc 5.9 liters V 12"/>
+ <nt:unstructured jcr:name="Infiniti G37" maker="Infiniti" model="G37" year="2008" msrp="$34,900" userRating="3.5" valueRating="4" mpgCity="18" mpgHighway="24" />
</Sports>
<Luxury>
- <car jcr:name="Cadillac DTS" maker="Cadillac" model="DTS" year="2008" engine="3.6-liter V6" userRating="0"/>
- <car jcr:name="Bentley Continental" maker="Bentley" model="Continental" year="2008" msrp="$170,990" mpgCity="10" mpgHighway="17" />
- <car jcr:name="Lexus IS350" maker="Lexus" model="IS350" year="2008" msrp="$36,305" mpgCity="18" mpgHighway="25" userRating="4" valueRating="5" />
+ <nt:unstructured jcr:name="Cadillac DTS" maker="Cadillac" model="DTS" year="2008" engine="3.6-liter V6" userRating="0"/>
+ <nt:unstructured jcr:name="Bentley Continental" maker="Bentley" model="Continental" year="2008" msrp="$170,990" mpgCity="10" mpgHighway="17" />
+ <nt:unstructured jcr:name="Lexus IS350" maker="Lexus" model="IS350" year="2008" msrp="$36,305" mpgCity="18" mpgHighway="25" userRating="4" valueRating="5" />
</Luxury>
<Utility>
- <car jcr:name="Land Rover LR2" maker="Land Rover" model="LR2" year="2008" msrp="$33,985" userRating="4.5" valueRating="5" mpgCity="16" mpgHighway="23" />
- <car jcr:name="Land Rover LR3" maker="Land Rover" model="LR3" year="2008" msrp="$48,525" userRating="5" valueRating="2" mpgCity="12" mpgHighway="17" />
- <car jcr:name="Hummer H3" maker="Hummer" model="H3" year="2008" msrp="$30,595" userRating="3.5" valueRating="4" mpgCity="13" mpgHighway="16" />
- <car jcr:name="Ford F-150" maker="Ford" model="F-150" year="2008" msrp="$23,910" userRating="4" valueRating="1" mpgCity="14" mpgHighway="20" />
+ <nt:unstructured jcr:name="Land Rover LR2" maker="Land Rover" model="LR2" year="2008" msrp="$33,985" userRating="4.5" valueRating="5" mpgCity="16" mpgHighway="23" />
+ <nt:unstructured jcr:name="Land Rover LR3" maker="Land Rover" model="LR3" year="2008" msrp="$48,525" userRating="5" valueRating="2" mpgCity="12" mpgHighway="17" />
+ <nt:unstructured jcr:name="Hummer H3" maker="Hummer" model="H3" year="2008" msrp="$30,595" userRating="3.5" valueRating="4" mpgCity="13" mpgHighway="16" />
+ <nt:unstructured jcr:name="Ford F-150" maker="Ford" model="F-150" year="2008" msrp="$23,910" userRating="4" valueRating="1" mpgCity="14" mpgHighway="20" />
</Utility>
</Cars>
\ No newline at end of file
Modified: trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -139,19 +139,32 @@
getNodeInfo("Cars", "/Cars");
assertThat(children, hasItems("Hybrid", "Sports", "Luxury", "Utility"));
assertThat(properties.containsKey("jcr:primaryType"), is(true));
- assertThat(properties.containsKey("dna:uuid"), is(true));
- assertThat(properties.size(), is(2));
+ switch (getApi()) {
+ case DNA:
+ assertThat(properties.containsKey("dna:uuid"), is(true));
+ assertThat(properties.size(), is(2));
+ break;
+ case JCR:
+ assertThat(properties.size(), is(1));
+ break;
+ }
getNodeInfo("Cars", "/Cars/Hybrid");
assertThat(children, hasItems("Toyota Prius", "Toyota Highlander", "Nissan Altima"));
assertThat(properties.containsKey("jcr:primaryType"), is(true));
- assertThat(properties.containsKey("dna:uuid"), is(true));
- assertThat(properties.size(), is(2));
+ switch (getApi()) {
+ case DNA:
+ assertThat(properties.containsKey("dna:uuid"), is(true));
+ assertThat(properties.size(), is(2));
+ break;
+ case JCR:
+ assertThat(properties.size(), is(1));
+ break;
+ }
getNodeInfo("Cars", "/Cars/Sports/Aston Martin DB9");
assertThat(children.size(), is(0));
assertThat(properties.containsKey("jcr:primaryType"), is(true));
- assertThat(properties.containsKey("dna:uuid"), is(true));
assertProperty("maker", "Aston Martin");
assertProperty("maker", "Aston Martin");
assertProperty("model", "DB9");
@@ -163,7 +176,15 @@
assertProperty("lengthInInches", "185.5");
assertProperty("wheelbaseInInches", "108.0");
assertProperty("engine", "5,935 cc 5.9 liters V 12");
- assertThat(properties.size(), is(12));
+ switch (getApi()) {
+ case DNA:
+ assertThat(properties.containsKey("dna:uuid"), is(true));
+ assertThat(properties.size(), is(12));
+ break;
+ case JCR:
+ assertThat(properties.size(), is(11));
+ break;
+ }
}
@Test
@@ -173,8 +194,7 @@
getNodeInfo("Aircraft", "/Aircraft");
assertThat(children, hasItems("Business", "Commercial", "Vintage", "Homebuilt"));
assertThat(properties.containsKey("jcr:primaryType"), is(true));
- assertThat(properties.containsKey("dna:uuid"), is(true));
- assertThat(properties.size(), is(2));
+ // assertThat(properties.containsKey("dna:uuid"), is(true)); // not referenceable in JCR
getNodeInfo("Aircraft", "/Aircraft/Commercial");
assertThat(children, hasItems("Boeing 777",
@@ -186,20 +206,18 @@
"Airbus A310",
"Embraer RJ-175"));
assertThat(properties.containsKey("jcr:primaryType"), is(true));
- assertThat(properties.containsKey("dna:uuid"), is(true));
- assertThat(properties.size(), is(2));
+ // assertThat(properties.containsKey("dna:uuid"), is(true)); // not referenceable in JCR
getNodeInfo("Aircraft", "/Aircraft/Vintage/Wright Flyer");
assertThat(children.size(), is(0));
assertThat(properties.containsKey("jcr:primaryType"), is(true));
- assertThat(properties.containsKey("dna:uuid"), is(true));
+ // assertThat(properties.containsKey("dna:uuid"), is(true));
assertProperty("maker", "Wright Brothers");
assertProperty("introduced", "1903");
assertProperty("range", "852ft");
assertProperty("maxSpeed", "30mph");
assertProperty("emptyWeight", "605lb");
assertProperty("crew", "1");
- assertThat(properties.size(), is(8));
}
@Test
@@ -208,29 +226,20 @@
getNodeInfo("Vehicles", "/");
assertThat(children, hasItems("Vehicles", "jcr:system"));
- assertThat(properties.containsKey("dna:uuid"), is(true));
- assertThat(properties.size(), is(1));
getNodeInfo("Vehicles", "/Vehicles");
assertThat(children, hasItems("Cars", "Aircraft"));
- assertThat(properties.containsKey("dna:uuid"), is(true));
- assertThat(properties.size(), is(1));
getNodeInfo("Vehicles", "/");
assertThat(children, hasItems("Vehicles", "jcr:system"));
- assertThat(properties.containsKey("dna:uuid"), is(true));
- assertThat(properties.size(), is(1));
getNodeInfo("Vehicles", "/Vehicles/Cars/Hybrid");
assertThat(children, hasItems("Toyota Prius", "Toyota Highlander", "Nissan Altima"));
assertThat(properties.containsKey("jcr:primaryType"), is(true));
- assertThat(properties.containsKey("dna:uuid"), is(true));
- assertThat(properties.size(), is(2));
getNodeInfo("Vehicles", "/Vehicles/Cars/Sports/Aston Martin DB9");
assertThat(children.size(), is(0));
assertThat(properties.containsKey("jcr:primaryType"), is(true));
- assertThat(properties.containsKey("dna:uuid"), is(true));
assertProperty("maker", "Aston Martin");
assertProperty("maker", "Aston Martin");
assertProperty("model", "DB9");
@@ -242,19 +251,16 @@
assertProperty("lengthInInches", "185.5");
assertProperty("wheelbaseInInches", "108.0");
assertProperty("engine", "5,935 cc 5.9 liters V 12");
- assertThat(properties.size(), is(12));
getNodeInfo("Vehicles", "/Vehicles/Aircraft/Vintage/Wright Flyer");
assertThat(children.size(), is(0));
assertThat(properties.containsKey("jcr:primaryType"), is(true));
- assertThat(properties.containsKey("dna:uuid"), is(true));
assertProperty("maker", "Wright Brothers");
assertProperty("introduced", "1903");
assertProperty("range", "852ft");
assertProperty("maxSpeed", "30mph");
assertProperty("emptyWeight", "605lb");
assertProperty("crew", "1");
- assertThat(properties.size(), is(8));
}
@Test
Modified: trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientUsingJcrTest.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientUsingJcrTest.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientUsingJcrTest.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -39,4 +39,14 @@
protected Api getApi() {
return RepositoryClient.Api.JCR;
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.example.dna.repository.RepositoryClientTest#shouldHaveContentFromVehiclesRepository()
+ */
+ @Override
+ public void shouldHaveContentFromVehiclesRepository() throws Throwable {
+ super.shouldHaveContentFromVehiclesRepository();
+ }
}
Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedWorkspace.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedWorkspace.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedWorkspace.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -184,6 +184,16 @@
}
/**
+ * Return the unmodifiable list of projections for the source name.
+ *
+ * @param sourceName the name of the source
+ * @return the list of projections for this source, or null if there are none
+ */
+ public List<Projection> getProjectionsFor( String sourceName ) {
+ return this.projectionsBySourceName.get(sourceName);
+ }
+
+ /**
* Determine whether this workspace has a projection supplied contribution
*
* @param sourceName the name of the source
Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -28,12 +28,14 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
+import net.jcip.annotations.Immutable;
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.util.CheckArg;
@@ -43,6 +45,7 @@
import org.jboss.dna.connector.federation.merge.MergePlan;
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.NodeConflictBehavior;
import org.jboss.dna.graph.cache.CachePolicy;
@@ -56,6 +59,7 @@
import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.PathNotFoundException;
import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.PropertyFactory;
import org.jboss.dna.graph.request.CloneWorkspaceRequest;
import org.jboss.dna.graph.request.CompositeRequest;
import org.jboss.dna.graph.request.CopyBranchRequest;
@@ -70,6 +74,7 @@
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
import org.jboss.dna.graph.request.ReadNodeRequest;
import org.jboss.dna.graph.request.Request;
+import org.jboss.dna.graph.request.UnsupportedRequestException;
import org.jboss.dna.graph.request.UpdatePropertiesRequest;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
import org.jboss.dna.graph.request.processor.RequestProcessor;
@@ -87,6 +92,7 @@
private final RepositoryConnectionFactory connectionFactory;
/** The set of all connections, including the cache connection */
private final Map<String, RepositoryConnection> connectionsBySourceName;
+ protected final PathFactory pathFactory;
private Logger logger;
/**
@@ -116,6 +122,7 @@
this.logger = context.getLogger(getClass());
this.connectionsBySourceName = new HashMap<String, RepositoryConnection>();
this.defaultWorkspace = defaultWorkspace; // may be null
+ this.pathFactory = context.getValueFactories().getPathFactory();
}
protected DateTime getCurrentTimeInUtc() {
@@ -248,31 +255,118 @@
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CopyBranchRequest)
+ * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CreateNodeRequest)
*/
@Override
- public void process( CopyBranchRequest request ) {
- throw new UnsupportedOperationException();
+ public void process( CreateNodeRequest request ) {
+ FederatedWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ if (workspace == null) return;
+
+ // Can push this down if and only if the entire request is within a single federated source ...
+ SingleProjection projection = asSingleProjection(workspace, request.under(), request);
+ if (projection == null) return;
+
+ // Push down the request ...
+ Location parentLocation = Location.create(projection.pathInSource);
+ String workspaceName = projection.projection.getWorkspaceName();
+ CreateNodeRequest sourceRequest = new CreateNodeRequest(parentLocation, workspaceName, request.named(),
+ request.properties());
+ execute(sourceRequest, projection.projection);
+
+ // Copy/transform the results ...
+ if (sourceRequest.hasError()) {
+ request.setError(sourceRequest.getError());
+ } else {
+ request.setActualLocationOfNode(projection.convertToRepository(sourceRequest.getActualLocationOfNode()));
+ }
}
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CreateNodeRequest)
+ * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.DeleteBranchRequest)
*/
@Override
- public void process( CreateNodeRequest request ) {
- throw new UnsupportedOperationException();
+ public void process( DeleteBranchRequest request ) {
+ FederatedWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ if (workspace == null) return;
+
+ // Can push this down if and only if the entire request is within a single federated source ...
+ SingleProjection projection = asSingleProjection(workspace, request.at(), request);
+ if (projection == null) return;
+
+ // Push down the request ...
+ Location sourceLocation = Location.create(projection.pathInSource);
+ String workspaceName = projection.projection.getWorkspaceName();
+ DeleteBranchRequest sourceRequest = new DeleteBranchRequest(sourceLocation, workspaceName);
+ execute(sourceRequest, projection.projection);
+
+ // Copy/transform the results ...
+ if (sourceRequest.hasError()) {
+ request.setError(sourceRequest.getError());
+ } else {
+ request.setActualLocationOfNode(projection.convertToRepository(sourceRequest.getActualLocationOfNode()));
+ }
+
+ // Delete in the cache ...
+ DeleteBranchRequest cacheRequest = new DeleteBranchRequest(request.at(), workspace.getCacheProjection()
+ .getWorkspaceName());
+ executeInCache(cacheRequest, workspace);
}
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.DeleteBranchRequest)
+ * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CopyBranchRequest)
*/
@Override
- public void process( DeleteBranchRequest request ) {
- throw new UnsupportedOperationException();
+ public void process( CopyBranchRequest request ) {
+ FederatedWorkspace fromWorkspace = getWorkspace(request, request.fromWorkspace());
+ if (fromWorkspace == null) return;
+ FederatedWorkspace intoWorkspace = getWorkspace(request, request.intoWorkspace());
+ if (intoWorkspace == null) return;
+ if (!fromWorkspace.equals(intoWorkspace)) {
+ // Otherwise there wasn't a single projection with a single path ...
+ String msg = FederationI18n.unableToPerformOperationSpanningWorkspaces.text(fromWorkspace.getName(),
+ intoWorkspace.getName());
+ request.setError(new UnsupportedRequestException(msg));
+ }
+
+ // Can push this down if and only if the entire request is within a single federated source ...
+ SingleProjection fromProjection = asSingleProjection(fromWorkspace, request.from(), request);
+ if (fromProjection == null) return;
+ SingleProjection intoProjection = asSingleProjection(intoWorkspace, request.into(), request);
+ if (intoProjection == null) return;
+ if (!intoProjection.projection.equals(fromProjection.projection)) {
+ // Otherwise there wasn't a single projection with a single path ...
+ String msg = FederationI18n.unableToPerformOperationUnlessLocationsAreFromSingleProjection.text(request.from(),
+ request.into(),
+ fromWorkspace.getName(),
+ fromProjection.projection.getRules(),
+ intoProjection.projection.getRules());
+ request.setError(new UnsupportedRequestException(msg));
+ }
+
+ // Push down the request ...
+ Location fromLocation = Location.create(fromProjection.pathInSource);
+ Location intoLocation = Location.create(intoProjection.pathInSource);
+ String workspaceName = fromProjection.projection.getWorkspaceName();
+ CopyBranchRequest sourceRequest = new CopyBranchRequest(fromLocation, workspaceName, intoLocation, workspaceName,
+ request.desiredName(), request.conflictBehavior());
+ execute(sourceRequest, fromProjection.projection);
+
+ // Copy/transform the results ...
+ if (sourceRequest.hasError()) {
+ request.setError(sourceRequest.getError());
+ } else {
+ request.setActualLocations(fromProjection.convertToRepository(sourceRequest.getActualLocationBefore()),
+ intoProjection.convertToRepository(sourceRequest.getActualLocationAfter()));
+ }
+
+ // Delete from the cache the parent of the new location ...
+ DeleteBranchRequest cacheRequest = new DeleteBranchRequest(request.into(), fromWorkspace.getCacheProjection()
+ .getWorkspaceName());
+ executeInCache(cacheRequest, fromWorkspace);
}
/**
@@ -282,7 +376,43 @@
*/
@Override
public void process( MoveBranchRequest request ) {
- throw new UnsupportedOperationException();
+ FederatedWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ if (workspace == null) return;
+
+ // Can push this down if and only if the entire request is within a single federated source ...
+ SingleProjection fromProjection = asSingleProjection(workspace, request.from(), request);
+ if (fromProjection == null) return;
+ SingleProjection intoProjection = asSingleProjection(workspace, request.into(), request);
+ if (intoProjection == null) return;
+ if (!intoProjection.projection.equals(fromProjection.projection)) {
+ // Otherwise there wasn't a single projection with a single path ...
+ String msg = FederationI18n.unableToPerformOperationUnlessLocationsAreFromSingleProjection.text(request.from(),
+ request.into(),
+ workspace.getName(),
+ fromProjection.projection.getRules(),
+ intoProjection.projection.getRules());
+ request.setError(new UnsupportedRequestException(msg));
+ }
+
+ // Push down the request ...
+ Location fromLocation = Location.create(fromProjection.pathInSource);
+ Location intoLocation = Location.create(intoProjection.pathInSource);
+ String workspaceName = fromProjection.projection.getWorkspaceName();
+ MoveBranchRequest sourceRequest = new MoveBranchRequest(fromLocation, intoLocation, workspaceName, request.desiredName(),
+ request.conflictBehavior());
+ execute(sourceRequest, fromProjection.projection);
+
+ // Copy/transform the results ...
+ if (sourceRequest.hasError()) {
+ request.setError(sourceRequest.getError());
+ } else {
+ request.setActualLocations(fromProjection.convertToRepository(sourceRequest.getActualLocationBefore()),
+ intoProjection.convertToRepository(sourceRequest.getActualLocationAfter()));
+ }
+ // Delete from the cache ...
+ DeleteBranchRequest cacheRequest = new DeleteBranchRequest(request.from(), workspace.getCacheProjection()
+ .getWorkspaceName());
+ executeInCache(cacheRequest, workspace);
}
/**
@@ -292,7 +422,31 @@
*/
@Override
public void process( UpdatePropertiesRequest request ) {
- throw new UnsupportedOperationException();
+ FederatedWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ if (workspace == null) return;
+
+ // Can push this down if and only if the entire request is within a single federated source ...
+ SingleProjection projection = asSingleProjection(workspace, request.on(), request);
+ if (projection == null) return;
+
+ // Push down the request ...
+ Location sourceLocation = Location.create(projection.pathInSource);
+ String workspaceName = projection.projection.getWorkspaceName();
+ UpdatePropertiesRequest sourceRequest = new UpdatePropertiesRequest(sourceLocation, workspaceName, request.properties());
+ execute(sourceRequest, projection.projection);
+
+ // Copy/transform the results ...
+ if (sourceRequest.hasError()) {
+ request.setError(sourceRequest.getError());
+ } else {
+ request.setActualLocationOfNode(projection.convertToRepository(sourceRequest.getActualLocationOfNode()));
+ }
+
+ // Update the cache ...
+ UpdatePropertiesRequest cacheRequest = new UpdatePropertiesRequest(request.on(), workspace.getCacheProjection()
+ .getWorkspaceName(),
+ request.properties());
+ executeInCache(cacheRequest, workspace);
}
/**
@@ -305,7 +459,7 @@
FederatedWorkspace workspace = getWorkspace(request, request.workspaceName());
if (workspace != null) {
request.setActualWorkspaceName(workspace.getName());
- Location root = Location.create(getExecutionContext().getValueFactories().getPathFactory().createRootPath());
+ Location root = Location.create(pathFactory.createRootPath());
ReadNodeRequest nodeInfo = getNode(root, workspace);
if (nodeInfo.hasError()) return;
request.setActualRootLocation(nodeInfo.getActualLocationOfNode());
@@ -353,6 +507,96 @@
throw new UnsupportedOperationException();
}
+ @Immutable
+ protected class SingleProjection {
+ protected final Projection projection;
+ protected final Path pathInSource;
+ protected final Location federatedLocation;
+
+ protected SingleProjection( Projection projection,
+ Path pathInSource,
+ Location federatedLocation ) {
+ this.projection = projection;
+ this.federatedLocation = federatedLocation;
+ this.pathInSource = pathInSource;
+ }
+
+ protected Location convertToRepository( Location sourceLocation ) {
+ assert sourceLocation != null;
+ if (sourceLocation.hasPath()) {
+ Set<Path> paths = projection.getPathsInRepository(sourceLocation.getPath(), pathFactory);
+ assert paths.size() == 1;
+ return sourceLocation.with(paths.iterator().next());
+ }
+ return sourceLocation;
+ }
+ }
+
+ protected SingleProjection asSingleProjection( FederatedWorkspace federatedWorkspace,
+ Location location,
+ Request request ) {
+ // Check the cache for this location ...
+ ReadNodeRequest nodeInfo = getNode(location, federatedWorkspace);
+ if (nodeInfo.hasError()) {
+ request.setError(nodeInfo.getError());
+ return null;
+ }
+ Location actualLocation = nodeInfo.getActualLocationOfNode();
+ Path pathInRepository = actualLocation.getPath();
+ assert pathInRepository != null;
+
+ // Get the merge plan for the node ...
+ MergePlan plan = getMergePlan(nodeInfo);
+ assert plan != null;
+ if (plan.getRealContributionCount() == 1) {
+ for (Contribution contribution : plan) {
+ if (contribution.isEmpty() || contribution.isPlaceholder()) continue;
+ for (Projection projection : federatedWorkspace.getProjectionsFor(contribution.getSourceName())) {
+ Set<Path> paths = projection.getPathsInSource(pathInRepository, pathFactory);
+ if (paths.size() == 1) {
+ return new SingleProjection(projection, paths.iterator().next(), actualLocation);
+ }
+ }
+ }
+ }
+
+ // Otherwise there wasn't a single projection with a single path ...
+ StringBuilder projections = new StringBuilder();
+ boolean first = true;
+ for (Contribution contribution : plan) {
+ if (contribution.isPlaceholder() || contribution.isEmpty()) continue;
+ if (first) first = false;
+ else projections.append(", ");
+ for (Projection projection : federatedWorkspace.getProjectionsFor(contribution.getSourceName())) {
+ Set<Path> paths = projection.getPathsInSource(pathInRepository, pathFactory);
+ if (paths.size() == 1) {
+ projections.append(FederationI18n.pathInProjection.text(paths.iterator().next(), projection.getRules()));
+ } else {
+ projections.append(FederationI18n.pathInProjection.text(paths, projection.getRules()));
+ }
+ }
+ }
+ String msg = FederationI18n.unableToPerformOperationUnlessLocationIsFromSingleProjection.text(location,
+ federatedWorkspace.getName(),
+ projections);
+ request.setError(new UnsupportedRequestException(msg));
+ return null;
+ }
+
+ protected void execute( Request request,
+ Projection projection ) {
+ RepositoryConnection connection = getConnection(projection);
+ connection.execute(getExecutionContext(), request);
+ // Don't need to close, as we'll close all connections when this processor is closed
+ }
+
+ protected void executeInCache( Request request,
+ FederatedWorkspace workspace ) {
+ RepositoryConnection connection = getConnectionToCacheFor(workspace);
+ connection.execute(getExecutionContext(), request);
+ // Don't need to close, as we'll close all connections when this processor is closed
+ }
+
/**
* Get the node information from the underlying sources or, if possible, from the cache.
*
@@ -363,12 +607,9 @@
*/
protected ReadNodeRequest getNode( Location location,
FederatedWorkspace workspace ) throws RepositorySourceException {
- final ExecutionContext context = getExecutionContext();
-
// Check the cache first ...
- RepositoryConnection cacheConnection = getConnectionToCacheFor(workspace);
ReadNodeRequest fromCache = new ReadNodeRequest(location, workspace.getCacheProjection().getWorkspaceName());
- cacheConnection.execute(context, fromCache);
+ executeInCache(fromCache, workspace);
// Look at the cache results from the cache for problems, or if found a plan in the cache look
// at the contributions. We'll be putting together the set of source names for which we need to
@@ -395,13 +636,19 @@
Location locationToLoad = Location.create(pathToLoad);
loadContributionsFromSources(locationToLoad, workspace, null, contributions); // sourceNames may be
// null or empty
- FederatedNode mergedNode = createFederatedNode(locationToLoad, workspace, contributions, true);
+ FederatedNode mergedNode = createFederatedNode(locationToLoad, workspace, fromCache, contributions, true);
if (mergedNode == null) {
// No source had a contribution ...
I18n msg = FederationI18n.nodeDoesNotExistAtPath;
fromCache.setError(new PathNotFoundException(location, ancestor, msg.text(path, ancestor)));
return fromCache;
}
+ MergePlan mergePlan = mergedNode.getMergePlan();
+ if (mergePlan != null) {
+ Property mergePlanProperty = getExecutionContext().getPropertyFactory().create(DnaLexicon.MERGE_PLAN,
+ (Object)mergePlan);
+ fromCache.addProperty(mergePlanProperty);
+ }
contributions.clear();
// Move to the next child along the path ...
pathToLoad = pathToLoad.getParent();
@@ -449,7 +696,7 @@
location = fromCache.at();
}
loadContributionsFromSources(location, workspace, sourceNames, contributions); // sourceNames may be null or empty
- FederatedNode mergedNode = createFederatedNode(location, workspace, contributions, true);
+ FederatedNode mergedNode = createFederatedNode(location, workspace, fromCache, contributions, true);
if (mergedNode == null) {
// No source had a contribution ...
if (location.hasPath()) {
@@ -467,6 +714,7 @@
protected FederatedNode createFederatedNode( Location location,
FederatedWorkspace federatedWorkspace,
+ ReadNodeRequest fromCache,
List<Contribution> contributions,
boolean updateCache ) throws RepositorySourceException {
assert location != null;
@@ -492,7 +740,7 @@
// Create the node, and use the existing UUID if one is found in the cache ...
ExecutionContext context = getExecutionContext();
assert context != null;
- FederatedNode mergedNode = new FederatedNode(location.with((UUID)null), federatedWorkspace.getName());
+ FederatedNode mergedNode = new FederatedNode(location, federatedWorkspace.getName());
// Merge the results into a single set of results ...
assert contributions.size() > 0;
@@ -502,7 +750,7 @@
}
if (updateCache) {
// Place the results into the cache ...
- updateCache(federatedWorkspace, mergedNode);
+ updateCache(federatedWorkspace, mergedNode, fromCache);
}
// And return the results ...
return mergedNode;
@@ -525,7 +773,6 @@
List<Contribution> contributions ) throws RepositorySourceException {
// At this point, there is no merge plan, so read information from the sources ...
final ExecutionContext context = getExecutionContext();
- final PathFactory pathFactory = context.getValueFactories().getPathFactory();
CachePolicy cachePolicy = federatedWorkspace.getCachePolicy();
// If the location has no path, then we have to submit a request to ALL sources ...
@@ -720,9 +967,9 @@
}
protected void updateCache( FederatedWorkspace federatedWorkspace,
- FederatedNode mergedNode ) throws RepositorySourceException {
+ FederatedNode mergedNode,
+ ReadNodeRequest fromCache ) throws RepositorySourceException {
final ExecutionContext context = getExecutionContext();
- final RepositoryConnection cacheConnection = getConnectionToCacheFor(federatedWorkspace);
final Location location = mergedNode.at();
final Path path = location.getPath();
final String cacheWorkspace = federatedWorkspace.getCacheProjection().getWorkspaceName();
@@ -733,29 +980,126 @@
// If the merged node has a merge plan, then add it to the properties if it is not already there ...
Map<Name, Property> properties = mergedNode.getPropertiesByName();
MergePlan mergePlan = mergedNode.getMergePlan();
- if (mergePlan != null) {
+ if (mergePlan != null && !properties.containsKey(DnaLexicon.MERGE_PLAN)) {
// Record the merge plan on the merged node ...
Property mergePlanProperty = getExecutionContext().getPropertyFactory().create(DnaLexicon.MERGE_PLAN,
(Object)mergePlan);
properties.put(mergePlanProperty.getName(), mergePlanProperty);
}
- if (path.isRoot()) {
- // Set the properties ...
- requests.add(new UpdatePropertiesRequest(location, cacheWorkspace, properties));
- } else {
- // This is not the root node, so we need to create the node ...
+ // Make sure the UUID is being stored ...
+ PropertyFactory propertyFactory = getExecutionContext().getPropertyFactory();
+ Property uuidProperty = properties.get(DnaLexicon.UUID);
+ if (uuidProperty == null) uuidProperty = properties.get(JcrLexicon.UUID);
+ if (uuidProperty == null) {
+ UUID uuid = mergedNode.at().getUuid();
+ if (uuid == null) uuid = UUID.randomUUID();
+ uuidProperty = propertyFactory.create(DnaLexicon.UUID, uuid);
+ properties.put(uuidProperty.getName(), uuidProperty);
+ }
+
+ // Have the children changed ...
+ if (mergedNode.hasError() && !path.isRoot()) {
+ // This is not the root node, so we need to create the node (or replace it if it exists) ...
final Location parentLocation = Location.create(path.getParent());
childName = path.getLastSegment().getName();
requests.add(new CreateNodeRequest(parentLocation, cacheWorkspace, childName, NodeConflictBehavior.REPLACE,
mergedNode.getProperties()));
+ // logger.trace("Adding {0} to cache with properties {1}", location, properties);
+ // Now create all of the children that this federated node knows of ...
+ for (Location child : mergedNode.getChildren()) {
+ childName = child.getPath().getLastSegment().getName();
+ requests.add(new CreateNodeRequest(location, cacheWorkspace, childName, NodeConflictBehavior.APPEND, child));
+ // logger.trace("Caching child of {0} named {1}", location, childName);
+ }
+ } else if (fromCache.getChildren().equals(mergedNode.getChildren())) {
+ // Just update the properties ...
+ requests.add(new UpdatePropertiesRequest(location, cacheWorkspace, properties));
+ // logger.trace("Updating cached properties on the root to {0}", properties);
+ } else {
+ // The children have changed, so figure out how ...
+ if (fromCache.getChildren().isEmpty()) {
+ // No children in the cache, so just update the properties of the node ...
+ requests.add(new UpdatePropertiesRequest(location, cacheWorkspace, properties));
+ // logger.trace("Updating cached properties on {0} to {1}", location, properties);
+
+ // And create all of the children that this federated node knows of ...
+ for (Location child : mergedNode.getChildren()) {
+ childName = child.getPath().getLastSegment().getName();
+ requests.add(new CreateNodeRequest(location, cacheWorkspace, childName, NodeConflictBehavior.APPEND, child));
+ // logger.trace("Caching child of {0} named {1}", location, childName);
+ }
+ } else if (mergedNode.getChildren().isEmpty()) {
+ // There were children in the cache but not in the merged node, so update the cached properties
+ requests.add(new UpdatePropertiesRequest(location, cacheWorkspace, properties));
+
+ // and delete all the children ...
+ for (Location child : fromCache.getChildren()) {
+ requests.add(new DeleteBranchRequest(child, cacheWorkspace));
+ // logger.trace("Removing {0} from cache", child);
+ }
+ } else {
+ // There were children in the cache and in the merged node. The easy way is to just remove the
+ // branch from the cache, the create it again ...
+ if (path.isRoot()) {
+ requests.add(new UpdatePropertiesRequest(location, cacheWorkspace, properties));
+ // logger.trace("Updating cached properties on {0} to {1}", location, properties);
+
+ // and delete all the children ...
+ for (Location child : fromCache.getChildren()) {
+ requests.add(new DeleteBranchRequest(child, cacheWorkspace));
+ // logger.trace("Removing child node {0} from cache", child);
+ }
+
+ // Now create all of the children that this federated node knows of ...
+ for (Location child : mergedNode.getChildren()) {
+ childName = child.getPath().getLastSegment().getName();
+ requests.add(new CreateNodeRequest(location, cacheWorkspace, childName, NodeConflictBehavior.APPEND,
+ child));
+ // logger.trace("Caching child of {0} named {1}", location, childName);
+ }
+ } else {
+ requests.add(new DeleteBranchRequest(location, cacheWorkspace));
+ // logger.trace("Replacing node {0} from cache", location);
+
+ // This is not the root node, so we need to create the node (or replace it if it exists) ...
+ final Location parentLocation = Location.create(path.getParent());
+ childName = path.getLastSegment().getName();
+ requests.add(new CreateNodeRequest(parentLocation, cacheWorkspace, childName, NodeConflictBehavior.REPLACE,
+ mergedNode.getProperties()));
+ // logger.trace("Adding {0} to cache with properties {1}", location, properties);
+ // Now create all of the children that this federated node knows of ...
+ for (Location child : mergedNode.getChildren()) {
+ childName = child.getPath().getLastSegment().getName();
+ requests.add(new CreateNodeRequest(location, cacheWorkspace, childName, NodeConflictBehavior.APPEND,
+ child));
+ // logger.trace("Caching child of {0} named {1}", location, childName);
+ }
+ }
+ }
}
- // Now create all of the children that this federated node knows of ...
- for (Location child : mergedNode.getChildren()) {
- childName = child.getPath().getLastSegment().getName();
- requests.add(new CreateNodeRequest(location, cacheWorkspace, childName, NodeConflictBehavior.APPEND));
+ // Execute all the requests ...
+ final RepositoryConnection cacheConnection = getConnectionToCacheFor(federatedWorkspace);
+ cacheConnection.execute(context, CompositeRequest.with(requests));
+
+ // If the children did not have UUIDs, then find the actual locations for each of the cached nodes ...
+ if (requests.size() > 1) {
+ Iterator<Request> requestIter = requests.iterator();
+ requestIter.next(); // Skip the first request, which creates/updates the node (we want children)
+ List<Location> children = mergedNode.getChildren();
+ for (int i = 0; i != children.size(); ++i) {
+ Request request = requestIter.next();
+ while (!(request instanceof CreateNodeRequest)) { // skip non-create requests
+ request = requestIter.next();
+ }
+ Location actual = ((CreateNodeRequest)request).getActualLocationOfNode();
+ Location child = children.get(i);
+ if (!child.hasIdProperties()) {
+ assert child.getPath().equals(actual.getPath());
+ children.set(i, actual);
+ }
+ }
}
- cacheConnection.execute(context, CompositeRequest.with(requests));
}
}
Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -43,6 +43,11 @@
public static I18n unableToAuthenticateConnectionToFederatedRepository;
public static I18n repositoryHasBeenShutDown;
public static I18n errorAddingProjectionRuleParseMethod;
+ public static I18n pathInProjection;
+ public static I18n pathsInProjection;
+ public static I18n unableToPerformOperationUnlessLocationIsFromSingleProjection;
+ public static I18n unableToPerformOperationUnlessLocationsAreFromSingleProjection;
+ public static I18n unableToPerformOperationSpanningWorkspaces;
public static I18n workspaceDoesNotExist;
public static I18n noDefaultWorkspace;
Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -242,6 +242,21 @@
public abstract int getContributionCount();
/**
+ * Get the number of contributions that are not placeholders or empty.
+ *
+ * @return the number of real contributions
+ */
+ public int getRealContributionCount() {
+ int count = 0;
+ for (Contribution contribution : this) {
+ if (contribution.isPlaceholder()) continue;
+ if (contribution.isEmpty()) continue;
+ ++count;
+ }
+ return count;
+ }
+
+ /**
* Get the plan annotation property with the given name. Plan annotations are custom properties that may be set by
* MergeProcessor implementations to store custom properties on the plan. This method does nothing if the supplied name is
* null
Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -91,26 +91,32 @@
}
if (dnaUuidProperty != null) uuidProperty = dnaUuidProperty; // use "dna:uuid" if there is one
- // Look for the UUID property on the properties, and update the federated node ...
- if (uuidProperty != null && !uuidProperty.isEmpty()) {
- UUID uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getFirstValue());
- uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, uuid); // Use the "dna:uuid" name
- federatedNode.setActualLocationOfNode(federatedNode.at().with(uuidProperty));
+ if (federatedNode.at().getUuid() != null) {
+ federatedNode.setActualLocationOfNode(federatedNode.at());
} else {
- // Make sure there's a UUID for an identification property ...
- if (location.getUuid() == null) {
- location = location.with(UUID.randomUUID());
+ // Look for the UUID property on the properties, and update the federated node ...
+ if (uuidProperty != null && !uuidProperty.isEmpty()) {
+ UUID uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getFirstValue());
+ uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, uuid); // Use the "dna:uuid" name
+ federatedNode.setActualLocationOfNode(federatedNode.at().with(uuidProperty));
+ } else {
+ // Make sure there's a UUID for an identification property ...
+ if (location.getUuid() == null) {
+ location = location.with(UUID.randomUUID());
+ }
+ // Set the UUID as a property (it wasn't set already) ...
+ uuidProperty = location.getIdProperty(DnaLexicon.UUID);
+ assert uuidProperty != null; // there should be one!
+ federatedNode.addProperty(uuidProperty);
+ federatedNode.setActualLocationOfNode(location);
}
- // Set the UUID as a property (it wasn't set already) ...
- uuidProperty = location.getIdProperty(DnaLexicon.UUID);
- assert uuidProperty != null; // there should be one!
- federatedNode.addProperty(uuidProperty);
- federatedNode.setActualLocationOfNode(location);
}
// Assign the merge plan ...
MergePlan mergePlan = MergePlan.create(contributions);
federatedNode.setMergePlan(mergePlan);
+ Property mergePlanProperty = context.getPropertyFactory().create(DnaLexicon.MERGE_PLAN, (Object)mergePlan);
+ federatedNode.addProperty(mergePlanProperty);
}
private boolean hasUuidValue( ExecutionContext context,
Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -110,7 +110,7 @@
if (!childNames.containsKey(childName)) {
childNames.put(childName, 1);
Path pathToChild = pathFactory.create(location.getPath(), childName);
- federatedNode.addChild(Location.create(pathToChild));
+ federatedNode.addChild(child.with(pathToChild));
}
}
} else {
@@ -140,7 +140,7 @@
index = previousValue;
}
Path pathToChild = pathFactory.create(location.getPath(), childName, index);
- federatedNode.addChild(Location.create(pathToChild));
+ federatedNode.addChild(child.with(pathToChild)); // keep the same identifiers
}
// Add in the properties ...
@@ -152,7 +152,7 @@
// Record the property ...
Property existing = properties.put(property.getName(), property);
- if (existing != null) {
+ if (existing != null && !existing.equals(property)) {
// There's already an existing property, so we need to merge them ...
Property merged = merge(existing, property, context.getPropertyFactory(), removeDuplicateProperties);
properties.put(property.getName(), merged);
@@ -181,6 +181,8 @@
// Assign the merge plan ...
MergePlan mergePlan = MergePlan.create(contributions);
federatedNode.setMergePlan(mergePlan);
+ Property mergePlanProperty = context.getPropertyFactory().create(DnaLexicon.MERGE_PLAN, (Object)mergePlan);
+ properties.put(mergePlanProperty.getName(), mergePlanProperty);
}
/**
Modified: trunk/extensions/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/extensions/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties 2009-04-30 04:32:26 UTC (rev 866)
@@ -32,6 +32,11 @@
unableToAuthenticateConnectionToFederatedRepository = Unable to authenticate "{1}" for federated repository "{0}"
repositoryHasBeenShutDown = The "{0}" federated repository has been shut down and may no longer be used.
errorAddingProjectionRuleParseMethod = Error while adding a parsing method for a federation projection rule
+pathInProjection = path "{0}" in projection {1}
+pathsInProjection = paths "{0}" in projection {1}
+unableToPerformOperationUnlessLocationIsFromSingleProjection = The node "{0}" in workspace "{1}" must be within a single projection for this operation to succeed, but is in {2}
+unableToPerformOperationUnlessLocationsAreFromSingleProjection = The nodes "{0}" and "{1}" in workspace "{2}" must both be within a single projection for this operation to succeed, but come from projections "{3}" and "{4}"
+unableToPerformOperationSpanningWorkspaces = Unable to perform operation spanning workspaces ("{0}" and "{1}")
workspaceDoesNotExist = The "{0}" federated repository does not have a workspace named "{1}"
noDefaultWorkspace = The "{0}" federated repository does not have a default workspace
\ No newline at end of file
Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatingRequestProcessorTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatingRequestProcessorTest.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatingRequestProcessorTest.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -41,10 +41,6 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import org.jboss.dna.connector.federation.FederatedWorkspace;
-import org.jboss.dna.connector.federation.FederatingRequestProcessor;
-import org.jboss.dna.connector.federation.Projection;
-import org.jboss.dna.connector.federation.ProjectionParser;
import org.jboss.dna.connector.federation.contribution.Contribution;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
@@ -55,8 +51,19 @@
import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
import org.jboss.dna.graph.property.DateTime;
+import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.request.CopyBranchRequest;
+import org.jboss.dna.graph.request.CreateNodeRequest;
+import org.jboss.dna.graph.request.DeleteBranchRequest;
+import org.jboss.dna.graph.request.MoveBranchRequest;
+import org.jboss.dna.graph.request.ReadAllChildrenRequest;
+import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
+import org.jboss.dna.graph.request.ReadPropertyRequest;
+import org.jboss.dna.graph.request.UnsupportedRequestException;
+import org.jboss.dna.graph.request.UpdatePropertiesRequest;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
@@ -93,6 +100,7 @@
cachePolicy = new BasicCachePolicy(219L, TimeUnit.SECONDS);
cacheSource = new InMemoryRepositorySource();
cacheSource.setName("Cache");
+ cacheSource.setDefaultWorkspaceName("cacheSpace");
ProjectionParser ruleParser = ProjectionParser.getInstance();
cacheProjectionRules = ruleParser.rulesFromStrings(context, "/ => /cache/repo/A");
cacheProjection = new Projection(cacheSource.getName(), "cacheSpace", cacheProjectionRules);
@@ -128,6 +136,82 @@
doReturn(cacheSource.getConnection()).when(connectionFactory).createConnection(cacheSource.getName());
}
+ protected Name name( String name ) {
+ return context.getValueFactories().getNameFactory().create(name);
+ }
+
+ protected Path path( String path ) {
+ return pathFactory.create(path);
+ }
+
+ protected Path.Segment segment( String path ) {
+ return pathFactory.createSegment(path);
+ }
+
+ protected Property property( String name,
+ Object... values ) {
+ return context.getPropertyFactory().create(name(name), values);
+ }
+
+ protected Map<Name, Property> addProperty( Map<Name, Property> properties,
+ String name,
+ Object... values ) {
+ Property property = property(name, values);
+ properties.put(property.getName(), property);
+ return properties;
+ }
+
+ protected void assertNodeHasChildren( String path,
+ String... expectedChildSegments ) {
+ Location parent = Location.create(path(path));
+ ReadAllChildrenRequest request = new ReadAllChildrenRequest(parent, "fedSpace");
+ executor.process(request);
+ assertThat(request.hasError(), is(false));
+ assertThat(request.getActualLocationOfNode().getPath(), is(path(path)));
+ List<Location> actualChildLocations = request.getChildren();
+ Path.Segment[] actualChildren = new Path.Segment[actualChildLocations.size()];
+ for (int i = 0; i != actualChildren.length; ++i) {
+ Path actualChildPath = actualChildLocations.get(i).getPath();
+ actualChildren[i] = actualChildPath.getLastSegment();
+ assertThat(actualChildPath.getParent(), is(path(path)));
+ }
+ Path.Segment[] expectedChildren = new Path.Segment[expectedChildSegments.length];
+ for (int i = 0; i != expectedChildren.length; ++i) {
+ expectedChildren[i] = segment(expectedChildSegments[i]);
+ }
+ assertThat(actualChildren, is(expectedChildren));
+ }
+
+ protected void assertNodeHasProperty( String path,
+ String propertyName,
+ Object... expectedValues ) {
+ Location parent = Location.create(path(path));
+ ReadPropertyRequest request = new ReadPropertyRequest(parent, "fedSpace", name(propertyName));
+ executor.process(request);
+ assertThat(request.hasError(), is(false));
+ assertThat(request.getActualLocationOfNode().getPath(), is(path(path)));
+ Object[] actualValues = request.getProperty().getValuesAsArray();
+ String[] actualValuesAsStrings = new String[actualValues.length];
+ for (int i = 0; i != actualValues.length; ++i) {
+ actualValuesAsStrings[i] = context.getValueFactories().getStringFactory().create(actualValues[i]);
+ }
+ String[] expectedValuesAsStrings = new String[expectedValues.length];
+ for (int i = 0; i != expectedValues.length; ++i) {
+ expectedValuesAsStrings[i] = context.getValueFactories().getStringFactory().create(expectedValues[i]);
+ }
+ assertThat(actualValuesAsStrings, is(expectedValuesAsStrings));
+ }
+
+ protected void assertNodeHasNoProperty( String path,
+ String propertyName ) {
+ Location parent = Location.create(path(path));
+ ReadAllPropertiesRequest request = new ReadAllPropertiesRequest(parent, "fedSpace");
+ executor.process(request);
+ assertThat(request.hasError(), is(false));
+ assertThat(request.getActualLocationOfNode().getPath(), is(path(path)));
+ assertThat(request.getPropertiesByName().containsKey(name(propertyName)), is(false));
+ }
+
@Test( expected = IllegalArgumentException.class )
public void shouldFailWhenExecutionContextIsNull() {
context = null;
@@ -568,9 +652,203 @@
assertThat(contributions.get(2).isExpired(nowPlus310InUtc), is(true)); // expired by cache @ 219
}
+ /**
+ * Set up the sources such that:
+ * <ul>
+ * <li>Source 1: "{@code /a => /source/one/a}", "{@code /b => /source/one/b}"</li>
+ * <li>Source 2: "{@code /a => /source/two/a}"</li>
+ * <li>Source 1: "{@code / => /}"</li>
+ * </ul>
+ */
+ protected void initializeSourcesWithContent() {
+ // Set up the content of source 1
+ Graph repository1 = Graph.create(source1, context);
+ repository1.createWorkspace().named("workspace1");
+ Graph.Batch batch = repository1.batch();
+ batch.create("/source").and();
+ batch.create("/source/one").and();
+ batch.create("/source/one/a").with("desc", "source 1 node a description").and();
+ batch.create("/source/one/a/nA").with("desc", "source 1 node nA description").and();
+ batch.create("/source/one/a/nB").with("desc", "source 1 node nB description").and();
+ batch.create("/source/one/a/nC").with("desc", "source 1 node nC description").and();
+ batch.create("/source/one/b").with("desc", "source 1 node b description").and();
+ batch.create("/source/one/b/pA").with("desc", "source 1 node pA description").and();
+ batch.create("/source/one/b/pB").with("desc", "source 1 node pB description").and();
+ batch.create("/source/one/b/pC").with("desc", "source 1 node pC description").and();
+ batch.execute();
+
+ // Set up the content of source 2
+ Graph repository2 = Graph.create(source2, context);
+ repository2.createWorkspace().named("workspace2");
+ batch = repository2.batch();
+ batch.create("/source").and();
+ batch.create("/source/two").and();
+ batch.create("/source/two/a").with("desc", "source 2 node a description").and();
+ batch.create("/source/two/a/qA").with("desc", "source 2 node qA description").and();
+ batch.create("/source/two/a/qB").with("desc", "source 2 node qB description").and();
+ batch.create("/source/two/a/qC").with("desc", "source 2 node qC description").and();
+ batch.execute();
+
+ // Set up the content of source 3
+ Graph repository3 = Graph.create(source3, context);
+ repository3.createWorkspace().named("workspace3");
+ batch = repository3.batch();
+ batch.create("/x").and();
+ batch.create("/x/y").with("desc", "y description").and();
+ batch.create("/x/y/zA").with("desc", "zA description").and();
+ batch.create("/x/y/zB").with("desc", "zB description").and();
+ batch.create("/x/y/zC").with("desc", "zC description").and();
+ batch.create("/b").and();
+ batch.create("/b/by").with("desc", "by description").and();
+ batch.create("/b/by/bzA").with("desc", "bzA description").and();
+ batch.create("/b/by/bzB").with("desc", "bzB description").and();
+ batch.create("/a").and();
+ batch.create("/a/ay").with("desc", "ay description").and();
+ batch.create("/a/ay/azA").with("desc", "azA description").and();
+ batch.create("/a/ay/azB").with("desc", "azB description").and();
+ batch.execute();
+
+ }
+
+ @Test( expected = UnsupportedRequestException.class )
+ public void shouldNotCreateNodeIfParentIsOutsideSingleProjection() throws Throwable {
+ initializeSourcesWithContent();
+ Location parent = Location.create(path("/a")); // source 2 or 3?
+ CreateNodeRequest request = new CreateNodeRequest(parent, "fedSpace", name("child"));
+ executor.process(request);
+ if (request.hasError()) throw request.getError();
+ }
+
@Test
- public void shouldGetNodeUsingPath() {
+ public void shouldCreateNodeOnlyIfParentIsInsideSingleProjection() throws Throwable {
+ initializeSourcesWithContent();
+ Location parent = Location.create(path("/a/ay")); // source 3
+ CreateNodeRequest request = new CreateNodeRequest(parent, "fedSpace", name("child"));
+ executor.process(request);
+ assertThat(request.hasError(), is(false));
+ assertThat(request.getActualLocationOfNode().getPath(), is(path("/a/ay/child")));
+ assertNodeHasChildren("/a/ay", "azA", "azB", "child");
+ }
+ @Test( expected = UnsupportedRequestException.class )
+ public void shouldNotDestroyNodeIfOutsideSingleProjection() throws Throwable {
+ initializeSourcesWithContent();
+ Location location = Location.create(path("/a")); // source 2 or 3?
+ DeleteBranchRequest request = new DeleteBranchRequest(location, "fedSpace");
+ executor.process(request);
+ if (request.hasError()) throw request.getError();
}
+ @Test
+ public void shouldDestroyNodeOnlyIfInsideSingleProjection() throws Throwable {
+ initializeSourcesWithContent();
+ assertNodeHasChildren("/a", "nA", "nB", "nC", "qA", "qB", "qC", "ay");
+ Location location = Location.create(path("/a/ay")); // source 3
+ DeleteBranchRequest request = new DeleteBranchRequest(location, "fedSpace");
+ executor.process(request);
+ assertThat(request.hasError(), is(false));
+ assertThat(request.getActualLocationOfNode().getPath(), is(path("/a/ay")));
+ assertNodeHasChildren("/a", "nA", "nB", "nC", "qA", "qB", "qC");
+ }
+
+ @Test( expected = UnsupportedRequestException.class )
+ public void shouldNotUpdateNodeIfOutsideSingleProjection() throws Throwable {
+ initializeSourcesWithContent();
+ Location location = Location.create(path("/a")); // source 2 or 3?
+ Map<Name, Property> properties = new HashMap<Name, Property>();
+ addProperty(properties, "prop1", "value1");
+ addProperty(properties, "prop2", "value2a", "value2b");
+ UpdatePropertiesRequest request = new UpdatePropertiesRequest(location, "fedSpace", properties);
+ executor.process(request);
+ if (request.hasError()) throw request.getError();
+ }
+
+ @Test
+ public void shouldUpdateNodeOnlyIfInsideSingleProjection() throws Throwable {
+ initializeSourcesWithContent();
+ // assertNodeHasChildren("/a", "nA", "nB", "nC", "qA", "qB", "qC", "ay");
+ assertNodeHasProperty("/a/ay", "desc", "ay description");
+ assertNodeHasNoProperty("/a/ay", "prop1");
+ assertNodeHasNoProperty("/a/ay", "prop2");
+ Location location = Location.create(path("/a/ay")); // source 3
+ Map<Name, Property> properties = new HashMap<Name, Property>();
+ addProperty(properties, "desc", "ay description 2");
+ addProperty(properties, "prop1", "value1");
+ addProperty(properties, "prop2", "value2a", "value2b");
+ UpdatePropertiesRequest request = new UpdatePropertiesRequest(location, "fedSpace", properties);
+ executor.process(request);
+ assertThat(request.hasError(), is(false));
+ assertThat(request.getActualLocationOfNode().getPath(), is(path("/a/ay")));
+ assertNodeHasProperty("/a/ay", "desc", "ay description 2");
+ assertNodeHasProperty("/a/ay", "prop1", "value1");
+ assertNodeHasProperty("/a/ay", "prop2", "value2a", "value2b");
+ assertNodeHasChildren("/a", "nA", "nB", "nC", "qA", "qB", "qC", "ay");
+ }
+
+ @Test( expected = UnsupportedRequestException.class )
+ public void shouldNotMoveNodeIfParentIsOutsideSingleProjection() throws Throwable {
+ initializeSourcesWithContent();
+ Location from = Location.create(path("/a/ay")); // source 3
+ Location into = Location.create(path("/b")); // source 1 or source 3?
+ assertNodeHasChildren("/a", "nA", "nB", "nC", "qA", "qB", "qC", "ay");
+ assertNodeHasChildren("/b", "pA", "pB", "pC", "by");
+ MoveBranchRequest request = new MoveBranchRequest(from, into, "fedSpace");
+ executor.process(request);
+ if (request.hasError()) throw request.getError();
+ }
+
+ @Test
+ public void shouldMoveNodeOnlyIfParentIsInsideSingleProjection() throws Throwable {
+ initializeSourcesWithContent();
+ Location from = Location.create(path("/a/ay")); // source 3
+ Location into = Location.create(path("/b/by")); // source 3
+ assertNodeHasChildren("/a", "nA", "nB", "nC", "qA", "qB", "qC", "ay");
+ assertNodeHasChildren("/b", "pA", "pB", "pC", "by");
+ assertNodeHasChildren("/b/by", "bzA", "bzB");
+ MoveBranchRequest request = new MoveBranchRequest(from, into, "fedSpace");
+ executor.process(request);
+ if (request.hasError()) {
+ System.out.println(request.getError().getMessage());
+ }
+ assertThat(request.hasError(), is(false));
+ assertThat(request.getActualLocationBefore().getPath(), is(path("/a/ay")));
+ assertThat(request.getActualLocationAfter().getPath(), is(path("/b/by/ay")));
+ assertNodeHasChildren("/a", "nA", "nB", "nC", "qA", "qB", "qC");
+ assertNodeHasChildren("/b/by", "bzA", "bzB", "ay");
+ }
+
+ @Test( expected = UnsupportedRequestException.class )
+ public void shouldNotCopyNodeIfParentIsOutsideSingleProjection() throws Throwable {
+ initializeSourcesWithContent();
+ Location from = Location.create(path("/a/ay")); // source 3
+ Location into = Location.create(path("/b")); // source 1 or source 3?
+ assertNodeHasChildren("/a", "nA", "nB", "nC", "qA", "qB", "qC", "ay");
+ assertNodeHasChildren("/b", "pA", "pB", "pC", "by");
+ CopyBranchRequest request = new CopyBranchRequest(from, "fedSpace", into, "fedSpace");
+ executor.process(request);
+ if (request.hasError()) throw request.getError();
+ }
+
+ @Test
+ public void shouldCopyNodeOnlyIfParentIsInsideSingleProjection() throws Throwable {
+ initializeSourcesWithContent();
+ Location from = Location.create(path("/a/ay")); // source 3
+ Location into = Location.create(path("/b/by")); // source 3
+ assertNodeHasChildren("/a", "nA", "nB", "nC", "qA", "qB", "qC", "ay");
+ assertNodeHasChildren("/a/ay", "azA", "azB");
+ assertNodeHasChildren("/b", "pA", "pB", "pC", "by");
+ assertNodeHasChildren("/b/by", "bzA", "bzB");
+ CopyBranchRequest request = new CopyBranchRequest(from, "fedSpace", into, "fedSpace");
+ executor.process(request);
+ if (request.hasError()) {
+ System.out.println(request.getError().getMessage());
+ }
+ assertThat(request.hasError(), is(false));
+ assertThat(request.getActualLocationBefore().getPath(), is(path("/a/ay")));
+ assertThat(request.getActualLocationAfter().getPath(), is(path("/b/by/ay")));
+ assertNodeHasChildren("/a", "nA", "nB", "nC", "qA", "qB", "qC", "ay");
+ assertNodeHasChildren("/b/by", "bzA", "bzB", "ay");
+ assertNodeHasChildren("/b/by/ay", "azA", "azB");
+ }
+
}
Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -104,6 +104,7 @@
stub(contribution.getProperties()).toReturn(properties.values().iterator());
strategy.merge(node, contributions, context);
properties.put(DnaLexicon.UUID, node.getPropertiesByName().get(DnaLexicon.UUID));
+ properties.put(DnaLexicon.MERGE_PLAN, node.getPropertiesByName().get(DnaLexicon.MERGE_PLAN));
assertThat(node.getPropertiesByName(), is(properties));
}
Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java 2009-04-30 04:32:26 UTC (rev 866)
@@ -88,8 +88,9 @@
public void shouldCombinePropertiesFromOneContribution() {
addContribution("source1").setProperty("p1", "p1 value");
strategy.merge(node, contributions, context);
- assertThat(node.getProperties().size(), is(2));
+ assertThat(node.getProperties().size(), is(3));
assertThat(node.getPropertiesByName().get(DnaLexicon.UUID), is(notNullValue()));
+ assertThat(node.getPropertiesByName().get(DnaLexicon.MERGE_PLAN), is(notNullValue()));
assertThat(node.getPropertiesByName().get(name("p1")), is(property("p1", "p1 value")));
}
@@ -122,8 +123,9 @@
addContribution("source1").setProperty("p1", "p1 value");
addContribution("source2").setProperty("p2", "p2 value");
strategy.merge(node, contributions, context);
- assertThat(node.getProperties().size(), is(3));
+ assertThat(node.getProperties().size(), is(4));
assertThat(node.getPropertiesByName().get(DnaLexicon.UUID), is(notNullValue()));
+ assertThat(node.getPropertiesByName().get(DnaLexicon.MERGE_PLAN), is(notNullValue()));
assertThat(node.getPropertiesByName().get(name("p1")), is(property("p1", "p1 value")));
assertThat(node.getPropertiesByName().get(name("p2")), is(property("p2", "p2 value")));
}
@@ -133,8 +135,9 @@
addContribution("source1").setProperty("p1", "p1 value").setProperty("p12", "1", "2", "3");
addContribution("source2").setProperty("p2", "p2 value").setProperty("p12", "3", "4");
strategy.merge(node, contributions, context);
- assertThat(node.getProperties().size(), is(4));
+ assertThat(node.getProperties().size(), is(5));
assertThat(node.getPropertiesByName().get(DnaLexicon.UUID), is(notNullValue()));
+ assertThat(node.getPropertiesByName().get(DnaLexicon.MERGE_PLAN), is(notNullValue()));
assertThat(node.getPropertiesByName().get(name("p1")), is(property("p1", "p1 value")));
assertThat(node.getPropertiesByName().get(name("p2")), is(property("p2", "p2 value")));
assertThat(node.getPropertiesByName().get(name("p12")), is(property("p12", "1", "2", "3", "4")));
@@ -145,7 +148,8 @@
addContribution("source1").setProperty("p1", "p1 value").setProperty("p12", "1", "2", "3");
addContribution("source2").setProperty("p2", "p2 value").setProperty("p12", "3", "4");
strategy.merge(node, contributions, context);
- assertThat(node.getProperties().size(), is(4));
+ assertThat(node.getProperties().size(), is(5));
+ assertThat(node.getPropertiesByName().get(DnaLexicon.MERGE_PLAN), is(notNullValue()));
assertThat(node.getPropertiesByName().get(DnaLexicon.UUID), is(notNullValue()));
for (Contribution contribution : contributions) {
Iterator<Property> iter = contribution.getProperties();
@@ -173,8 +177,9 @@
addContribution("source1").setProperty("p1", "p1 value").setProperty("p12", "1", "2", "3");
addContribution("source2").setProperty("p2", "p2 value").setProperty("p12", 3, 4);
strategy.merge(node, contributions, context);
- assertThat(node.getProperties().size(), is(4));
+ assertThat(node.getProperties().size(), is(5));
assertThat(node.getPropertiesByName().get(DnaLexicon.UUID), is(notNullValue()));
+ assertThat(node.getPropertiesByName().get(DnaLexicon.MERGE_PLAN), is(notNullValue()));
assertThat(node.getPropertiesByName().get(name("p1")), is(property("p1", "p1 value")));
assertThat(node.getPropertiesByName().get(name("p2")), is(property("p2", "p2 value")));
assertThat(node.getPropertiesByName().get(name("p12")), is(property("p12", "1", "2", "3", 4)));
Modified: trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties 2009-04-30 04:32:26 UTC (rev 866)
@@ -9,7 +9,7 @@
# Set up the default logging to be INFO level, then override specific units
log4j.logger.org.jboss.dna=INFO
-log4j.logger.org.jboss.dna.connector.federation.executor=INFO
+log4j.logger.org.jboss.dna.connector.federation=TRACE
# Jackrabbit logging
log4j.logger.org.apache.jackrabbit=WARN, stdout
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2009-04-29 14:31:49 UTC (rev 865)
+++ trunk/pom.xml 2009-04-30 04:32:26 UTC (rev 866)
@@ -135,7 +135,7 @@
<module>extensions/dna-common-jdbc</module>
<module>extensions/dna-connector-jdbc-metadata</module>
<module>dna-integration-tests</module>
- <!--module>docs/examples/gettingstarted</module-->
+ <module>docs/examples/gettingstarted</module>
</modules>
<profiles>
16 years, 7 months
DNA SVN: r865 - trunk/dna-jcr/src/main/java/org/jboss/dna/jcr.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-29 10:31:49 -0400 (Wed, 29 Apr 2009)
New Revision: 865
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
Log:
DNA-376 Add request to change the order of a child node (or nodes) relative to the other children
Added a partial implementation of the AbstractJcrNode.orderBefore(...) method, though this partial implementation is never reached because the method still throws an UnsupportedOperationException. This partial implementation should be completed when the Graph API has support for reordering children.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-04-29 14:23:58 UTC (rev 864)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-04-29 14:31:49 UTC (rev 865)
@@ -69,6 +69,7 @@
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NamespaceRegistry;
import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.ValueFactories;
import org.jboss.dna.jcr.SessionCache.NodeEditor;
import org.jboss.dna.jcr.cache.ChildNode;
@@ -1437,8 +1438,44 @@
* @see javax.jcr.Node#orderBefore(java.lang.String, java.lang.String)
*/
public final void orderBefore( String srcChildRelPath,
- String destChildRelPath ) throws UnsupportedRepositoryOperationException {
- throw new UnsupportedRepositoryOperationException();
+ String destChildRelPath ) throws UnsupportedRepositoryOperationException, RepositoryException {
+ if (true) throw new UnsupportedRepositoryOperationException();
+
+ // This implementation is correct, except for not calling the SessionCache or graph layer to do the re-order
+ if (!getPrimaryNodeType().hasOrderableChildNodes()) {
+ throw new UnsupportedRepositoryOperationException();
+ }
+
+ PathFactory pathFactory = this.cache.pathFactory();
+
+ Path srcPath = pathFactory.create(srcChildRelPath);
+ ChildNode source;
+
+ if (srcPath.isAbsolute() || srcPath.size() != 1) {
+ throw new ItemNotFoundException();
+ }
+ // getLastSegment should return the only segment, since we verified that size() == 1
+ source = nodeInfo().getChildren().getChild(srcPath.getLastSegment());
+ if (source == null) {
+ throw new ItemNotFoundException();
+ }
+
+ Path destPath = null;
+ ChildNode destination = null;
+
+ if (destChildRelPath != null) {
+ destPath = pathFactory.create(destChildRelPath);
+ if (destPath.isAbsolute() || destPath.size() != 1) {
+ throw new ItemNotFoundException();
+ }
+
+ // getLastSegment should return the only segment, since we verified that size() == 1
+ destination = nodeInfo().getChildren().getChild(destPath.getLastSegment());
+ if (destination == null) {
+ throw new ItemNotFoundException();
+ }
+ }
+
}
protected static List<Object> createPatternsFor( String namePattern ) throws RepositoryException {
16 years, 7 months
DNA SVN: r864 - in trunk/dna-jcr/src: test/java/org/jboss/dna/jcr and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-29 10:23:58 -0400 (Wed, 29 Apr 2009)
New Revision: 864
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
Log:
DNA-388 AbstractJcrNode.getReferences() is incorrectly implemented
The method now throws an UnsupportedOperationException, since the method is not implemented correctly. Also commented out some unit tests that were testing these methods.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-04-29 14:14:34 UTC (rev 863)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-04-29 14:23:58 UTC (rev 864)
@@ -420,6 +420,8 @@
* @see javax.jcr.Node#getReferences()
*/
public final PropertyIterator getReferences() throws RepositoryException {
+ if (true) throw new UnsupportedOperationException();
+ // This implementation is just wrong.
// Iterate through the properties to see which ones have a REFERENCE type ...
Collection<AbstractJcrProperty> properties = cache.findJcrPropertiesFor(nodeUuid);
Collection<AbstractJcrProperty> references = new LinkedList<AbstractJcrProperty>();
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java 2009-04-29 14:14:34 UTC (rev 863)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java 2009-04-29 14:23:58 UTC (rev 864)
@@ -25,12 +25,9 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsSame.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.stub;
-import java.util.Arrays;
-import java.util.List;
import java.util.UUID;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
@@ -39,7 +36,6 @@
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
@@ -399,49 +395,49 @@
node.getPrimaryItem();
}
- @Test
- public void shouldReturnEmptyIteratorFromGetReferencesWhenThereAreNoProperties() throws Exception {
- // Set up two properties (one containing references, the other not) ...
- List<AbstractJcrProperty> props = Arrays.asList(new AbstractJcrProperty[] {});
- stub(cache.findJcrPropertiesFor(uuid)).toReturn(props);
- // Now call the method ...
- PropertyIterator iter = node.getReferences();
- assertThat(iter.getSize(), is(0L));
- assertThat(iter.hasNext(), is(false));
- }
+ // @Test
+ // public void shouldReturnEmptyIteratorFromGetReferencesWhenThereAreNoProperties() throws Exception {
+ // // Set up two properties (one containing references, the other not) ...
+ // List<AbstractJcrProperty> props = Arrays.asList(new AbstractJcrProperty[] {});
+ // stub(cache.findJcrPropertiesFor(uuid)).toReturn(props);
+ // // Now call the method ...
+ // PropertyIterator iter = node.getReferences();
+ // assertThat(iter.getSize(), is(0L));
+ // assertThat(iter.hasNext(), is(false));
+ // }
+ //
+ // @Test
+ // public void shouldReturnEmptyIteratorFromGetReferencesWhenThereAreNoReferenceProperties() throws Exception {
+ // // Set up two properties (one containing references, the other not) ...
+ // AbstractJcrProperty propertyA = mock(AbstractJcrProperty.class);
+ // AbstractJcrProperty propertyB = mock(AbstractJcrProperty.class);
+ // List<AbstractJcrProperty> props = Arrays.asList(new AbstractJcrProperty[] {propertyA, propertyB});
+ // stub(cache.findJcrPropertiesFor(uuid)).toReturn(props);
+ // stub(propertyA.getType()).toReturn(PropertyType.LONG);
+ // stub(propertyB.getType()).toReturn(PropertyType.BOOLEAN);
+ // // Now call the method ...
+ // PropertyIterator iter = node.getReferences();
+ // assertThat(iter.getSize(), is(0L));
+ // assertThat(iter.hasNext(), is(false));
+ // }
+ //
+ // @Test
+ // public void shouldReturnIteratorFromGetReferencesWhenThereIsAtLeastOneReferenceProperty() throws Exception {
+ // // Set up two properties (one containing references, the other not) ...
+ // AbstractJcrProperty propertyA = mock(AbstractJcrProperty.class);
+ // AbstractJcrProperty propertyB = mock(AbstractJcrProperty.class);
+ // List<AbstractJcrProperty> props = Arrays.asList(new AbstractJcrProperty[] {propertyA, propertyB});
+ // stub(cache.findJcrPropertiesFor(uuid)).toReturn(props);
+ // stub(propertyA.getType()).toReturn(PropertyType.LONG);
+ // stub(propertyB.getType()).toReturn(PropertyType.REFERENCE);
+ // // Now call the method ...
+ // PropertyIterator iter = node.getReferences();
+ // assertThat(iter.getSize(), is(1L));
+ // assertThat(iter.next(), is(sameInstance((Object)propertyB)));
+ // assertThat(iter.hasNext(), is(false));
+ // }
@Test
- public void shouldReturnEmptyIteratorFromGetReferencesWhenThereAreNoReferenceProperties() throws Exception {
- // Set up two properties (one containing references, the other not) ...
- AbstractJcrProperty propertyA = mock(AbstractJcrProperty.class);
- AbstractJcrProperty propertyB = mock(AbstractJcrProperty.class);
- List<AbstractJcrProperty> props = Arrays.asList(new AbstractJcrProperty[] {propertyA, propertyB});
- stub(cache.findJcrPropertiesFor(uuid)).toReturn(props);
- stub(propertyA.getType()).toReturn(PropertyType.LONG);
- stub(propertyB.getType()).toReturn(PropertyType.BOOLEAN);
- // Now call the method ...
- PropertyIterator iter = node.getReferences();
- assertThat(iter.getSize(), is(0L));
- assertThat(iter.hasNext(), is(false));
- }
-
- @Test
- public void shouldReturnIteratorFromGetReferencesWhenThereIsAtLeastOneReferenceProperty() throws Exception {
- // Set up two properties (one containing references, the other not) ...
- AbstractJcrProperty propertyA = mock(AbstractJcrProperty.class);
- AbstractJcrProperty propertyB = mock(AbstractJcrProperty.class);
- List<AbstractJcrProperty> props = Arrays.asList(new AbstractJcrProperty[] {propertyA, propertyB});
- stub(cache.findJcrPropertiesFor(uuid)).toReturn(props);
- stub(propertyA.getType()).toReturn(PropertyType.LONG);
- stub(propertyB.getType()).toReturn(PropertyType.REFERENCE);
- // Now call the method ...
- PropertyIterator iter = node.getReferences();
- assertThat(iter.getSize(), is(1L));
- assertThat(iter.next(), is(sameInstance((Object)propertyB)));
- assertThat(iter.hasNext(), is(false));
- }
-
- @Test
public void shouldProvideSession() throws Exception {
assertThat((JcrSession)node.getSession(), is(session));
}
16 years, 7 months
DNA SVN: r863 - trunk/dna-jcr/src/main/java/org/jboss/dna/jcr.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-29 10:14:34 -0400 (Wed, 29 Apr 2009)
New Revision: 863
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
Log:
DNA-386 AbstractJcrNode Javadoc Throws Clause Are Out Of Sync
Removed the "@throws UnsupportedOperationException always" line from the JavaDoc of several methods. These lines were leftovers from when the methods were indeed not implemented.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-04-29 12:58:43 UTC (rev 862)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-04-29 14:14:34 UTC (rev 863)
@@ -126,8 +126,8 @@
throw new RepositoryException(msg);
}
}
-
- final NodeEditor editorFor(Graph.Batch operations) throws RepositoryException {
+
+ final NodeEditor editorFor( Graph.Batch operations ) throws RepositoryException {
try {
return cache.getEditorFor(nodeUuid, operations);
} catch (ItemNotFoundException err) {
@@ -137,7 +137,7 @@
String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
throw new RepositoryException(msg);
}
- }
+ }
final JcrValue valueFrom( int propertyType,
Object value ) {
@@ -241,7 +241,6 @@
/**
* {@inheritDoc}
*
- * @throws UnsupportedOperationException always
* @see javax.jcr.Node#getPrimaryNodeType()
*/
public JcrNodeType getPrimaryNodeType() throws RepositoryException {
@@ -252,11 +251,10 @@
Name getPrimaryTypeName() throws RepositoryException {
return nodeInfo().getPrimaryTypeName();
}
-
+
/**
* {@inheritDoc}
*
- * @throws UnsupportedOperationException always
* @see javax.jcr.Node#getMixinNodeTypes()
*/
public NodeType[] getMixinNodeTypes() throws RepositoryException {
@@ -564,7 +562,6 @@
/**
* {@inheritDoc}
*
- * @throws UnsupportedOperationException always
* @see javax.jcr.Node#getNodes(java.lang.String)
*/
public NodeIterator getNodes( String namePattern ) throws RepositoryException {
@@ -944,17 +941,17 @@
NodeInfo grandparentInfo;
if (parentPath.size() > 1) {
// Per the TCK, if relPath references a property, then we have to throw a ConstraintViolationException
- // So, if we can't find the parent, try for the parent's parent and see if the last segment of the parent's
+ // So, if we can't find the parent, try for the parent's parent and see if the last segment of the
+ // parent's
// path contains a property ...
Path grandparentPath = parentPath.getParent();
assert grandparentPath != null;
-
+
grandparentInfo = cache.findNodeInfo(nodeUuid, grandparentPath); // throws PathNotFoundException
- }
- else {
+ } else {
grandparentInfo = this.nodeInfo();
}
-
+
if (grandparentInfo.getProperty(parentPath.getLastSegment().getName()) != null) {
// Need to throw a ConstraintViolationException since the request was to add a child to
// a property ...
@@ -999,8 +996,7 @@
throw new UnsupportedOperationException();
}
- protected final Property removeExistingValuedProperty( String name )
- throws ConstraintViolationException, RepositoryException {
+ protected final Property removeExistingValuedProperty( String name ) throws ConstraintViolationException, RepositoryException {
PropertyId id = new PropertyId(nodeUuid, nameFrom(name));
AbstractJcrProperty property = cache.findJcrProperty(id);
if (property != null) {
@@ -1133,7 +1129,9 @@
return removeExistingValuedProperty(name);
}
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), valuesFrom(PropertyType.STRING, values), PropertyType.UNDEFINED));
+ return cache.findJcrProperty(editor().setProperty(nameFrom(name),
+ valuesFrom(PropertyType.STRING, values),
+ PropertyType.UNDEFINED));
}
/**
@@ -1306,8 +1304,7 @@
public final boolean isModified() {
try {
return nodeInfo().isModified();
- }
- catch (RepositoryException re) {
+ } catch (RepositoryException re) {
throw new IllegalStateException(re);
}
}
@@ -1320,8 +1317,7 @@
public final boolean isNew() {
try {
return nodeInfo().isNew();
- }
- catch (RepositoryException re) {
+ } catch (RepositoryException re) {
throw new IllegalStateException(re);
}
}
16 years, 7 months
DNA SVN: r862 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory and 10 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-29 08:58:43 -0400 (Wed, 29 Apr 2009)
New Revision: 862
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPathAndProperty.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/JodaDateTime.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
trunk/docs/examples/gettingstarted/repositories/src/main/resources/configRepository.xml
trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceIntegrationTest.java
Log:
DNA-282 Federation connector improperly handles root-level node with one projection of a non-root node from a single source
Corrected the connector to properly handle root-level nodes in this particular case. The problem was in how the UUIDs were being handled. Fixed a couple of other minor issues as well.
Found another issue while getting the Getting Started repository examples running (see DNA-387).
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPathAndProperty.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPathAndProperty.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/LocationWithPathAndProperty.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -182,8 +182,8 @@
@Override
public Location with( UUID uuid ) {
Property idProperty = idProperties.get(0); // fast
+ if (uuid == null) return Location.create(path);
assert !DnaLexicon.UUID.equals(idProperty.getName());
- if (uuid == null) return Location.create(path);
Property newUuidProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
return Location.create(path, idProperty, newUuidProperty);
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -71,21 +71,26 @@
*/
public static final int DEFAULT_RETRY_LIMIT = 0;
+ /**
+ * The default name for the workspace used by this source, which is a blank string.
+ */
+ public static final String DEFAULT_WORKSPACE_NAME = "";
+
protected static final RepositorySourceCapabilities CAPABILITIES = new RepositorySourceCapabilities(true, true, false, true,
true);
- protected static final String ROOT_NODE_UUID = "rootNodeUuid";
- protected static final String SOURCE_NAME = "sourceName";
- protected static final String DEFAULT_WORKSPACE_NAME = "defaultWorkspaceName";
- protected static final String DEFAULT_CACHE_POLICY = "defaultCachePolicy";
- protected static final String JNDI_NAME = "jndiName";
- protected static final String RETRY_LIMIT = "retryLimit";
+ protected static final String ROOT_NODE_UUID_ATTR = "rootNodeUuid";
+ protected static final String SOURCE_NAME_ATTR = "sourceName";
+ protected static final String DEFAULT_WORKSPACE_NAME_ATTR = "defaultWorkspaceName";
+ protected static final String DEFAULT_CACHE_POLICY_ATTR = "defaultCachePolicy";
+ protected static final String JNDI_NAME_ATTR = "jndiName";
+ protected static final String RETRY_LIMIT_ATTR = "retryLimit";
@GuardedBy( "sourcesLock" )
private String name;
@GuardedBy( "this" )
private String jndiName;
- private String defaultWorkspaceName;
+ private String defaultWorkspaceName = DEFAULT_WORKSPACE_NAME;
private UUID rootNodeUuid = UUID.randomUUID();
private CachePolicy defaultCachePolicy;
private final AtomicInteger retryLimit = new AtomicInteger(DEFAULT_RETRY_LIMIT);
@@ -164,7 +169,7 @@
* @param defaultWorkspaceName the name of the workspace that should be used by default, or null if "" should be used
*/
public void setDefaultWorkspaceName( String defaultWorkspaceName ) {
- this.defaultWorkspaceName = defaultWorkspaceName;
+ this.defaultWorkspaceName = defaultWorkspaceName != null ? defaultWorkspaceName : DEFAULT_WORKSPACE_NAME;
}
/**
@@ -265,16 +270,16 @@
Reference ref = new Reference(className, factoryClassName, null);
if (getName() != null) {
- ref.add(new StringRefAddr(SOURCE_NAME, getName()));
+ ref.add(new StringRefAddr(SOURCE_NAME_ATTR, getName()));
}
if (getRootNodeUuid() != null) {
- ref.add(new StringRefAddr(ROOT_NODE_UUID, getRootNodeUuid().toString()));
+ ref.add(new StringRefAddr(ROOT_NODE_UUID_ATTR, getRootNodeUuid().toString()));
}
if (getJndiName() != null) {
- ref.add(new StringRefAddr(JNDI_NAME, getJndiName()));
+ ref.add(new StringRefAddr(JNDI_NAME_ATTR, getJndiName()));
}
if (getDefaultWorkspaceName() != null) {
- ref.add(new StringRefAddr(DEFAULT_WORKSPACE_NAME, getDefaultWorkspaceName()));
+ ref.add(new StringRefAddr(DEFAULT_WORKSPACE_NAME_ATTR, getDefaultWorkspaceName()));
}
if (getDefaultCachePolicy() != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -282,13 +287,13 @@
try {
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(policy);
- ref.add(new BinaryRefAddr(DEFAULT_CACHE_POLICY, baos.toByteArray()));
+ ref.add(new BinaryRefAddr(DEFAULT_CACHE_POLICY_ATTR, baos.toByteArray()));
} catch (IOException e) {
I18n msg = GraphI18n.errorSerializingInMemoryCachePolicyInSource;
throw new RepositorySourceException(getName(), msg.text(policy.getClass().getName(), getName()), e);
}
}
- ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
+ ref.add(new StringRefAddr(RETRY_LIMIT_ATTR, Integer.toString(getRetryLimit())));
return ref;
}
@@ -321,12 +326,12 @@
}
}
}
- String sourceName = (String)values.get(SOURCE_NAME);
- String rootNodeUuidString = (String)values.get(ROOT_NODE_UUID);
- String jndiName = (String)values.get(JNDI_NAME);
- String defaultWorkspaceName = (String)values.get(DEFAULT_WORKSPACE_NAME);
- Object defaultCachePolicy = values.get(DEFAULT_CACHE_POLICY);
- String retryLimit = (String)values.get(RETRY_LIMIT);
+ String sourceName = (String)values.get(SOURCE_NAME_ATTR);
+ String rootNodeUuidString = (String)values.get(ROOT_NODE_UUID_ATTR);
+ String jndiName = (String)values.get(JNDI_NAME_ATTR);
+ String defaultWorkspaceName = (String)values.get(DEFAULT_WORKSPACE_NAME_ATTR);
+ Object defaultCachePolicy = values.get(DEFAULT_CACHE_POLICY_ATTR);
+ String retryLimit = (String)values.get(RETRY_LIMIT_ATTR);
// Create the source instance ...
InMemoryRepositorySource source = new InMemoryRepositorySource();
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/JodaDateTime.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/JodaDateTime.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/JodaDateTime.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -320,6 +320,7 @@
if (that instanceof JodaDateTime) {
return this.instance.compareTo(((JodaDateTime)that).instance);
}
+ if (that == null) return 1;
long diff = this.toUtcTimeZone().getMilliseconds() - that.toUtcTimeZone().getMilliseconds();
return (int)diff;
}
@@ -406,7 +407,7 @@
* @see org.jboss.dna.graph.property.DateTime#minus(long, java.util.concurrent.TimeUnit)
*/
public org.jboss.dna.graph.property.DateTime minus( long timeAmount,
- TimeUnit unit ) {
+ TimeUnit unit ) {
CheckArg.isNotNull(unit, "unit");
return new JodaDateTime(this.instance.minus(TimeUnit.MILLISECONDS.convert(timeAmount, unit)));
}
@@ -489,7 +490,7 @@
* @see org.jboss.dna.graph.property.DateTime#plus(long, java.util.concurrent.TimeUnit)
*/
public org.jboss.dna.graph.property.DateTime plus( long timeAmount,
- TimeUnit unit ) {
+ TimeUnit unit ) {
CheckArg.isNotNull(unit, "unit");
return new JodaDateTime(this.instance.plus(TimeUnit.MILLISECONDS.convert(timeAmount, unit)));
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -348,7 +348,7 @@
// No attribute defines the node name ...
nodeName = nameFactory.create(uri, localName, decoder);
} else {
- typePropertyValue = nameFactory.create(uri, localName, decoder);
+ if (typePropertyValue == null) typePropertyValue = nameFactory.create(uri, localName, decoder);
}
if (typeAttribute != null) {
// A attribute defines the node name. Set the type property, if required
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -305,7 +305,7 @@
String workspaceName ) throws RepositoryException {
// Ensure credentials are either null or provide a JAAS method
Map<String, Object> sessionAttributes = new HashMap<String, Object>();
- ExecutionContext execContext;
+ ExecutionContext execContext = null;
if (credentials == null) {
execContext = executionContext;
} else {
@@ -371,7 +371,7 @@
// Per JCR 1.0 6.1.1, if the workspaceName is not recognized, a NoSuchWorkspaceException is thrown
throw new NoSuchWorkspaceException(JcrI18n.workspaceNameIsInvalid.text(sourceName, workspaceName));
}
- workspaceName = graph.getCurrentWorkspace().getName();
+ graph.useWorkspace(workspaceName);
} catch (InvalidWorkspaceException e) {
throw new NoSuchWorkspaceException(JcrI18n.workspaceNameIsInvalid.text(sourceName, workspaceName), e);
} catch (RepositorySourceException e) {
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -147,6 +147,7 @@
this.graph = Graph.create(this.repository.getRepositorySourceName(),
this.repository.getConnectionFactory(),
this.executionContext);
+ this.graph.useWorkspace(workspace.getName());
this.cache = new SessionCache(this, workspace.getName(), this.executionContext, this.workspace.nodeTypeManager(),
this.graph);
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -139,6 +139,8 @@
Graph namespaceGraph = Graph.create(this.repository.getRepositorySourceName(),
this.repository.getConnectionFactory(),
context);
+ namespaceGraph.useWorkspace(workspaceName);
+
Name uriProperty = DnaLexicon.NAMESPACE_URI;
PathFactory pathFactory = context.getValueFactories().getPathFactory();
Path root = pathFactory.createRootPath();
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -2134,6 +2134,11 @@
// Start with the primary type ...
JcrNodeType primaryType = nodeTypes().getNodeType(primaryTypeName);
+ if (primaryType == null) {
+ Path path = location.getPath();
+ String msg = JcrI18n.missingNodeTypeForExistingNode.text(primaryTypeName.getString(namespaces), path, workspaceName);
+ throw new RepositorySourceException(msg);
+ }
if (primaryType.isNodeType(JcrMixLexicon.REFERENCEABLE)) referenceable = true;
// The process the mixin types ...
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-04-28 19:33:35 UTC (rev 861)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -149,16 +149,15 @@
config.importXmlFrom(location + "/configRepository.xml").into("/");
// Now instantiate the Repository Service ...
- repositoryService = new RepositoryService(sources, configSource.getName(), "default", context);
+ Path configRoot = context.getValueFactories().getPathFactory().create("/jcr:system");
+ repositoryService = new RepositoryService(sources, configSource.getName(), "default", configRoot, context);
repositoryService.getAdministrator().start();
// Now import the conten for two of the other in-memory repositories ...
Graph cars = Graph.create("Cars", sources, context);
- cars.createWorkspace().named("default");
cars.importXmlFrom(location + "/cars.xml").into("/");
Graph aircraft = Graph.create("Aircraft", sources, context);
- aircraft.createWorkspace().named("default");
aircraft.importXmlFrom(location + "/aircraft.xml").into("/");
}
@@ -249,9 +248,9 @@
Session session = null;
if (loginContext != null) {
Credentials credentials = new JaasCredentials(loginContext);
- session = jcrRepository.login(credentials, sourceName);
+ session = jcrRepository.login(credentials, "default");
} else {
- session = jcrRepository.login(sourceName);
+ session = jcrRepository.login("default");
}
try {
// Make the path relative to the root by removing the leading slash(es) ...
Modified: trunk/docs/examples/gettingstarted/repositories/src/main/resources/configRepository.xml
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/main/resources/configRepository.xml 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/resources/configRepository.xml 2009-04-29 12:58:43 UTC (rev 862)
@@ -24,39 +24,41 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-<dna:system xmlns:dna="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+<jcr:system xmlns:dna="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <dna:namespaces jcr:primaryType="dna:namespaces">
+ </dna:namespaces>
<!-- Define the sources from which content is made available -->
- <dna:sources>
- <dna:source jcr:name="SourceA" dna:name="Cars" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" dna:retryLimit="3" />
- <dna:source jcr:name="SourceB" dna:name="Aircraft" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" />
- <dna:source jcr:name="SourceC" dna:name="Vehicles" dna:classname="org.jboss.dna.connector.federation.FederatedRepositorySource"
+ <dna:sources jcr:primaryType="nt:unstructured">
+ <dna:source jcr:name="SourceA" jcr:primaryType="nt:unstructured" dna:name="Cars" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" dna:retryLimit="3" defaultWorkspaceName="default"/>
+ <dna:source jcr:name="SourceB" jcr:primaryType="nt:unstructured" dna:name="Aircraft" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" defaultWorkspaceName="default"/>
+ <dna:source jcr:name="SourceC" jcr:primaryType="nt:unstructured" dna:name="Vehicles" dna:classname="org.jboss.dna.connector.federation.FederatedRepositorySource"
dna:repositoryName="Configuration Repository"
dna:configurationSourceName="Configuration"
dna:configurationWorkspaceName="default"
- dna:configurationSourcePath="/dna:system/dna:federatedRepositories/Vehicles"
+ dna:configurationSourcePath="/jcr:system/dna:federatedRepositories/Vehicles"
dna:repositoryConnectionFactoryJndiName="/dna/connectionFactory"
dna:executionContextFactoryJndiName="/dna/contextFactory"/>
- <dna:source jcr:name="SourceD" dna:name="Cache" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" />
+ <dna:source jcr:name="SourceD" jcr:primaryType="nt:unstructured" dna:name="Cache" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" defaultWorkspaceName="default"/>
</dna:sources>
- <dna:federatedRepositories>
+ <dna:federatedRepositories jcr:primaryType="nt:unstructured">
<!-- This section defines from where the content of the 'Vehicles' federated repository is obtained.
The name of this node must match the 'name' of the source listed above. -->
- <dna:federatedRepository jcr:name="Vehicles">
+ <dna:federatedRepository jcr:name="Vehicles" jcr:primaryType="nt:unstructured">
<!-- Define the workspace(s) for this repository -->
- <dna:workspaces>
- <dna:workspace jcr:name="default">
+ <dna:workspaces jcr:primaryType="nt:unstructured">
+ <dna:workspace jcr:name="default" jcr:primaryType="nt:unstructured">
<!-- 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="/ => /" />
+ <dna:cache jcr:primaryType="nt:unstructured" dna:sourceName="Cache" dna:workspaceName="default" dna:projectionRules="/ => /" />
<!-- Define how the content in the difference 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:workspaceName="default" dna:projectionRules="/Vehicles => /" />
- <dna:projection jcr:name="Aircraft" dna:workspaceName="default" dna:projectionRules="/Vehicles => /" />
- <dna:projection jcr:name="Configuration" dna:workspaceName="default" dna:projectionRules="/ => /" />
+ <dna:projections jcr:primaryType="nt:unstructured">
+ <dna:projection jcr:primaryType="nt:unstructured" jcr:name="Cars" dna:workspaceName="default" dna:projectionRules="/Vehicles => /" />
+ <dna:projection jcr:primaryType="nt:unstructured" jcr:name="Aircraft" dna:workspaceName="default" dna:projectionRules="/Vehicles => /" />
+ <dna:projection jcr:primaryType="nt:unstructured" jcr:name="Configuration" dna:workspaceName="default" dna:projectionRules="/ => /" />
</dna:projections>
</dna:workspace>
</dna:workspaces>
</dna:federatedRepository>
</dna:federatedRepositories>
-</dna:system>
\ No newline at end of file
+</jcr:system>
\ No newline at end of file
Modified: trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -109,26 +109,27 @@
public void shouldHaveContentFromConfigurationRepository() throws Throwable {
client.startRepositories();
- getNodeInfo("Configuration", "/dna:system");
+ getNodeInfo("Configuration", "/jcr:system");
assertThat(children, hasItems("dna:sources", "dna:federatedRepositories"));
assertThat(properties.containsKey("jcr:primaryType"), is(true));
- assertThat(properties.containsKey("dna:uuid"), is(true));
- assertThat(properties.size(), is(2));
+ // assertThat(properties.containsKey("dna:uuid"), is(true));
+ assertThat(properties.size() >= 1, is(true));
- getNodeInfo("Configuration", "/dna:system/dna:sources");
+ getNodeInfo("Configuration", "/jcr:system/dna:sources");
assertThat(children, hasItems("SourceA", "SourceB", "SourceC", "SourceD"));
assertThat(properties.containsKey("jcr:primaryType"), is(true));
- assertThat(properties.containsKey("dna:uuid"), is(true));
- assertThat(properties.size(), is(2));
+ // assertThat(properties.containsKey("dna:uuid"), is(true));
+ assertThat(properties.size() >= 1, is(true));
- getNodeInfo("Configuration", "/dna:system/dna:sources/SourceA");
+ getNodeInfo("Configuration", "/jcr:system/dna:sources/SourceA");
assertThat(children.size(), is(0));
assertThat(properties.containsKey("jcr:primaryType"), is(true));
- assertThat(properties.containsKey("dna:uuid"), is(true));
+ // assertThat(properties.containsKey("dna:uuid"), is(true));
assertProperty("dna:classname", org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource.class.getName());
assertProperty("dna:name", "Cars");
assertProperty("dna:retryLimit", "3");
- assertThat(properties.size(), is(5));
+ assertProperty("defaultWorkspaceName", "default");
+ assertThat(properties.size() >= 5, is(true));
}
@Test
@@ -206,7 +207,7 @@
client.startRepositories();
getNodeInfo("Vehicles", "/");
- assertThat(children, hasItems("Vehicles"));
+ assertThat(children, hasItems("Vehicles", "jcr:system"));
assertThat(properties.containsKey("dna:uuid"), is(true));
assertThat(properties.size(), is(1));
@@ -216,7 +217,7 @@
assertThat(properties.size(), is(1));
getNodeInfo("Vehicles", "/");
- assertThat(children, hasItems("Vehicles"));
+ assertThat(children, hasItems("Vehicles", "jcr:system"));
assertThat(properties.containsKey("dna:uuid"), is(true));
assertThat(properties.size(), is(1));
Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -25,12 +25,14 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import java.util.concurrent.TimeUnit;
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.common.i18n.I18n;
@@ -78,6 +80,8 @@
@NotThreadSafe
public class FederatingRequestProcessor extends RequestProcessor {
+ private static final Set<Name> HIDDEN_PROPERTIES = Collections.singleton(DnaLexicon.MERGE_PLAN);
+
private final Map<String, FederatedWorkspace> workspaces;
private final FederatedWorkspace defaultWorkspace;
private final RepositoryConnectionFactory connectionFactory;
@@ -214,6 +218,7 @@
ReadNodeRequest nodeInfo = getNode(request.at(), workspace);
if (nodeInfo.hasError()) return;
for (Property property : nodeInfo.getProperties()) {
+ if (HIDDEN_PROPERTIES.contains(property.getName())) continue;
request.addProperty(property);
}
request.setActualLocationOfNode(nodeInfo.getActualLocationOfNode());
@@ -231,6 +236,7 @@
ReadNodeRequest nodeInfo = getNode(request.at(), workspace);
if (nodeInfo.hasError()) return;
for (Property property : nodeInfo.getProperties()) {
+ if (HIDDEN_PROPERTIES.contains(property.getName())) continue;
request.addProperty(property);
}
for (Location child : nodeInfo.getChildren()) {
@@ -357,8 +363,9 @@
*/
protected ReadNodeRequest getNode( Location location,
FederatedWorkspace workspace ) throws RepositorySourceException {
+ final ExecutionContext context = getExecutionContext();
+
// Check the cache first ...
- final ExecutionContext context = getExecutionContext();
RepositoryConnection cacheConnection = getConnectionToCacheFor(workspace);
ReadNodeRequest fromCache = new ReadNodeRequest(location, workspace.getCacheProjection().getWorkspaceName());
cacheConnection.execute(context, fromCache);
@@ -410,7 +417,7 @@
if (mergePlan != null) {
// We found the merge plan, so check whether it's still valid ...
final DateTime now = getCurrentTimeInUtc();
- if (mergePlan.isExpired(now)) {
+ if (!mergePlan.isExpired(now)) {
// It is still valid, so check whether any contribution is from a non-existant projection ...
for (Contribution contribution : mergePlan) {
if (!workspace.contains(contribution.getSourceName(), contribution.getWorkspaceName())) {
@@ -424,10 +431,10 @@
// the valid contributions in the 'contributions' list; any expired contribution
// needs to be loaded by adding the name to the 'sourceNames'
if (mergePlan.getContributionCount() > 0) {
- sourceNames = new HashSet<String>(sourceNames);
+ sourceNames = new HashSet<String>();
for (Contribution contribution : mergePlan) {
- if (!contribution.isExpired(now)) {
- sourceNames.remove(contribution.getSourceName());
+ if (contribution.isExpired(now)) {
+ sourceNames.add(contribution.getSourceName());
contributions.add(contribution);
}
}
@@ -437,7 +444,10 @@
// Get the contributions from the sources given their names ...
location = fromCache.getActualLocationOfNode();
- if (location == null) location = fromCache.at(); // not yet in the cache
+ if (location == null) {
+ // Not yet in the cache ...
+ location = fromCache.at();
+ }
loadContributionsFromSources(location, workspace, sourceNames, contributions); // sourceNames may be null or empty
FederatedNode mergedNode = createFederatedNode(location, workspace, contributions, true);
if (mergedNode == null) {
@@ -482,7 +492,7 @@
// Create the node, and use the existing UUID if one is found in the cache ...
ExecutionContext context = getExecutionContext();
assert context != null;
- FederatedNode mergedNode = new FederatedNode(location, federatedWorkspace.getName());
+ FederatedNode mergedNode = new FederatedNode(location.with((UUID)null), federatedWorkspace.getName());
// Merge the results into a single set of results ...
assert contributions.size() > 0;
@@ -719,7 +729,21 @@
assert path != null;
List<Request> requests = new ArrayList<Request>();
Name childName = null;
- if (!path.isRoot()) {
+
+ // If the merged node has a merge plan, then add it to the properties if it is not already there ...
+ Map<Name, Property> properties = mergedNode.getPropertiesByName();
+ MergePlan mergePlan = mergedNode.getMergePlan();
+ if (mergePlan != null) {
+ // Record the merge plan on the merged node ...
+ Property mergePlanProperty = getExecutionContext().getPropertyFactory().create(DnaLexicon.MERGE_PLAN,
+ (Object)mergePlan);
+ properties.put(mergePlanProperty.getName(), mergePlanProperty);
+ }
+
+ if (path.isRoot()) {
+ // Set the properties ...
+ requests.add(new UpdatePropertiesRequest(location, cacheWorkspace, properties));
+ } else {
// This is not the root node, so we need to create the node ...
final Location parentLocation = Location.create(path.getParent());
childName = path.getLastSegment().getName();
Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -303,6 +303,7 @@
public boolean isExpired( DateTime utcTime ) {
assert utcTime != null;
assert utcTime.toUtcTimeZone().equals(utcTime); // check that it is passed UTC time
+ if (expirationTimeInUtc == null) return false;
return !expirationTimeInUtc.isAfter(utcTime);
}
Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -196,7 +196,8 @@
public boolean isExpired( DateTime utcTime ) {
assert utcTime != null;
assert utcTime.toUtcTimeZone().equals(utcTime); // check that it is passed UTC time
- return utcTime.isAfter(getExpirationTimeInUtc());
+ DateTime expirationTimeInUtc = getExpirationTimeInUtc();
+ return expirationTimeInUtc == null ? false : utcTime.isAfter(expirationTimeInUtc);
}
/**
Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceIntegrationTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceIntegrationTest.java 2009-04-28 19:33:35 UTC (rev 861)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceIntegrationTest.java 2009-04-29 12:58:43 UTC (rev 862)
@@ -51,7 +51,6 @@
import org.jboss.dna.graph.property.PathNotFoundException;
import org.jboss.dna.graph.property.Property;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentMatcher;
import org.mockito.MockitoAnnotations;
@@ -227,7 +226,6 @@
}
}
- @Ignore
@Test
public void shouldProvideReadAccessToContentFederatedFromOneSourceThatMatchesTheContentFromTheSource() throws Exception {
// Set up the configuration to use a single source.
@@ -292,7 +290,6 @@
assertChildren(source, "/b/c");
}
- @Ignore
@Test
public void shouldProvideReadAccessToContentFederatedFromMultipleSources() throws Exception {
// Set up the configuration to use multiple sources.
@@ -312,12 +309,12 @@
batch.create("/repos/RepoX/dna:workspaces/fedSpace/dna:projections/projection1")
.with(FederatedLexicon.PROJECTION_RULES, "/ => /s1")
.with(FederatedLexicon.SOURCE_NAME, "source 1")
- .with(FederatedLexicon.WORKSPACE_NAME, "s1 workspace")
+ .with(FederatedLexicon.WORKSPACE_NAME, "s1Space")
.and();
batch.create("/repos/RepoX/dna:workspaces/fedSpace/dna:projections/projection2")
.with(FederatedLexicon.PROJECTION_RULES, "/ => /s2")
.with(FederatedLexicon.SOURCE_NAME, "source 2")
- .with(FederatedLexicon.WORKSPACE_NAME, "s2 worskspace")
+ .with(FederatedLexicon.WORKSPACE_NAME, "s2 workspace")
.and();
batch.execute();
16 years, 7 months
DNA SVN: r861 - trunk/dna-jcr/src/test/java/org/jboss/dna/jcr.
by dna-commits@lists.jboss.org
Author: spagop
Date: 2009-04-28 15:33:35 -0400 (Tue, 28 Apr 2009)
New Revision: 861
Modified:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyDefinitionTest.java
Log:
patched of BCar
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyDefinitionTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyDefinitionTest.java 2009-04-28 15:04:22 UTC (rev 860)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyDefinitionTest.java 2009-04-28 19:33:35 UTC (rev 861)
@@ -300,12 +300,12 @@
NodeType constrainedType = validateTypeDefinition();
JcrPropertyDefinition prop = propertyDefinitionFor(constrainedType, TestLexicon.CONSTRAINED_DATE);
- assertThat(prop.satisfiesConstraints(valueFor("-1945-08-01T01:30:00.000", PropertyType.DATE)), is(true));
- assertThat(prop.satisfiesConstraints(valueFor("+1945-07-31T01:30:00.000", PropertyType.DATE)), is(true));
- assertThat(prop.satisfiesConstraints(valueFor("+0001-08-01T01:30:00.000", PropertyType.DATE)), is(true));
- assertThat(prop.satisfiesConstraints(valueFor("+1975-08-01T01:30:00.000", PropertyType.DATE)), is(true));
- assertThat(prop.satisfiesConstraints(valueFor("+1975-08-01T01:31:00.000", PropertyType.DATE)), is(true));
- assertThat(prop.satisfiesConstraints(valueFor("+2009-08-01T01:30:00.000", PropertyType.DATE)), is(true));
+ assertThat(prop.satisfiesConstraints(valueFor("-1945-08-01T01:30:00.000Z", PropertyType.DATE)), is(true));
+ assertThat(prop.satisfiesConstraints(valueFor("+1945-07-31T01:30:00.000Z", PropertyType.DATE)), is(true));
+ assertThat(prop.satisfiesConstraints(valueFor("+0001-08-01T01:30:00.000Z", PropertyType.DATE)), is(true));
+ assertThat(prop.satisfiesConstraints(valueFor("+1975-08-01T01:30:00.000Z", PropertyType.DATE)), is(true));
+ assertThat(prop.satisfiesConstraints(valueFor("+1975-08-01T01:31:00.000Z", PropertyType.DATE)), is(true));
+ assertThat(prop.satisfiesConstraints(valueFor("+2009-08-01T01:30:00.000Z", PropertyType.DATE)), is(true));
}
@Test
@@ -313,10 +313,10 @@
NodeType constrainedType = validateTypeDefinition();
JcrPropertyDefinition prop = propertyDefinitionFor(constrainedType, TestLexicon.CONSTRAINED_DATE);
- Value[] values = new Value[] {valueFor("-1945-08-01T01:30:00.000", PropertyType.DATE),
- valueFor("+2009-08-01T01:30:00.000", PropertyType.DATE),};
+ Value[] values = new Value[] {valueFor("-1945-08-01T01:30:00.000Z", PropertyType.DATE),
+ valueFor("+2009-08-01T01:30:00.000Z", PropertyType.DATE),};
assertThat(satisfiesConstraints(prop, new Value[] {}), is(true));
- assertThat(satisfiesConstraints(prop, new Value[] {valueFor("+1975-08-01T01:31:00.000", PropertyType.DATE)}), is(true));
+ assertThat(satisfiesConstraints(prop, new Value[] {valueFor("+1975-08-01T01:31:00.000Z", PropertyType.DATE)}), is(true));
assertThat(satisfiesConstraints(prop, values), is(true));
}
16 years, 7 months
DNA SVN: r860 - in trunk/docs: reference/src/main/docbook/en-US/content and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-28 11:04:22 -0400 (Tue, 28 Apr 2009)
New Revision: 860
Modified:
trunk/docs/gettingstarted/src/main/docbook/en-US/content/introduction.xml
trunk/docs/gettingstarted/src/main/docbook/en-US/content/understanding_dna.xml
trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml
trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml
trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml
trunk/docs/reference/src/main/docbook/en-US/content/sequencing.xml
Log:
DNA-385 Documentation Updates for 0.4
Applied the patch that updated some of the content in the Getting Started and Reference Guide documents.
Modified: trunk/docs/gettingstarted/src/main/docbook/en-US/content/introduction.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/introduction.xml 2009-04-28 01:50:54 UTC (rev 859)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/introduction.xml 2009-04-28 15:04:22 UTC (rev 860)
@@ -95,7 +95,7 @@
</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 is
+ 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>
Modified: 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-04-28 01:50:54 UTC (rev 859)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/understanding_dna.xml 2009-04-28 15:04:22 UTC (rev 860)
@@ -32,7 +32,7 @@
<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 allows end users to access, visualize, and edit this information in
+ 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
@@ -356,10 +356,16 @@
<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. Some ideas for connectors include:</para>
+ 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.
@@ -372,28 +378,22 @@
This is a powerful connector that is discussed in more detail in the <link linkend="federated_repositories">next section</link>.
</para>
</listitem>
- </itemizedlist>
- <para>There are also a number of 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">File System Connector</emphasis>
- Expose the files and directories on a file system through JCR.
</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.
+ <emphasis role="strong">JDBC 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>
@@ -402,35 +402,44 @@
</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">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">CVS Connector</emphasis>
- - Interact with CVS software configuration management (SCM) repositories to expose the managed resources through
+ <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">JDBC Storage Connector</emphasis>
- - Store and access information in a relational database. Also useful for persisting information in the federated
- repository not stored elsewhere.
+ <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>
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-04-28 01:50:54 UTC (rev 859)
+++ trunk/docs/reference/src/main/docbook/en-US/content/development_tools.xml 2009-04-28 15:04:22 UTC (rev 860)
@@ -50,7 +50,8 @@
<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. We periodically try to build JBoss DNA using JDK 6, but it's not our official JDK (yet).
+ 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
Modified: trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml 2009-04-28 01:50:54 UTC (rev 859)
+++ trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml 2009-04-28 15:04:22 UTC (rev 860)
@@ -179,7 +179,7 @@
</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 is
+ 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>
</sect1>
@@ -289,15 +289,30 @@
</listitem>
<listitem>
<para>
+ <emphasis role="strong">dna-cnd</emphasis>
+ provides a utilities for reading and writing files in the CND (Compact Node Definition) format.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
<emphasis role="strong">dna-jcr</emphasis>
provides the JBoss DNA implementation of the JCR API, which relies upon a repository connector, such as the
Federation Connector (see
<code>dna-connector-federation</code>
- ).
+ ). As DNA does not fully implement the JCR 1.0.1 specification, there are a series of tests that are currently commented
+ out in this module. The <code>dna-jcr-tck</code> module contains all of these tests.
</para>
</listitem>
<listitem>
<para>
+ <emphasis role="strong">dna-jcr-tck</emphasis>
+ provides a separate testing project that executes all JackRabbit JCR TCK tests on a nightly basis to track implementation
+ progress against the JCR 1.0 specification. This module will likely be retired when the <code>dna-jcr</code> implementation
+ is complete.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
<emphasis role="strong">dna-integration-tests</emphasis>
provides a home for all of the integration tests that involve more components that just unit tests. Integration
tests are often more complicated, take longer, and involve testing the integration and functionality of many
@@ -313,7 +328,7 @@
<itemizedlist>
<listitem>
<para>
- <emphasis role="strong">dna-maven-classloader</emphasis>
+ <emphasis role="strong">dna-classloader-maven</emphasis>
is a small library that provides a
<code>ClassLoaderFactory</code>
implementation that can create
@@ -324,6 +339,12 @@
</listitem>
<listitem>
<para>
+ <emphasis role="strong">dna-common-jdbc</emphasis>
+ contains several helpful utility classes for interacting with JDBC connections.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
<emphasis role="strong">dna-connector-federation</emphasis>
is a DNA repository connector that federates, integrates and caches information from multiple sources (via other
repository connectors).
@@ -331,6 +352,21 @@
</listitem>
<listitem>
<para>
+ <emphasis role="strong">dna-connector-filesystem</emphasis>
+ is a DNA repository connector that provides read-only access to file systems, allowing their structure and data to be
+ viewed as repository content.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">dna-connector-jdbc-metadata</emphasis>
+ is a prototype DNA repository connector that provides read-only access to metadata from relational databases through a JDBC
+ connection.
+ <emphasis>This is still under development.</emphasis>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
<emphasis role="strong">dna-connector-jbosscache</emphasis>
is a DNA repository connector that manages content within a
<ulink url="http://www.jboss.org/jbosscache/">JBoss Cache</ulink>
@@ -340,6 +376,13 @@
</listitem>
<listitem>
<para>
+ <emphasis role="strong">dna-connector-store-jpa</emphasis>
+ is a DNA sequencer that provides for persistent storage and access of DNA content in a relational database. This connector
+ is based on JPA technology.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
<emphasis role="strong">dna-connector-svn</emphasis>
is a prototype DNA sequencer that obtains content from a Subversion repository, providing that content in
the form of <code>nt:file</code> and <code>nt:folder</code> nodes.
@@ -390,8 +433,7 @@
<listitem>
<para>
<emphasis role="strong">dna-sequencer-cnd</emphasis>
- is a prototype DNA sequencer that extracts JCR node definitions from JCR Compact Node Definition (CND) files.
- <emphasis>This is still under development.</emphasis>
+ is a DNA sequencer that extracts JCR node definitions from JCR Compact Node Definition (CND) files.
</para>
</listitem>
<listitem>
@@ -403,6 +445,12 @@
</listitem>
<listitem>
<para>
+ <emphasis role="strong">dna-sequencer-java</emphasis>
+ is a DNA sequencer that extracts the structure (methods, fields) from Java source files.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
<emphasis role="strong">dna-mimetype-detector-aperture</emphasis>
is a DNA MIME type detector that uses the
<ulink url="http://aperture.sourceforge.net/">Aperture</ulink>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml 2009-04-28 01:50:54 UTC (rev 859)
+++ trunk/docs/reference/src/main/docbook/en-US/content/jcr.xml 2009-04-28 15:04:22 UTC (rev 860)
@@ -35,7 +35,7 @@
<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 JCR 1.0 implementation that allows you to work with the contents of a repository using the
+ 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">
Modified: trunk/docs/reference/src/main/docbook/en-US/content/sequencing.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/sequencing.xml 2009-04-28 01:50:54 UTC (rev 859)
+++ trunk/docs/reference/src/main/docbook/en-US/content/sequencing.xml 2009-04-28 15:04:22 UTC (rev 860)
@@ -341,17 +341,12 @@
<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 Excel spreadsheets
- and PowerPoint presentations. With presentations, the sequencer extracts the slides, titles, text and slide thumbnails.
+ 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>
- <note>
- <para>
- Currently, Word documents are not supported. For more information and the latest status, see
- <ulink url="&JIRA;-153">DNA-153</ulink>.
- </para>
- </note>
<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
@@ -441,10 +436,24 @@
<sect2 id="dna-sequencer-cnd">
<title>JCR Compact Node Definition (CND) file sequencer</title>
<para>
- This sequencer is incomplete and is not currently usable. The purpose is to sequence JCR Compact Node Definition (CND) files
- to extract the node definitions with their property definitions, and inserting these into the repository using JCR standard notation.
+ 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>
16 years, 7 months