Index: C:/data/jackrabbit/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/xml/TestAll.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/xml/TestAll.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/xml/TestAll.java	(working copy)
@@ -21,6 +21,7 @@
 
 import org.apache.jackrabbit.api.JackrabbitNodeTypeManager;
 import org.apache.jackrabbit.core.TestRepository;
+import org.apache.jackrabbit.core.data.FileDataStore;
 import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
 import org.apache.jackrabbit.core.nodetype.NodeDef;
 import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
@@ -37,6 +38,7 @@
 import javax.jcr.version.OnParentVersionAction;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Arrays;
@@ -45,6 +47,9 @@
  * Test cases for reading and writing node type definition files.
  */
 public class TestAll extends TestCase {
+    
+    /** The dummy test data store. */
+    private static final String TEST_DATA_STORE_DIRECTORY = "testDataStore";
 
     /** The dummy test namespace. */
     private static final String TEST_NAMESPACE = "test-namespace";
@@ -66,6 +71,8 @@
 
     /** Registry for the test namespaces. */
     private NamespaceRegistry registry;
+    
+    private FileDataStore dataStore;
 
     /**
      * Initializes the node type formatter tests.
@@ -73,10 +80,13 @@
      * @throws Exception on initialization errors
      */
     protected void setUp() throws Exception {
+        File directory = new File(TEST_DATA_STORE_DIRECTORY);
+        dataStore = new FileDataStore(directory);
+        
         InputStream xml =
             getClass().getClassLoader().getResourceAsStream(TEST_NODETYPES);
 
-        types = NodeTypeReader.read(xml);
+        types = NodeTypeReader.read(xml, dataStore);
 
         registry = new SimpleNamespaceRegistry();
         registry.registerNamespace("test", TEST_NAMESPACE);
@@ -569,7 +579,7 @@
             NodeTypeWriter.write(xml, types, registry);
             byte[] bytes = xml.toByteArray();
             NodeTypeDef[] output =
-                NodeTypeReader.read(new ByteArrayInputStream(bytes));
+                NodeTypeReader.read(new ByteArrayInputStream(bytes), dataStore);
             assertTrue("write output", Arrays.equals(types, output));
         } catch (InvalidNodeTypeDefException e) {
             fail(e.getMessage());
Index: C:/data/jackrabbit/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/compact/CompactNodeTypeDefTest.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/compact/CompactNodeTypeDefTest.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/compact/CompactNodeTypeDefTest.java	(working copy)
@@ -17,6 +17,8 @@
 package org.apache.jackrabbit.core.nodetype.compact;
 
 import junit.framework.TestCase;
+
+import org.apache.jackrabbit.core.data.FileDataStore;
 import org.apache.jackrabbit.core.nodetype.NodeDef;
 import org.apache.jackrabbit.core.nodetype.NodeDefImpl;
 import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
@@ -30,6 +32,8 @@
 
 import javax.jcr.PropertyType;
 import javax.jcr.version.OnParentVersionAction;
+
+import java.io.File;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.io.StringReader;
@@ -38,6 +42,7 @@
 
 public class CompactNodeTypeDefTest extends TestCase {
     private static final String TEST_FILE = "cnd-reader-test-input.cnd";
+    private static final String TEST_DATA_STORE_DIRECTORY = "testDataStore";
     private static final String NS_PREFIX = "ex";
     private static final String NS_URI = "http://example.org/jackrabbit/example";
 
@@ -105,8 +110,10 @@
         // Read in node type def from test file
         Reader reader = new InputStreamReader(
             getClass().getClassLoader().getResourceAsStream(TEST_FILE));
+        File directory = new File(TEST_DATA_STORE_DIRECTORY);
+        FileDataStore dataStore = new FileDataStore(directory);
         CompactNodeTypeDefReader cndReader =
-            new CompactNodeTypeDefReader(reader, TEST_FILE);
+            new CompactNodeTypeDefReader(reader, TEST_FILE, dataStore);
         List ntdList = cndReader.getNodeTypeDefs();
         NamespaceMapping nsm = cndReader.getNamespaceMapping();
         NodeTypeDef ntd = (NodeTypeDef)ntdList.get(0);
@@ -122,7 +129,7 @@
         CompactNodeTypeDefWriter.write(ntdList, nsm, sw);
 
         // Rerun the reader on the product of the writer
-        cndReader = new CompactNodeTypeDefReader(new StringReader(sw.toString()), TEST_FILE);
+        cndReader = new CompactNodeTypeDefReader(new StringReader(sw.toString()), TEST_FILE, dataStore);
         ntdList = cndReader.getNodeTypeDefs();
         ntd = (NodeTypeDef)ntdList.get(0);
 
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterContext.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterContext.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterContext.java	(working copy)
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.core.cluster;
 
 import org.apache.jackrabbit.core.config.ClusterConfig;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.name.NamespaceResolver;
 
 import javax.jcr.RepositoryException;
@@ -57,4 +58,11 @@
      * @throws RepositoryException if the context is unable to provide the listener
      */
     public void lockEventsReady(String workspace) throws RepositoryException;
+
+    /**
+     * Return the data store
+     *
+     * @return data store
+     */    
+    public DataStore getDataStore();
 }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java	(working copy)
@@ -230,7 +230,7 @@
             instanceRevision = new FileRevision(new File(revisionName));
 
             journal = (Journal) jc.newInstance();
-            journal.init(clusterNodeId, clusterContext.getNamespaceResovler());
+            journal.init(clusterNodeId, clusterContext.getNamespaceResovler(), clusterContext.getDataStore());
             journal.register(this);
         } catch (ConfigurationException e) {
             throw new ClusterException(e.getMessage(), e.getCause());
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/xml/XMLPersistenceManager.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/xml/XMLPersistenceManager.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/xml/XMLPersistenceManager.java	(working copy)
@@ -18,6 +18,7 @@
 
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.fs.BasedFileSystem;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.fs.FileSystemException;
@@ -35,9 +36,8 @@
 import org.apache.jackrabbit.core.state.PropertyState;
 import org.apache.jackrabbit.core.persistence.util.BLOBStore;
 import org.apache.jackrabbit.core.persistence.util.FileSystemBLOBStore;
-import org.apache.jackrabbit.core.persistence.util.ResourceBasedBLOBStore;
 import org.apache.jackrabbit.core.util.DOMWalker;
-import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.value.BLOBValue;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.util.Text;
@@ -122,6 +122,11 @@
     private BLOBStore blobStore;
 
     /**
+     * Data store for binary properties.
+     */
+    private DataStore dataStore;
+
+    /**
      * Template for the subdirectory path for the files associated with
      * a single node. The template is processed by replacing each
      * "<code>x</code>" with the next hex digit in the UUID string.
@@ -336,7 +341,7 @@
                 String content = walker.getContent();
                 if (PropertyType.STRING == type) {
                     // STRING value can be empty; ignore length
-                    values.add(InternalValue.valueOf(content, type));
+                    values.add(InternalValue.valueOf(content, type, dataStore));
                 } else if (content.length() > 0) {
                     // non-empty non-STRING value
                     if (type == PropertyType.BINARY) {
@@ -344,25 +349,7 @@
                             // special handling required for binary value:
                             // the value stores the id of the BLOB data
                             // in the BLOB store
-                            if (blobStore instanceof ResourceBasedBLOBStore) {
-                                // optimization: if the BLOB store is resource-based
-                                // retrieve the resource directly rather than having
-                                // to read the BLOB from an input stream
-                                FileSystemResource fsRes =
-                                        ((ResourceBasedBLOBStore) blobStore).getResource(content);
-                                values.add(InternalValue.create(fsRes));
-                            } else {
-                                InputStream in = blobStore.get(content);
-                                try {
-                                    values.add(InternalValue.create(in, false));
-                                } finally {
-                                    try {
-                                        in.close();
-                                    } catch (IOException e) {
-                                        // ignore
-                                    }
-                                }
-                            }
+                            values.add(InternalValue.create(blobStore, content, dataStore));
                         } catch (Exception e) {
                             String msg = "error while reading serialized binary value";
                             log.debug(msg);
@@ -370,7 +357,7 @@
                         }
                     } else {
                         // non-empty non-STRING non-BINARY value
-                        values.add(InternalValue.valueOf(content, type));
+                        values.add(InternalValue.valueOf(content, type, dataStore));
                     }
                 } else {
                     // empty non-STRING value
@@ -428,6 +415,7 @@
         blobFS.init();
         this.blobFS = blobFS;
         blobStore = new FileSystemBLOBStore(blobFS);
+        dataStore = context.getDataStore();
 
         initialized = true;
     }
@@ -664,10 +652,10 @@
                         writer.write("\t\t<" + VALUE_ELEMENT + ">");
                         InternalValue val = values[i];
                         if (val != null) {
-                            if (type == PropertyType.BINARY) {
+                            if (type == PropertyType.BINARY && !InternalValue.USE_DATA_STORE) {
                                 // special handling required for binary value:
                                 // put binary value in BLOB store
-                                BLOBFileValue blobVal = val.getBLOBFileValue();
+                                BLOBValue blobVal = val.getBLOBValue();
                                 InputStream in = blobVal.getStream();
                                 String blobId = blobStore.createId(state.getPropertyId(), i);
                                 try {
@@ -683,25 +671,7 @@
                                 writer.write(blobId);
                                 // replace value instance with value backed by resource
                                 // in BLOB store and discard old value instance (e.g. temp file)
-                                if (blobStore instanceof ResourceBasedBLOBStore) {
-                                    // optimization: if the BLOB store is resource-based
-                                    // retrieve the resource directly rather than having
-                                    // to read the BLOB from an input stream
-                                    FileSystemResource fsRes =
-                                            ((ResourceBasedBLOBStore) blobStore).getResource(blobId);
-                                    values[i] = InternalValue.create(fsRes);
-                                } else {
-                                    in = blobStore.get(blobId);
-                                    try {
-                                        values[i] = InternalValue.create(in, false);
-                                    } finally {
-                                        try {
-                                            in.close();
-                                        } catch (IOException e) {
-                                            // ignore
-                                        }
-                                    }
-                                }
+                                values[i] = InternalValue.create(blobStore, blobId, dataStore);
                                 blobVal.discard();
                             } else {
                                 writer.write(Text.encodeIllegalXMLCharacters(val.toString()));
@@ -760,7 +730,7 @@
                 InternalValue val = values[i];
                 if (val != null) {
                     if (val.getType() == PropertyType.BINARY) {
-                        BLOBFileValue blobVal = val.getBLOBFileValue();
+                        BLOBValue blobVal = val.getBLOBValue();
                         // delete blob file and prune empty parent folders
                         blobVal.delete(true);
                     }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.persistence;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.NodeId;
@@ -58,6 +59,11 @@
     private final NodeId rootNodeId;
 
     /**
+     * Data store for binary properties.
+     */
+    private final DataStore dataStore;
+
+    /**
      * Creates a new <code>PMContext</code>.
      *
      * @param homeDir the physical home directory
@@ -70,12 +76,13 @@
                      FileSystem fs,
                      NodeId rootNodeId,
                      NamespaceRegistry nsReg,
-                     NodeTypeRegistry ntReg) {
+                     NodeTypeRegistry ntReg, DataStore dataStore) {
         this.physicalHomeDir = homeDir;
         this.fs = fs;
         this.rootNodeId = rootNodeId;
         this.nsReg = nsReg;
         this.ntReg = ntReg;
+        this.dataStore = dataStore;
     }
 
 
@@ -120,4 +127,13 @@
     public NodeTypeRegistry getNodeTypeRegistry() {
         return ntReg;
     }
+    
+    /**
+     * Returns the data store
+     *
+     * @return the data store
+     */
+    public DataStore getDataStore() {
+        return dataStore;
+    }
 }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java	(working copy)
@@ -18,6 +18,7 @@
 
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.fs.local.LocalFileSystem;
 import org.apache.jackrabbit.core.persistence.AbstractPersistenceManager;
@@ -33,7 +34,7 @@
 import org.apache.jackrabbit.core.state.NodeReferencesId;
 import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.jackrabbit.core.state.PropertyState;
-import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.value.BLOBValue;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.util.Text;
 import org.slf4j.Logger;
@@ -143,6 +144,11 @@
     protected BLOBStore blobStore;
 
     /**
+     * Data store for binary properties.
+     */
+    protected DataStore dataStore;
+
+    /**
      * Creates a new <code>DatabasePersistenceManager</code> instance.
      */
     public DatabasePersistenceManager() {
@@ -223,6 +229,8 @@
              */
             blobStore = new DbBLOBStore();
         }
+        
+        dataStore = context.getDataStore();
 
         initialized = true;
     }
@@ -380,7 +388,7 @@
 
                 in = rs.getBinaryStream(1);
                 PropertyState state = createNew(id);
-                Serializer.deserialize(state, in, blobStore);
+                Serializer.deserialize(state, in, blobStore, dataStore);
 
                 return state;
             } catch (Exception e) {
@@ -459,7 +467,7 @@
             ByteArrayOutputStream out =
                     new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);
             // serialize property state
-            Serializer.serialize(state, out, blobStore);
+            Serializer.serialize(state, out, blobStore, dataStore);
 
             // we are synchronized on this instance, therefore we do not
             // not have to additionally synchronize on the sql statement
@@ -510,7 +518,7 @@
                 InternalValue val = values[i];
                 if (val != null) {
                     if (val.getType() == PropertyType.BINARY) {
-                        BLOBFileValue blobVal = val.getBLOBFileValue();
+                        BLOBValue blobVal = val.getBLOBValue();
                         // delete internal resource representation of BLOB value
                         blobVal.delete(true);
                         // also remove from BLOBStore
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/db/OraclePersistenceManager.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/db/OraclePersistenceManager.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/db/OraclePersistenceManager.java	(working copy)
@@ -190,7 +190,7 @@
             ByteArrayOutputStream out =
                     new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);
             // serialize property state
-            Serializer.serialize(state, out, blobStore);
+            Serializer.serialize(state, out, blobStore, dataStore);
 
             // we are synchronized on this instance, therefore we do not
             // not have to additionally synchronize on the sql statement
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java	(working copy)
@@ -564,7 +564,7 @@
             nodeReferenceDelete = con.prepareStatement("delete from " + schemaObjectPrefix + "REFS where NODE_ID_HI = ? and NODE_ID_LO = ?");
         }
         // load namespaces
-        binding = new BundleBinding(errorHandling, blobStore, getNsIndex(), getNameIndex());
+        binding = new BundleBinding(errorHandling, blobStore, getNsIndex(), getNameIndex(), context.getDataStore());
         binding.setMinBlobSize(minBlobSize);
 
         initialized = true;
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java	(working copy)
@@ -370,7 +370,7 @@
         }
 
         // load namespaces
-        binding = new BundleBinding(errorHandling, blobStore, getNsIndex(), getNameIndex());
+        binding = new BundleBinding(errorHandling, blobStore, getNsIndex(), getNameIndex(), context.getDataStore());
         binding.setMinBlobSize(minBlobSize);
 
         initialized = true;
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/NodePropBundle.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/NodePropBundle.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/NodePropBundle.java	(working copy)
@@ -682,7 +682,7 @@
             if (type == PropertyType.BINARY) {
                 // destroy binary property values
                 for (int i=0; i<values.length; i++) {
-                    values[i].getBLOBFileValue().delete(true);
+                    values[i].getBLOBValue().delete(true);
                 }
             }
         }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/BundleBinding.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/BundleBinding.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/BundleBinding.java	(working copy)
@@ -19,11 +19,11 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.jackrabbit.core.persistence.util.BLOBStore;
-import org.apache.jackrabbit.core.persistence.util.ResourceBasedBLOBStore;
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.PropertyId;
 import org.apache.jackrabbit.core.value.InternalValue;
-import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.value.BLOBValue;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.nodetype.NodeDefId;
 import org.apache.jackrabbit.core.nodetype.PropDefId;
 import org.apache.jackrabbit.name.QName;
