You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by to...@apache.org on 2013/05/21 11:56:38 UTC

svn commit: r1484726 - in /jackrabbit/branches/2.6: ./ jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/ jackrabbit-c...

Author: tommaso
Date: Tue May 21 09:56:38 2013
New Revision: 1484726

URL: http://svn.apache.org/r1484726
Log:
2.6: Merged revisions 1480574,1481964,1484440,1484442,1484444 (JCR-3534)

Added:
    jackrabbit/branches/2.6/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ReferenceBinary.java
      - copied unchanged from r1480574, jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ReferenceBinary.java
    jackrabbit/branches/2.6/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ReferenceBinaryException.java
      - copied unchanged from r1480574, jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ReferenceBinaryException.java
    jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java
      - copied, changed from r1480574, jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java
    jackrabbit/branches/2.6/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/value/ReferenceBinaryTest.java
      - copied unchanged from r1480574, jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/value/ReferenceBinaryTest.java
    jackrabbit/branches/2.6/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/jackrabbit/SimpleReferenceBinary.java
      - copied unchanged from r1480574, jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/jackrabbit/SimpleReferenceBinary.java
Modified:
    jackrabbit/branches/2.6/   (props changed)
    jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java
    jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataIdentifier.java
    jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataRecord.java
    jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java
    jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataRecord.java
    jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java
    jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/MultiDataStore.java
    jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataRecord.java
    jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
    jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java
    jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/ValueFactoryImpl.java
    jackrabbit/branches/2.6/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/DataStoreTest.java
    jackrabbit/branches/2.6/jackrabbit-core/src/test/repository/repository.xml

