You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2014/02/05 10:27:23 UTC

svn commit: r1564687 [1/6] - in /jackrabbit/trunk: ./ jackrabbit-aws-ext/ jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/ jackrabbit-aws-ext/src/test/java/org/apache/jac...

Author: thomasm
Date: Wed Feb  5 09:27:20 2014
New Revision: 1564687

URL: http://svn.apache.org/r1564687
Log:
JCR-3705 Extract data store API and implementations from jackrabbit-core

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/gc/
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/gc/GarbageCollector.java
    jackrabbit/trunk/jackrabbit-data/   (with props)
    jackrabbit/trunk/jackrabbit-data/pom.xml
    jackrabbit/trunk/jackrabbit-data/src/
    jackrabbit/trunk/jackrabbit-data/src/main/
    jackrabbit/trunk/jackrabbit-data/src/main/java/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/config/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/config/ConfigurationException.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/config/DataSourceConfig.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/Backend.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/CachingDataRecord.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/CachingDataStore.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/DataIdentifier.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/DataRecord.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/DataStore.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/DataStoreException.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/DataStoreFactory.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/FileDataRecord.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/LazyFileInputStream.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/LocalCache.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/MultiDataStore.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/MultiDataStoreAware.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/ScanEventListener.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbDataRecord.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbInputStream.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DerbyDataStore.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/TempFileInputStream.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/BasedFileSystem.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/FileSystem.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/FileSystemException.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/FileSystemFactory.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/FileSystemPathUtil.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/FileSystemResource.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/RandomAccessOutputStream.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/local/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/local/FileUtil.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/local/HandleMonitor.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/fs/local/LocalFileSystem.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/CheckSchemaOperation.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionFactory.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/DataSourceWrapper.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/DatabaseAware.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/DbUtility.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/DerbyConnectionHelper.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/Oracle10R1ConnectionHelper.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/OracleConnectionHelper.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/PostgreSQLConnectionHelper.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/ResultSetWrapper.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/StreamWrapper.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/data/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/data/core/
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/data/core/InternalXAResource.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/data/core/TransactionContext.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/data/core/TransactionException.java
    jackrabbit/trunk/jackrabbit-data/src/main/resources/
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/data/
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/data/db/
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/data/db/azure.properties
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/data/db/db2.properties
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/data/db/derby.properties
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/data/db/h2.properties
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/data/db/ingres.properties
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/data/db/mssql.properties
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/data/db/mysql.properties
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/data/db/oracle.properties
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/data/db/postgresql.properties
    jackrabbit/trunk/jackrabbit-data/src/main/resources/org/apache/jackrabbit/core/data/db/sqlserver.properties
Removed:
    jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/LocalCache.java
    jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/Backend.java
    jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/CachingDataRecord.java
    jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/CachingDataStore.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/InternalXAResource.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransactionContext.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransactionException.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationException.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/DataSourceConfig.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/BasedFileSystem.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/FileSystem.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/FileSystemException.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/FileSystemFactory.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/FileSystemPathUtil.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/FileSystemResource.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/RandomAccessOutputStream.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/fs/local/
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/
    jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/data/
Modified:
    jackrabbit/trunk/jackrabbit-aws-ext/pom.xml
    jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3Backend.java
    jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3DataStore.java
    jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/TestLocalCache.java
    jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/InMemoryBackend.java
    jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/InMemoryDataStore.java
    jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestCaseBase.java
    jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestInMemDs.java
    jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestInMemDsCacheOff.java
    jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3Ds.java
    jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DsCacheOff.java
    jackrabbit/trunk/jackrabbit-core/pom.xml
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/XASessionImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/FineGrainedISMLocking.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/XAReentrantLock.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/XAReentrantWriterPreferenceReadWriteLock.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalXAVersionManager.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCEventListenerTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCSubtreeMoveTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCThread.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java
    jackrabbit/trunk/pom.xml

Modified: jackrabbit/trunk/jackrabbit-aws-ext/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-aws-ext/pom.xml?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-aws-ext/pom.xml (original)
+++ jackrabbit/trunk/jackrabbit-aws-ext/pom.xml Wed Feb  5 09:27:20 2014
@@ -27,6 +27,7 @@
     <artifactId>jackrabbit-aws-ext</artifactId>
     <name>Jackrabbit AWS Extension</name>
     <description>Jackrabbit extenstion to Amazon Webservices</description>
+    <packaging>bundle</packaging>
 
     <!-- ====================================================================== -->
     <!-- D E P E N D E N C I E S -->
@@ -48,7 +49,7 @@
         </dependency>
         <dependency>
             <groupId>org.apache.jackrabbit</groupId>
-            <artifactId>jackrabbit-core</artifactId>
+            <artifactId>jackrabbit-data</artifactId>
             <version>${project.version}</version>
         </dependency>
         <dependency>
@@ -85,6 +86,20 @@
                     </includes>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>.checkstyle</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
 </project>

Modified: jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3Backend.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3Backend.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3Backend.java (original)
+++ jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3Backend.java Wed Feb  5 09:27:20 2014
@@ -32,6 +32,8 @@ import java.util.concurrent.ThreadPoolEx
 
 import org.apache.jackrabbit.aws.ext.S3Constants;
 import org.apache.jackrabbit.aws.ext.Utils;
+import org.apache.jackrabbit.core.data.Backend;
+import org.apache.jackrabbit.core.data.CachingDataStore;
 import org.apache.jackrabbit.core.data.DataIdentifier;
 import org.apache.jackrabbit.core.data.DataStoreException;
 import org.slf4j.Logger;