@@ -62,8 +62,8 @@
      * @param nameIndex the name index
      */
     public BundleBinding(ErrorHandling errorHandling, BLOBStore blobStore,
-                         StringIndex nsIndex, StringIndex nameIndex) {
-        super(errorHandling, blobStore, nsIndex, nameIndex);
+                         StringIndex nsIndex, StringIndex nameIndex, DataStore dataStore) {
+        super(errorHandling, blobStore, nsIndex, nameIndex, dataStore);
     }
 
     /**
@@ -320,14 +320,17 @@
             switch (type) {
                 case PropertyType.BINARY:
                     int size = in.readInt();
-                    if (size == -1) {
+                    if (InternalValue.USE_DATA_STORE && size == -2) {
+                        String s = in.readUTF();
+                        try {
+                            val = InternalValue.create(blobStore, s, dataStore);
+                        } catch (Exception e) {
+                            throw new IOException("Unable to create property value: " + e.toString());
+                        }
+                    } else if (size == -1) {
                         blobIds[i] = in.readUTF();
                         try {
-                            if (blobStore instanceof ResourceBasedBLOBStore) {
-                                val = InternalValue.create(((ResourceBasedBLOBStore) blobStore).getResource(blobIds[i]));
-                            } else {
-                                val = InternalValue.create(blobStore.get(blobIds[i]), false);
-                            }
+                            val = InternalValue.create(blobStore, blobIds[i], dataStore);
                         } catch (IOException e) {
                             if (errorHandling.ignoreMissingBlobs()) {
                                 log.warn("Ignoring error while reading blob-resource: " + e);
@@ -369,7 +372,7 @@
                     while (pos<len) {
                         pos+= in.read(bytes, pos, len-pos);
                     }
-                    val = InternalValue.valueOf(new String(bytes, "UTF-8"), type);
+                    val = InternalValue.valueOf(new String(bytes, "UTF-8"), type, dataStore);
             }
             values[i] = val;
         }
@@ -547,9 +550,14 @@
             InternalValue val = values[i];
             switch (state.getType()) {
                 case PropertyType.BINARY:
+                    if(InternalValue.USE_DATA_STORE) {
+                        out.writeInt(-2);
+                        out.writeUTF(val.toString());
+                        break;
+                    }
                     // special handling required for binary value:
                     // spool binary value to file in blob store
-                    BLOBFileValue blobVal = val.getBLOBFileValue();
+                    BLOBValue blobVal = val.getBLOBValue();
                     long size = blobVal.getLength();
                     if (size < 0) {
                         log.warn("Blob has negative size. Potential loss of data. " +
@@ -583,11 +591,7 @@
                             try {
                                 // replace value instance with value
                                 // backed by resource in blob store and delete temp file
-                                if (blobStore instanceof ResourceBasedBLOBStore) {
-                                    values[i] = InternalValue.create(((ResourceBasedBLOBStore) blobStore).getResource(blobId));
-                                } else {
-                                    values[i] = InternalValue.create(blobStore.get(blobId), false);
-                                }
+                                values[i] = InternalValue.create(blobStore, blobId, dataStore);
                             } catch (Exception e) {
                                 log.error("Error while reloading blob. truncating. id=" + state.getId() +
                                         " idx=" + i + " size=" + size, e);
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ItemStateBinding.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ItemStateBinding.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ItemStateBinding.java	(working copy)
@@ -19,33 +19,25 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.jackrabbit.core.persistence.util.BLOBStore;
-import org.apache.jackrabbit.core.persistence.util.ResourceBasedBLOBStore;
 import org.apache.jackrabbit.core.persistence.PersistenceManager;
 import org.apache.jackrabbit.core.state.NodeReferencesId;
 import org.apache.jackrabbit.core.state.NodeReferences;
 import org.apache.jackrabbit.core.state.NodeState;
-import org.apache.jackrabbit.core.state.PropertyState;
 import org.apache.jackrabbit.core.PropertyId;
 import org.apache.jackrabbit.core.NodeId;
-import org.apache.jackrabbit.core.value.InternalValue;
-import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.nodetype.NodeDefId;
-import org.apache.jackrabbit.core.nodetype.PropDefId;
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.uuid.UUID;
 
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
-import java.io.EOFException;
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
 
-import javax.jcr.PropertyType;
-
 /**
  * This Class implements relatively efficient serialization methods for item
  * states.
@@ -96,6 +88,11 @@
     protected final ErrorHandling errorHandling;
 
     /**
+     * Data store for binary properties.
+     */
+    protected final DataStore dataStore;
+
+    /**
      * Creates a new item state binding
      *
      * @param errorHandling the error handing configuration
@@ -105,11 +102,12 @@
      */
     public ItemStateBinding(ErrorHandling errorHandling,
                             BLOBStore blobStore,
-                            StringIndex nsIndex, StringIndex nameIndex) {
+                            StringIndex nsIndex, StringIndex nameIndex, DataStore dataStore) {
         this.errorHandling = errorHandling;
         this.nsIndex = nsIndex;
         this.nameIndex = nameIndex;
         this.blobStore = blobStore;
+        this.dataStore = dataStore;
     }
 
     /**
@@ -266,201 +264,6 @@
     }
 
     /**
-     * Deserializes a <code>PropertyState</code> from the data input stream.
-     *
-     * @param in the input stream
-     * @param id the id for the new property state
-     * @param pMgr the persistence manager
-     * @return the property state
-     * @throws IOException in an I/O error occurs.
-     */
-    public PropertyState readState(DataInputStream in, PropertyId id,
-                                   PersistenceManager pMgr)
-            throws IOException {
-        PropertyState state = pMgr.createNew(id);
-        // type and modcount
-        int type = in.readInt();
-        state.setModCount((short) ((type >> 16) & 0x0ffff));
-        type&=0x0ffff;
-        state.setType(type);
-        // multiValued
-        state.setMultiValued(in.readBoolean());
-        // definitionId
-        state.setDefinitionId(PropDefId.valueOf(in.readUTF()));
-        // values
-        int count = in.readInt();   // count
-        InternalValue[] values = new InternalValue[count];
-        for (int i = 0; i < count; i++) {
-            InternalValue val;
-            switch (type) {
-                case PropertyType.BINARY:
-                    int size = in.readInt();
-                    if (size == -1) {
-                        String s = in.readUTF();
-                        try {
-                            if (blobStore instanceof ResourceBasedBLOBStore) {
-                                val = InternalValue.create(
-                                        ((ResourceBasedBLOBStore) blobStore).getResource(s));
-                            } else {
-                                val = InternalValue.create(blobStore.get(s), false);
-                            }
-                        } catch (IOException e) {
-                            if (errorHandling.ignoreMissingBlobs()) {
-                                log.warn("Ignoring error while reading blob-resource: " + e);
-                                val = InternalValue.create(new byte[0]);
-                            } else {
-                                throw e;
-                            }
-                        } catch (Exception e) {
-                            throw new IOException("Unable to create property value: " + e.toString());
-                        }
-                    } else {
-                        // short values into memory
-                        byte[] data = new byte[size];
-                        in.readFully(data);
-                        val = InternalValue.create(data);
-                    }
-                    break;
-                case PropertyType.DOUBLE:
-                    val = InternalValue.create(in.readDouble());
-                    break;
-                case PropertyType.LONG:
-                    val = InternalValue.create(in.readLong());
-                    break;
-                case PropertyType.BOOLEAN:
-                    val = InternalValue.create(in.readBoolean());
-                    break;
-                case PropertyType.NAME:
-                    val = InternalValue.create(readQName(in));
-                    break;
-                case PropertyType.REFERENCE:
-                    val = InternalValue.create(readUUID(in));
-                    break;
-                default:
-                    // because writeUTF(String) has a size limit of 64k,
-                    // Strings are serialized as <length><byte[]>
-                    int len = in.readInt();
-                    byte[] bytes = new byte[len];
-                    int pos=0;
-                    while (pos < len) {
-                        pos+= in.read(bytes, pos, len-pos);
-                    }
-                    val = InternalValue.valueOf(new String(bytes, "UTF-8"), type);
-            }
-            values[i] = val;
-        }
-        state.setValues(values);
-        return state;
-    }
-
-    /**
-     * Serializes a <code>PropertyState</code> to the data output stream
-     * @param out the output stream
-     * @param state the property state to write
-     * @throws IOException in an I/O error occurs.
-     */
-    public void writeState(DataOutputStream out, PropertyState state)
-            throws IOException {
-        // type & mod count
-        out.writeInt(state.getType() | (state.getModCount() << 16));
-        // multiValued
-        out.writeBoolean(state.isMultiValued());
-        // definitionId
-        out.writeUTF(state.getDefinitionId().toString());
-        // values
-        InternalValue[] values = state.getValues();
-        out.writeInt(values.length); // count
-        for (int i = 0; i < values.length; i++) {
-            InternalValue val = values[i];
-            switch (state.getType()) {
-                case PropertyType.BINARY:
-                    try {
-                        // special handling required for binary value:
-                        // spool binary value to file in blob store
-                        BLOBFileValue blobVal = val.getBLOBFileValue();
-                        long size = blobVal.getLength();
-                        if (size > minBlobSize) {
-                            out.writeInt(-1);
-                            InputStream in = blobVal.getStream();
-                            String blobId = blobStore.createId((PropertyId) state.getId(), i);
-                            try {
-                                blobStore.put(blobId, in, size);
-                            } finally {
-                                try {
-                                    in.close();
-                                } catch (IOException e) {
-                                    // ignore
-                                }
-                            }
-                            // store id of blob as property value
-                            out.writeUTF(blobId);   // value
-                            // replace value instance with value
-                            // backed by resource in blob store and delete temp file
-                            if (blobStore instanceof ResourceBasedBLOBStore) {
-                                values[i] = InternalValue.create(((ResourceBasedBLOBStore) blobStore).getResource(blobId));
-                            } else {
-                                values[i] = InternalValue.create(blobStore.get(blobId), false);
-                            }
-                            blobVal.discard();
-                        } else {
-                            // delete evt. blob
-                            out.writeInt((int) size);
-                            byte[] data = new byte[(int) size];
-                            InputStream in = blobVal.getStream();
-                            try {
-                                int pos = 0;
-                                while (pos < size) {
-                                    int n = in.read(data, pos, (int) size-pos);
-                                    if (n < 0) {
-                                        throw new EOFException();
-                                    }
-                                    pos += n;
-                                }
-                            } finally {
-                                try {
-                                    in.close();
-                                } catch (IOException e) {
-                                    // ignore
-                                }
-                            }
-                            out.write(data, 0, data.length);
-                            // replace value instance with value
-                            // backed by resource in blob store and delete temp file
-                            values[i] = InternalValue.create(data);
-                            blobVal.discard();
-                        }
-                    } catch (IOException e) {
-                        throw e;
-                    } catch (Exception e) {
-                        throw new IOException("Error converting: " + e.toString());
-                    }
-                    break;
-                case PropertyType.DOUBLE:
-                    out.writeDouble(val.getDouble());
-                    break;
-                case PropertyType.LONG:
-                    out.writeLong(val.getLong());
-                    break;
-                case PropertyType.BOOLEAN:
-                    out.writeBoolean(val.getBoolean());
-                    break;
-                case PropertyType.NAME:
-                    writeQName(out, val.getQName());
-                    break;
-                case PropertyType.REFERENCE:
-                    writeUUID(out, val.getUUID());
-                    break;
-                default:
-                    // because writeUTF(String) has a size limit of 64k,
-                    // we're using write(byte[]) instead
-                    byte[] bytes = val.toString().getBytes("UTF-8");
-                    out.writeInt(bytes.length); // lenght of byte[]
-                    out.write(bytes);   // byte[]
-            }
-        }
-    }
-
-    /**
      * Deserializes a UUID
      * @param in the input stream
      * @return the uuid
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/obj/ObjectPersistenceManager.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/obj/ObjectPersistenceManager.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/obj/ObjectPersistenceManager.java	(working copy)
@@ -18,6 +18,7 @@
 
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.fs.BasedFileSystem;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.fs.FileSystemException;
@@ -34,7 +35,7 @@
 import org.apache.jackrabbit.core.state.NodeReferencesId;
 import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.jackrabbit.core.state.PropertyState;
-import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.value.BLOBValue;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -76,6 +77,11 @@
     private BLOBStore blobStore;
 
     /**
+     * Data store for binary properties.
+     */
+    private DataStore dataStore;
+
+    /**
      * Creates a new <code>ObjectPersistenceManager</code> instance.
      */
     public ObjectPersistenceManager() {
@@ -151,6 +157,7 @@
         blobFS.init();
         this.blobFS = blobFS;
         blobStore = new FileSystemBLOBStore(blobFS);
+        dataStore = context.getDataStore();
 
         initialized = true;
     }