Propchange: jackrabbit/branches/2.6/
------------------------------------------------------------------------------
  Merged /jackrabbit/trunk:r1480574,1481964,1484440,1484442,1484444

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java Tue May 21 09:56:38 2013
@@ -26,6 +26,11 @@ package org.apache.jackrabbit.core.data;
 public abstract class AbstractDataRecord implements DataRecord {
 
     /**
+     * The data store that contains this record.
+     */
+    private final AbstractDataStore store;
+
+    /**
      * The binary identifier;
      */
     private final DataIdentifier identifier;
@@ -35,7 +40,9 @@ public abstract class AbstractDataRecord
      *
      * @param identifier data identifier
      */
-    public AbstractDataRecord(DataIdentifier identifier) {
+    public AbstractDataRecord(
+            AbstractDataStore store, DataIdentifier identifier) {
+        this.store = store;
         this.identifier = identifier;
     }
 
@@ -48,6 +55,10 @@ public abstract class AbstractDataRecord
         return identifier;
     }
 
+    public String getReference() {
+        return store.getReferenceFromIdentifier(identifier);
+    }
+
     /**
      * Returns the string representation of the data identifier.
      *

Copied: jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java (from r1480574, jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java)
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java?p2=jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java&p1=jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java&r1=1480574&r2=1484726&rev=1484726&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataStore.java Tue May 21 09:56:38 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.data;
 
+import java.security.SecureRandom;
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
 
@@ -28,12 +29,42 @@ public abstract class AbstractDataStore 
      */
     private static final char[] HEX = "0123456789abcdef".toCharArray();
 
-    private String secret;
+    /**
+     * 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 void setSecret(String secret) {
-        this.secret = secret;
+    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.
      *
@@ -49,45 +80,55 @@ public abstract class AbstractDataStore 
         return new String(buffer);
     }
 
+    protected String getReferenceFromIdentifier(DataIdentifier identifier) {
+        try {
+            String id = identifier.toString();
 
-    @Override
-    public DataIdentifier getIdentifierFromReference(String reference) {
-        if (secret != null) {
-            int colon = reference.indexOf(':');
-            if (colon != -1) {
-                String identifier = reference.substring(0, colon);
-                String signature = reference.substring(colon + 1);
-                if (signature.equals(sign(identifier))) {
-                    return new DataIdentifier(identifier, reference);
-                }
-            }
+            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;
     }
 
-    //---------------------------------------------------------< protected >--
-
-    protected DataIdentifier createIdentifier(final String identifier) {
-        if (secret != null) {
-            return new DataIdentifier(identifier) {
-                public String getReference() {
-                    return identifier + ':' + sign(identifier);
-                }
-            };
-        } else {
-            return new DataIdentifier(identifier);
-        }
+    /**
+     * 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 String sign(String identifier) {
-        try {
-            Mac mac = Mac.getInstance(ALGORITHM);
-            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), ALGORITHM));
-            return encodeHexString(mac.doFinal(identifier.getBytes("UTF-8")));
-        } catch (Exception e) {
-            // TODO: log a warning about this exception
-            return null;
+    //-----------------------------------------------------------< 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

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataIdentifier.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataIdentifier.java?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataIdentifier.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataIdentifier.java Tue May 21 09:56:38 2013
@@ -23,7 +23,7 @@ import java.io.Serializable;
  * All identifiers must be serializable and implement the standard
  * object equality and hash code methods.
  */
-public final class DataIdentifier implements Serializable {
+public class DataIdentifier implements Serializable {
 
     /**
      * Serial version UID.
@@ -31,11 +31,6 @@ public final class DataIdentifier implem
     private static final long serialVersionUID = -9197191401131100016L;
 
     /**
-     * Array of hexadecimal digits.
-     */
-    private static final char[] HEX = "0123456789abcdef".toCharArray();
-
-    /**
      * Data identifier.
      */
     private final String identifier;
@@ -46,22 +41,7 @@ public final class DataIdentifier implem
      * @param identifier data identifier
      */
     public DataIdentifier(String identifier) {
-        this.identifier = identifier;
-    }
-
-    /**
-     * Creates a data identifier from the hexadecimal string
-     * representation of the given bytes.
-     *
-     * @param identifier data identifier
-     */
-    public DataIdentifier(byte[] identifier) {
-        char[] buffer = new char[identifier.length * 2];
-        for (int i = 0; i < identifier.length; i++) {
-            buffer[2 * i] = HEX[(identifier[i] >> 4) & 0x0f];
-            buffer[2 * i + 1] = HEX[identifier[i] & 0x0f];
-        }
-        this.identifier = new String(buffer);
+        this.identifier  = identifier;
     }
 
     //-------------------------------------------------------------< Object >

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataRecord.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataRecord.java?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataRecord.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataRecord.java Tue May 21 09:56:38 2013
@@ -31,6 +31,14 @@ public interface DataRecord {
     DataIdentifier getIdentifier();
 
     /**
+     * Returns a secure reference to this binary, or {@code null} if no such
+     * reference is available.
+     *
+     * @return binary reference, or {@code null}
+     */
+    String getReference();
+
+    /**
      * Returns the length of the binary stream in this record.
      *
      * @return length of the binary stream

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java Tue May 21 09:56:38 2013
@@ -40,8 +40,10 @@ public interface DataStore {
      * 
      * @param identifier data identifier
      * @return the record if found, and null if not
+     * @throws DataStoreException if the data store could not be accessed
      */
-    DataRecord getRecordIfStored(DataIdentifier identifier) throws DataStoreException;
+    DataRecord getRecordIfStored(DataIdentifier identifier)
+            throws DataStoreException;
 
     /**
      * Returns the identified data record. The given identifier should be
@@ -58,6 +60,18 @@ public interface DataStore {
     DataRecord getRecord(DataIdentifier identifier) throws DataStoreException;
 
     /**
+     * Returns the record that matches the given binary reference.
+     * Returns {@code null} if the reference is invalid, for example if it
+     * points to a record that does not exist.
+     *
+     * @param reference binary reference
+     * @return matching record, or {@code null}
+     * @throws DataStoreException if the data store could not be accessed
+     */
+    DataRecord getRecordFromReference(String reference)
+        throws DataStoreException;
+
+    /**
      * Creates a new data record. The given binary stream is consumed and
      * a binary record containing the consumed stream is created and returned.
      * If the same stream already exists in another record, then that record

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataRecord.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataRecord.java?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataRecord.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataRecord.java Tue May 21 09:56:38 2013
@@ -36,8 +36,9 @@ public class FileDataRecord extends Abst
      * @param identifier data identifier
      * @param file file that contains the binary stream
      */
-    public FileDataRecord(DataIdentifier identifier, File file) {
-        super(identifier);
+    public FileDataRecord(
+            AbstractDataStore store, DataIdentifier identifier, File file) {
+        super(store, identifier);
         assert file.isFile();
         this.file = file;
     }

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java Tue May 21 09:56:38 2013
@@ -34,6 +34,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.WeakHashMap;
 
+import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,7 +60,8 @@ import org.slf4j.LoggerFactory;
  * This implementation relies on the underlying file system to support
  * atomic O(1) move operations with {@link File#renameTo(File)}.
  */
-public class FileDataStore implements DataStore, MultiDataStoreAware {
+public class FileDataStore extends AbstractDataStore
+        implements MultiDataStoreAware {
 
     /**
      * Logger instance
@@ -131,23 +133,16 @@ public class FileDataStore implements Da
         directory.mkdirs();
     }
 
-    public DataRecord getRecordIfStored(DataIdentifier identifier) throws DataStoreException {
-        return getRecord(identifier, true);
-    }
-
     /**
      * Get a data record for the given identifier.
-     * This method only checks if the file exists if the verify flag is set.
-     * If the verify flag is set and the file doesn't exist, the method returns null.
      *
      * @param identifier the identifier
-     * @param verify whether to check if the file exists
      * @return the data record or null
      */
-    private DataRecord getRecord(DataIdentifier identifier, boolean verify) throws DataStoreException {
+    public DataRecord getRecordIfStored(DataIdentifier identifier) throws DataStoreException {
         File file = getFile(identifier);
         synchronized (this) {
-            if (verify && !file.exists()) {
+            if (!file.exists()) {
                 return null;
             }
             if (minModifiedDate != 0) {
@@ -157,23 +152,10 @@ public class FileDataStore implements Da
                 }
             }
             usesIdentifier(identifier);
-            return new FileDataRecord(identifier, file);
+            return new FileDataRecord(this, identifier, file);
         }
     }
 
-    /**
-     * Returns the record with the given identifier. Note that this method
-     * performs no sanity checks on the given identifier. It is up to the
-     * caller to ensure that only identifiers of previously created data
-     * records are used.
-     *
-     * @param identifier data identifier
-     * @return identified data record
-     */
-    public DataRecord getRecord(DataIdentifier identifier) throws DataStoreException {
-        return getRecord(identifier, false);
-    }
-
     private void usesIdentifier(DataIdentifier identifier) {
         inUse.put(identifier, new WeakReference<DataIdentifier>(identifier));
     }
@@ -207,7 +189,8 @@ public class FileDataStore implements Da
             } finally {
                 output.close();
             }
-            DataIdentifier identifier = new DataIdentifier(digest.digest());
+            DataIdentifier identifier =
+                    new DataIdentifier(encodeHexString(digest.digest()));
             File file;
 
             synchronized (this) {
@@ -245,7 +228,7 @@ public class FileDataStore implements Da
             // this will also make sure that
             // tempId is not garbage collected until here
             inUse.remove(tempId);
-            return new FileDataRecord(identifier, file);
+            return new FileDataRecord(this, identifier, file);
         } catch (NoSuchAlgorithmException e) {
             throw new DataStoreException(DIGEST + " not available", e);
         } catch (IOException e) {
@@ -305,7 +288,13 @@ public class FileDataStore implements Da
 	}
 
     public int deleteAllOlderThan(long min) {
-        return deleteOlderRecursive(directory, min);
+        int count = 0;
+        for (File file : directory.listFiles()) {
+            if (file.isDirectory()) { // skip top-level files
+                count += deleteOlderRecursive(file, min);
+            }
+        }
+        return count;
     }
 
     private int deleteOlderRecursive(File file, long min) {
@@ -346,11 +335,9 @@ public class FileDataStore implements Da
             // JCR-1396: FileDataStore Garbage Collector and empty directories
             // Automatic removal of empty directories (but not the root!)
             synchronized (this) {
-                if (file != directory) {
-                    list = file.listFiles();
-                    if (list != null && list.length == 0) {
-                        file.delete();
-                    }
+                list = file.listFiles();
+                if (list != null && list.length == 0) {
+                    file.delete();
                 }
             }
         }
@@ -372,14 +359,16 @@ public class FileDataStore implements Da
 
     public Iterator<DataIdentifier> getAllIdentifiers() {
         ArrayList<File> files = new ArrayList<File>();
-        listRecursive(files, directory);
+        for (File file : directory.listFiles()) {
+            if (file.isDirectory()) { // skip top-level files
+                listRecursive(files, file);
+            }
+        }
+
         ArrayList<DataIdentifier> identifiers = new ArrayList<DataIdentifier>();
         for (File f: files) {
             String name = f.getName();
-            if (!name.startsWith(TMP)) {
-                DataIdentifier id = new DataIdentifier(name);
-                identifiers.add(id);
-            }
+            identifiers.add(new DataIdentifier(name));
         }
         log.debug("Found " + identifiers.size() + " identifiers.");
         return identifiers.iterator();
@@ -424,6 +413,27 @@ public class FileDataStore implements Da
         // nothing to do
     }
 
+    //---------------------------------------------------------< protected >--
+
+    @Override
+    protected byte[] getOrCreateReferenceKey() throws DataStoreException {
+        File file = new File(directory, "reference.key");
+        try {
+            if (file.exists()) {
+                return FileUtils.readFileToByteArray(file);
+            } else {
+                byte[] key = super.getOrCreateReferenceKey();
+                FileUtils.writeByteArrayToFile(file, key);
+                return key;
+            }
+        } catch (IOException e) {
+            throw new DataStoreException(
+                    "Unable to access reference key file " + file.getPath(), e);
+        }
+    }
+
+    //-----------------------------------------------------------< private >--
+
     /**
      * Get the last modified date of a file.
      *

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/MultiDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/MultiDataStore.java?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/MultiDataStore.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/MultiDataStore.java Tue May 21 09:56:38 2013
@@ -313,6 +313,15 @@ public class MultiDataStore implements D
         return archiveDataStore.getAllIdentifiers();
     }
 
+    public DataRecord getRecordFromReference(String reference)
+            throws DataStoreException {
+        DataRecord record = primaryDataStore.getRecordFromReference(reference);
+        if (record == null) {
+            record = archiveDataStore.getRecordFromReference(reference);
+        }
+        return record;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -709,4 +718,5 @@ public class MultiDataStore implements D
             }
         }
     }
+
 }

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataRecord.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataRecord.java?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataRecord.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataRecord.java Tue May 21 09:56:38 2013
@@ -40,7 +40,7 @@ public class DbDataRecord extends Abstra
      * @param lastModified
      */
     public DbDataRecord(DbDataStore store, DataIdentifier identifier, long length, long lastModified) {
-        super(identifier);
+        super(store, identifier);
         this.store = store;
         this.length = length;
         this.lastModified = lastModified;

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java Tue May 21 09:56:38 2013
@@ -17,9 +17,9 @@
 package org.apache.jackrabbit.core.data.db;
 
 import org.apache.commons.io.input.CountingInputStream;
+import org.apache.jackrabbit.core.data.AbstractDataStore;
 import org.apache.jackrabbit.core.data.DataIdentifier;
 import org.apache.jackrabbit.core.data.DataRecord;
-import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.data.DataStoreException;
 import org.apache.jackrabbit.core.data.MultiDataStoreAware;
 import org.apache.jackrabbit.core.util.db.CheckSchemaOperation;
@@ -98,7 +98,8 @@ import javax.sql.DataSource;
  * The tablePrefix can be used to specify a schema and / or catalog name:
  * &lt;param name="tablePrefix" value="ds.">
  */
-public class DbDataStore implements DataStore, DatabaseAware, MultiDataStoreAware {
+public class DbDataStore extends AbstractDataStore
+        implements DatabaseAware, MultiDataStoreAware {
 
     /**
      * The default value for the minimum object size.
@@ -355,7 +356,8 @@ public class DbDataStore implements Data
             // UPDATE DATASTORE SET DATA=? WHERE ID=?
             conHelper.exec(updateDataSQL, wrapper, tempId);
             long length = in.getByteCount();
-            DataIdentifier identifier = new DataIdentifier(digest.digest());
+            DataIdentifier identifier =
+                    new DataIdentifier(encodeHexString(digest.digest()));
             usesIdentifier(identifier);
             String id = identifier.toString();
             long newModified;
@@ -560,14 +562,6 @@ public class DbDataStore implements Data
         }
     }
 
-    public DataRecord getRecord(DataIdentifier identifier) throws DataStoreException {
-        DataRecord record = getRecordIfStored(identifier);
-        if (record == null) {
-            throw new DataStoreException("Record not found: " + identifier);
-        }
-        return record;
-    }
-
     /**
      * Open the input stream. This method sets those fields of the caller
      * that need to be closed once the input stream is read.

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java Tue May 21 09:56:38 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.value;
 
+import org.apache.jackrabbit.api.ReferenceBinary;
 import org.apache.jackrabbit.core.data.DataIdentifier;
 import org.apache.jackrabbit.core.data.DataRecord;
 import org.apache.jackrabbit.core.data.DataStore;
@@ -30,7 +31,7 @@ import javax.jcr.RepositoryException;
 /**
  * Represents binary data which is stored in the data store.
  */
-class BLOBInDataStore extends BLOBFileValue {
+class BLOBInDataStore extends BLOBFileValue implements ReferenceBinary {
 
     private final DataStore store;
     private final DataIdentifier identifier;
@@ -103,6 +104,16 @@ class BLOBInDataStore extends BLOBFileVa
         return getDataRecord().getStream();
     }
 
+    @Override
+    public String getReference() {
+        try {
+            return getDataRecord().getReference();
+        } catch (DataStoreException e) {
+            log.warn("Unable to access the reference to " + identifier, e);
+            return null;
+        }
+    }
+
     public String toString() {
         return PREFIX + identifier;
     }

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/ValueFactoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/ValueFactoryImpl.java?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/ValueFactoryImpl.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/ValueFactoryImpl.java Tue May 21 09:56:38 2013
@@ -17,7 +17,9 @@
 package org.apache.jackrabbit.core.value;
 
 import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.api.ReferenceBinary;
 import org.apache.jackrabbit.core.data.DataIdentifier;
+import org.apache.jackrabbit.core.data.DataRecord;
 import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
 import org.apache.jackrabbit.spi.commons.value.ValueFactoryQImpl;
@@ -106,6 +108,13 @@ public class ValueFactoryImpl extends Va
                 }
             } else if (binary instanceof BLOBFileValue) {
                 return new BinaryValueImpl(((BLOBFileValue) binary).copy());
+            } else if (binary instanceof ReferenceBinary) {
+                String reference = ((ReferenceBinary) binary).getReference();
+                DataRecord record = store.getRecordFromReference(reference);
+                if (record != null) {
+                    return new BinaryValueImpl(BLOBInDataStore.getInstance(
+                            store, record.getIdentifier()));
+                }
             }
             return createValue(binary.getStream());
         } catch (RepositoryException e) {

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/DataStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/DataStoreTest.java?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/DataStoreTest.java (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/DataStoreTest.java Tue May 21 09:56:38 2013
@@ -102,6 +102,49 @@ public class DataStoreTest extends JUnit
         }
     }
 
+    public void testReference() throws Exception {
+        byte[] data = new byte[12345];
+        new Random(12345).nextBytes(data);
+        String reference;
+
+        FileDataStore store = new FileDataStore();
+        store.init(testDir + "/reference");
+        try {
+            DataRecord record = store.addRecord(new ByteArrayInputStream(data));
+            reference = record.getReference();
+
+            assertReference(data, reference, store);
+        } finally {
+            store.close();
+        }
+
+        store = new FileDataStore();
+        store.init(testDir + "/reference");
+        try {
+            assertReference(data, reference, store);
+        } finally {
+            store.close();
+        }
+    }
+
+    private void assertReference(
+            byte[] expected, String reference, DataStore store)
+            throws Exception {
+        DataRecord record = store.getRecordFromReference(reference);
+        assertNotNull(record);
+        assertEquals(expected.length, record.getLength());
+
+        InputStream stream = record.getStream();
+        try {
+            for (int i = 0; i < expected.length; i++) {
+                assertEquals(expected[i] & 0xff, stream.read());
+            }
+            assertEquals(-1, stream.read());
+        } finally {
+            stream.close();
+        }
+    }
+
     private void shutdownDatabase(String url) {
         if (url.startsWith("jdbc:derby:") || url.startsWith("jdbc:hsqldb:")) {
             try {

Modified: jackrabbit/branches/2.6/jackrabbit-core/src/test/repository/repository.xml
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.6/jackrabbit-core/src/test/repository/repository.xml?rev=1484726&r1=1484725&r2=1484726&view=diff
==============================================================================
--- jackrabbit/branches/2.6/jackrabbit-core/src/test/repository/repository.xml (original)
+++ jackrabbit/branches/2.6/jackrabbit-core/src/test/repository/repository.xml Tue May 21 09:56:38 2013
@@ -30,7 +30,9 @@
     <!--
         data store configuration
     -->
-	<DataStore class="org.apache.jackrabbit.core.data.FileDataStore"/>
+    <DataStore class="org.apache.jackrabbit.core.data.FileDataStore">
+        <param name="secret" value="a very well kept secret"/>
+    </DataStore>
     <!--
         sample database data store configuration
         <DataStore class="org.apache.jackrabbit.core.data.db.DbDataStore">