@@ -340,7 +342,7 @@ public class S3Backend implements Backen
             for (S3ObjectSummary s3ObjSumm : prevObjectListing.getObjectSummaries()) {
                 DataIdentifier identifier = new DataIdentifier(
                     getIdentifierName(s3ObjSumm.getKey()));
-                if (!store.inUse.containsKey(identifier)
+                if (!store.isInUse(identifier)
                     && s3ObjSumm.getLastModified().getTime() < min) {
                     LOG.info("add id :" + s3ObjSumm.getKey()
                         + " to delete lists");

Modified: jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3DataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3DataStore.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3DataStore.java (original)
+++ jackrabbit/trunk/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3DataStore.java Wed Feb  5 09:27:20 2014
@@ -16,6 +16,9 @@
  */
 package org.apache.jackrabbit.aws.ext.ds;
 
+import org.apache.jackrabbit.core.data.Backend;
+import org.apache.jackrabbit.core.data.CachingDataStore;
+
 /**
  * An Amazon S3 data store.
  */

Modified: jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/TestLocalCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/TestLocalCache.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/TestLocalCache.java (original)
+++ jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/TestLocalCache.java Wed Feb  5 09:27:20 2014
@@ -27,6 +27,7 @@ import java.util.Random;
 import junit.framework.TestCase;
 
 import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.core.data.LocalCache;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

Modified: jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/InMemoryBackend.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/InMemoryBackend.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/InMemoryBackend.java (original)
+++ jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/InMemoryBackend.java Wed Feb  5 09:27:20 2014
@@ -29,6 +29,8 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.jackrabbit.core.data.Backend;
+import org.apache.jackrabbit.core.data.CachingDataStore;
 import org.apache.jackrabbit.core.data.DataIdentifier;
 import org.apache.jackrabbit.core.data.DataStoreException;
 

Modified: jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/InMemoryDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/InMemoryDataStore.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/InMemoryDataStore.java (original)
+++ jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/InMemoryDataStore.java Wed Feb  5 09:27:20 2014
@@ -16,19 +16,21 @@
  */
 package org.apache.jackrabbit.aws.ext.ds;
 
+import org.apache.jackrabbit.core.data.Backend;
+import org.apache.jackrabbit.core.data.CachingDataStore;
+
 /**
  * A caching data store that uses the in-memory backend.
  */
 public class InMemoryDataStore extends CachingDataStore {
 
     @Override
-    Backend createBackend() {
+    protected Backend createBackend() {
         return new InMemoryBackend();
     }
 
     @Override
-    String getMarkerFile() {
+    protected String getMarkerFile() {
         return "mem.init.done";
     }
-
 }

Modified: jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestCaseBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestCaseBase.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestCaseBase.java (original)
+++ jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestCaseBase.java Wed Feb  5 09:27:20 2014
@@ -32,6 +32,7 @@ import javax.jcr.RepositoryException;
 import junit.framework.TestCase;
 
 import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.core.data.CachingDataStore;
 import org.apache.jackrabbit.core.data.DataIdentifier;
 import org.apache.jackrabbit.core.data.DataRecord;
 import org.apache.jackrabbit.core.data.DataStore;

Modified: jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestInMemDs.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestInMemDs.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestInMemDs.java (original)
+++ jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestInMemDs.java Wed Feb  5 09:27:20 2014
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.aws.ext.ds;
 
+import org.apache.jackrabbit.core.data.CachingDataStore;
+
 /**
  * Test {@link CachingDataStore} with InMemoryBackend and local cache on.
  */

Modified: jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestInMemDsCacheOff.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestInMemDsCacheOff.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestInMemDsCacheOff.java (original)
+++ jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestInMemDsCacheOff.java Wed Feb  5 09:27:20 2014
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.aws.ext.ds;
 
+import org.apache.jackrabbit.core.data.CachingDataStore;
+
 /**
  * Test {@link CachingDataStore} with InMemoryBackend and local cache off.
  */

Modified: jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3Ds.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3Ds.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3Ds.java (original)
+++ jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3Ds.java Wed Feb  5 09:27:20 2014
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.util.Properties;
 
 import org.apache.jackrabbit.aws.ext.Utils;
+import org.apache.jackrabbit.core.data.CachingDataStore;
 
 /**
  * Test {@link CachingDataStore} with S3Backend and local cache on. It requires

Modified: jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DsCacheOff.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DsCacheOff.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DsCacheOff.java (original)
+++ jackrabbit/trunk/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DsCacheOff.java Wed Feb  5 09:27:20 2014
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.aws.ext.ds;
 
+import org.apache.jackrabbit.core.data.CachingDataStore;
+
 /**
  * Test {@link CachingDataStore} with S3Backend and local cache Off. It requires
  * to pass aws config file via system property. For e.g.

Modified: jackrabbit/trunk/jackrabbit-core/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/pom.xml?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/pom.xml (original)
+++ jackrabbit/trunk/jackrabbit-core/pom.xml Wed Feb  5 09:27:20 2014
@@ -247,6 +247,11 @@ org.apache.jackrabbit.core.data.GarbageC
     </dependency>
     <dependency>
       <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-data</artifactId>
+      <version>${project.version}</version>
+    </dependency>    
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
       <artifactId>jackrabbit-spi-commons</artifactId>
       <version>${project.version}</version>
     </dependency>

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java Wed Feb  5 09:27:20 2014
@@ -72,10 +72,10 @@ import org.apache.jackrabbit.core.config
 import org.apache.jackrabbit.core.config.WorkspaceConfig;
 import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.data.DataStoreException;
-import org.apache.jackrabbit.core.data.GarbageCollector;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.fs.FileSystemException;
 import org.apache.jackrabbit.core.fs.FileSystemResource;
+import org.apache.jackrabbit.core.gc.GarbageCollector;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.id.NodeIdFactory;
 import org.apache.jackrabbit.core.lock.LockManager;
@@ -106,6 +106,7 @@ import org.apache.jackrabbit.core.util.R
 import org.apache.jackrabbit.core.version.InternalVersionManager;
 import org.apache.jackrabbit.core.version.InternalVersionManagerImpl;
 import org.apache.jackrabbit.core.xml.ClonedInputSource;
+import org.apache.jackrabbit.data.core.TransactionException;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
 import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
 import org.apache.jackrabbit.spi.commons.namespace.RegistryNamespaceResolver;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java Wed Feb  5 09:27:20 2014
@@ -70,7 +70,7 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.commons.AbstractSession;
 import org.apache.jackrabbit.core.config.WorkspaceConfig;
-import org.apache.jackrabbit.core.data.GarbageCollector;
+import org.apache.jackrabbit.core.gc.GarbageCollector;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
 import org.apache.jackrabbit.core.observation.ObservationManagerImpl;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/XASessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/XASessionImpl.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/XASessionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/XASessionImpl.java Wed Feb  5 09:27:20 2014
@@ -23,6 +23,8 @@ import org.apache.jackrabbit.core.securi
 import org.apache.jackrabbit.core.state.XAItemStateManager;
 import org.apache.jackrabbit.core.version.InternalVersionManager;
 import org.apache.jackrabbit.core.version.InternalXAVersionManager;
+import org.apache.jackrabbit.data.core.InternalXAResource;
+import org.apache.jackrabbit.data.core.TransactionContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/gc/GarbageCollector.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/gc/GarbageCollector.java?rev=1564687&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/gc/GarbageCollector.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/gc/GarbageCollector.java Wed Feb  5 09:27:20 2014
@@ -0,0 +1,511 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.gc;
+
+import org.apache.jackrabbit.api.management.DataStoreGarbageCollector;
+import org.apache.jackrabbit.api.management.MarkEventListener;
+import org.apache.jackrabbit.core.RepositoryContext;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.data.DataStore;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.PropertyId;
+import org.apache.jackrabbit.core.observation.SynchronousEventListener;
+import org.apache.jackrabbit.core.persistence.IterablePersistenceManager;
+import org.apache.jackrabbit.core.persistence.util.NodeInfo;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NoSuchItemStateException;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.spi.Name;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Workspace;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.ObservationManager;
+
+/**
+ * Garbage collector for DataStore. This implementation iterates through all
+ * nodes and reads the binary properties. To detect nodes that are moved while
+ * the scan runs, event listeners are started. Like the well known garbage
+ * collection in Java, the items that are still in use are marked. Currently
+ * this is achieved by updating the modified date of the entries. Newly added
+ * entries are detected because the modified date is changed when they are
+ * added.
+ * <p>
+ * Example code to run the data store garbage collection:
+ * <pre>
+ * JackrabbitRepositoryFactory jf = (JackrabbitRepositoryFactory) factory;
+ * RepositoryManager m = jf.getRepositoryManager((JackrabbitRepository) repository);
+ * GarbageCollector gc = m.createDataStoreGarbageCollector();
+ * try {
+ *     gc.mark();
+ *     gc.sweep();
+ * } finally {
+ *     gc.close();
+ * }
+ * </pre>
+ */
+public class GarbageCollector implements DataStoreGarbageCollector {
+
+    /** logger instance */
+    static final Logger LOG = LoggerFactory.getLogger(GarbageCollector.class);
+
+    /**
+     * The number of nodes to fetch at once from the persistence manager. Defaults to 8kb
+     */
+    private static final int NODESATONCE = Integer.getInteger("org.apache.jackrabbit.garbagecollector.nodesatonce", 1024 * 8);
+
+    /**
+     * Set this System Property to true to speed up the node traversing in a binary focused repository.
+     * See JCR-3708
+     */
+    private static final boolean NODE_ID_SCAN = Boolean.getBoolean("org.apache.jackrabbit.garbagecollector.node_id.scan");
+
+    private MarkEventListener callback;
+
+    private long sleepBetweenNodes;
+
+    protected int testDelay;
+
+    private final DataStore store;
+
+    private long startScanTimestamp;
+
+    private final ArrayList<Listener> listeners = new ArrayList<Listener>();
+
+    private final IterablePersistenceManager[] pmList;
+
+    private final SessionImpl[] sessionList;
+
+    private final AtomicBoolean closed = new AtomicBoolean();
+    
+    private final RepositoryContext context;
+
+    private boolean persistenceManagerScan;
+
+    private volatile RepositoryException observationException;
+
+    /**
+     * Create a new garbage collector.
+     * This method is usually not called by the application, it is called
+     * by SessionImpl.createDataStoreGarbageCollector().
+     * 
+     * @param context repository context
+     * @param dataStore the data store to be garbage-collected
+     * @param list the persistence managers
+     * @param sessionList the sessions to access the workspaces
+     */
+    
+    public GarbageCollector(RepositoryContext context, 
+            DataStore dataStore, IterablePersistenceManager[] list,
+            SessionImpl[] sessionList) {
+        this.context = context;
+        this.store = dataStore;
+        this.pmList = list;
+        this.persistenceManagerScan = list != null;
+        this.sessionList = sessionList;
+    }
+
+    public void setSleepBetweenNodes(long millis) {
+        this.sleepBetweenNodes = millis;
+    }
+
+    public long getSleepBetweenNodes() {
+        return sleepBetweenNodes;
+    }
+
+    /**
+     * When testing the garbage collection, a delay is used instead of simulating concurrent access.
+     *
+     * @param testDelay the delay in milliseconds
+     */
+    public void setTestDelay(int testDelay) {
+        this.testDelay = testDelay;
+    }
+
+    public void setMarkEventListener(MarkEventListener callback) {
+        this.callback = callback;
+    }
+
+    public void mark() throws RepositoryException {
+        if (store == null) {
+            throw new RepositoryException("No DataStore configured.");
+        }
+        long now = System.currentTimeMillis();
+        if (startScanTimestamp == 0) {
+            startScanTimestamp = now;
+            store.updateModifiedDateOnAccess(startScanTimestamp);
+        }
+
+        if (pmList == null || !persistenceManagerScan) {
+            for (SessionImpl s : sessionList) {
+                scanNodes(s);
+            }
+        } else {
+            try {
+                if (!NODE_ID_SCAN) {
+                    scanPersistenceManagersByNodeInfos();
+                } else {
+                    scanPersistenceManagersByNodeIds();
+                }
+            } catch (ItemStateException e) {
+                throw new RepositoryException(e);
+            }
+        }
+    }
+
+    private void scanNodes(SessionImpl session) throws RepositoryException {
+
+        // add a listener to get 'moved' nodes
+        Session clonedSession = session.createSession(session.getWorkspace().getName());
+        listeners.add(new Listener(this, clonedSession));
+
+        // adding a link to a BLOB updates the modified date
+        // reading usually doesn't, but when scanning, it does
+        recurse(session.getRootNode(), sleepBetweenNodes);
+    }
+
+    public void setPersistenceManagerScan(boolean allow) {
+        persistenceManagerScan = allow;
+    }
+
+    public boolean isPersistenceManagerScan() {
+        return persistenceManagerScan;
+    }
+
+    private void scanPersistenceManagersByNodeInfos() throws RepositoryException, ItemStateException {
+        int pmCount = 0;
+        for (IterablePersistenceManager pm : pmList) {
+            pmCount++;
+            int count = 0;
+            Map<NodeId,NodeInfo> batch = pm.getAllNodeInfos(null, NODESATONCE);
+            while (!batch.isEmpty()) {
+                NodeId lastId = null;
+                for (NodeInfo info : batch.values()) {
+                    count++;
+                    if (count % 1000 == 0) {
+                        LOG.debug(pm.toString() + " ("+pmCount + "/" + pmList.length + "): analyzed " + count + " nodes...");
+                    }
+                    lastId = info.getId();
+                    if (callback != null) {
+                        callback.beforeScanning(null);
+                    }
+                    if (info.hasBlobsInDataStore()) {
+                        try {
+                            NodeState state = pm.load(info.getId());
+                            Set<Name> propertyNames = state.getPropertyNames();
+                            for (Name name : propertyNames) {
+                                PropertyId pid = new PropertyId(info.getId(), name);
+                                PropertyState ps = pm.load(pid);
+                                if (ps.getType() == PropertyType.BINARY) {
+                                    for (InternalValue v : ps.getValues()) {
+                                        // getLength will update the last modified date
+                                        // if the persistence manager scan is running
+                                        v.getLength();
+                                    }
+                                }
+                            }
+                        } catch (NoSuchItemStateException ignored) {
+                            // the node may have been deleted in the meantime
+                        }
+                    }
+                }
+                batch = pm.getAllNodeInfos(lastId, NODESATONCE);
+            }
+        }
+        NodeInfo.clearPool();
+    }
+
+    private void scanPersistenceManagersByNodeIds() throws RepositoryException, ItemStateException {
+        int pmCount = 0;
+        for (IterablePersistenceManager pm : pmList) {
+            pmCount++;
+            List<NodeId> allNodeIds = pm.getAllNodeIds(null, 0);
+            int overAllCount = allNodeIds.size();
+            int count = 0;
+            for (NodeId id : allNodeIds) {
+                count++;
+                if (count % 1000 == 0) {
+                    LOG.debug(pm.toString() + " ("+pmCount + "/" + pmList.length + "): analyzed " + count + " nodes [" + overAllCount + "]...");
+                }
+                if (callback != null) {
+                    callback.beforeScanning(null);
+                }
+                try {
+                    NodeState state = pm.load(id);
+                    Set<Name> propertyNames = state.getPropertyNames();
+                    for (Name name : propertyNames) {
+                        PropertyId pid = new PropertyId(id, name);
+                        PropertyState ps = pm.load(pid);
+                        if (ps.getType() == PropertyType.BINARY) {
+                            for (InternalValue v : ps.getValues()) {
+                                // getLength will update the last modified date
+                                // if the persistence manager scan is running
+                                v.getLength();
+                            }
+                        }
+                    }
+                } catch (NoSuchItemStateException e) {
+                    // the node may have been deleted or moved in the meantime
+                    // ignore it
+                }
+            }
+        }
+    }
+
+    /**
+     * Reset modifiedDateOnAccess to 0 and stop the observation 
+     * listener if any are installed.
+     */
+    public void stopScan() throws RepositoryException {
+         // reset updateModifiedDateOnAccess to OL
+        store.updateModifiedDateOnAccess(0L);
+        
+        if (listeners.size() > 0) {
+            for (Listener listener : listeners) {
+                listener.stop();
+            }
+            listeners.clear();
+        }
+        checkObservationException();
+        context.setGcRunning(false);
+    }
+
+    public int sweep() throws RepositoryException {
+        if (startScanTimestamp == 0) {
+            throw new RepositoryException("scan must be called first");
+        }
+        stopScan();
+        return store.deleteAllOlderThan(startScanTimestamp);
+    }
+
+    /**
+     * Get the data store if one is used.
+     *
+     * @return the data store, or null
+     */
+    public DataStore getDataStore() {
+        return store;
+    }
+
+    void recurse(final Node n, long sleep) throws RepositoryException {
+        if (sleep > 0) {
+            try {
+                Thread.sleep(sleep);
+            } catch (InterruptedException e) {
+                // ignore
+            }
+        }
+        if (callback != null) {
+            callback.beforeScanning(n);
+        }
+        try {
+            for (PropertyIterator it = n.getProperties(); it.hasNext();) {
+                Property p = it.nextProperty();
+                try {
+                    if (p.getType() == PropertyType.BINARY) {
+                        if (n.hasProperty("jcr:uuid")) {
+                            rememberNode(n.getProperty("jcr:uuid").getString());
+                        } else {
+                            rememberNode(n.getPath());
+                        }
+                        if (p.isMultiple()) {
+                            checkLengths(p.getLengths());
+                        } else {
+                        	checkLengths(p.getLength());
+                        }
+                    }
+                } catch (InvalidItemStateException e) {
+                    LOG.debug("Property removed concurrently - ignoring", e);
+                }
+            }
+        } catch (InvalidItemStateException e) {
+            LOG.debug("Node removed concurrently - ignoring", e);
+        }
+        try {
+            for (NodeIterator it = n.getNodes(); it.hasNext();) {
+                recurse(it.nextNode(), sleep);
+            }
+        } catch (InvalidItemStateException e) {
+            LOG.debug("Node removed concurrently - ignoring", e);
+        }
+        checkObservationException();
+    }
+
+    private void rememberNode(String path) {
+        // Do nothing at the moment
+        // TODO It may be possible to delete some items early
+        /*
+         * To delete files early in the garbage collection scan, we could do
+         * this:
+         *
+         * A) If garbage collection was run before, see if there a file with the
+         * list of UUIDs ('uuids.txt').
+         *
+         * B) If yes, and if the checksum is ok, read all those nodes first (if
+         * not so many). This updates the modified date of all old files that
+         * are still in use. Afterwards, delete all files with an older modified
+         * date than the last scan! Newer files, and files that are read have a
+         * newer modification date.
+         *
+         * C) Delete the 'uuids.txt' file (in any case).
+         *
+         * D) Iterate (recurse) through all nodes and properties like now. If a
+         * node has a binary property, store the UUID of the node in the file
+         * ('uuids.txt'). Also store the time when the scan started.
+         *
+         * E) Checksum and close the file.
+         *
+         * F) Like now, delete files with an older modification date than this
+         * scan.
+         *
+         * We can't use node path for this, UUIDs are required as nodes could be
+         * moved around.
+         *
+         * This mechanism requires that all data stores update the last modified
+         * date when calling addRecord and that record already exists.
+         *
+         */
+    }
+
+    private static void checkLengths(long... lengths) throws RepositoryException {
+        for (long length : lengths) {
+            if (length == -1) {
+                throw new RepositoryException("mark failed to access a property");
+            }
+        }
+    }
+
+    public void close() {
+        if (!closed.getAndSet(true)) {
+            try {
+                stopScan();
+            } catch (RepositoryException e) {
+                LOG.warn("An error occured when stopping the event listener", e);
+            }
+            for (Session s : sessionList) {
+                s.logout();
+            }
+        }
+    }
+
+    private void checkObservationException() throws RepositoryException {
+        RepositoryException e = observationException;
+        if (e != null) {
+            observationException = null;
+            String message = "Exception while processing concurrent events";
+            LOG.warn(message, e);
+            e = new RepositoryException(message, e);
+        }
+    }
+
+    void onObservationException(Exception e) {
+        if (e instanceof RepositoryException) {
+            observationException = (RepositoryException) e;
+        } else {
+            observationException = new RepositoryException(e);
+        }
+    }
+
+    /**
+     * Auto-close in case the application didn't call it explicitly.
+     */
+    protected void finalize() throws Throwable {
+        close();
+        super.finalize();
+    }
+
+    /**
+     * Event listener to detect moved nodes.
+     * A SynchronousEventListener is used to make sure this method is called before the main iteration ends.
+     */
+    class Listener implements SynchronousEventListener {
+
+        private final GarbageCollector gc;
+        private final Session session;
+        private final ObservationManager manager;
+
+        Listener(GarbageCollector gc, Session session)
+                throws UnsupportedRepositoryOperationException,
+                RepositoryException {
+            this.gc = gc;
+            this.session = session;
+            Workspace ws = session.getWorkspace();
+            manager = ws.getObservationManager();
+            manager.addEventListener(this, Event.NODE_MOVED, "/", true, null,
+                    null, false);
+        }
+
+        void stop() throws RepositoryException {
+            manager.removeEventListener(this);
+            session.logout();
+        }
+
+        public void onEvent(EventIterator events) {
+            if (testDelay > 0) {
+                try {
+                    Thread.sleep(testDelay);
+                } catch (InterruptedException e) {
+                    // ignore
+                }
+            }
+            while (events.hasNext()) {
+                Event event = events.nextEvent();
+                try {
+                    String path = event.getPath();
+                    try {
+                        Item item = session.getItem(path);
+                        if (item.isNode()) {
+                            Node n = (Node) item;
+                            recurse(n, testDelay);
+                        }
+                    } catch (PathNotFoundException e) {
+                        // ignore
+                    }
+                } catch (Exception e) {
+                    gc.onObservationException(e);
+                    try {
+                        stop();
+                    } catch (RepositoryException e2) {
+                        LOG.warn("Exception removing the observation listener - ignored", e2);
+                    }
+                }
+            }
+        }
+    }
+
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java Wed Feb  5 09:27:20 2014
@@ -16,11 +16,11 @@
  */
 package org.apache.jackrabbit.core.lock;
 
-import org.apache.jackrabbit.core.TransactionException;
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.WorkspaceImpl;
 import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.data.core.TransactionException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java Wed Feb  5 09:27:20 2014
@@ -16,11 +16,11 @@
  */
 package org.apache.jackrabbit.core.lock;
 
-import org.apache.jackrabbit.core.InternalXAResource;
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
-import org.apache.jackrabbit.core.TransactionContext;
-import org.apache.jackrabbit.core.TransactionException;
+import org.apache.jackrabbit.data.core.InternalXAResource;
+import org.apache.jackrabbit.data.core.TransactionContext;
+import org.apache.jackrabbit.data.core.TransactionException;
 import org.apache.jackrabbit.spi.Path;
 
 import javax.jcr.RepositoryException;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java Wed Feb  5 09:27:20 2014
@@ -16,8 +16,8 @@
  */
 package org.apache.jackrabbit.core.state;
 
-import static org.apache.jackrabbit.core.TransactionContext.getCurrentThreadId;
-import static org.apache.jackrabbit.core.TransactionContext.isSameThreadId;
+import static org.apache.jackrabbit.data.core.TransactionContext.getCurrentThreadId;
+import static org.apache.jackrabbit.data.core.TransactionContext.isSameThreadId;
 
 import org.apache.jackrabbit.core.id.ItemId;
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/FineGrainedISMLocking.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/FineGrainedISMLocking.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/FineGrainedISMLocking.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/FineGrainedISMLocking.java Wed Feb  5 09:27:20 2014
@@ -16,8 +16,8 @@
  */
 package org.apache.jackrabbit.core.state;
 
-import static org.apache.jackrabbit.core.TransactionContext.getCurrentThreadId;
-import static org.apache.jackrabbit.core.TransactionContext.isSameThreadId;
+import static org.apache.jackrabbit.data.core.TransactionContext.getCurrentThreadId;
+import static org.apache.jackrabbit.data.core.TransactionContext.isSameThreadId;
 
 import java.util.Collections;
 import java.util.HashMap;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/XAItemStateManager.java Wed Feb  5 09:27:20 2014
@@ -26,15 +26,15 @@ import javax.jcr.ReferentialIntegrityExc
 
 import org.apache.commons.collections.Predicate;
 import org.apache.commons.collections.iterators.FilterIterator;
-import org.apache.jackrabbit.core.InternalXAResource;
-import org.apache.jackrabbit.core.TransactionContext;
-import org.apache.jackrabbit.core.TransactionException;
 import org.apache.jackrabbit.core.id.ItemId;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.id.PropertyId;
 import org.apache.jackrabbit.core.observation.EventStateCollectionFactory;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.core.virtual.VirtualItemStateProvider;
+import org.apache.jackrabbit.data.core.InternalXAResource;
+import org.apache.jackrabbit.data.core.TransactionContext;
+import org.apache.jackrabbit.data.core.TransactionException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/XAReentrantLock.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/XAReentrantLock.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/XAReentrantLock.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/XAReentrantLock.java Wed Feb  5 09:27:20 2014
@@ -16,8 +16,10 @@
  */
 package org.apache.jackrabbit.core.util;
 
-import static org.apache.jackrabbit.core.TransactionContext.isSameThreadId;
-import org.apache.jackrabbit.core.TransactionContext;
+import static org.apache.jackrabbit.data.core.TransactionContext.isSameThreadId;
+
+import org.apache.jackrabbit.data.core.TransactionContext;
+
 import EDU.oswego.cs.dl.util.concurrent.ReentrantLock;
 
 /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/XAReentrantWriterPreferenceReadWriteLock.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/XAReentrantWriterPreferenceReadWriteLock.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/XAReentrantWriterPreferenceReadWriteLock.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/XAReentrantWriterPreferenceReadWriteLock.java Wed Feb  5 09:27:20 2014
@@ -16,8 +16,8 @@
  */
 package org.apache.jackrabbit.core.util;
 
-import static org.apache.jackrabbit.core.TransactionContext.getCurrentThreadId;
-import static org.apache.jackrabbit.core.TransactionContext.isSameThreadId;
+import static org.apache.jackrabbit.data.core.TransactionContext.getCurrentThreadId;
+import static org.apache.jackrabbit.data.core.TransactionContext.isSameThreadId;
 import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock;
 
 /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalXAVersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalXAVersionManager.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalXAVersionManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalXAVersionManager.java Wed Feb  5 09:27:20 2014
@@ -24,10 +24,7 @@ import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.version.VersionException;
 
-import org.apache.jackrabbit.core.InternalXAResource;
 import org.apache.jackrabbit.core.SessionImpl;
-import org.apache.jackrabbit.core.TransactionContext;
-import org.apache.jackrabbit.core.TransactionException;
 import org.apache.jackrabbit.core.id.ItemId;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
@@ -45,6 +42,9 @@ import org.apache.jackrabbit.core.state.
 import org.apache.jackrabbit.core.virtual.VirtualItemStateProvider;
 import org.apache.jackrabbit.core.virtual.VirtualNodeState;
 import org.apache.jackrabbit.core.virtual.VirtualPropertyState;
+import org.apache.jackrabbit.data.core.InternalXAResource;
+import org.apache.jackrabbit.data.core.TransactionContext;
+import org.apache.jackrabbit.data.core.TransactionException;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
 

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCEventListenerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCEventListenerTest.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCEventListenerTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCEventListenerTest.java Wed Feb  5 09:27:20 2014
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.core.data;
 import org.apache.jackrabbit.api.management.DataStoreGarbageCollector;
 import org.apache.jackrabbit.api.management.MarkEventListener;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.gc.GarbageCollector;
 import org.apache.jackrabbit.test.AbstractJCRTest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCSubtreeMoveTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCSubtreeMoveTest.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCSubtreeMoveTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCSubtreeMoveTest.java Wed Feb  5 09:27:20 2014
@@ -35,6 +35,7 @@ import org.apache.jackrabbit.api.Jackrab
 import org.apache.jackrabbit.api.management.MarkEventListener;
 import org.apache.jackrabbit.core.RepositoryFactoryImpl;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.gc.GarbageCollector;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCThread.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCThread.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCThread.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GCThread.java Wed Feb  5 09:27:20 2014
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.core.data;
 import org.apache.jackrabbit.api.management.DataStoreGarbageCollector;
 import org.apache.jackrabbit.api.management.MarkEventListener;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.gc.GarbageCollector;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java?rev=1564687&r1=1564686&r2=1564687&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java Wed Feb  5 09:27:20 2014
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.core.data;
 import org.apache.jackrabbit.api.management.DataStoreGarbageCollector;
 import org.apache.jackrabbit.api.management.MarkEventListener;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.gc.GarbageCollector;
 import org.apache.jackrabbit.test.AbstractJCRTest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

Propchange: jackrabbit/trunk/jackrabbit-data/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Wed Feb  5 09:27:20 2014
@@ -0,0 +1,2 @@
+.classpath
+.project

Added: jackrabbit/trunk/jackrabbit-data/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/pom.xml?rev=1564687&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/pom.xml (added)
+++ jackrabbit/trunk/jackrabbit-data/pom.xml Wed Feb  5 09:27:20 2014
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor 
+	license agreements. See the NOTICE file distributed with this work for additional 
+	information regarding copyright ownership. The ASF licenses this file to 
+	You under the Apache License, Version 2.0 (the "License"); you may not use 
+	this file except in compliance with the License. You may obtain a copy of 
+	the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required 
+	by applicable law or agreed to in writing, software distributed under the 
+	License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 
+	OF ANY KIND, either express or implied. See the License for the specific 
+	language governing permissions and limitations under the License. -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd ">
+	<modelVersion>4.0.0</modelVersion>
+
+	<!-- ====================================================================== -->
+	<!-- P R O J E C T D E S C R I P T I O N -->
+	<!-- ====================================================================== -->
+	<parent>
+		<groupId>org.apache.jackrabbit</groupId>
+		<artifactId>jackrabbit-parent</artifactId>
+		<version>2.8-SNAPSHOT</version>
+		<relativePath>../jackrabbit-parent/pom.xml</relativePath>
+	</parent>
+	<artifactId>jackrabbit-data</artifactId>
+	<name>Jackrabbit Data</name>
+	<description>Jackrabbit DataStore Implentations</description>
+	<packaging>bundle</packaging>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-bundle-plugin</artifactId>
+				<extensions>true</extensions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.rat</groupId>
+				<artifactId>apache-rat-plugin</artifactId>
+				<configuration>
+					<excludes>
+						<exclude>.checkstyle</exclude>
+					</excludes>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+	<!-- ====================================================================== -->
+	<!-- D E P E N D E N C I E S -->
+	<!-- ====================================================================== -->
+	<dependencies>
+		<dependency>
+			<groupId>javax.jcr</groupId>
+			<artifactId>jcr</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.jackrabbit</groupId>
+			<artifactId>jackrabbit-api</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.jackrabbit</groupId>
+			<artifactId>jackrabbit-jcr-commons</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-collections</groupId>
+			<artifactId>commons-collections</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>commons-dbcp</groupId>
+			<artifactId>commons-dbcp</artifactId>
+			<version>1.3</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.derby</groupId>
+			<artifactId>derby</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>jcl-over-slf4j</artifactId>
+		</dependency>
+
+	</dependencies>
+</project>
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/config/ConfigurationException.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/config/ConfigurationException.java?rev=1564687&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/config/ConfigurationException.java (added)
+++ jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/config/ConfigurationException.java Wed Feb  5 09:27:20 2014
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.config;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Exception class used for configuration errors.
+ */
+public class ConfigurationException extends RepositoryException {
+
+    /**
+     * Creates a configuration exception.
+     *
+     * @param message configuration message
+     */
+    public ConfigurationException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates a configuration exception that is caused by another exception.
+     *
+     * @param message configuration error message
+     * @param cause root cause of the configuration error
+     */
+    public ConfigurationException(String message, Exception cause) {
+        super(message, cause);
+    }
+
+}

Added: jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/config/DataSourceConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/config/DataSourceConfig.java?rev=1564687&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/config/DataSourceConfig.java (added)
+++ jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/config/DataSourceConfig.java Wed Feb  5 09:27:20 2014
@@ -0,0 +1,225 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.config;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import javax.naming.Context;
+
+/**
+ * This class contains list of definitions for {@code DataSource} instances.
+ */
+public class DataSourceConfig {
+
+    public static final String DRIVER = "driver";
+
+    public static final String URL = "url";
+
+    public static final String USER = "user";
+
+    public static final String PASSWORD = "password";
+
+    public static final String DB_TYPE = "databaseType";
+
+    public static final String VALIDATION_QUERY = "validationQuery";
+
+    public static final String MAX_POOL_SIZE = "maxPoolSize";
+
+    private final List<DataSourceDefinition> defs = new ArrayList<DataSourceDefinition>();
+
+    /**
+     * Adds a DataSourceDefinition from the given properties.
+     * 
+     * @param props the properties (key and values must be strings)
+     * @throws ConfigurationException on error
+     */
+    public void addDataSourceDefinition(String name, Properties props) throws ConfigurationException {
+        DataSourceDefinition def = new DataSourceDefinition(name, props);
+        for (DataSourceDefinition existing : defs) {
+            if (existing.getLogicalName().equals(def.getLogicalName())) {
+                throw new ConfigurationException("Duplicate logicalName for a DataSource: "
+                        + def.getLogicalName());
+            }
+        }
+        defs.add(def);
+    }
+
+    /**
+     * @return the unmodifiable list of the current {@link DataSourceDefinition}s
+     */
+    public List<DataSourceDefinition> getDefinitions() {
+        return Collections.unmodifiableList(defs);
+    }
+
+    /**
+     * The definition of a DataSource. 
+     */
+    public static final class DataSourceDefinition {
+
+        private static final List<String> allPropNames =
+            Arrays.asList(DRIVER, URL, USER, PASSWORD, DB_TYPE, VALIDATION_QUERY, MAX_POOL_SIZE);
+
+        private static final List<String> allJndiPropNames =
+            Arrays.asList(DRIVER, URL, USER, PASSWORD, DB_TYPE);
+
+        private final String logicalName;
+
+        private final String driver;
+
+        private final String url;
+
+        private final String user;
+
+        private final String password;
+
+        private final String dbType;
+
+        private final String validationQuery;
+
+        private final int maxPoolSize;
+
+        /**
+         * Creates a DataSourceDefinition from the given properties and 
+         * throws a {@link ConfigurationException} when the set of properties does not
+         * satisfy some validity constraints.
+         * 
+         * @param name the logical name of the data source
+         * @param props the properties (string keys and values)
+         * @throws ConfigurationException on error
+         */
+        public DataSourceDefinition(String name, Properties props) throws ConfigurationException {
+            this.logicalName = name;
+            this.driver = (String) props.getProperty(DRIVER);
+            this.url = (String) props.getProperty(URL);
+            this.user = (String) props.getProperty(USER);
+            this.password = (String) props.getProperty(PASSWORD);
+            this.dbType = (String) props.getProperty(DB_TYPE);
+            this.validationQuery = (String) props.getProperty(VALIDATION_QUERY);
+            try {
+                this.maxPoolSize = Integer.parseInt((String) props.getProperty(MAX_POOL_SIZE, "-1"));
+            } catch (NumberFormatException e) {
+                throw new ConfigurationException("failed to parse " + MAX_POOL_SIZE
+                        + " property for DataSource " + logicalName);
+            }
+            verify(props);
+        }
+
+        private void verify(Properties props) throws ConfigurationException {
+            // Check required properties
+            if (logicalName == null || "".equals(logicalName.trim())) {
+                throw new ConfigurationException("DataSource logical name must not be null or empty");
+            }
+            if (driver == null || "".equals(driver)) {
+                throw new ConfigurationException("DataSource driver must not be null or empty");
+            }
+            if (url == null || "".equals(url)) {
+                throw new ConfigurationException("DataSource URL must not be null or empty");
+            }
+            if (dbType == null || "".equals(dbType)) {
+                throw new ConfigurationException("DataSource databaseType must not be null or empty");
+            }
+            // Check unknown properties
+            for (Object propName : props.keySet()) {
+                if (!allPropNames.contains((String) propName)) {
+                    throw new ConfigurationException("Unknown DataSource property: " + propName);
+                }
+            }
+            // Check JNDI config:
+            if (isJndiConfig()) {
+                for (Object propName : props.keySet()) {
+                    if (!allJndiPropNames.contains((String) propName)) {
+                        throw new ConfigurationException("Property " + propName
+                                + " is not allowed for a DataSource obtained through JNDI"
+                                + ", DataSource logicalName = " + logicalName);
+                    }
+                }
+            }
+        }
+
+        private boolean isJndiConfig() throws ConfigurationException {
+            Class<?> driverClass = null;
+            try {
+                if (driver.length() > 0) {
+                    driverClass = Class.forName(driver);
+                }
+            } catch (ClassNotFoundException e) {
+                throw new ConfigurationException("Could not load JDBC driver class " + driver, e);
+            }
+            return driverClass != null && Context.class.isAssignableFrom(driverClass);
+        }
+
+        /**
+         * @return the logicalName
+         */
+        public String getLogicalName() {
+            return logicalName;
+        }
+
+        /**
+         * @return the driver
+         */
+        public String getDriver() {
+            return driver;
+        }
+
+        /**
+         * @return the url
+         */
+        public String getUrl() {
+            return url;
+        }
+
+        /**
+         * @return the user
+         */
+        public String getUser() {
+            return user;
+        }
+
+        /**
+         * @return the dbType
+         */
+        public String getDbType() {
+            return dbType;
+        }
+
+        /**
+         * @return the password
+         */
+        public String getPassword() {
+            return password;
+        }
+
+        /**
+         * @return the validationQuery
+         */
+        public String getValidationQuery() {
+            return validationQuery;
+        }
+
+        /**
+         * @return the maxPoolSize
+         */
+        public int getMaxPoolSize() {
+            return maxPoolSize;
+        }
+    }
+}

Added: jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java?rev=1564687&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java (added)
+++ jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java Wed Feb  5 09:27:20 2014
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.core.data;
+
+
+/**
+ * Abstract data record base class. This base class contains only
+ * a reference to the data identifier of the record and implements
+ * the standard {@link Object} equality, hash code, and string
+ * representation methods based on the identifier.
+ */
+public abstract class AbstractDataRecord implements DataRecord {
+
+    /**
+     * The data store that contains this record.
+     */
+    private final AbstractDataStore store;
+
+    /**
+     * The binary identifier;
+     */
+    private final DataIdentifier identifier;
+
+    /**
+     * Creates a data record with the given identifier.
+     *
+     * @param identifier data identifier
+     */
+    public AbstractDataRecord(
+            AbstractDataStore store, DataIdentifier identifier) {
+        this.store = store;
+        this.identifier = identifier;
+    }
+
+    /**
+     * Returns the data identifier.
+     *
+     * @return data identifier
+     */
+    public DataIdentifier getIdentifier() {
+        return identifier;
+    }
+
+    public String getReference() {
+        return store.getReferenceFromIdentifier(identifier);
+    }
+
+    /**
+     * Returns the string representation of the data identifier.
+     *
+     * @return string representation
+     */
+    public String toString() {
+        return identifier.toString();
+    }
+
+    /**
+     * Checks if the given object is a data record with the same identifier
+     * as this one.
+     *
+     * @param object other object
+     * @return <code>true</code> if the other object is a data record and has
+     *         the same identifier as this one, <code>false</code> otherwise
+     */
+    public boolean equals(Object object) {
+        return (object instanceof DataRecord)
+            && identifier.equals(((DataRecord) object).getIdentifier());
+    }
+
+    /**
+     * Returns the hash code of the data identifier.
+     *
+     * @return hash code
+     */
+    public int hashCode() {
+        return identifier.hashCode();
+    }
+
+}

Added: jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java?rev=1564687&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java (added)
+++ jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java Wed Feb  5 09:27:20 2014
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.data;
+
+import java.security.SecureRandom;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+
+public abstract class AbstractDataStore implements DataStore {
+
+    private static final String ALGORITHM = "HmacSHA1";
+
+    /**
+     * Array of hexadecimal digits.
+     */
+    private static final char[] HEX = "0123456789abcdef".toCharArray();
+
+    /**
+     * Cached copy of the reference key of this data store. Initialized in
+     * {@link #getReferenceKey()} when the key is first accessed.
+     */
+    private byte[] referenceKey = null;
+
+    //---------------------------------------------------------< DataStore >--
+
+    public DataRecord getRecord(DataIdentifier identifier)
+            throws DataStoreException {
+        DataRecord record = getRecordIfStored(identifier);
+        if (record != null) {
+            return record;
+        } else {
+            throw new DataStoreException(
+                    "Record " + identifier + " does not exist");
+        }
+    }
+
+    public DataRecord getRecordFromReference(String reference)
+            throws DataStoreException {
+        if (reference != null) {
+            int colon = reference.indexOf(':');
+            if (colon != -1) {
+                DataIdentifier identifier =
+                        new DataIdentifier(reference.substring(0, colon));
+                if (reference.equals(getReferenceFromIdentifier(identifier))) {
+                    return getRecordIfStored(identifier);
+                }
+            }
+        }
+        return null;
+    }
+
+    //---------------------------------------------------------< protected >--
+
+    /**
+     * Returns the hex encoding of the given bytes.
+     *
+     * @param value value to be encoded
+     * @return encoded value
+     */
+    protected static String encodeHexString(byte[] value) {
+        char[] buffer = new char[value.length * 2];
+        for (int i = 0; i < value.length; i++) {
+            buffer[2 * i] = HEX[(value[i] >> 4) & 0x0f];
+            buffer[2 * i + 1] = HEX[value[i] & 0x0f];
+        }
+        return new String(buffer);
+    }
+
+    protected String getReferenceFromIdentifier(DataIdentifier identifier) {
+        try {
+            String id = identifier.toString();
+
+            Mac mac = Mac.getInstance(ALGORITHM);
+            mac.init(new SecretKeySpec(getReferenceKey(), ALGORITHM));
+            byte[] hash = mac.doFinal(id.getBytes("UTF-8"));
+
+            return id + ':' + encodeHexString(hash);
+        } catch (Exception e) {
+            // TODO: log a warning about this exception
+        }
+        return null;
+    }
+
+    /**
+     * Returns the reference key of this data store. If one does not already
+     * exist, it is automatically created in an implementation-specific way.
+     * The default implementation simply creates a temporary random key that's
+     * valid only until the data store gets restarted. Subclasses can override
+     * and/or decorate this method to support a more persistent reference key.
+     * <p>
+     * This method is called only once during the lifetime of a data store
+     * instance and the return value is cached in memory, so it's no problem
+     * if the implementation is slow.
+     *
+     * @return reference key
+     * @throws DataStoreException if the key is not available
+     */
+    protected byte[] getOrCreateReferenceKey() throws DataStoreException {
+        byte[] referenceKeyValue = new byte[256];
+        new SecureRandom().nextBytes(referenceKeyValue);
+        return referenceKeyValue;
+    }
+
+    //-----------------------------------------------------------< private >--
+
+    /**
+     * Returns the reference key of this data store. Synchronized to
+     * control concurrent access to the cached {@link #referenceKey} value.
+     *
+     * @return reference key
+     * @throws DataStoreException if the key is not available
+     */
+    private synchronized byte[] getReferenceKey() throws DataStoreException {
+        if (referenceKey == null) {
+            referenceKey = getOrCreateReferenceKey();
+        }
+        return referenceKey;
+    }
+
+}
\ No newline at end of file