@@ -246,7 +253,7 @@
                     new BufferedInputStream(itemStateFS.getInputStream(propFilePath));
             try {
                 PropertyState state = createNew(id);
-                Serializer.deserialize(state, in, blobStore);
+                Serializer.deserialize(state, in, blobStore, dataStore);
                 return state;
             } finally {
                 in.close();
@@ -338,7 +345,7 @@
             BufferedOutputStream out = new BufferedOutputStream(propFile.getOutputStream());
             try {
                 // serialize property state
-                Serializer.serialize(state, out, blobStore);
+                Serializer.serialize(state, out, blobStore, dataStore);
             } finally {
                 out.close();
             }
@@ -411,7 +418,7 @@
                 InternalValue val = values[i];
                 if (val != null) {
                     if (val.getType() == PropertyType.BINARY) {
-                        BLOBFileValue blobVal = val.getBLOBFileValue();
+                        BLOBValue blobVal = val.getBLOBValue();
                         // delete blob file and prune empty parent folders
                         blobVal.delete(true);
                     }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/Serializer.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/Serializer.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/Serializer.java	(working copy)
@@ -18,13 +18,13 @@
 
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.PropertyId;
-import org.apache.jackrabbit.core.fs.FileSystemResource;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.nodetype.NodeDefId;
 import org.apache.jackrabbit.core.nodetype.PropDefId;
 import org.apache.jackrabbit.core.state.NodeReferences;
 import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.jackrabbit.core.state.PropertyState;
-import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.value.BLOBValue;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.uuid.UUID;
@@ -173,7 +173,7 @@
      */
     public static void serialize(PropertyState state,
                                  OutputStream stream,
-                                 BLOBStore blobStore)
+                                 BLOBStore blobStore, DataStore store)
             throws Exception {
         DataOutputStream out = new DataOutputStream(stream);
 
@@ -190,10 +190,10 @@
         out.writeInt(values.length); // count
         for (int i = 0; i < values.length; i++) {
             InternalValue val = values[i];
-            if (state.getType() == PropertyType.BINARY) {
+            if (state.getType() == PropertyType.BINARY && !InternalValue.USE_DATA_STORE) {
                 // special handling required for binary value:
                 // put binary value in BLOB store
-                BLOBFileValue blobVal = val.getBLOBFileValue();
+                BLOBValue blobVal = val.getBLOBValue();
                 InputStream in = blobVal.getStream();
                 String blobId = blobStore.createId(state.getPropertyId(), i);
                 try {
@@ -209,25 +209,7 @@
                 out.writeUTF(blobId);   // value
                 // replace value instance with value backed by resource
                 // in BLOB store and discard old value instance (e.g. temp file)
-                if (blobStore instanceof ResourceBasedBLOBStore) {
-                    // optimization: if the BLOB store is resource-based
-                    // retrieve the resource directly rather than having
-                    // to read the BLOB from an input stream
-                    FileSystemResource fsRes =
-                            ((ResourceBasedBLOBStore) blobStore).getResource(blobId);
-                    values[i] = InternalValue.create(fsRes);
-                } else {
-                    in = blobStore.get(blobId);
-                    try {
-                        values[i] = InternalValue.create(in, false);
-                    } finally {
-                        try {
-                            in.close();
-                        } catch (IOException e) {
-                            // ignore
-                        }
-                    }
-                }
+                values[i] = InternalValue.create(blobStore, blobId, store);
                 blobVal.discard();
             } else {
                 /**
@@ -256,7 +238,7 @@
      */
     public static void deserialize(PropertyState state,
                                    InputStream stream,
-                                   BLOBStore blobStore)
+                                   BLOBStore blobStore, DataStore store)
             throws Exception {
         DataInputStream in = new DataInputStream(stream);
 
@@ -277,30 +259,12 @@
         InternalValue[] values = new InternalValue[count];
         for (int i = 0; i < count; i++) {
             InternalValue val;
-            if (type == PropertyType.BINARY) {
+            if (type == PropertyType.BINARY && !InternalValue.USE_DATA_STORE) {
                 s = in.readUTF();   // value (i.e. blobId)
                 // special handling required for binary value:
                 // the value stores the id of the BLOB data
                 // in the BLOB store
-                if (blobStore instanceof ResourceBasedBLOBStore) {
-                    // optimization: if the BLOB store is resource-based
-                    // retrieve the resource directly rather than having
-                    // to read the BLOB from an input stream
-                    FileSystemResource fsRes =
-                            ((ResourceBasedBLOBStore) blobStore).getResource(s);
-                    val = InternalValue.create(fsRes);
-                } else {
-                    InputStream is = blobStore.get(s);
-                    try {
-                        val = InternalValue.create(is, false);
-                    } finally {
-                        try {
-                            is.close();
-                        } catch (IOException e) {
-                            // ignore
-                        }
-                    }
-                }
+                val = InternalValue.create(blobStore, s, store);
             } else {
                 /**
                  * because writeUTF(String) has a size limit of 65k,
@@ -311,7 +275,7 @@
                 byte[] bytes = new byte[len];
                 in.readFully(bytes); // byte[]
                 s = new String(bytes, ENCODING);
-                val = InternalValue.valueOf(s, type);
+                val = InternalValue.valueOf(s, type, store);
             }
             values[i] = val;
         }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemPersistenceManager.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemPersistenceManager.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemPersistenceManager.java	(working copy)
@@ -19,6 +19,7 @@
 import org.apache.jackrabbit.core.ItemId;
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.fs.FileSystemPathUtil;
 import org.apache.jackrabbit.core.fs.FileSystemResource;
@@ -34,7 +35,7 @@
 import org.apache.jackrabbit.core.state.PropertyState;
 import org.apache.jackrabbit.core.persistence.util.FileSystemBLOBStore;
 import org.apache.jackrabbit.core.persistence.util.Serializer;
-import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.value.BLOBValue;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.name.QName;
 import org.slf4j.Logger;
@@ -92,6 +93,11 @@
     protected BLOBStore blobStore;
 
     /**
+     * Data store for binary properties.
+     */
+    protected DataStore dataStore;
+
+    /**
      * file system where the content of the hash maps are read from/written to
      * (if <code>persistent==true</code>)
      */
@@ -307,6 +313,7 @@
         blobFS.init();
         this.blobFS = blobFS;
         blobStore = new FileSystemBLOBStore(blobFS);
+        dataStore = context.getDataStore();
 
         if (persistent) {
             // deserialize contents of state and refs stores
@@ -403,7 +410,7 @@
         ByteArrayInputStream in = new ByteArrayInputStream(data);
         try {
             PropertyState state = createNew(id);
-            Serializer.deserialize(state, in, blobStore);
+            Serializer.deserialize(state, in, blobStore, dataStore);
             return state;
         } catch (Exception e) {
             String msg = "failed to read property state: " + id;
@@ -449,7 +456,7 @@
             ByteArrayOutputStream out =
                     new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);
             // serialize property state
-            Serializer.serialize(state, out, blobStore);
+            Serializer.serialize(state, out, blobStore, dataStore);
 
             // store in serialized format in map for better memory efficiency
             stateStore.put(state.getPropertyId(), out.toByteArray());
@@ -489,7 +496,7 @@
                 InternalValue val = values[i];
                 if (val != null) {
                     if (val.getType() == PropertyType.BINARY) {
-                        BLOBFileValue blobVal = val.getBLOBFileValue();
+                        BLOBValue blobVal = val.getBLOBValue();
                         // delete blob file and prune empty parent folders
                         blobVal.delete(true);
                     }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java	(working copy)
@@ -246,7 +246,7 @@
         }
         this.subject = subject;
         nsMappings = new LocalNamespaceMappings(rep.getNamespaceRegistry());
-        ntMgr = new NodeTypeManagerImpl(rep.getNodeTypeRegistry(), rep.getNamespaceRegistry(), getNamespaceResolver());
+        ntMgr = new NodeTypeManagerImpl(rep.getNodeTypeRegistry(), rep.getNamespaceRegistry(), getNamespaceResolver(), rep.getDataStore());
         String wspName = wspConfig.getName();
         wsp = createWorkspaceInstance(wspConfig,
                 rep.getWorkspaceStateManager(wspName), rep, this);
@@ -1088,7 +1088,7 @@
         parent.checkLock();
 
         SessionImporter importer = new SessionImporter(parent, this, uuidBehavior);
-        return new ImportHandler(importer, getNamespaceResolver(), rep.getNamespaceRegistry());
+        return new ImportHandler(importer, getNamespaceResolver(), rep.getNamespaceRegistry(), rep.getDataStore());
     }
 
     /**
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java	(working copy)
@@ -19,7 +19,7 @@
 import org.apache.jackrabbit.core.state.ItemState;
 import org.apache.jackrabbit.core.state.ItemStateException;
 import org.apache.jackrabbit.core.state.PropertyState;
-import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.value.BLOBValue;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.name.Path;
 import org.apache.jackrabbit.name.QName;
@@ -176,7 +176,7 @@
                 return session.getJCRPath(path).length();
 
             case PropertyType.BINARY:
-                BLOBFileValue blob = value.getBLOBFileValue();
+                BLOBValue blob = value.getBLOBValue();
                 return blob.getLength();
 
             default:
@@ -274,7 +274,7 @@
                 if (old != null && old.getType() == PropertyType.BINARY) {
                     // make sure temporarily allocated data is discarded
                     // before overwriting it
-                    old.getBLOBFileValue().discard();
+                    old.getBLOBValue().discard();
                 }
             }
         }
@@ -329,7 +329,7 @@
                     InternalValue.create(name).toJCRValue(session.getNamespaceResolver()),
                     reqType,
                     ValueFactoryImpl.getInstance());
-            internalValue = InternalValue.create(targetValue, session.getNamespaceResolver());
+            internalValue = InternalValue.create(targetValue, session.getNamespaceResolver(), rep.getDataStore());
         } else {
             // no type conversion required
             internalValue = InternalValue.create(name);
@@ -380,7 +380,7 @@
                                 InternalValue.create(name).toJCRValue(session.getNamespaceResolver()),
                                 reqType,
                                 ValueFactoryImpl.getInstance());
-                        internalValue = InternalValue.create(targetValue, session.getNamespaceResolver());
+                        internalValue = InternalValue.create(targetValue, session.getNamespaceResolver(), rep.getDataStore());
                     } else {
                         // no type conversion required
                         internalValue = InternalValue.create(name);
@@ -671,7 +671,7 @@
             Value targetVal = ValueHelper.convert(
                     new DateValue(date), reqType,
                     ValueFactoryImpl.getInstance());
-            value = InternalValue.create(targetVal, session.getNamespaceResolver());
+            value = InternalValue.create(targetVal, session.getNamespaceResolver(), rep.getDataStore());
         } else {
             // no type conversion required
             value = InternalValue.create(date);
@@ -705,7 +705,7 @@
             Value targetVal = ValueHelper.convert(
                     new DoubleValue(number), reqType,
                     ValueFactoryImpl.getInstance());
-            value = InternalValue.create(targetVal, session.getNamespaceResolver());
+            value = InternalValue.create(targetVal, session.getNamespaceResolver(), rep.getDataStore());
         } else {
             // no type conversion required
             value = InternalValue.create(number);
@@ -740,15 +740,13 @@
 
         InternalValue value;
         try {
+            value = InternalValue.create(stream, rep.getDataStore());
             if (reqType != PropertyType.BINARY) {
                 // type conversion required
+                Value jcrValue = value.toJCRValue(session.getNamespaceResolver());
                 Value targetVal = ValueHelper.convert(
-                        new BLOBFileValue(stream), reqType,
-                        ValueFactoryImpl.getInstance());
-                value = InternalValue.create(targetVal, session.getNamespaceResolver());
-            } else {
-                // no type conversion required
-                value = InternalValue.create(stream);
+                        jcrValue, reqType, ValueFactoryImpl.getInstance());
+                value = InternalValue.create(targetVal, session.getNamespaceResolver(), rep.getDataStore());
             }
         } catch (IOException ioe) {
             String msg = "failed to spool stream to internal storage";
@@ -789,7 +787,7 @@
             Value targetValue = ValueHelper.convert(
                     string, reqType,
                     ValueFactoryImpl.getInstance());
-            internalValue = InternalValue.create(targetValue, session.getNamespaceResolver());
+            internalValue = InternalValue.create(targetValue, session.getNamespaceResolver(), rep.getDataStore());
         } else {
             // no type conversion required
             internalValue = InternalValue.create(string);
@@ -829,7 +827,7 @@
                         Value targetValue = ValueHelper.convert(
                                 string, reqType,
                                 ValueFactoryImpl.getInstance());
-                        internalValue = InternalValue.create(targetValue, session.getNamespaceResolver());
+                        internalValue = InternalValue.create(targetValue, session.getNamespaceResolver(), rep.getDataStore());
                     } else {
                         // no type conversion required
                         internalValue = InternalValue.create(string);
@@ -867,7 +865,7 @@
             Value targetVal = ValueHelper.convert(
                     new BooleanValue(b), reqType,
                     ValueFactoryImpl.getInstance());
-            value = InternalValue.create(targetVal, session.getNamespaceResolver());
+            value = InternalValue.create(targetVal, session.getNamespaceResolver(), rep.getDataStore());
         } else {
             // no type conversion required
             value = InternalValue.create(b);
@@ -943,7 +941,7 @@
             Value targetVal = ValueHelper.convert(
                     new LongValue(number), reqType,
                     ValueFactoryImpl.getInstance());
-            value = InternalValue.create(targetVal, session.getNamespaceResolver());
+            value = InternalValue.create(targetVal, session.getNamespaceResolver(), rep.getDataStore());
         } else {
             // no type conversion required
             value = InternalValue.create(number);
@@ -986,10 +984,10 @@
             Value targetVal = ValueHelper.convert(
                     value, reqType,
                     ValueFactoryImpl.getInstance());
-            internalValue = InternalValue.create(targetVal, session.getNamespaceResolver());
+            internalValue = InternalValue.create(targetVal, session.getNamespaceResolver(), rep.getDataStore());
         } else {
             // no type conversion required
-            internalValue = InternalValue.create(value, session.getNamespaceResolver());
+            internalValue = InternalValue.create(value, session.getNamespaceResolver(), rep.getDataStore());
         }
         internalSetValue(new InternalValue[]{internalValue}, reqType);
     }
@@ -1046,10 +1044,10 @@
                         Value targetVal = ValueHelper.convert(
                                 value, reqType,
                                 ValueFactoryImpl.getInstance());
-                        internalValue = InternalValue.create(targetVal, session.getNamespaceResolver());
+                        internalValue = InternalValue.create(targetVal, session.getNamespaceResolver(), rep.getDataStore());
                     } else {
                         // no type conversion required
-                        internalValue = InternalValue.create(value, session.getNamespaceResolver());
+                        internalValue = InternalValue.create(value, session.getNamespaceResolver(), rep.getDataStore());
                     }
                 }
                 internalValues[i] = internalValue;
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java	(working copy)
@@ -4010,26 +4010,6 @@
         }
     }
 
-    /**
-     * Copies a property to this node
-     *
-     * @param prop
-     * @throws RepositoryException
-     */
-    protected void internalCopyPropertyFrom(PropertyImpl prop) throws RepositoryException {
-        if (prop.getDefinition().isMultiple()) {
-            Value[] values = prop.getValues();
-            InternalValue[] ivalues = new InternalValue[values.length];
-            for (int i = 0; i < values.length; i++) {
-                ivalues[i] = InternalValue.create(values[i], session.getNamespaceResolver());
-            }
-            internalSetProperty(prop.getQName(), ivalues);
-        } else {
-            InternalValue value = InternalValue.create(prop.getValue(), session.getNamespaceResolver());
-            internalSetProperty(prop.getQName(), value);
-        }
-    }
-
     //------------------------------------------------------< locking support >
     /**
      * {@inheritDoc}
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/TextFilterExtractor.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/TextFilterExtractor.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/TextFilterExtractor.java	(working copy)
@@ -29,7 +29,6 @@
 import org.apache.jackrabbit.core.query.TextFilter;
 import org.apache.jackrabbit.core.state.ItemState;
 import org.apache.jackrabbit.core.state.PropertyState;
-import org.apache.jackrabbit.core.value.BLOBFileValue;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.extractor.TextExtractor;
 
@@ -97,7 +96,7 @@
      */
     public Reader extractText(InputStream stream, String type, String encoding)
             throws IOException {
-        final InternalValue value = InternalValue.create(stream);
+        final InternalValue value = InternalValue.createTemporary(stream);
         try {
             PropertyState state = new PropertyState(
                     (PropertyId) null, ItemState.STATUS_EXISTING, true);
@@ -108,15 +107,15 @@
                 return new FilterReader((Reader) fulltext) {
                     public void close() throws IOException {
                         super.close();
-                        value.getBLOBFileValue().discard();
+                        value.getBLOBValue().discard();
                     }
                 };
             } else {
-                value.getBLOBFileValue().discard();
+                value.getBLOBValue().discard();
                 return new StringReader("");
             }
         } catch (RepositoryException e) {
-            value.getBLOBFileValue().discard();
+            value.getBLOBValue().discard();
             return new StringReader("");
         }
     }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java	(working copy)
@@ -23,7 +23,7 @@
 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.BLOBFileValue;
+import org.apache.jackrabbit.core.value.BLOBValue;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.extractor.TextExtractor;
 import org.apache.jackrabbit.name.NoPrefixDeclaredException;
@@ -252,7 +252,7 @@
         switch (value.getType()) {
             case PropertyType.BINARY:
                 if (isIndexed(name)) {
-                    addBinaryValue(doc, fieldName, value.getBLOBFileValue());
+                    addBinaryValue(doc, fieldName, value.getBLOBValue());
                 }
                 break;
             case PropertyType.BOOLEAN:
@@ -346,7 +346,7 @@
                 }
 
                 InputStream stream =
-                        ((BLOBFileValue) internalValue).getStream();
+                        ((BLOBValue) internalValue).getStream();
                 Reader reader = extractor.extractText(stream, type, encoding);
                 doc.add(createFulltextField(reader));
             }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/TextExtractorFilter.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/TextExtractorFilter.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/TextExtractorFilter.java	(working copy)
@@ -25,7 +25,7 @@
 
 import org.apache.jackrabbit.core.query.TextFilter;
 import org.apache.jackrabbit.core.state.PropertyState;
-import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.value.BLOBValue;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.extractor.TextExtractor;
 
@@ -100,7 +100,7 @@
                     type = types[0];
                 }
 
-                BLOBFileValue blob = values[0].getBLOBFileValue();
+                BLOBValue blob = values[0].getBLOBValue();
                 Reader reader =
                     extractor.extractText(blob.getStream(), type, encoding);
 
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java	(revision 0)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java	(revision 0)
@@ -0,0 +1,198 @@
+/*
+ * 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.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Random;
+
+/**
+ * Simple file-based data store. Data records are stored as normal files
+ * named using a message digest of the contained binary stream.
+ * <p>
+ * A three level directory structure is used to avoid placing too many
+ * files in a single directory. The chosen structure is designed to scale
+ * up to billions of distinct records.
+ * <p>
+ * 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 {
+
+    /**
+     * The digest algorithm used to uniquely identify records.
+     */
+    private static final String DIGEST = "SHA-1";
+
+    /**
+     * Name of the directory used for temporary files.
+     */
+    private static final String TMP = "tmp";
+
+    /**
+     * Temporary file counter used to guarantee that concurrent threads
+     * in this JVM do not accidentally use the same temporary file names.
+     * <p>
+     * This variable is static to allow multiple separate data store
+     * instances in the same JVM to access the same data store directory
+     * on disk. The counter is initialized to a random number based on the
+     * time when this class was first loaded to minimize the chance of two
+     * separate JVM processes (or class loaders within the same JVM) using
+     * the same temporary file names. 
+     */
+    private static long counter = new Random().nextLong();
+
+    /**
+     * Returns the next value of the internal temporary file counter.
+     *
+     * @return next counter value
+     */
+    private static synchronized long nextCount() {
+        return counter++;
+    }
+
+    /**
+     * The directory that contains all the data record files. The structure
+     * of content within this directory is controlled by this class.
+     */
+    private final File directory;
+
+    /**
+     * Creates a data store based on the given directory.
+     *
+     * @param directory data store directory
+     */
+    public FileDataStore(File directory) {
+        this.directory = directory;
+    }
+
+    /**
+     * 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) {
+        return new FileDataRecord(identifier, getFile(identifier));
+    }
+
+    /**
+     * Creates a new record based on the given input stream. The stream
+     * is first consumed and the contents are saved in a temporary file
+     * and the SHA-1 message digest of the stream is calculated. If a
+     * record with the same SHA-1 digest (and length) is found then it is
+     * returned. Otherwise the temporary file is moved in place to become
+     * the new data record that gets returned.
+     *
+     * @param input binary stream
+     * @return data record that contains the given stream
+     * @throws IOException if the record could not be created
+     */
+    public DataRecord addRecord(InputStream input) throws IOException {
+        File temporary = newTemporaryFile();
+        try {
+            // Copy the stream to the temporary file and calculate the
+            // stream length and the message digest of the stream
+            long length = 0;
+            MessageDigest digest = MessageDigest.getInstance(DIGEST);
+            OutputStream output = new FileOutputStream(temporary);
+            try {
+                byte[] b = new byte[4096];
+                for (int n = input.read(b); n != -1; n = input.read(b)) {
+                    output.write(b, 0, n);
+                    digest.update(b, 0, n);
+                    length += n;
+                }
+            } finally {
+                output.close();
+            }
+
+            // Check if the same record already exists, or
+            // move the temporary file in place if needed
+            DataIdentifier identifier = new DataIdentifier(digest.digest());
+            File file = getFile(identifier);
+            File parent = file.getParentFile();
+            if (!parent.isDirectory()) {
+                parent.mkdirs();
+            }
+            if (!file.exists()) {
+                temporary.renameTo(file);
+            }
+
+            // Sanity checks on the record file. These should never fail,
+            // but better safe than sorry...
+            if (!file.isFile()) {
+                throw new IOException("Not a file: " + file);
+            }
+            if (file.length() != length) {
+                throw new IOException(DIGEST + " collision: " + file);
+            }
+
+            return new FileDataRecord(identifier, file);
+        } catch (NoSuchAlgorithmException e) {
+            throw new IOException(DIGEST + " not available: " + e.getMessage());
+        } finally {
+            temporary.delete();
+        }
+    }
+
+    /**
+     * Returns the identified file. This method implements the pattern
+     * used to avoid problems with too many files in a single directory.
+     * <p>
+     * No sanity checks are performed on the given identifier.
+     *
+     * @param identifier data identifier
+     * @return identified file
+     */
+    private File getFile(DataIdentifier identifier) {
+        String string = identifier.toString();
+        File file = directory;
+        file = new File(file, string.substring(0, 2));
+        file = new File(file, string.substring(2, 4));
+        file = new File(file, string.substring(4, 6));
+        return new File(file, string);
+    }
+
+    /**
+     * Returns a unique temporary file to be used for creating a new
+     * data record. A synchronized counter value and the current time are
+     * used to construct the name of the temporary file in a way that
+     * minimizes the chance of collisions across concurrent threads or
+     * processes.
+     *
+     * @return temporary file
+     */
+    private File newTemporaryFile() {
+        File temporary = new File(directory, TMP);
+
+        if (!temporary.isDirectory()) {
+            temporary.mkdirs();
+        }
+        String name = TMP + "-" + nextCount() + "-" + System.currentTimeMillis();
+        return new File(temporary, name);
+    }
+
+}
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java	(revision 0)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java	(revision 0)
@@ -0,0 +1,73 @@
+/*
+ * 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.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Append-only store for binary streams. A data store consists of a number
+ * of identifiable data records that each contain a distinct binary stream.
+ * New binary streams can be added to the data store, but existing streams
+ * are never removed or modified.
+ * <p>
+ * A data store should be fully thread-safe, i.e. it should be possible to
+ * add and access data records concurrently. Optimally even separate processes
+ * should be able to concurrently access the data store with zero interprocess
+ * synchronization.
+ */
+public interface DataStore {
+
+    /**
+     * Returns the identified data record. The given identifier should be
+     * the identifier of a previously saved data record. Since records are
+     * never removed, there should never be cases where the identified record
+     * is not found. Abnormal cases like that are treated as errors and
+     * handled by throwing an exception.
+     *
+     * @param identifier data identifier
+     * @return identified data record
+     * @throws IOException if the data store could not be accessed,
+     *                     or if the given identifier is invalid
+     */
+    DataRecord getRecord(DataIdentifier identifier) throws IOException;
+
+    /**
+     * 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
+     * is returned instead of creating a new one.
+     * <p>
+     * The given stream is consumed and <strong>not closed</strong> by this
+     * method. It is the responsibility of the caller to close the stream.
+     * A typical call pattern would be:
+     * <pre>
+     *     InputStream stream = ...;
+     *     try {
+     *         record = store.addRecord(stream);
+     *     } finally {
+     *         stream.close();
+     *     }
+     * </pre>
+     *
+     * @param stream binary stream
+     * @return data record that contains the given stream
+     * @throws IOException if the data store could not be accessed
+     */
+    DataRecord addRecord(InputStream stream) throws IOException;
+
+}
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataRecord.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataRecord.java	(revision 0)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataRecord.java	(revision 0)
@@ -0,0 +1,66 @@
+/*
+ * 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.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * Data record that is based on a normal file.
+ */
+class FileDataRecord extends AbstractDataRecord {
+
+    /**
+     * The file that contains the binary stream.
+     */
+    private final File file;
+
+    /**
+     * Creates a data record based on the given identifier and file.
+     *
+     * @param identifier data identifier
+     * @param file file that contains the binary stream
+     */
+    public FileDataRecord(DataIdentifier identifier, File file) {
+        super(identifier);
+        assert file.isFile();
+        this.file = file;
+    }
+
+    /**
+     * Returns the length of the file.
+     *
+     * @return file length
+     */
+    public long getLength() {
+        return file.length();
+    }
+
+    /**
+     * Returns an input stream for reading the file.
+     *
+     * @return file input stream
+     * @throws IOException if the file could not be opened
+     */
+    public InputStream getStream() throws IOException {
+        return new FileInputStream(file);
+    }
+
+}
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataRecord.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataRecord.java	(revision 0)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataRecord.java	(revision 0)
@@ -0,0 +1,50 @@
+/*
+ * 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.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Immutable data record that consists of a binary stream.
+ */
+public interface DataRecord {
+
+    /**
+     * Returns the identifier of this record.
+     *
+     * @return data identifier
+     */
+    DataIdentifier getIdentifier();
+
+    /**
+     * Returns the length of the binary stream in this record.
+     *
+     * @return length of the binary stream
+     * @throws IOException if the record could not be accessed
+     */
+    long getLength() throws IOException;
+
+    /**
+     * Returns the the binary stream in this record.
+     *
+     * @return binary stream
+     * @throws IOException if the record could not be accessed
+     */
+    InputStream getStream() throws IOException;
+
+}
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java	(revision 0)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/AbstractDataRecord.java	(revision 0)
@@ -0,0 +1,82 @@
+/*
+ * 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 binary identifier;
+     */
+    private final DataIdentifier identifier;
+
+    /**
+     * Creates a data record with the given identifier.
+     *
+     * @param identifier data identifier
+     */
+    public AbstractDataRecord(DataIdentifier identifier) {
+        this.identifier = identifier;
+    }
+
+    /**
+     * Returns the data identifier.
+     *
+     * @param data identifier
+     */
+    public DataIdentifier getIdentifier() {
+        return 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();
+    }
+
+}
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataIdentifier.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataIdentifier.java	(revision 0)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataIdentifier.java	(revision 0)
@@ -0,0 +1,100 @@
+/*
+ * 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.io.Serializable;
+
+/**
+ * Opaque data identifier used to identify records in a data store. 
+ * All identifiers must be serializable and implement the standard
+ * object equality and hash code methods.
+ */
+public final class DataIdentifier implements Serializable {
+
+    /**
+     * Serial version UID.
+     */
+    private static final long serialVersionUID = -9197191401131100016L;
+
+    /**
+     * Array of hexadecimal digits.
+     */
+    private static final char[] HEX = "0123456789abcdef".toCharArray();
+
+    /**
+     * Data identifier.
+     */
+    private final String identifier;
+
+    /**
+     * Creates a data identifier from the given string.
+     *
+     * @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);
+    }
+
+    //-------------------------------------------------------------< Object >
+
+    /**
+     * Returns the identifier string.
+     *
+     * @return identifier string
+     */
+    public String toString() {
+        return identifier;
+    }
+
+    /**
+     * Checks if the given object is a data identifier and has the same
+     * string representation as this one.
+     *
+     * @param object other object
+     * @return <code>true</code> if the given object is the same identifier,
+     *         <code>false</code> otherwise
+     */
+    public boolean equals(Object object) {
+        return (object instanceof DataIdentifier)
+            && identifier.equals(object.toString()); 
+    }
+
+    /**
+     * Returns the hash code of the identifier string.
+     *
+     * @return hash code
+     */
+    public int hashCode() {
+        return identifier.hashCode();
+    }
+
+}
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/InternalValue.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/InternalValue.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/InternalValue.java	(working copy)
@@ -16,7 +16,9 @@
  */
 package org.apache.jackrabbit.core.value;
 
-import org.apache.jackrabbit.core.fs.FileSystemResource;
+import org.apache.jackrabbit.core.data.DataStore;
+import org.apache.jackrabbit.core.persistence.util.BLOBStore;
+import org.apache.jackrabbit.core.persistence.util.ResourceBasedBLOBStore;
 import org.apache.jackrabbit.name.MalformedPathException;
 import org.apache.jackrabbit.name.NameException;
 import org.apache.jackrabbit.name.NamespaceResolver;
@@ -41,9 +43,11 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 import javax.jcr.ValueFormatException;
-import java.io.File;
+
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.SequenceInputStream;
 import java.util.Calendar;
 
 /**
@@ -69,10 +73,20 @@
 
     public static final InternalValue[] EMPTY_ARRAY = new InternalValue[0];
 
-    public static final InternalValue BOOLEAN_TRUE = create(true);
+    private static final InternalValue BOOLEAN_TRUE = new InternalValue(true);
 
-    public static final InternalValue BOOLEAN_FALSE = create(false);
+    private static final InternalValue BOOLEAN_FALSE = new InternalValue(false);
+    
+    /**
+     * If set to 'true', the new global data store will be used, otherwise the old blob store implementation
+     */
+    public static final boolean USE_DATA_STORE = Boolean.valueOf(System.getProperty("org.jackrabbit.useDataStore", "false")).booleanValue();
 
+    /**
+     * Byte arrays smaller or equal this size are always kept in memory
+     */
+    private final static int MIN_BLOB_FILE_SIZE = Integer.parseInt(System.getProperty("org.jackrabbit.minBlobFileSize", "128"));
+
     private final Object val;
     private final int type;
 
@@ -84,32 +98,31 @@
      * @throws ValueFormatException
      * @throws RepositoryException
      */
-    public static InternalValue create(Value value, NamespaceResolver nsResolver)
+    public static InternalValue create(Value value, NamespaceResolver nsResolver, DataStore store)
             throws ValueFormatException, RepositoryException {
         if (value == null) {
             throw new IllegalArgumentException("null value");
         }
-
         switch (value.getType()) {
             case PropertyType.BINARY:
+                BLOBValue lob;
+                InputStream stream = value.getStream();
                 try {
-                    if (value instanceof BLOBFileValue) {
-                        return new InternalValue((BLOBFileValue) value);
+                    if(USE_DATA_STORE) {
+                        lob = getBLOBValue(store, stream);
                     } else {
-                        InputStream stream = value.getStream();
-                        try {
-                            return new InternalValue(new BLOBFileValue(stream));
-                        } finally {
-                            try {
-                                stream.close();
-                            } catch (IOException e) {
-                                // ignore
-                            }
-                        }
+                        lob = new BLOBFileValue(stream);
                     }
                 } catch (IOException ioe) {
                     throw new ValueFormatException(ioe.getMessage());
+                } finally {
+                    try {
+                        stream.close();
+                    } catch (IOException e) {
+                        // ignore
+                    }
                 }
+                return new InternalValue(lob);
             case PropertyType.BOOLEAN:
                 return value.getBoolean() ? BOOLEAN_TRUE : BOOLEAN_FALSE;
             case PropertyType.DATE:
@@ -177,7 +190,7 @@
      * @return the created value
      */
     public static InternalValue create(boolean value) {
-        return new InternalValue(value);
+        return value ? BOOLEAN_TRUE : BOOLEAN_FALSE;
     }
 
     /**
@@ -185,49 +198,67 @@
      * @return the created value
      */
     public static InternalValue create(byte[] value) {
-        return new InternalValue(new BLOBFileValue(value));
+        if(USE_DATA_STORE) {        
+            return new InternalValue(BLOBInMemory.getInstance(value));
+        } else {
+            return new InternalValue(new BLOBFileValue(value));
+        }
     }
 
     /**
-     * @param value
+     * @param in
      * @return
      * @throws IOException
      */
-    public static InternalValue create(InputStream value) throws IOException {
-        return new InternalValue(new BLOBFileValue(value));
+    public static InternalValue createTemporary(InputStream in) throws IOException {
+        if(USE_DATA_STORE) {        
+            return new InternalValue(BLOBInTempFile.getInstance(in));
+        }
+        return new InternalValue(new BLOBFileValue(in));
     }
 
     /**
-     * @param value
-     * @param temp
+     * @param in
      * @return
      * @throws IOException
      */
-    public static InternalValue create(InputStream value, boolean temp) throws IOException {
-        return new InternalValue(new BLOBFileValue(value, temp));
+    public static InternalValue create(InputStream in, DataStore store) throws IOException {
+        if(USE_DATA_STORE) {
+            return new InternalValue(getBLOBValue(store, in));
+        }
+        return new InternalValue(new BLOBFileValue(in));
     }
+    
 
     /**
      * @param value
      * @return
-     * @throws IOException
+     * @throws Exception 
+     * @throws Exception 
      */
-    public static InternalValue create(FileSystemResource value)
-            throws IOException {
-        return new InternalValue(new BLOBFileValue(value));
+    public static InternalValue create(BLOBStore blobStore, String blobId, DataStore store) throws Exception {
+        if(USE_DATA_STORE) {
+            return new InternalValue(getBLOBValue(store, blobId));
+        }
+        if (blobStore instanceof ResourceBasedBLOBStore) {
+            ResourceBasedBLOBStore r = (ResourceBasedBLOBStore) blobStore;
+            return new InternalValue(new BLOBFileValue(r.getResource(blobId)));
+        } else {
+            InputStream in = blobStore.get(blobId);
+            try {            
+                return new InternalValue(new BLOBFileValue(in, false));
+            } finally {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    // ignore
+                }                    
+            }
+        }
     }
 
     /**
      * @param value
-     * @return
-     * @throws IOException
-     */
-    public static InternalValue create(File value) throws IOException {
-        return new InternalValue(new BLOBFileValue(value));
-    }
-
-    /**
-     * @param value
      * @return the created value
      */
     public static InternalValue create(QName value) {
@@ -247,30 +278,6 @@
     }
 
     /**
-     * @param values
-     * @return the created value
-     */
-    public static InternalValue[] create(String[] values) {
-        InternalValue[] ret = new InternalValue[values.length];
-        for (int i = 0; i < values.length; i++) {
-            ret[i] = new InternalValue(values[i]);
-        }
-        return ret;
-    }
-
-    /**
-     * @param values
-     * @return the created value
-     */
-    public static InternalValue[] create(Calendar[] values) {
-        InternalValue[] ret = new InternalValue[values.length];
-        for (int i = 0; i < values.length; i++) {
-            ret[i] = new InternalValue(values[i]);
-        }
-        return ret;
-    }
-
-    /**
      * @param value
      * @return the created value
      */
@@ -296,7 +303,7 @@
             throws RepositoryException {
         switch (type) {
             case PropertyType.BINARY:
-                return new BinaryValue(((BLOBFileValue) val).getStream());
+                return new BinaryValue(((BLOBValue) val).getStream());
             case PropertyType.BOOLEAN:
                 return new BooleanValue(((Boolean) val));
             case PropertyType.DATE:
@@ -331,9 +338,9 @@
         return val;
     }
     
-    public BLOBFileValue getBLOBFileValue() {
+    public BLOBValue getBLOBValue() {
         assert val != null && type == PropertyType.BINARY;
-        return (BLOBFileValue) val;
+        return (BLOBValue) val;
     }
     
     public UUID getUUID() {
@@ -388,10 +395,13 @@
      * @throws RepositoryException
      */
     public InternalValue createCopy() throws RepositoryException {
+        if(USE_DATA_STORE) {
+            return this;
+        }
         if (type == PropertyType.BINARY) {
             // return a copy since the wrapped BLOBFileValue instance is mutable
             try {
-                InputStream stream = ((BLOBFileValue) val).getStream();
+                InputStream stream = ((BLOBValue) val).getStream();
                 try {
                     return new InternalValue(new BLOBFileValue(stream));
                 } finally {
@@ -419,13 +429,14 @@
      * @param s a <code>String</code> containing the <code>InternalValue</code>
      *          representation to be parsed.
      * @param type
+     * @param dataStore must be set for data store based values
      * @return the <code>InternalValue</code> represented by the arguments
      * @throws IllegalArgumentException if the specified string can not be parsed
      *                                  as an <code>InternalValue</code> of the
      *                                  specified type.
      * @see #toString()
      */
-    public static InternalValue valueOf(String s, int type) {
+    public static InternalValue valueOf(String s, int type, DataStore store) {
         switch (type) {
             case PropertyType.BOOLEAN:
                 return new InternalValue(Boolean.valueOf(s).booleanValue());
@@ -443,12 +454,13 @@
                 return new InternalValue(QName.valueOf(s));
             case PropertyType.STRING:
                 return new InternalValue(s);
-
-            case PropertyType.BINARY:
-                throw new IllegalArgumentException(
-                        "this method does not support the type PropertyType.BINARY");
+            case PropertyType.BINARY: {
+                if(USE_DATA_STORE) {
+                    return new InternalValue(getBLOBValue(store, s));
+                }
+            }
             default:
-                throw new IllegalArgumentException("illegal type");
+                throw new IllegalArgumentException("illegal type: " + type);
         }
     }
 
@@ -518,7 +530,7 @@
         type = PropertyType.BOOLEAN;
     }
 
-    private InternalValue(BLOBFileValue value) {
+    private InternalValue(BLOBValue value) {
         val = value;
         type = PropertyType.BINARY;
     }
@@ -532,4 +544,41 @@
         val = value;
         type = PropertyType.REFERENCE;
     }
+    
+    private static BLOBValue getBLOBValue(DataStore store, InputStream in) throws IOException {
+        byte[] buffer = new byte[MIN_BLOB_FILE_SIZE];
+        int pos = 0, len = MIN_BLOB_FILE_SIZE;
+        while(pos < MIN_BLOB_FILE_SIZE) {
+            int l = in.read(buffer, pos, len);
+            if(l < 0) {
+                break;
+            }
+            pos += l;
+            len -= l;
+        }
+        if(pos < MIN_BLOB_FILE_SIZE) {
+            // shrink the buffer
+            byte[] data = new byte[pos];
+            System.arraycopy(buffer, 0, data, 0, pos);
+            return BLOBInMemory.getInstance(data);
+        } else {
+            // a few bytes are already read, need to re-build the input stream
+            in = new SequenceInputStream(new ByteArrayInputStream(buffer, 0, pos), in);
+            if(InternalValue.USE_DATA_STORE) {
+                return BLOBInDataStore.getInstance(store, in);
+            }
+            return new BLOBFileValue(in);
+        }
+    }
+
+    private static BLOBValue getBLOBValue(DataStore store, String s) {
+        if(BLOBInMemory.isInstance(s)) {
+            return BLOBInMemory.getInstance(s);
+        } else if(BLOBInDataStore.isInstance(s)) {
+            return BLOBInDataStore.getInstance(store, s);
+        } else {
+            throw new IllegalArgumentException("illegal binary value: " + s);
+        }
+    }
+
 }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBFileValue.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBFileValue.java	(revision 549117)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBFileValue.java	(working copy)
@@ -18,17 +18,11 @@
 
 import org.apache.jackrabbit.core.fs.FileSystemException;
 import org.apache.jackrabbit.core.fs.FileSystemResource;
-import org.apache.jackrabbit.util.ISO8601;
 import org.apache.jackrabbit.util.TransientFileFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-import javax.jcr.ValueFormatException;
 import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -36,10 +30,11 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
-import java.util.Calendar;
 
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+
 /**
  * <code>BLOBFileValue</code> represents a binary <code>Value</code> which is
  * backed by a resource or byte[]. Unlike <code>BinaryValue</code> it has no
@@ -50,7 +45,7 @@
  * This is class is for Jackrabbit-internal use only. Applications should
  * use <code>javax.jcr.ValueFactory</code> to create binary values.
  */
-public class BLOBFileValue implements Value {
+public class BLOBFileValue extends BLOBValue {
 
     /**
      * The default logger
@@ -100,11 +95,6 @@
     private final FileSystemResource fsResource;
 
     /**
-     * converted text
-     */
-    private String text = null;
-
-    /**
      * Creates a new <code>BLOBFileValue</code> instance from an
      * <code>InputStream</code>. The contents of the stream is spooled
      * to a temporary file or to a byte buffer if its size is smaller than
@@ -117,7 +107,7 @@
      * @throws IOException if an error occurs while reading from the stream or
      *                     writing to the temporary file
      */
-    public BLOBFileValue(InputStream in) throws IOException {
+    BLOBFileValue(InputStream in) throws IOException {
         this(in, true);
     }
 
@@ -131,6 +121,9 @@
      * resources will be freed explicitly on {@link #discard()}. Note that any
      * dynamically allocated resources (temp file/buffer) will be freed
      * implicitly once this instance has been gc'ed.
+     * 
+     * This constructor does currently not close the input stream, but reads until the end of the stream.
+     * Maybe this is a bug.
      *
      * @param in stream to be represented as a <code>BLOBFileValue</code> instance
      * @param temp flag indicating whether this instance represents a
@@ -139,7 +132,7 @@
      * @throws IOException if an error occurs while reading from the stream or
      *                     writing to the temporary file
      */
-    public BLOBFileValue(InputStream in, boolean temp) throws IOException {
+    BLOBFileValue(InputStream in, boolean temp) throws IOException {
         byte[] spoolBuffer = new byte[0x2000];
         int read;
         int len = 0;
@@ -181,7 +174,7 @@
         fsResource = null;
         this.temp = temp;
     }
-
+    
     /**
      * Creates a new <code>BLOBFileValue</code> instance from a
      * <code>byte[]</code> array.
@@ -195,7 +188,7 @@
         fsResource = null;
         // this instance is not backed by a temporarily allocated buffer
         temp = false;
-    }
+    }    
 
     /**
      * Creates a new <code>BLOBFileValue</code> instance from a <code>File</code>.
@@ -203,7 +196,7 @@
      * @param file file to be represented as a <code>BLOBFileValue</code> instance
      * @throws IOException if the file can not be read
      */
-    public BLOBFileValue(File file) throws IOException {
+    BLOBFileValue(File file) throws IOException {
         String path = file.getCanonicalPath();
         if (!file.isFile()) {
             throw new IOException(path + ": the specified file does not exist");
@@ -225,7 +218,7 @@
      * @param fsResource resource in virtual file system
      * @throws IOException if the resource can not be read
      */
-    public BLOBFileValue(FileSystemResource fsResource) throws IOException {
+    BLOBFileValue(FileSystemResource fsResource) throws IOException {
         try {
             if (!fsResource.exists()) {
                 throw new IOException(fsResource.getPath()
@@ -244,10 +237,7 @@
     }
 
     /**
-     * Returns the length of this <code>BLOBFileValue</code>.
-     *
-     * @return The length, in bytes, of this <code>BLOBFileValue</code>,
-     *         or -1L if the length can't be determined.
+     * {@inheritDoc}
      */
     public long getLength() {
         if (file != null) {
@@ -271,12 +261,7 @@
     }
 
     /**
-     * Frees temporarily allocated resources such as temporary file, buffer, etc.
-     * If this <code>BLOBFileValue</code> is backed by a persistent resource
-     * calling this method will have no effect.
-     *
-     * @see #delete()
-     * @see #delete(boolean)
+     * {@inheritDoc}
      */
     public void discard() {
         if (!temp) {
@@ -294,26 +279,8 @@
     }
 
     /**
-     * Deletes the persistent resource backing this <code>BLOBFileValue</code>.
-     * Same as <code>{@link #delete(false)}</code>.
-     * <p/>
-     * If this <code>BLOBFileValue</code> is <i>not</i> backed by a persistent
-     * resource calling this method will have no effect.
-     *
-     * @see #discard()
+     * {@inheritDoc}
      */
-    public void delete() {
-        if (!temp) {
-            delete(false);
-        }
-    }
-
-    /**
-     * Deletes the persistent resource backing this <code>BLOBFileValue</code>.
-     *
-     * @param pruneEmptyParentDirs if <code>true</code>, empty parent directories
-     *                             will automatically be deleted
-     */
     public void delete(boolean pruneEmptyParentDirs) {
         if (file != null) {
             // this instance is backed by a 'real' file
@@ -339,51 +306,6 @@
         }
     }
 
-    /**
-     * Spools the contents of this <code>BLOBFileValue</code> to the given
-     * output stream.
-     *
-     * @param out output stream
-     * @throws RepositoryException if the input stream for this
-     *                             <code>BLOBFileValue</code> could not be obtained
-     * @throws IOException         if an error occurs while while spooling
-     */
-    public void spool(OutputStream out) throws RepositoryException, IOException {
-        InputStream in;
-        if (file != null) {
-            // this instance is backed by a 'real' file
-            try {
-                in = new FileInputStream(file);
-            } catch (FileNotFoundException fnfe) {
-                throw new RepositoryException("file backing binary value not found",
-                        fnfe);
-            }
-        } else if (fsResource != null) {
-            // this instance is backed by a resource in the virtual file system
-            try {
-                in = fsResource.getInputStream();
-            } catch (FileSystemException fse) {
-                throw new RepositoryException(fsResource.getPath()
-                        + ": the specified resource does not exist", fse);
-            }
-        } else {
-            // this instance is backed by an in-memory buffer
-            in = new ByteArrayInputStream(buffer);
-        }
-        try {
-            byte[] buffer = new byte[0x2000];
-            int read;
-            while ((read = in.read(buffer)) > 0) {
-                out.write(buffer, 0, read);
-            }
-        } finally {
-            try {
-                in.close();
-            } catch (IOException ignore) {
-            }
-        }
-    }
-
     //-------------------------------------------< java.lang.Object overrides >
     /**
      * Returns a string representation of this <code>BLOBFileValue</code>
@@ -424,55 +346,8 @@
     }
 
     /**
-     * Returns zero to satisfy the Object equals/hashCode contract.
-     * This class is mutable and not meant to be used as a hash key.
-     *
-     * @return always zero
-     * @see Object#hashCode()
-     */
-    public int hashCode() {
-        return 0;
-    }
-
-    //----------------------------------------------------------------< Value >
-    /**
      * {@inheritDoc}
      */
-    public int getType() {
-        return TYPE;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String getString()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        if (text == null) {
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            try {
-                spool(out);
-                byte[] data = out.toByteArray();
-                text = new String(data, DEFAULT_ENCODING);
-            } catch (UnsupportedEncodingException e) {
-                throw new RepositoryException(DEFAULT_ENCODING
-                        + " not supported on this platform", e);
-            } catch (IOException e) {
-                throw new ValueFormatException("conversion from stream to string failed", e);
-            } finally {
-                try {
-                    out.close();
-                } catch (IOException e) {
-                    // ignore
-                }
-            }
-        }
-        return text;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
     public InputStream getStream()
             throws IllegalStateException, RepositoryException {
         // always return a 'fresh' stream
@@ -497,52 +372,4 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public double getDouble()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        try {
-            return Double.parseDouble(getString());
-        } catch (NumberFormatException e) {
-            throw new ValueFormatException("conversion to double failed", e);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public Calendar getDate()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        Calendar cal = ISO8601.parse(getString());
-        if (cal != null) {
-            return cal;
-        } else {
-            throw new ValueFormatException("not a valid date format");
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public long getLong()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        try {
-            return Long.parseLong(getString());
-        } catch (NumberFormatException e) {
-            throw new ValueFormatException("conversion to long failed", e);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean getBoolean()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        return Boolean.valueOf(getString()).booleanValue();
-    }
 }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBValue.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBValue.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBValue.java	(working copy)
@@ -1,274 +1,37 @@
-/*
- * 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.value;
 
-import org.apache.jackrabbit.core.fs.FileSystemException;
-import org.apache.jackrabbit.core.fs.FileSystemResource;
-import org.apache.jackrabbit.util.ISO8601;
-import org.apache.jackrabbit.util.TransientFileFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-import javax.jcr.ValueFormatException;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-import java.util.Calendar;
 
+import javax.jcr.RepositoryException;
+
 /**
- * <code>BLOBFileValue</code> represents a binary <code>Value</code> which is
- * backed by a resource or byte[]. Unlike <code>BinaryValue</code> it has no
- * state, i.e. the <code>getStream()</code> method always returns a fresh
+ * Represents binary data which is backed by a resource or byte[]. 
+ * Unlike <code>BinaryValue</code> it has no state, i.e. 
+ * the <code>getStream()</code> method always returns a fresh
  * <code>InputStream</code> instance.
  * <p/>
  * <b>Important Note:</b><p/>
- * This is class is for Jackrabbit-internal use only. Applications should
+ * This interface is for Jackrabbit-internal use only. Applications should
  * use <code>javax.jcr.ValueFactory</code> to create binary values.
  */
-public class BLOBFileValue implements Value {
+public abstract class BLOBValue {
 
     /**
-     * The default logger
+     * Returns an InputStream representation of this value.
+     * 
+     * @return An InputStream representation of this value.
      */
-    private static Logger log = LoggerFactory.getLogger(BLOBFileValue.class);
+    abstract public InputStream getStream() throws IllegalStateException, RepositoryException;
 
     /**
-     * the property type
-     */
-    public static final int TYPE = PropertyType.BINARY;
-
-    /**
-     * the default encoding
-     */
-    protected static final String DEFAULT_ENCODING = "UTF-8";
-
-    /**
-     * empty array
-     */
-    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
-
-    /**
-     * max size for keeping tmp data in memory
-     */
-    private static final int MAX_BUFFER_SIZE = 0x10000;
-
-    /**
-     * underlying file
-     */
-    private final File file;
-
-    /**
-     * flag indicating if this instance represents a <i>temporary</i> value
-     * whose dynamically allocated resources can be explicitly freed on
-     * {@link #discard()}.
-     */
-    private final boolean temp;
-
-    /**
-     * buffer for small-sized data
-     */
-    private byte[] buffer = EMPTY_BYTE_ARRAY;
-
-    /**
-     * underlying file system resource
-     */
-    private final FileSystemResource fsResource;
-
-    /**
-     * converted text
-     */
-    private String text = null;
-
-    /**
-     * Creates a new <code>BLOBFileValue</code> instance from an
-     * <code>InputStream</code>. The contents of the stream is spooled
-     * to a temporary file or to a byte buffer if its size is smaller than
-     * {@link #MAX_BUFFER_SIZE}.
-     * <p/>
-     * The new instance represents a <i>temporary</i> value whose dynamically
-     * allocated resources will be freed explicitly on {@link #discard()}.
-     *
-     * @param in stream to be represented as a <code>BLOBFileValue</code> instance
-     * @throws IOException if an error occurs while reading from the stream or
-     *                     writing to the temporary file
-     */
-    public BLOBFileValue(InputStream in) throws IOException {
-        this(in, true);
-    }
-
-    /**
-     * Creates a new <code>BLOBFileValue</code> instance from an
-     * <code>InputStream</code>. The contents of the stream is spooled
-     * to a temporary file or to a byte buffer if its size is smaller than
-     * {@link #MAX_BUFFER_SIZE}.
-     * <p/>
-     * The <code>temp</code> parameter governs whether dynamically allocated
-     * resources will be freed explicitly on {@link #discard()}. Note that any
-     * dynamically allocated resources (temp file/buffer) will be freed
-     * implicitly once this instance has been gc'ed.
-     *
-     * @param in stream to be represented as a <code>BLOBFileValue</code> instance
-     * @param temp flag indicating whether this instance represents a
-     *             <i>temporary</i> value whose resources can be explicitly freed
-     *             on {@link #discard()}.
-     * @throws IOException if an error occurs while reading from the stream or
-     *                     writing to the temporary file
-     */
-    public BLOBFileValue(InputStream in, boolean temp) throws IOException {
-        byte[] spoolBuffer = new byte[0x2000];
-        int read;
-        int len = 0;
-        OutputStream out = null;
-        File spoolFile = null;
-        try {
-            while ((read = in.read(spoolBuffer)) > 0) {
-                if (out != null) {
-                    // spool to temp file
-                    out.write(spoolBuffer, 0, read);
-                    len += read;
-                } else if (len + read > MAX_BUFFER_SIZE) {
-                    // threshold for keeping data in memory exceeded;
-                    // create temp file and spool buffer contents
-                    TransientFileFactory fileFactory = TransientFileFactory.getInstance();
-                    spoolFile = fileFactory.createTransientFile("bin", null, null);
-                    out = new FileOutputStream(spoolFile);
-                    out.write(buffer, 0, len);
-                    out.write(spoolBuffer, 0, read);
-                    buffer = null;
-                    len += read;
-                } else {
-                    // reallocate new buffer and spool old buffer contents
-                    byte[] newBuffer = new byte[len + read];
-                    System.arraycopy(buffer, 0, newBuffer, 0, len);
-                    System.arraycopy(spoolBuffer, 0, newBuffer, len, read);
-                    buffer = newBuffer;
-                    len += read;
-                }
-            }
-        } finally {
-            if (out != null) {
-                out.close();
-            }
-        }
-
-        // init vars
-        file = spoolFile;
-        fsResource = null;
-        this.temp = temp;
-    }
-
-    /**
-     * Creates a new <code>BLOBFileValue</code> instance from a
-     * <code>byte[]</code> array.
-     *
-     * @param bytes byte array to be represented as a <code>BLOBFileValue</code>
-     *              instance
-     */
-    public BLOBFileValue(byte[] bytes) {
-        buffer = bytes;
-        file = null;
-        fsResource = null;
-        // this instance is not backed by a temporarily allocated buffer
-        temp = false;
-    }
-
-    /**
-     * Creates a new <code>BLOBFileValue</code> instance from a <code>File</code>.
-     *
-     * @param file file to be represented as a <code>BLOBFileValue</code> instance
-     * @throws IOException if the file can not be read
-     */
-    public BLOBFileValue(File file) throws IOException {
-        String path = file.getCanonicalPath();
-        if (!file.isFile()) {
-            throw new IOException(path + ": the specified file does not exist");
-        }
-        if (!file.canRead()) {
-            throw new IOException(path + ": the specified file can not be read");
-        }
-        this.file = file;
-        // this instance is backed by a 'real' file; set virtual fs resource to null
-        fsResource = null;
-        // this instance is not backed by temporarily allocated resource/buffer
-        temp = false;
-    }
-
-    /**
-     * Creates a new <code>BLOBFileValue</code> instance from a resource in the
-     * virtual file system.
-     *
-     * @param fsResource resource in virtual file system
-     * @throws IOException if the resource can not be read
-     */
-    public BLOBFileValue(FileSystemResource fsResource) throws IOException {
-        try {
-            if (!fsResource.exists()) {
-                throw new IOException(fsResource.getPath()
-                        + ": the specified resource does not exist");
-            }
-        } catch (FileSystemException fse) {
-            throw new IOException(fsResource.getPath()
-                    + ": Error while creating value: " + fse.toString());
-        }
-        // this instance is backed by a resource in the virtual file system
-        this.fsResource = fsResource;
-        // set 'real' file to null
-        file = null;
-        // this instance is not backed by temporarily allocated resource/buffer
-        temp = false;
-    }
-
-    /**
      * Returns the length of this <code>BLOBFileValue</code>.
      *
      * @return The length, in bytes, of this <code>BLOBFileValue</code>,
      *         or -1L if the length can't be determined.
+     * @throws IOException 
      */
-    public long getLength() {
-        if (file != null) {
-            // this instance is backed by a 'real' file
-            if (file.exists()) {
-                return file.length();
-            } else {
-                return -1;
-            }
-        } else if (fsResource != null) {
-            // this instance is backed by a resource in the virtual file system
-            try {
-                return fsResource.length();
-            } catch (FileSystemException fse) {
-                return -1;
-            }
-        } else {
-            // this instance is backed by an in-memory buffer
-            return buffer.length;
-        }
-    }
+    abstract public long getLength();
 
     /**
      * Frees temporarily allocated resources such as temporary file, buffer, etc.
@@ -278,154 +41,29 @@
      * @see #delete()
      * @see #delete(boolean)
      */
-    public void discard() {
-        if (!temp) {
-            // do nothing if this instance is not backed by temporarily
-            // allocated resource/buffer
-            return;
-        }
-        if (file != null) {
-            // this instance is backed by a temp file
-            file.delete();
-        } else if (buffer != null) {
-            // this instance is backed by an in-memory buffer
-            buffer = EMPTY_BYTE_ARRAY;
-        }
-    }
+    abstract public void discard();
 
     /**
      * Deletes the persistent resource backing this <code>BLOBFileValue</code>.
-     * Same as <code>{@link #delete(false)}</code>.
-     * <p/>
-     * If this <code>BLOBFileValue</code> is <i>not</i> backed by a persistent
-     * resource calling this method will have no effect.
      *
-     * @see #discard()
-     */
-    public void delete() {
-        if (!temp) {
-            delete(false);
-        }
-    }
-
-    /**
-     * Deletes the persistent resource backing this <code>BLOBFileValue</code>.
-     *
      * @param pruneEmptyParentDirs if <code>true</code>, empty parent directories
      *                             will automatically be deleted
      */
-    public void delete(boolean pruneEmptyParentDirs) {
-        if (file != null) {
-            // this instance is backed by a 'real' file
-            file.delete();
-            if (pruneEmptyParentDirs) {
-                // prune empty parent directories
-                File parent = file.getParentFile();
-                while (parent != null && parent.delete()) {
-                    parent = parent.getParentFile();
-                }
-            }
-        } else if (fsResource != null) {
-            // this instance is backed by a resource in the virtual file system
-            try {
-                fsResource.delete(pruneEmptyParentDirs);
-            } catch (FileSystemException fse) {
-                // ignore
-                log.warn("Error while deleting BLOBFileValue: " + fse.getMessage());
-            }
-        } else {
-            // this instance is backed by an in-memory buffer
-            buffer = EMPTY_BYTE_ARRAY;
-        }
-    }
+    abstract public void delete(boolean pruneEmptyParentDirs);
 
     /**
-     * Spools the contents of this <code>BLOBFileValue</code> to the given
-     * output stream.
-     *
-     * @param out output stream
-     * @throws RepositoryException if the input stream for this
-     *                             <code>BLOBFileValue</code> could not be obtained
-     * @throws IOException         if an error occurs while while spooling
+     * {@inheritDoc}
      */
-    public void spool(OutputStream out) throws RepositoryException, IOException {
-        InputStream in;
-        if (file != null) {
-            // this instance is backed by a 'real' file
-            try {
-                in = new FileInputStream(file);
-            } catch (FileNotFoundException fnfe) {
-                throw new RepositoryException("file backing binary value not found",
-                        fnfe);
-            }
-        } else if (fsResource != null) {
-            // this instance is backed by a resource in the virtual file system
-            try {
-                in = fsResource.getInputStream();
-            } catch (FileSystemException fse) {
-                throw new RepositoryException(fsResource.getPath()
-                        + ": the specified resource does not exist", fse);
-            }
-        } else {
-            // this instance is backed by an in-memory buffer
-            in = new ByteArrayInputStream(buffer);
-        }
-        try {
-            byte[] buffer = new byte[0x2000];
-            int read;
-            while ((read = in.read(buffer)) > 0) {
-                out.write(buffer, 0, read);
-            }
-        } finally {
-            try {
-                in.close();
-            } catch (IOException ignore) {
-            }
-        }
-    }
-
-    //-------------------------------------------< java.lang.Object overrides >
+    abstract public boolean equals(Object obj);
+    
     /**
-     * Returns a string representation of this <code>BLOBFileValue</code>
-     * instance. The string representation of a resource backed value is
-     * the path of the underlying resource. If this instance is backed by an
-     * in-memory buffer the generic object string representation of the byte
-     * array will be used instead.
-     *
-     * @return A string representation of this <code>BLOBFileValue</code> instance.
-     */
-    public String toString() {
-        if (file != null) {
-            // this instance is backed by a 'real' file
-            return file.toString();
-        } else if (fsResource != null) {
-            // this instance is backed by a resource in the virtual file system
-            return fsResource.toString();
-        } else {
-            // this instance is backed by an in-memory buffer
-            return buffer.toString();
-        }
-    }
-
-    /**
      * {@inheritDoc}
      */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof BLOBFileValue) {
-            BLOBFileValue other = (BLOBFileValue) obj;
-            return ((file == null ? other.file == null : file.equals(other.file))
-                    && (fsResource == null ? other.fsResource == null : fsResource.equals(other.fsResource))
-                    && Arrays.equals(buffer, other.buffer));
-        }
-        return false;
-    }
+    abstract public String toString();
 
     /**
      * Returns zero to satisfy the Object equals/hashCode contract.
-     * This class is mutable and not meant to be used as a hash key.
+     * This class is not meant to be used as a hash key.
      *
      * @return always zero
      * @see Object#hashCode()
@@ -434,115 +72,4 @@
         return 0;
     }
 
-    //----------------------------------------------------------------< Value >
-    /**
-     * {@inheritDoc}
-     */
-    public int getType() {
-        return TYPE;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String getString()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        if (text == null) {
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            try {
-                spool(out);
-                byte[] data = out.toByteArray();
-                text = new String(data, DEFAULT_ENCODING);
-            } catch (UnsupportedEncodingException e) {
-                throw new RepositoryException(DEFAULT_ENCODING
-                        + " not supported on this platform", e);
-            } catch (IOException e) {
-                throw new ValueFormatException("conversion from stream to string failed", e);
-            } finally {
-                try {
-                    out.close();
-                } catch (IOException e) {
-                    // ignore
-                }
-            }
-        }
-        return text;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public InputStream getStream()
-            throws IllegalStateException, RepositoryException {
-        // always return a 'fresh' stream
-        if (file != null) {
-            // this instance is backed by a 'real' file
-            try {
-                return new FileInputStream(file);
-            } catch (FileNotFoundException fnfe) {
-                throw new RepositoryException("file backing binary value not found",
-                        fnfe);
-            }
-        } else if (fsResource != null) {
-            // this instance is backed by a resource in the virtual file system
-            try {
-                return fsResource.getInputStream();
-            } catch (FileSystemException fse) {
-                throw new RepositoryException(fsResource.getPath()
-                        + ": the specified resource does not exist", fse);
-            }
-        } else {
-            return new ByteArrayInputStream(buffer);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public double getDouble()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        try {
-            return Double.parseDouble(getString());
-        } catch (NumberFormatException e) {
-            throw new ValueFormatException("conversion to double failed", e);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public Calendar getDate()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        Calendar cal = ISO8601.parse(getString());
-        if (cal != null) {
-            return cal;
-        } else {
-            throw new ValueFormatException("not a valid date format");
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public long getLong()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        try {
-            return Long.parseLong(getString());
-        } catch (NumberFormatException e) {
-            throw new ValueFormatException("conversion to long failed", e);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean getBoolean()
-            throws ValueFormatException, IllegalStateException,
-            RepositoryException {
-        return Boolean.valueOf(getString()).booleanValue();
-    }
 }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInTempFile.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInTempFile.java	(revision 0)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInTempFile.java	(revision 0)
@@ -0,0 +1,123 @@
+package org.apache.jackrabbit.core.value;
+
+import org.apache.jackrabbit.util.TransientFileFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.jcr.RepositoryException;
+
+public class BLOBInTempFile extends BLOBValue {
+    
+    /**
+     * the prefix of the string representation of this value
+     */    
+    private static final String PREFIX = "tempFile:";
+    
+    private File file;
+    private long length;
+    
+    /**
+     * Creates a new instance from a
+     * <code>byte[]</code> array.
+     *
+     * @param data the byte array
+     * @throws IOException 
+     * @throws IOException 
+     */    
+    private BLOBInTempFile(InputStream in) throws IOException {
+        OutputStream out = null;
+        try {
+            TransientFileFactory fileFactory = TransientFileFactory.getInstance();
+            file = fileFactory.createTransientFile("bin", null, null);
+            out = new FileOutputStream(file);
+            byte[] buffer = new byte[4 * 1024];
+            while(true) {
+                int len = in.read(buffer);
+                if(len < 0) {
+                    break;
+                }
+                out.write(buffer, 0, len);
+                length += len;                
+            }
+        } finally {
+            if(out != null) {
+                out.close();
+            }
+            in.close();
+        }
+    }
+    
+    /**
+     * Creates a new instance from a
+     * <code>in[]</code> stream.
+     *
+     * @param in the stream
+     */    
+    static BLOBInTempFile getInstance(InputStream in) throws IOException {
+        return new BLOBInTempFile(in);
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void delete(boolean pruneEmptyParentDirs) {
+        file.delete();
+        length = -1;
+        file = null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void discard() {
+        file.delete();
+        length = -1;
+        file = null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public long getLength() {
+        return length;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public InputStream getStream() throws IllegalStateException, RepositoryException {
+        try {
+            return new FileInputStream(file);
+        } catch (FileNotFoundException fnfe) {
+            throw new RepositoryException("file backing binary value not found", fnfe);
+        }        
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() {
+        return PREFIX + file.toString();
+    }    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof BLOBInTempFile) {
+            BLOBInTempFile other = (BLOBInTempFile) obj;
+            return (file == other.file) || (length == other.length && file != null && file.equals(other.file));
+        }
+        return false;
+    }
+    
+}
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java	(revision 0)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java	(revision 0)
@@ -0,0 +1,111 @@
+package org.apache.jackrabbit.core.value;
+
+import org.apache.jackrabbit.core.data.DataIdentifier;
+import org.apache.jackrabbit.core.data.DataRecord;
+import org.apache.jackrabbit.core.data.DataStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.RepositoryException;
+
+public class BLOBInDataStore extends BLOBValue {
+    
+    private final DataStore store;
+    private final DataIdentifier identifier;
+    private DataRecord dataRecord;
+    
+    /**
+     * the prefix of the string representation of this value
+     */    
+    private static final String PREFIX = "dataStore:";
+    
+    /**
+     * The default logger
+     */
+    private static Logger log = LoggerFactory.getLogger(BLOBInDataStore.class);
+    
+
+    private BLOBInDataStore(DataStore store, DataIdentifier identifier) {
+        assert store != null;
+        assert identifier != null;
+        this.store = store;
+        this.identifier = identifier;
+    }
+
+    public void delete(boolean pruneEmptyParentDirs) {
+        // do nothing
+        // TODO need to implement garbage collection
+    }
+
+    public void discard() {
+        // do nothing
+        // TODO need to implement garbage collection
+    }
+
+    public boolean equals(Object obj) {
+        if(!(obj instanceof BLOBInDataStore) || obj == null) {
+            return false;
+        }
+        BLOBInDataStore other = (BLOBInDataStore) obj;
+        return store == other.store && identifier.equals(other.identifier);
+    }
+
+    public long getLength() {
+        try {
+            return getDataRecord().getLength();
+        } catch (IOException e) {
+            log.warn("getLength for " + identifier + " failed", e);
+            return -1;
+        }
+    }
+
+    public InputStream getStream() throws IllegalStateException, RepositoryException {
+        try {
+            return getDataRecord().getStream();
+        } catch (IOException e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() {
+        StringBuffer buff = new StringBuffer(20);
+        buff.append(PREFIX);
+        buff.append(identifier.toString());
+        return buff.toString();
+    }   
+    
+    static BLOBInDataStore getInstance(DataStore store, String s) {
+        String id = s.substring(PREFIX.length());
+        DataIdentifier identifier = new DataIdentifier(id);
+        return new BLOBInDataStore(store, identifier);
+    }
+    
+    static BLOBInDataStore getInstance(DataStore store, InputStream in) throws IOException {
+        DataRecord rec = store.addRecord(in);
+        DataIdentifier identifier = rec.getIdentifier();
+        return new BLOBInDataStore(store, identifier);
+    }    
+    
+    /**
+     * Checks if String can be converted to an instance of this class.
+     * @param s
+     * @return true if it can be converted
+     */
+    static boolean isInstance(String s) {
+        return s.startsWith(PREFIX);
+    }    
+    
+    private DataRecord getDataRecord() throws IOException {
+        if(dataRecord == null) {
+            dataRecord = store.getRecord(identifier);
+        }
+        return dataRecord;
+    }
+
+}
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInMemory.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInMemory.java	(revision 0)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInMemory.java	(revision 0)
@@ -0,0 +1,163 @@
+package org.apache.jackrabbit.core.value;
+
+import org.apache.jackrabbit.uuid.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Arrays;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Represents binary data which is backed by a byte[]. 
+ */
+public class BLOBInMemory extends BLOBValue {
+    
+    /**
+     * Logger instance for this class
+     */
+    private static Logger log = LoggerFactory.getLogger(BLOBInMemory.class);
+    
+    /**
+     * the prefix of the string representation of this value
+     */    
+    private static final String PREFIX = "0x";
+    
+    /**
+     * the data
+     */
+    private byte[] data;
+    
+    /**
+     * empty array
+     */    
+    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+    
+    /**
+     * empty instance
+     */
+    private static final BLOBInMemory EMPTY = new BLOBInMemory(EMPTY_BYTE_ARRAY);
+    
+    /**
+     * Creates a new instance from a
+     * <code>byte[]</code> array.
+     *
+     * @param data the byte array
+     */    
+    private BLOBInMemory(byte[] data) {
+        this.data = data;
+    }
+    
+    /**
+     * Creates a new instance from a
+     * <code>byte[]</code> array.
+     *
+     * @param data the byte array
+     */    
+    static BLOBInMemory getInstance(byte[] data) {
+        if(data.length == 0) {
+            return EMPTY;
+        } else {
+            return new BLOBInMemory(data);
+        }
+    }
+    
+    /**
+     * Checks if String can be converted to an instance of this class.
+     * @param s
+     * @return true if it can be converted
+     */
+    static boolean isInstance(String s) {
+        return s.startsWith(PREFIX);
+    }    
+    
+    /**
+     * Convert a String to an instance of this class.
+     * @param s
+     * @return the instance
+     */
+    static BLOBInMemory getInstance(String s) throws IllegalArgumentException {
+        assert s.startsWith(PREFIX);
+        s = s.substring(PREFIX.length());
+        int len = s.length();
+        if (len % 2 != 0) {
+            String msg = "unable to deserialize byte array " + s + " , length=" + s.length();
+            log.debug(msg);            
+            throw new IllegalArgumentException(msg);
+        }
+        len /= 2;
+        byte[] data = new byte[len];
+        try {
+            for (int i = 0; i < len; i++) {
+                data[i] = (byte) ((Character.digit(s.charAt(i+i), 16) << 4) | (Character.digit(s.charAt(i+i+1), 16)));
+            }
+        } catch (NumberFormatException e) {
+            String msg = "unable to deserialize byte array " + s;
+            log.debug(msg);            
+            throw new IllegalArgumentException(msg);
+        }
+        return BLOBInMemory.getInstance(data);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void delete(boolean pruneEmptyParentDirs) {
+        // TODO avoid: this makes the value mutable
+        data = EMPTY_BYTE_ARRAY;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void discard() {
+        // TODO avoid: this makes the value mutable
+        data = EMPTY_BYTE_ARRAY;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public long getLength() {
+        return data.length;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public InputStream getStream() throws IllegalStateException, RepositoryException {
+        return new ByteArrayInputStream(data);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() {
+        StringBuffer buff = new StringBuffer(PREFIX.length() + 2 * data.length);
+        buff.append(PREFIX);
+        char[] hex = Constants.hexDigits;
+        for (int i = 0; i < data.length; i++) {
+            int c = data[i] & 0xff;
+            buff.append(hex[c >> 4]);
+            buff.append(hex[c & 0xf]);
+        }
+        return buff.toString();
+    }    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof BLOBInMemory) {
+            BLOBInMemory other = (BLOBInMemory) obj;
+            return Arrays.equals(data, other.data);
+        }
+        return false;
+    }
+
+}
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/PMContext.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/PMContext.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/PMContext.java	(working copy)
@@ -1,37 +0,0 @@
-/*
- * 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.state;
-
-import org.apache.jackrabbit.core.NodeId;
-import org.apache.jackrabbit.core.fs.FileSystem;
-import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
-
-import javax.jcr.NamespaceRegistry;
-import java.io.File;
-
-/**
- * Legacy class kept for backward compatibility reasons.
- * @deprecated use {@link org.apache.jackrabbit.core.persistence.PMContext}
- *             instead.
- */
-public class PMContext extends org.apache.jackrabbit.core.persistence.PMContext {
-
-    public PMContext(File homeDir, FileSystem fs, NodeId rootNodeId,
-                         NamespaceRegistry nsReg, NodeTypeRegistry ntReg) {
-        super(homeDir, fs, rootNodeId, nsReg, ntReg);
-    }
-}
\ No newline at end of file
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/PropertyState.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/PropertyState.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/PropertyState.java	(working copy)
@@ -20,7 +20,7 @@
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.ItemId;
 import org.apache.jackrabbit.core.nodetype.PropDefId;
-import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.value.BLOBValue;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.name.QName;
 
@@ -263,7 +263,7 @@
                 try {
                     if (type == PropertyType.BINARY) {
                         // special handling required for binary value
-                        BLOBFileValue blob = val.getBLOBFileValue();
+                        BLOBValue blob = val.getBLOBValue();
                         InputStream in = blob.getStream();
                         out.writeLong(blob.getLength());
                         byte[] buf = new byte[0x2000];
@@ -305,8 +305,7 @@
                     final long length = in.readLong();
                     final InputStream stream = in;
                     // create InputStream wrapper of size 'length'
-                    values[i] = InternalValue.create(new InputStream() {
-
+                    InputStream wrapper = new InputStream() {
                         private long consumed = 0;
 
                         public int read() throws IOException {
@@ -345,9 +344,10 @@
                         public void close() {
                             // nop
                         }
-                    }, false);
+                    };
+                    values[i] = InternalValue.createTemporary(wrapper);
                 } else {
-                    values[i] = InternalValue.valueOf(in.readUTF(), type);
+                    values[i] = InternalValue.valueOf(in.readUTF(), type, null);
                 }
             }
         }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/util/Serializer.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/util/Serializer.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/util/Serializer.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.state.util;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.state.NodeReferences;
 import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.jackrabbit.core.state.PropertyState;
@@ -53,10 +54,10 @@
      */
     public static void serialize(PropertyState state,
                                  OutputStream stream,
-                                 BLOBStore blobStore)
+                                 BLOBStore blobStore, DataStore dataStore)
             throws Exception {
         // delegate to replacement
-        org.apache.jackrabbit.core.persistence.util.Serializer.serialize(state, stream, blobStore);
+        org.apache.jackrabbit.core.persistence.util.Serializer.serialize(state, stream, blobStore, dataStore);
     }
 
     /**
@@ -64,10 +65,10 @@
      */
     public static void deserialize(PropertyState state,
                                    InputStream stream,
-                                   BLOBStore blobStore)
+                                   BLOBStore blobStore, DataStore dataStore)
             throws Exception {
         // delegate to replacement
-        org.apache.jackrabbit.core.persistence.util.Serializer.deserialize(state, stream, blobStore);
+        org.apache.jackrabbit.core.persistence.util.Serializer.deserialize(state, stream, blobStore, dataStore);
     }
 
     /**
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java	(working copy)
@@ -35,6 +35,8 @@
 import org.apache.jackrabbit.core.config.RepositoryConfig;
 import org.apache.jackrabbit.core.config.VersioningConfig;
 import org.apache.jackrabbit.core.config.WorkspaceConfig;
+import org.apache.jackrabbit.core.data.DataStore;
+import org.apache.jackrabbit.core.data.FileDataStore;
 import org.apache.jackrabbit.core.fs.BasedFileSystem;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.fs.FileSystemException;
@@ -157,6 +159,11 @@
 
     // sub file system where the repository stores meta data such as uuid of root node, etc.
     private final FileSystem metaDataStore;
+    
+    /**
+     * Data store for binary properties.
+     */
+    private final DataStore dataStore;    
 
     /**
      * the delegating observation dispatcher for all workspaces
@@ -241,6 +248,8 @@
             throw new RepositoryException(msg, fse);
         }
         metaDataStore = new BasedFileSystem(repStore, fsRootPath);
+        dataStore =
+            new FileDataStore(new File(repConfig.getHomeDir(), "datastore"));        
 
         // init root node uuid
         rootNodeId = loadRootNodeId(metaDataStore);
@@ -321,6 +330,10 @@
 
         log.info("Repository started");
     }
+    
+    public DataStore getDataStore() {
+        return dataStore;
+    }    
 
     /**
      * Get the cache manager of this repository, useful
@@ -360,7 +373,8 @@
                 vConfig.getPersistenceManagerConfig(),
                 rootNodeId,
                 nsReg,
-                ntReg);
+                ntReg,
+                dataStore);
 
         return new VersionManagerImpl(pm, fs, ntReg, delegatingDispatcher,
                 VERSION_STORAGE_NODE_ID, SYSTEM_ROOT_NODE_ID, cacheFactory);
@@ -505,7 +519,7 @@
     protected NodeTypeRegistry createNodeTypeRegistry(NamespaceRegistry nsReg,
                                                       FileSystem fs)
             throws RepositoryException {
-        return NodeTypeRegistry.create(nsReg, fs);
+        return NodeTypeRegistry.create(nsReg, fs, dataStore);
     }
 
     /**
@@ -1110,11 +1124,12 @@
                                                                PersistenceManagerConfig pmConfig,
                                                                NodeId rootNodeId,
                                                                NamespaceRegistry nsReg,
-                                                               NodeTypeRegistry ntReg)
+                                                               NodeTypeRegistry ntReg,
+                                                               DataStore store)
             throws RepositoryException {
         try {
             PersistenceManager pm = (PersistenceManager) pmConfig.newInstance();
-            pm.init(new PMContext(homeDir, fs, rootNodeId, nsReg, ntReg));
+            pm.init(new PMContext(homeDir, fs, rootNodeId, nsReg, ntReg, store));
             return pm;
         } catch (Exception e) {
             String msg = "Cannot instantiate persistence manager " + pmConfig.getClassName();
@@ -1697,7 +1712,8 @@
                         config.getPersistenceManagerConfig(),
                         rootNodeId,
                         nsReg,
-                        ntReg);
+                        ntReg,
+                        dataStore);
 
                 // create item state manager
                 try {
@@ -2017,5 +2033,12 @@
             // toggle the initialization of some workspace's lock manager
             getWorkspaceInfo(workspace).getLockManager();
         }
+
+        /**
+         * {@inheritDoc}
+         */
+        public DataStore getDataStore() {
+            return getDataStore();
+        }
     }
 }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeManagerImpl.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeManagerImpl.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeManagerImpl.java	(working copy)
@@ -26,6 +26,7 @@
 import org.apache.jackrabbit.util.name.NamespaceMapping;
 import org.apache.jackrabbit.api.JackrabbitNodeTypeManager;
 import org.apache.jackrabbit.core.NamespaceRegistryImpl;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader;
 import org.apache.jackrabbit.core.nodetype.compact.ParseException;
 import org.apache.jackrabbit.core.nodetype.xml.NodeTypeReader;
@@ -101,6 +102,8 @@
      * <code>NodeTypeManager</code>
      */
     private final Map ndCache;
+    
+    private final DataStore store;
 
     /**
      * Creates a new <code>NodeTypeManagerImpl</code> instance.
@@ -111,11 +114,12 @@
      */
     public NodeTypeManagerImpl(
             NodeTypeRegistry ntReg, NamespaceRegistryImpl nsReg,
-            NamespaceResolver nsResolver) {
+            NamespaceResolver nsResolver, DataStore store) {
         this.nsResolver = nsResolver;
         this.ntReg = ntReg;
         this.nsReg = nsReg;
         this.ntReg.addListener(this);
+        this.store = store;
 
         // setup caches with soft references to node type
         // & item definition instances
@@ -182,7 +186,7 @@
             if (nt == null) {
                 EffectiveNodeType ent = ntReg.getEffectiveNodeType(name);
                 NodeTypeDef def = ntReg.getNodeTypeDef(name);
-                nt = new NodeTypeImpl(ent, def, this, nsResolver);
+                nt = new NodeTypeImpl(ent, def, this, nsResolver, store);
                 ntCache.put(name, nt);
             }
             return nt;
@@ -222,7 +226,7 @@
             if (contentType.equalsIgnoreCase(TEXT_XML)
                     || contentType.equalsIgnoreCase(APPLICATION_XML)) {
                 try {
-                    NodeTypeReader ntr = new NodeTypeReader(in);
+                    NodeTypeReader ntr = new NodeTypeReader(in, store);
 
                     Properties namespaces = ntr.getNamespaces();
                     if (namespaces != null) {
@@ -243,7 +247,7 @@
                 try {
                     NamespaceMapping mapping = new NamespaceMapping(nsResolver);
                     CompactNodeTypeDefReader reader = new CompactNodeTypeDefReader(
-                            new InputStreamReader(in), "cnd input stream", mapping);
+                            new InputStreamReader(in), "cnd input stream", mapping, store);
 
                     namespaceMap.putAll(mapping.getPrefixToURIMapping());
 
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/compact/CompactNodeTypeDefReader.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/compact/CompactNodeTypeDefReader.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/compact/CompactNodeTypeDefReader.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.nodetype.compact;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.nodetype.InvalidConstraintException;
 import org.apache.jackrabbit.core.nodetype.ItemDef;
 import org.apache.jackrabbit.core.nodetype.NodeDef;
@@ -143,6 +144,11 @@
      * the current token
      */
     private String currentToken;
+    
+    /**
+     * Data store for binary properties.
+     */
+    private final DataStore store;
 
     /**
      * Creates a new CND reader.
@@ -150,8 +156,8 @@
      * @param r
      * @throws ParseException
      */
-    public CompactNodeTypeDefReader(Reader r, String systemId) throws ParseException {
-        this(r, systemId, new NamespaceMapping());
+    public CompactNodeTypeDefReader(Reader r, String systemId, DataStore store) throws ParseException {
+        this(r, systemId, new NamespaceMapping(), store);
     }
 
 
@@ -161,10 +167,11 @@
      * @param r
      * @throws ParseException
      */
-    public CompactNodeTypeDefReader(Reader r, String systemId, NamespaceMapping mapping)
+    public CompactNodeTypeDefReader(Reader r, String systemId, NamespaceMapping mapping, DataStore store)
             throws ParseException {
         lexer = new Lexer(r, systemId);
         this.nsMapping = mapping;
+        this.store = store;
         nextToken();
         parse();
     }
@@ -486,7 +493,7 @@
             try {
                 value = InternalValue.create(ValueHelper.convert(
                         currentToken, pdi.getRequiredType(),
-                        ValueFactoryImpl.getInstance()), nsMapping);
+                        ValueFactoryImpl.getInstance()), nsMapping, store);
             } catch (ValueFormatException e) {
                 lexer.fail("'" + currentToken + "' is not a valid string representation of a value of type " + pdi.getRequiredType());
             } catch (RepositoryException e) {
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeImpl.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeImpl.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeImpl.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.nodetype;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.name.NameException;
 import org.apache.jackrabbit.name.NamespaceResolver;
@@ -50,6 +51,7 @@
     private final NodeTypeManagerImpl ntMgr;
     // namespace resolver used to translate qualified names to JCR names
     private final NamespaceResolver nsResolver;
+    private final DataStore store;
 
     /**
      * Package private constructor
@@ -64,11 +66,12 @@
      * @param nsResolver namespace resolver
      */
     NodeTypeImpl(EffectiveNodeType ent, NodeTypeDef ntd,
-                 NodeTypeManagerImpl ntMgr, NamespaceResolver nsResolver) {
+                 NodeTypeManagerImpl ntMgr, NamespaceResolver nsResolver, DataStore store) {
         this.ent = ent;
         this.ntMgr = ntMgr;
         this.nsResolver = nsResolver;
         this.ntd = ntd;
+        this.store = store;
     }
 
     /**
@@ -381,10 +384,10 @@
                 Value targetVal = ValueHelper.convert(
                         value, targetType,
                         ValueFactoryImpl.getInstance());
-                internalValue = InternalValue.create(targetVal, nsResolver);
+                internalValue = InternalValue.create(targetVal, nsResolver, store);
             } else {
                 // no type conversion required
-                internalValue = InternalValue.create(value, nsResolver);
+                internalValue = InternalValue.create(value, nsResolver, store);
             }
             EffectiveNodeType.checkSetPropertyValueConstraints(
                     def, new InternalValue[]{internalValue});
@@ -459,10 +462,10 @@
                         Value targetVal = ValueHelper.convert(
                                 values[i], targetType,
                                 ValueFactoryImpl.getInstance());
-                        internalValue = InternalValue.create(targetVal, nsResolver);
+                        internalValue = InternalValue.create(targetVal, nsResolver, store);
                     } else {
                         // no type conversion required
-                        internalValue = InternalValue.create(values[i], nsResolver);
+                        internalValue = InternalValue.create(values[i], nsResolver, store);
                     }
                     list.add(internalValue);
                 }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/xml/NodeTypeReader.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/xml/NodeTypeReader.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/xml/NodeTypeReader.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.nodetype.xml;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.nodetype.InvalidConstraintException;
 import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
 import org.apache.jackrabbit.core.nodetype.ItemDef;
@@ -60,10 +61,10 @@
      * @throws InvalidNodeTypeDefException if the node type definition
      *                                     format is invalid
      */
-    public static NodeTypeDef[] read(InputStream xml)
+    public static NodeTypeDef[] read(InputStream xml, DataStore store)
             throws IOException, InvalidNodeTypeDefException {
         try {
-            NodeTypeReader reader = new NodeTypeReader(xml);
+            NodeTypeReader reader = new NodeTypeReader(xml, store);
             return reader.getNodeTypeDefs();
         } catch (NameException e) {
             throw new InvalidNodeTypeDefException(
@@ -81,15 +82,21 @@
     private final NamespaceResolver resolver;
 
     /**
+     * Data store for binary properties.
+     */
+    private final DataStore store;
+
+    /**
      * Creates a node type definition file reader.
      *
      * @param xml node type definition file
      * @throws IOException if the node type definition file cannot be read
      */
-    public NodeTypeReader(InputStream xml) throws IOException {
+    public NodeTypeReader(InputStream xml, DataStore store) throws IOException {
         walker = new DOMWalker(xml);
         namespaces = walker.getNamespaces();
         resolver = new AdditionalNamespaceResolver(namespaces);
+        this.store = store;
     }
 
     /**
@@ -246,7 +253,7 @@
                 String value = walker.getContent();
                 try {
                     values.add(InternalValue.create(ValueHelper.convert(
-                            value, type, ValueFactoryImpl.getInstance()), resolver));
+                            value, type, ValueFactoryImpl.getInstance()), resolver, store));
                 } catch (RepositoryException e) {
                     throw new InvalidNodeTypeDefException(
                             "Unable to create default value: " + value, e);
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java	(working copy)
@@ -20,6 +20,7 @@
 import org.apache.commons.collections.map.ReferenceMap;
 import org.apache.jackrabbit.core.cluster.NodeTypeEventChannel;
 import org.apache.jackrabbit.core.cluster.NodeTypeEventListener;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.fs.FileSystemException;
 import org.apache.jackrabbit.core.fs.FileSystemResource;
@@ -106,6 +107,11 @@
     private NodeTypeEventChannel eventChannel;
 
     /**
+     * Data store for binary properties.
+     */
+    private final DataStore dataStore;
+
+    /**
      * Create a new <code>NodeTypeRegistry</codes>
      *
      * @param nsReg
@@ -113,9 +119,9 @@
      * @return <code>NodeTypeRegistry</codes> object
      * @throws RepositoryException
      */
-    public static NodeTypeRegistry create(NamespaceRegistry nsReg, FileSystem ntStore)
+    public static NodeTypeRegistry create(NamespaceRegistry nsReg, FileSystem ntStore, DataStore dataStore)
             throws RepositoryException {
-        NodeTypeRegistry ntMgr = new NodeTypeRegistry(nsReg, ntStore);
+        NodeTypeRegistry ntMgr = new NodeTypeRegistry(nsReg, ntStore, dataStore);
         return ntMgr;
     }
 
@@ -704,10 +710,11 @@
      * @param ntStore
      * @throws RepositoryException
      */
-    protected NodeTypeRegistry(NamespaceRegistry nsReg, FileSystem ntStore)
+    protected NodeTypeRegistry(NamespaceRegistry nsReg, FileSystem ntStore, DataStore dataStore)
             throws RepositoryException {
         this.nsReg = nsReg;
         this.ntStore = ntStore;
+        this.dataStore = dataStore;
         customNodeTypesResource =
                 new FileSystemResource(this.ntStore, CUSTOM_NODETYPES_RESOURCE_NAME);
         try {
@@ -784,7 +791,7 @@
         InputStream in = null;
         try {
             in = getClass().getClassLoader().getResourceAsStream(BUILTIN_NODETYPES_RESOURCE_PATH);
-            store.load(in);
+            store.load(in, dataStore);
         } catch (IOException ioe) {
             String error =
                     "internal error: failed to read built-in node type definitions stored in "
@@ -839,7 +846,7 @@
             log.info("no custom node type definitions found");
         } else {
             try {
-                store.load(in);
+                store.load(in, dataStore);
             } catch (IOException ioe) {
                 String error =
                         "internal error: failed to read custom node type definitions stored in "
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java	(working copy)
@@ -16,7 +16,7 @@
  */
 package org.apache.jackrabbit.core.nodetype;
 
-import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.value.BLOBValue;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.name.MalformedPathException;
 import org.apache.jackrabbit.name.NameException;
@@ -347,7 +347,7 @@
                 return;
 
             case PropertyType.BINARY:
-                BLOBFileValue blob = value.getBLOBFileValue();
+                BLOBValue blob = value.getBLOBValue();
                 long length = blob.getLength();
                 if (length != -1) {
                     check(length);
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.nodetype;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.nodetype.xml.NodeTypeReader;
 import org.apache.jackrabbit.core.nodetype.xml.NodeTypeWriter;
 import org.apache.jackrabbit.name.QName;
@@ -49,10 +50,10 @@
      * @throws IOException
      * @throws InvalidNodeTypeDefException
      */
-    public void load(InputStream in)
+    public void load(InputStream in, DataStore store)
             throws IOException, InvalidNodeTypeDefException,
             RepositoryException {
-        NodeTypeDef[] types = NodeTypeReader.read(in);
+        NodeTypeDef[] types = NodeTypeReader.read(in, store);
         for (int i = 0; i < types.length; i++) {
             add(types[i]);
         }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/Importer.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/Importer.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/Importer.java	(working copy)
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.core.xml;
 
+import org.apache.jackrabbit.core.data.DataStore;
+
 import java.util.List;
 
 import javax.jcr.RepositoryException;
@@ -47,7 +49,7 @@
      *                  (list of {@link PropInfo} instances)
      * @throws RepositoryException on a repository error
      */
-    void startNode(NodeInfo nodeInfo, List propInfos)
+    void startNode(NodeInfo nodeInfo, List propInfos, DataStore store)
             throws RepositoryException;
 
     /**
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java	(working copy)
@@ -20,6 +20,7 @@
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.name.NameFormat;
 import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 
@@ -59,8 +60,8 @@
      * @param importer
      * @param nsContext
      */
-    SysViewImportHandler(Importer importer) {
-        super(importer);
+    SysViewImportHandler(Importer importer, DataStore dataStore) {
+        super(importer, dataStore);
     }
 
     private void processNode(ImportState state, boolean start, boolean end)
@@ -82,7 +83,7 @@
         // call Importer
         try {
             if (start) {
-                importer.startNode(node, state.props);
+                importer.startNode(node, state.props, dataStore);
                 // dispose temporary property values
                 for (Iterator iter = state.props.iterator(); iter.hasNext();) {
                     PropInfo pi = (PropInfo) iter.next();
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/StringValue.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/StringValue.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/StringValue.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.xml;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.name.NamespaceResolver;
 import org.apache.jackrabbit.util.Base64;
@@ -51,7 +52,7 @@
 
     //--------------------------------------------------------< TextValue >
 
-    public Value getValue(int type, NamespaceResolver resolver)
+    public Value getValue(int type, NamespaceResolver resolver, DataStore store)
             throws ValueFormatException, RepositoryException {
         if (type == PropertyType.NAME || type == PropertyType.PATH) {
             // NAME and PATH require special treatment because
@@ -62,7 +63,7 @@
             // current namespace context of xml document
             InternalValue ival =
                     InternalValue.create(ValueHelper.convert(
-                            value, type, ValueFactoryImpl.getInstance()), nsContext);
+                            value, type, ValueFactoryImpl.getInstance()), nsContext, store);
             // convert InternalValue to Value using this
             // session's namespace mappings
             return ival.toJCRValue(resolver);
@@ -74,7 +75,7 @@
         }
     }
 
-    public InternalValue getInternalValue(int targetType)
+    public InternalValue getInternalValue(int targetType, DataStore store)
             throws ValueFormatException, RepositoryException {
         try {
             if (targetType == PropertyType.BINARY) {
@@ -87,7 +88,7 @@
                 // convert serialized value to InternalValue using
                 // current namespace context of xml document
                 return InternalValue.create(ValueHelper.convert(
-                        value, targetType, ValueFactoryImpl.getInstance()), nsContext);
+                        value, targetType, ValueFactoryImpl.getInstance()), nsContext, store);
             }
         } catch (IOException e) {
             throw new RepositoryException("Error decoding Base64 content", e);
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java	(working copy)
@@ -19,6 +19,7 @@
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.value.ReferenceValue;
@@ -191,7 +192,7 @@
     /**
      * {@inheritDoc}
      */
-    public void startNode(NodeInfo nodeInfo, List propInfos)
+    public void startNode(NodeInfo nodeInfo, List propInfos, DataStore store)
             throws RepositoryException {
         NodeImpl parent = (NodeImpl) parents.peek();
 
@@ -259,7 +260,7 @@
         Iterator iter = propInfos.iterator();
         while (iter.hasNext()) {
             PropInfo pi = (PropInfo) iter.next();
-            pi.apply(node, session.getNamespaceResolver(), refTracker);
+            pi.apply(node, session.getNamespaceResolver(), refTracker, store);
         }
 
         parents.push(node);
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.xml;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.name.NamespaceResolver;
 import org.apache.jackrabbit.util.Base64;
@@ -38,6 +39,7 @@
 import java.io.Reader;
 import java.io.StringReader;
 import java.io.Writer;
+import java.io.InputStream;
 
 /**
  * <code>BufferedStringValue</code> represents an appendable
@@ -226,7 +228,7 @@
 
     //--------------------------------------------------------< TextValue >
 
-    public Value getValue(int targetType, NamespaceResolver resolver)
+    public Value getValue(int targetType, NamespaceResolver resolver, DataStore store)
             throws ValueFormatException, RepositoryException {
         try {
             if (targetType == PropertyType.NAME
@@ -239,7 +241,7 @@
                 // current namespace context of xml document
                 InternalValue ival =
                     InternalValue.create(ValueHelper.convert(
-                            retrieve(), targetType, ValueFactoryImpl.getInstance()), nsContext);
+                            retrieve(), targetType, ValueFactoryImpl.getInstance()), nsContext, store);
                 // convert InternalValue to Value using this
                 // session's namespace mappings
                 return ival.toJCRValue(resolver);
@@ -267,7 +269,7 @@
         }
     }
 
-    public InternalValue getInternalValue(int type)
+    public InternalValue getInternalValue(int type, DataStore store)
             throws ValueFormatException, RepositoryException {
         try {
             if (type == PropertyType.BINARY) {
@@ -281,31 +283,62 @@
                     //baos.close();
                     return InternalValue.create(baos.toByteArray());
                 } else {
-                    // >= 65kb: deserialize BINARY type
-                    // using Reader and temporay file
-                    TransientFileFactory fileFactory = TransientFileFactory.getInstance();
-                    File tmpFile = fileFactory.createTransientFile("bin", null, null);
-                    FileOutputStream out = new FileOutputStream(tmpFile);
-                    Reader reader = reader();
-                    try {
-                        Base64.decode(reader, out);
-                    } finally {
-                        reader.close();
-                        out.close();
-                    }
-                    return InternalValue.create(tmpFile);
+                    // >= 65kb: deserialize BINARY type using a stream
+                    Base64ReaderInputStream in = new Base64ReaderInputStream(reader());
+                    return InternalValue.create(in, store);
                 }
             } else {
                 // convert serialized value to InternalValue using
                 // current namespace context of xml document
                 return InternalValue.create(ValueHelper.convert(
-                        retrieve(), type, ValueFactoryImpl.getInstance()), nsContext);
+                        retrieve(), type, ValueFactoryImpl.getInstance()), nsContext, store);
             }
         } catch (IOException e) {
             throw new RepositoryException("Error accessing property value", e);
         }
     }
+    
+    private static class Base64ReaderInputStream extends InputStream {
 
+        private final static int BUFFER_SIZE = 1024;
+        private final char[] chars;
+        private final ByteArrayOutputStream out;
+        private final Reader reader;
+        private int pos;
+        private int remaining;
+        private byte[] buffer;
+
+        public Base64ReaderInputStream(Reader reader) {
+            chars = new char[BUFFER_SIZE];
+            this.reader = reader;
+            out = new ByteArrayOutputStream(BUFFER_SIZE);
+        }
+
+        private void fillBuffer() throws IOException {
+            int len = reader.read(chars, 0, BUFFER_SIZE);
+            if (len < 0) {
+                remaining = -1;
+                return;
+            }
+            Base64.decode(chars, 0, len, out);
+            buffer = out.toByteArray();
+            pos = 0;
+            remaining = buffer.length;
+            out.reset();
+        }
+
+        public int read() throws IOException {
+            if (remaining == 0) {
+                fillBuffer();
+            }
+            if (remaining < 0) {
+                return -1;
+            }
+            remaining--;
+            return buffer[pos++] & 0xff;
+        }
+    }
+
     /**
      * {@inheritDoc}
      */
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ImportHandler.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ImportHandler.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ImportHandler.java	(working copy)
@@ -22,6 +22,7 @@
 import javax.jcr.RepositoryException;
 
 import org.apache.jackrabbit.core.NamespaceRegistryImpl;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.name.NamespaceResolver;
 import org.apache.jackrabbit.name.QName;
 import org.slf4j.Logger;
@@ -55,6 +56,7 @@
     protected final Importer importer;
     protected final NamespaceRegistryImpl nsReg;
     protected final NamespaceResolver nsResolver;
+    protected final DataStore dataStore;
 
     protected Locator locator;
 
@@ -69,10 +71,11 @@
     private Map localNamespaceMappings;
 
     public ImportHandler(Importer importer, NamespaceResolver nsResolver,
-                         NamespaceRegistryImpl nsReg) {
+                         NamespaceRegistryImpl nsReg, DataStore dataStore) {
         this.importer = importer;
         this.nsResolver = nsResolver;
         this.nsReg = nsReg;
+        this.dataStore = dataStore;
     }
 
     //---------------------------------------------------------< ErrorHandler >
@@ -176,9 +179,9 @@
             // the namespace of the first element determines the type of XML
             // (system view/document view)
             if (QName.NS_SV_URI.equals(namespaceURI)) {
-                targetHandler = new SysViewImportHandler(importer);
+                targetHandler = new SysViewImportHandler(importer, dataStore);
             } else {
-                targetHandler = new DocViewImportHandler(importer);
+                targetHandler = new DocViewImportHandler(importer, dataStore);
             }
 
             targetHandler.startDocument();
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.xml;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
@@ -40,9 +41,11 @@
      * that is currently being processed.
      */
     protected NamespaceContext nsContext;
+    protected final DataStore dataStore;
 
-    protected TargetImportHandler(Importer importer) {
+    protected TargetImportHandler(Importer importer, DataStore dataStore) {
         this.importer = importer;
+        this.dataStore = dataStore;
     }
 
     /**
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java	(working copy)
@@ -22,6 +22,7 @@
 import org.apache.jackrabbit.core.PropertyId;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.WorkspaceImpl;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
 import org.apache.jackrabbit.core.nodetype.NodeDef;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
@@ -346,7 +347,7 @@
     /**
      * {@inheritDoc}
      */
-    public void startNode(NodeInfo nodeInfo, List propInfos)
+    public void startNode(NodeInfo nodeInfo, List propInfos, DataStore store)
             throws RepositoryException {
         if (aborted) {
             // the import has been aborted, get outta here...
@@ -468,7 +469,7 @@
             Iterator iter = propInfos.iterator();
             while (iter.hasNext()) {
                 PropInfo pi = (PropInfo) iter.next();
-                pi.apply(node, itemOps, ntReg, refTracker);
+                pi.apply(node, itemOps, ntReg, refTracker, store);
             }
 
             // store affected nodes
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/TextValue.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/TextValue.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/TextValue.java	(working copy)
@@ -20,6 +20,7 @@
 import javax.jcr.Value;
 import javax.jcr.ValueFormatException;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.name.NamespaceResolver;
 
@@ -29,10 +30,10 @@
  */
 public interface TextValue {
 
-    Value getValue(int type, NamespaceResolver resolver)
+    Value getValue(int type, NamespaceResolver resolver, DataStore store)
         throws ValueFormatException, RepositoryException;
 
-    InternalValue getInternalValue(int type)
+    InternalValue getInternalValue(int type, DataStore store)
         throws ValueFormatException, RepositoryException;
 
     /**
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java	(working copy)
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.core.xml;
 
 import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.name.NameException;
 import org.apache.jackrabbit.name.NameFormat;
 import org.apache.jackrabbit.name.QName;
@@ -56,8 +57,8 @@
      *
      * @param importer
      */
-    DocViewImportHandler(Importer importer) {
-        super(importer);
+    DocViewImportHandler(Importer importer, DataStore dataStore) {
+        super(importer, dataStore);
     }
 
     /**
@@ -155,7 +156,7 @@
                         QName.JCR_XMLCHARACTERS, PropertyType.STRING, values);
                 props.add(prop);
                 // call Importer
-                importer.startNode(node, props);
+                importer.startNode(node, props, dataStore);
                 importer.endNode(node);
 
                 // reset handler
@@ -273,7 +274,7 @@
             NodeInfo node =
                     new NodeInfo(nodeName, nodeTypeName, mixinTypes, id);
             // all information has been collected, now delegate to importer
-            importer.startNode(node, props);
+            importer.startNode(node, props, dataStore);
             // push current node data onto stack
             stack.push(node);
         } catch (RepositoryException re) {
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java	(working copy)
@@ -26,6 +26,7 @@
 import org.apache.jackrabbit.core.BatchedItemOperations;
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.jackrabbit.core.nodetype.PropDef;
@@ -116,7 +117,7 @@
 
     public void apply(
             NodeImpl node, NamespaceResolver resolver,
-            ReferenceChangeTracker refTracker) throws RepositoryException {
+            ReferenceChangeTracker refTracker, DataStore store) throws RepositoryException {
         // find applicable definition
         PropDef def = getApplicablePropertyDef(node.getEffectiveNodeType());
         if (def.isProtected()) {
@@ -129,7 +130,7 @@
         Value[] va = new Value[values.length];
         int targetType = getTargetType(def);
         for (int i = 0; i < values.length; i++) {
-            va[i] = values[i].getValue(targetType, resolver);
+            va[i] = values[i].getValue(targetType, resolver, store);
         }
 
         // multi- or single-valued property?
@@ -161,7 +162,7 @@
 
     public void apply(
             NodeState node, BatchedItemOperations itemOps,
-            NodeTypeRegistry ntReg, ReferenceChangeTracker refTracker)
+            NodeTypeRegistry ntReg, ReferenceChangeTracker refTracker, DataStore store)
             throws RepositoryException {
         PropertyState prop = null;
         PropDef def = null;
@@ -206,7 +207,7 @@
         int targetType = getTargetType(def);
         InternalValue[] iva = new InternalValue[values.length];
         for (int i = 0; i < values.length; i++) {
-            iva[i] = values[i].getInternalValue(targetType);
+            iva[i] = values[i].getInternalValue(targetType, store);
         }
 
         // set values
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java	(working copy)
@@ -709,7 +709,7 @@
         Importer importer = new WorkspaceImporter(parentPath, this,
                 rep.getNodeTypeRegistry(), uuidBehavior);
         return new ImportHandler(importer, session.getNamespaceResolver(),
-                rep.getNamespaceRegistry());
+                rep.getNamespaceRegistry(), rep.getDataStore());
     }
 
     /**
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.journal;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.name.NamespaceResolver;
 import org.apache.jackrabbit.util.Text;
 import org.slf4j.Logger;
@@ -153,10 +154,10 @@
     /**
      * {@inheritDoc}
      */
-    public void init(String id, NamespaceResolver resolver)
+    public void init(String id, NamespaceResolver resolver, DataStore store)
             throws JournalException {
 
-        super.init(id, resolver);
+        super.init(id, resolver, store);
 
         // Provide valid defaults for arguments
         if (schemaObjectPrefix == null) {
@@ -266,7 +267,7 @@
             selectRevisionsStmt.execute();
 
             return new DatabaseRecordIterator(
-                    selectRevisionsStmt.getResultSet(), getResolver());
+                    selectRevisionsStmt.getResultSet(), getResolver(), store);
         } catch (SQLException e) {
             close(true);
 
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractRecord.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractRecord.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractRecord.java	(working copy)
@@ -27,6 +27,7 @@
 import org.apache.jackrabbit.name.MalformedPathException;
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
 import org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefWriter;
 import org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader;
@@ -64,12 +65,18 @@
      * Namespace resolver.
      */
     protected final NamespaceResolver resolver;
+    
+    /**
+     * Data store for binary properties.
+     */
+    protected final DataStore store;
 
     /**
      * Create a new instance of this class.
      */
-    public AbstractRecord(NamespaceResolver resolver) {
+    public AbstractRecord(NamespaceResolver resolver, DataStore store) {
         this.resolver = resolver;
+        this.store = store;
     }
 
     /**
@@ -234,7 +241,7 @@
         try {
             StringReader sr = new StringReader(readString());
 
-            CompactNodeTypeDefReader reader = new CompactNodeTypeDefReader(sr, "(internal)");
+            CompactNodeTypeDefReader reader = new CompactNodeTypeDefReader(sr, "(internal)", store);
             List ntds = reader.getNodeTypeDefs();
             if (ntds.size() != 1) {
                 throw new JournalException("Expected one node type definition: got " + ntds.size());
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AppendRecord.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AppendRecord.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AppendRecord.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.journal;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.slf4j.LoggerFactory;
 import org.slf4j.Logger;
 
@@ -105,8 +106,8 @@
      * @param journal journal where record is being appended
      * @param producerId producer identifier
      */
-    public AppendRecord(AbstractJournal journal, String producerId) {
-        super(journal.getResolver());
+    public AppendRecord(AbstractJournal journal, String producerId, DataStore store) {
+        super(journal.getResolver(), store);
 
         this.journal = journal;
         this.producerId = producerId;
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileJournal.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileJournal.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileJournal.java	(working copy)
@@ -18,6 +18,7 @@
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.name.NamespaceResolver;
 
 import java.util.Arrays;
@@ -100,8 +101,8 @@
     /**
      * {@inheritDoc}
      */
-    public void init(String id, NamespaceResolver resolver) throws JournalException {
-        super.init(id, resolver);
+    public void init(String id, NamespaceResolver resolver, DataStore store) throws JournalException {
+        super.init(id, resolver, store);
 
         if (directory == null) {
             String msg = "Directory not specified.";
@@ -156,7 +157,7 @@
                 }
             });
         }
-        return new FileRecordIterator(logFiles, startRevision, stopRevision, getResolver());
+        return new FileRecordIterator(logFiles, startRevision, stopRevision, getResolver(), store);
     }
 
     /**
@@ -173,10 +174,10 @@
             throws JournalException {
 
         try {
-            FileRecordLog recordLog = new FileRecordLog(journalFile);
+            FileRecordLog recordLog = new FileRecordLog(journalFile, store);
             if (recordLog.exceeds(maximumSize)) {
                 switchLogs();
-                recordLog = new FileRecordLog(journalFile);
+                recordLog = new FileRecordLog(journalFile, store);
             }
             if (recordLog.isNew()) {
                 recordLog.init(globalRevision.get());
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/Journal.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/Journal.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/Journal.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.journal;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.name.NamespaceResolver;
 
 /**
@@ -30,7 +31,7 @@
      * @param resolver resolver used when reading/writing records
      * @throws JournalException if an error occurs
      */
-    public void init(String id, NamespaceResolver resolver) throws JournalException;
+    public void init(String id, NamespaceResolver resolver, DataStore store) throws JournalException;
 
     /**
      * Register a record consumer.
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/ReadRecord.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/ReadRecord.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/ReadRecord.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.journal;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.name.NamespaceResolver;
 
@@ -62,9 +63,9 @@
      */
     public ReadRecord(String journalId, String producerId,
                       long revision, DataInputStream dataIn, int length,
-                      NamespaceResolver resolver) {
+                      NamespaceResolver resolver, DataStore store) {
 
-        super(resolver);
+        super(resolver, store);
 
         this.journalId = journalId;
         this.producerId = producerId;
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseRecordIterator.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseRecordIterator.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseRecordIterator.java	(working copy)
@@ -18,6 +18,7 @@
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.name.NamespaceResolver;
 
 import java.util.NoSuchElementException;
@@ -62,11 +63,17 @@
     private boolean isEOF;
 
     /**
+     * Data store for binary properties.
+     */
+    private final DataStore store;
+
+    /**
      * Create a new instance of this class.
      */
-    public DatabaseRecordIterator(ResultSet rs, NamespaceResolver resolver) {
+    public DatabaseRecordIterator(ResultSet rs, NamespaceResolver resolver, DataStore store) {
         this.rs = rs;
         this.resolver = resolver;
+        this.store = store;
     }
 
     /**
@@ -131,7 +138,7 @@
             String journalId = rs.getString(2);
             String producerId = rs.getString(3);
             DataInputStream dataIn = new DataInputStream(rs.getBinaryStream(4));
-            record = new ReadRecord(journalId, producerId, revision, dataIn, 0, resolver);
+            record = new ReadRecord(journalId, producerId, revision, dataIn, 0, resolver, store);
         } else {
             isEOF = true;
         }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileRecordLog.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileRecordLog.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileRecordLog.java	(working copy)
@@ -18,6 +18,7 @@
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.name.NamespaceResolver;
 
 import java.io.File;
@@ -105,13 +106,19 @@
     private short minor;
 
     /**
+     * Data store for binary properties.
+     */
+    private final DataStore store;
+
+    /**
      * Create a new instance of this class. Opens a record log in read-only mode.
      *
      * @param logFile file containing record log
      * @throws java.io.IOException if an I/O error occurs
      */
-    public FileRecordLog(File logFile) throws IOException {
+    public FileRecordLog(File logFile, DataStore store) throws IOException {
         this.logFile = logFile;
+        this.store = store;
 
         if (logFile.exists()) {
             DataInputStream in = new DataInputStream(new FileInputStream(logFile));
@@ -233,7 +240,7 @@
                 4 + length;
 
         long revision = previousRevision + position;
-        return new ReadRecord(journalId, producerId, revision, in, length, resolver);
+        return new ReadRecord(journalId, producerId, revision, in, length, resolver, store);
     }
 
     /**
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DefaultRecordProducer.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DefaultRecordProducer.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DefaultRecordProducer.java	(working copy)
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.core.journal;
 
+import org.apache.jackrabbit.core.data.DataStore;
+
 /**
  * Produces new records that can be appended to the journal.
  */
@@ -30,6 +32,11 @@
      * Producer identifier.
      */
     private String id;
+    
+    /**
+     * Data store for binary properties.
+     */
+    private final DataStore store;
 
     /**
      * Create a new instance of this class.
@@ -37,9 +44,10 @@
      * @param journal journal
      * @param id producer id
      */
-    public DefaultRecordProducer(AbstractJournal journal, String id) {
+    public DefaultRecordProducer(AbstractJournal journal, String id, DataStore store) {
         this.journal = journal;
         this.id = id;
+        this.store = store;
     }
 
     /**
@@ -67,6 +75,6 @@
      * @throws JournalException if an error occurs
      */
     protected AppendRecord createRecord() throws JournalException {
-        return new AppendRecord(journal, id);
+        return new AppendRecord(journal, id, store);
     }
 }
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileRecordIterator.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileRecordIterator.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileRecordIterator.java	(working copy)
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.journal;
 
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.name.NamespaceResolver;
 
 import java.io.File;
@@ -59,6 +60,11 @@
     private ReadRecord record;
 
     /**
+     * Data store for binary properties.
+     */
+    private final DataStore store;
+
+    /**
      * Creates a new instance of this class.
      *
      * @param logFiles available log files, sorted ascending by age
@@ -66,11 +72,12 @@
      * @param stopRevision stop point (inclusive)
      */
     public FileRecordIterator(File[] logFiles, long startRevision, long stopRevision,
-                              NamespaceResolver resolver) {
+                              NamespaceResolver resolver, DataStore store) {
         this.logFiles = logFiles;
         this.revision = startRevision;
         this.stopRevision = stopRevision;
         this.resolver = resolver;
+        this.store = store;
     }
 
 
@@ -144,7 +151,7 @@
      */
     private FileRecordLog getRecordLog(long revision) throws IOException {
         for (int i = 0; i < logFiles.length; i++) {
-            FileRecordLog recordLog = new FileRecordLog(logFiles[i]);
+            FileRecordLog recordLog = new FileRecordLog(logFiles[i], store);
             if (recordLog.contains(revision)) {
                 recordLog.seek(revision);
                 return recordLog;
Index: C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java
===================================================================
--- C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java	(revision 552445)
+++ C:/data/jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java	(working copy)
@@ -26,6 +26,7 @@
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.name.NamespaceResolver;
 
 /**
@@ -63,13 +64,19 @@
      * but only one writer (appending a new entry).
      */
     private final ReadWriteLock rwLock = new ReentrantWriterPreferenceReadWriteLock();
+    
+    /**
+     * Data store for binary properties.
+     */
+    protected DataStore store;
 
     /**
      * {@inheritDoc}
      */
-    public void init(String id, NamespaceResolver resolver) throws JournalException {
+    public void init(String id, NamespaceResolver resolver, DataStore store) throws JournalException {
         this.id = id;
         this.resolver = resolver;
+        this.store = store;
     }
 
     /**
@@ -131,7 +138,7 @@
      * @param identifier producer identifier
      */
     protected RecordProducer createProducer(String identifier) {
-        return new DefaultRecordProducer(this, identifier);
+        return new DefaultRecordProducer(this, identifier, store);
     }
 
     /**
