Author: mreutegg
Date: Wed Aug 22 08:51:41 2018
New Revision: 1838617

URL: http://svn.apache.org/viewvc?rev=1838617&view=rev
Log:
OAK-7569: Direct Binary Access

Remaining changes from Matt Ryan's PR 
https://github.com/apache/jackrabbit-oak/pull/96

Added:
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/AbstractBinaryAccessIT.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/BinaryAccessDSGCIT.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/BinaryAccessIT.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/BinaryAccessTest.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/BinaryAccessUnsupportedIT.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/fixtures/
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/fixtures/datastore/
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/fixtures/datastore/AzureDataStoreFixture.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/fixtures/datastore/DataStoreFixture.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/fixtures/datastore/FileDataStoreFixture.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/fixtures/datastore/S3DataStoreFixture.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/fixtures/nodestore/
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/fixtures/nodestore/DocumentMemoryNodeStoreFixture.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/fixtures/nodestore/FixtureUtils.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/fixtures/nodestore/SegmentMemoryNodeStoreFixture.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/util/
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/util/BinaryAccessTestUtils.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/util/Content.java
   (with props)
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/util/ComponentHolder.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizableImpl.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImpl.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImplTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/GroupImplTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/MembershipBaseTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserManagerImplTest.java
    jackrabbit/oak/trunk/oak-jcr/pom.xml
    
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java
    
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java
    
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventQueue.java
    
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java
    
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
    
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java
    
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java
    
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java
    
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionImpl.java
    
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java
    jackrabbit/oak/trunk/oak-parent/pom.xml
    
jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/plugins/value/jcr/BinaryImpl.java
    
jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/plugins/value/jcr/PartialValueFactory.java
    
jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/plugins/value/jcr/ValueFactoryImpl.java
    
jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/plugins/value/jcr/ValueImpl.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizableImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizableImpl.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizableImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizableImpl.java
 Wed Aug 22 08:51:41 2018
@@ -230,7 +230,7 @@ abstract class AuthorizableImpl implemen
      */
     private AuthorizableProperties getAuthorizableProperties() {
         if (properties == null) {
-            properties = new AuthorizablePropertiesImpl(this, 
userManager.getNamePathMapper());
+            properties = new AuthorizablePropertiesImpl(this, 
userManager.getPartialValueFactory());
         }
         return properties;
     }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImpl.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImpl.java
 Wed Aug 22 08:51:41 2018
@@ -30,7 +30,6 @@ import org.apache.jackrabbit.JcrConstant
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
 import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
 import org.apache.jackrabbit.oak.plugins.tree.TreeLocation;
@@ -53,11 +52,12 @@ class AuthorizablePropertiesImpl impleme
     private static final Logger log = 
LoggerFactory.getLogger(AuthorizablePropertiesImpl.class);
 
     private final AuthorizableImpl authorizable;
-    private final NamePathMapper namePathMapper;
+    private final PartialValueFactory valueFactory;
 
-    AuthorizablePropertiesImpl(@NotNull AuthorizableImpl authorizable, 
@NotNull NamePathMapper namePathMapper) {
+    AuthorizablePropertiesImpl(@NotNull AuthorizableImpl authorizable,
+                               @NotNull PartialValueFactory valueFactory) {
         this.authorizable = authorizable;
-        this.namePathMapper = namePathMapper;
+        this.valueFactory = valueFactory;
     }
 
     //---------------------------------------------< AuthorizableProperties 
>---
@@ -73,7 +73,7 @@ class AuthorizablePropertiesImpl impleme
             for (PropertyState property : parent.getProperties()) {
                 String propName = property.getName();
                 if (isAuthorizableProperty(tree, location.getChild(propName), 
false)) {
-                    l.add(namePathMapper.getJcrName(propName));
+                    
l.add(valueFactory.getNamePathMapper().getJcrName(propName));
                 }
             }
             return l.iterator();
@@ -102,10 +102,10 @@ class AuthorizablePropertiesImpl impleme
         PropertyState property = getAuthorizableProperty(tree, 
getLocation(tree, oakPath), true);
         if (property != null) {
             if (property.isArray()) {
-                List<Value> vs = new 
PartialValueFactory(namePathMapper).createValues(property);
+                List<Value> vs = valueFactory.createValues(property);
                 values = vs.toArray(new Value[vs.size()]);
             } else {
-                values = new Value[]{new 
PartialValueFactory(namePathMapper).createValue(property)};
+                values = new Value[]{valueFactory.createValue(property)};
             }
         }
         return values;
@@ -298,7 +298,7 @@ class AuthorizablePropertiesImpl impleme
         if (relPath == null || relPath.isEmpty() || relPath.charAt(0) == '/') {
             throw new RepositoryException("Relative path expected. Found " + 
relPath);
         }
-        String oakPath = namePathMapper.getOakPath(relPath);
+        String oakPath = valueFactory.getNamePathMapper().getOakPath(relPath);
         if (oakPath == null) {
             throw new RepositoryException("Failed to resolve relative path: " 
+ relPath);
         }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
 Wed Aug 22 08:51:41 2018
@@ -25,7 +25,9 @@ import java.util.Set;
 import com.google.common.collect.ImmutableList;
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.blob.BlobAccessProvider;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.value.jcr.PartialValueFactory;
 import org.apache.jackrabbit.oak.security.user.autosave.AutoSaveEnabledManager;
 import org.apache.jackrabbit.oak.spi.commit.MoveTracker;
 import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler;
@@ -41,17 +43,24 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
 import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
 import org.apache.jackrabbit.oak.spi.security.user.util.PasswordUtil;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardAware;
+import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils;
 import org.apache.jackrabbit.oak.spi.xml.ImportBehavior;
 import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.osgi.service.metatype.annotations.AttributeDefinition;
 import org.osgi.service.metatype.annotations.Designate;
 import org.osgi.service.metatype.annotations.ObjectClassDefinition;
 import org.osgi.service.metatype.annotations.Option;
 
+import static 
org.apache.jackrabbit.oak.plugins.value.jcr.PartialValueFactory.DEFAULT_BLOB_ACCESS_PROVIDER;
+
 /**
  * Default implementation of the {@link UserConfiguration}.
  */
@@ -176,6 +185,9 @@ public class UserConfigurationImpl exten
         setParameters(ConfigurationParameters.of(properties));
     }
 
+    @Reference(cardinality = ReferenceCardinality.OPTIONAL)
+    private BlobAccessProvider blobAccessProvider;
+
     //----------------------------------------------< SecurityConfiguration 
>---
     @NotNull
     @Override
@@ -230,7 +242,8 @@ public class UserConfigurationImpl exten
     @NotNull
     @Override
     public UserManager getUserManager(Root root, NamePathMapper 
namePathMapper) {
-        UserManager umgr = new UserManagerImpl(root, namePathMapper, 
getSecurityProvider());
+        PartialValueFactory vf = new PartialValueFactory(namePathMapper, 
getBlobAccessProvider());
+        UserManager umgr = new UserManagerImpl(root, vf, 
getSecurityProvider());
         if 
(getParameters().getConfigValue(UserConstants.PARAM_SUPPORT_AUTOSAVE, false)) {
             return new AutoSaveEnabledManager(umgr, root);
         } else {
@@ -243,4 +256,24 @@ public class UserConfigurationImpl exten
     public PrincipalProvider getUserPrincipalProvider(@NotNull Root root, 
@NotNull NamePathMapper namePathMapper) {
         return new UserPrincipalProvider(root, this, namePathMapper);
     }
+
+    //-----------------------------------------------------------< internal 
>---
+
+    private BlobAccessProvider getBlobAccessProvider() {
+        BlobAccessProvider provider = blobAccessProvider;
+        if (provider == null) {
+            SecurityProvider securityProvider = getSecurityProvider();
+            if (securityProvider instanceof WhiteboardAware) {
+                Whiteboard wb = ((WhiteboardAware) 
securityProvider).getWhiteboard();
+                if (wb != null) {
+                    provider = WhiteboardUtils.getService(wb, 
BlobAccessProvider.class);
+                }
+            }
+        }
+        if (provider == null) {
+            provider = DEFAULT_BLOB_ACCESS_PROVIDER;
+            blobAccessProvider = provider;
+        }
+        return provider;
+    }
 }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java
 Wed Aug 22 08:51:41 2018
@@ -50,6 +50,7 @@ import org.apache.jackrabbit.oak.api.Typ
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager;
 import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+import org.apache.jackrabbit.oak.plugins.value.jcr.PartialValueFactory;
 import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
@@ -193,7 +194,7 @@ class UserImporter implements ProtectedP
             return false;
         }
 
-        userManager = new UserManagerImpl(root, namePathMapper, 
securityProvider);
+        userManager = new UserManagerImpl(root, new 
PartialValueFactory(namePathMapper), securityProvider);
 
         initialized = true;
         return initialized;

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java
 Wed Aug 22 08:51:41 2018
@@ -39,6 +39,7 @@ import org.apache.jackrabbit.oak.api.Tre
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
+import org.apache.jackrabbit.oak.plugins.value.jcr.PartialValueFactory;
 import org.apache.jackrabbit.oak.security.user.query.UserQueryManager;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
@@ -68,6 +69,7 @@ public class UserManagerImpl implements
     private static final Logger log = 
LoggerFactory.getLogger(UserManagerImpl.class);
 
     private final Root root;
+    private final PartialValueFactory valueFactory;
     private final NamePathMapper namePathMapper;
     private final SecurityProvider securityProvider;
 
@@ -79,10 +81,12 @@ public class UserManagerImpl implements
     private UserQueryManager queryManager;
     private ReadOnlyNodeTypeManager ntMgr;
 
-    public UserManagerImpl(@NotNull Root root, @NotNull NamePathMapper 
namePathMapper,
+    public UserManagerImpl(@NotNull Root root,
+                           @NotNull PartialValueFactory valueFactory,
                            @NotNull SecurityProvider securityProvider) {
         this.root = root;
-        this.namePathMapper = namePathMapper;
+        this.valueFactory = valueFactory;
+        this.namePathMapper = valueFactory.getNamePathMapper();
         this.securityProvider = securityProvider;
 
         UserConfiguration uc = 
securityProvider.getConfiguration(UserConfiguration.class);
@@ -377,6 +381,11 @@ public class UserManagerImpl implements
     }
 
     @NotNull
+    PartialValueFactory getPartialValueFactory() {
+        return valueFactory;
+    }
+
+    @NotNull
     ReadOnlyNodeTypeManager getNodeTypeManager() {
         if (ntMgr == null) {
             ntMgr = ReadOnlyNodeTypeManager.getInstance(root, 
NamePathMapper.DEFAULT);

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
 Wed Aug 22 08:51:41 2018
@@ -53,6 +53,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.tree.TreeProvider;
 import org.apache.jackrabbit.oak.plugins.tree.impl.RootProviderService;
 import org.apache.jackrabbit.oak.plugins.tree.impl.TreeProviderService;
+import org.apache.jackrabbit.oak.plugins.value.jcr.PartialValueFactory;
 import org.apache.jackrabbit.oak.plugins.value.jcr.ValueFactoryImpl;
 import org.apache.jackrabbit.oak.plugins.version.VersionHook;
 import org.apache.jackrabbit.oak.query.QueryEngineSettings;
@@ -80,6 +81,7 @@ public abstract class AbstractSecurityTe
     private User testUser;
 
     protected NamePathMapper namePathMapper = NamePathMapper.DEFAULT;
+    protected PartialValueFactory valueFactory = new 
PartialValueFactory(namePathMapper);
     protected SecurityProvider securityProvider;
     protected ContentSession adminSession;
     protected Root root;
@@ -179,6 +181,10 @@ public abstract class AbstractSecurityTe
         return namePathMapper;
     }
 
+    protected PartialValueFactory getPartialValueFactory() {
+        return valueFactory;
+    }
+
     protected UserConfiguration getUserConfiguration() {
         return getConfig(UserConfiguration.class);
     }

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImplTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImplTest.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImplTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImplTest.java
 Wed Aug 22 08:51:41 2018
@@ -32,6 +32,7 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.oak.AbstractSecurityTest;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.value.jcr.PartialValueFactory;
 import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
 import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
 import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
@@ -57,7 +58,7 @@ public class AuthorizablePropertiesImplT
         super.before();
 
         User user = getTestUser();
-        emptyProperties = new AuthorizablePropertiesImpl((AuthorizableImpl) 
user, getNamePathMapper());
+        emptyProperties = new AuthorizablePropertiesImpl((AuthorizableImpl) 
user, getPartialValueFactory());
 
         String id2 = "user2" + UUID.randomUUID().toString();
         user2 = getUserManager(root).createUser(id2, null, new 
PrincipalImpl(id2), PathUtils.getAncestorPath(user.getPath(), 1));
@@ -73,7 +74,7 @@ public class AuthorizablePropertiesImplT
         user2.setProperty("relPath/mvProp", vArr);
         root.commit();
 
-        properties = new AuthorizablePropertiesImpl((AuthorizableImpl) user2, 
getNamePathMapper());
+        properties = new AuthorizablePropertiesImpl((AuthorizableImpl) user2, 
getPartialValueFactory());
     }
 
     @Override
@@ -116,7 +117,8 @@ public class AuthorizablePropertiesImplT
 
     @Test(expected = RepositoryException.class)
     public void testGetNamesMissingResolutionToOakPath() throws Exception {
-        AuthorizableProperties props = new 
AuthorizablePropertiesImpl((AuthorizableImpl) user2, new 
NamePathMapper.Default() {
+        AuthorizableProperties props = new 
AuthorizablePropertiesImpl((AuthorizableImpl) user2,
+                new PartialValueFactory(new NamePathMapper.Default() {
             @Override
             public String getOakNameOrNull(@NotNull String jcrName) {
                 return null;
@@ -126,7 +128,7 @@ public class AuthorizablePropertiesImplT
             public String getOakPath(String jcrPath) {
                 return null;
             }
-        });
+        }));
         props.getNames("relPath");
     }
 
@@ -210,7 +212,8 @@ public class AuthorizablePropertiesImplT
 
     @Test(expected = RepositoryException.class)
     public void testSetMissingResolutionToOakPath() throws Exception {
-        AuthorizableProperties props = new 
AuthorizablePropertiesImpl((AuthorizableImpl) user2, new 
NamePathMapper.Default() {
+        AuthorizableProperties props = new 
AuthorizablePropertiesImpl((AuthorizableImpl) user2,
+                new PartialValueFactory(new NamePathMapper.Default() {
             @Override
             public String getOakNameOrNull(@NotNull String jcrName) {
                 return null;
@@ -220,7 +223,7 @@ public class AuthorizablePropertiesImplT
             public String getOakPath(String jcrPath) {
                 return null;
             }
-        });
+        }));
         props.setProperty("relPath/prop", vf.createValue("value"));
     }
 
@@ -279,7 +282,8 @@ public class AuthorizablePropertiesImplT
 
     @Test(expected = RepositoryException.class)
     public void testRemoveMissingResolutionToOakPath() throws Exception {
-        AuthorizableProperties props = new 
AuthorizablePropertiesImpl((AuthorizableImpl) user2, new 
NamePathMapper.Default() {
+        AuthorizableProperties props = new 
AuthorizablePropertiesImpl((AuthorizableImpl) user2,
+                new PartialValueFactory(new NamePathMapper.Default() {
             @Override
             public String getOakNameOrNull(@NotNull String jcrName) {
                 return null;
@@ -289,7 +293,7 @@ public class AuthorizablePropertiesImplT
             public String getOakPath(String jcrPath) {
                 return null;
             }
-        });
+        }));
         props.removeProperty("relPath/prop");
     }
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/GroupImplTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/GroupImplTest.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/GroupImplTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/GroupImplTest.java
 Wed Aug 22 08:51:41 2018
@@ -44,7 +44,7 @@ public class GroupImplTest extends Abstr
     public void before() throws Exception {
         super.before();
 
-        uMgr = new UserManagerImpl(root, getNamePathMapper(), 
getSecurityProvider());
+        uMgr = new UserManagerImpl(root, getPartialValueFactory(), 
getSecurityProvider());
         Group g = uMgr.createGroup(groupId);
 
         group = new GroupImpl(groupId, root.getTree(g.getPath()), uMgr);

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/MembershipBaseTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/MembershipBaseTest.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/MembershipBaseTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/MembershipBaseTest.java
 Wed Aug 22 08:51:41 2018
@@ -61,7 +61,7 @@ public abstract class MembershipBaseTest
     @Before
     public void before() throws Exception {
         super.before();
-        userMgr = new UserManagerImpl(root, namePathMapper, 
getSecurityProvider());
+        userMgr = new UserManagerImpl(root, getPartialValueFactory(), 
getSecurityProvider());
         mp = userMgr.getMembershipProvider();
         // set the threshold low for testing
         mp.setMembershipSizeThreshold(SIZE_TH);

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserManagerImplTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserManagerImplTest.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserManagerImplTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserManagerImplTest.java
 Wed Aug 22 08:51:41 2018
@@ -66,7 +66,7 @@ public class UserManagerImplTest extends
     public void before() throws Exception {
         super.before();
 
-        userMgr = new UserManagerImpl(root, namePathMapper, 
getSecurityProvider());
+        userMgr = new UserManagerImpl(root, getPartialValueFactory(), 
getSecurityProvider());
         beforeAuthorizables.clear();
         Iterator<Authorizable> iter = 
userMgr.findAuthorizables("jcr:primaryType", null, 
UserManager.SEARCH_TYPE_AUTHORIZABLE);
         while (iter.hasNext()) {
@@ -305,7 +305,7 @@ public class UserManagerImplTest extends
                     try {
                         ContentSession admin = login(getAdminCredentials());
                         Root root = admin.getLatestRoot();
-                        UserManager userManager = new UserManagerImpl(root, 
namePathMapper, getSecurityProvider());
+                        UserManager userManager = new UserManagerImpl(root, 
getPartialValueFactory(), getSecurityProvider());
                         userManager.createUser(userId, "pass");
                         root.commit();
                         admin.close();

Modified: jackrabbit/oak/trunk/oak-jcr/pom.xml
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/pom.xml?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-jcr/pom.xml Wed Aug 22 08:51:41 2018
@@ -334,6 +334,19 @@
       <artifactId>jackrabbit-jcr-commons</artifactId>
       <version>${jackrabbit.version}</version>
     </dependency>
+    
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-blob-cloud</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-blob-cloud-azure</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
 
     <dependency>
       <groupId>com.google.guava</groupId>

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java
 Wed Aug 22 08:51:41 2018
@@ -40,6 +40,7 @@ import javax.jcr.observation.EventListen
 import org.apache.jackrabbit.api.jmx.EventListenerMBean;
 import org.apache.jackrabbit.commons.observation.ListenerTracker;
 import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.blob.BlobAccessProvider;
 import org.apache.jackrabbit.oak.commons.PerfLogger;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.observation.CommitRateLimiter;
@@ -172,6 +173,7 @@ class ChangeProcessor implements Filteri
     private final TimeSeriesMax maxQueueLengthRecorder;
     private final int queueLength;
     private final CommitRateLimiter commitRateLimiter;
+    private final BlobAccessProvider blobAccessProvider;
 
     /**
      * Lazy initialization via the {@link #start(Whiteboard)} method
@@ -206,7 +208,8 @@ class ChangeProcessor implements Filteri
             FilterProvider filter,
             StatisticManager statisticManager,
             int queueLength,
-            CommitRateLimiter commitRateLimiter) {
+            CommitRateLimiter commitRateLimiter,
+            BlobAccessProvider blobAccessProvider) {
         this.contentSession = contentSession;
         this.namePathMapper = namePathMapper;
         this.tracker = tracker;
@@ -217,6 +220,7 @@ class ChangeProcessor implements Filteri
         this.maxQueueLengthRecorder = statisticManager.maxQueLengthRecorder();
         this.queueLength = queueLength;
         this.commitRateLimiter = commitRateLimiter;
+        this.blobAccessProvider = blobAccessProvider;
     }
 
     /**
@@ -492,7 +496,8 @@ class ChangeProcessor implements Filteri
             // FIXME don't rely on toString for session id
             if (provider.includeCommit(contentSession.toString(), info)) {
                 EventFilter filter = provider.getFilter(before, after);
-                EventIterator events = new EventQueue(namePathMapper, info, 
before, after,
+                EventIterator events = new EventQueue(namePathMapper,
+                        blobAccessProvider, info, before, after,
                         provider.getSubTrees(), Filters.all(filter, 
VISIBLE_FILTER), 
                         provider.getEventAggregator());
 

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventFactory.java
 Wed Aug 22 08:51:41 2018
@@ -35,10 +35,12 @@ import com.google.common.collect.Immutab
 import com.google.common.collect.Lists;
 import org.apache.jackrabbit.api.observation.JackrabbitEvent;
 import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.blob.BlobAccessProvider;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.value.jcr.PartialValueFactory;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Event factory for generating JCR event instances that are optimized
@@ -64,9 +66,11 @@ public class EventFactory {
 
     private final boolean external;
 
-    EventFactory(NamePathMapper mapper, CommitInfo commitInfo) {
+    EventFactory(@NotNull NamePathMapper mapper,
+                 @NotNull BlobAccessProvider blobAccessProvider,
+                 @NotNull CommitInfo commitInfo) {
         this.mapper = mapper;
-        this.valueFactory = new PartialValueFactory(mapper);
+        this.valueFactory = new PartialValueFactory(mapper, 
blobAccessProvider);
         if (!commitInfo.isExternal()) {
             this.userID = commitInfo.getUserId();
             Object userData = commitInfo.getInfo().get(USER_DATA);

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventQueue.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventQueue.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventQueue.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/EventQueue.java
 Wed Aug 22 08:51:41 2018
@@ -26,6 +26,7 @@ import java.util.NoSuchElementException;
 import javax.jcr.observation.Event;
 import javax.jcr.observation.EventIterator;
 
+import org.apache.jackrabbit.oak.api.blob.BlobAccessProvider;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.observation.EventGenerator;
@@ -50,12 +51,13 @@ class EventQueue implements EventIterato
     private long position = 0;
 
     public EventQueue(
-            @NotNull NamePathMapper mapper, CommitInfo info,
+            @NotNull NamePathMapper mapper,
+            @NotNull BlobAccessProvider blobAccessProvider, CommitInfo info,
             @NotNull NodeState before, @NotNull NodeState after,
             @NotNull Iterable<String> basePaths, @NotNull EventFilter filter,
             @Nullable EventAggregator aggregator) {
         this.generator = new EventGenerator();
-        EventFactory factory = new EventFactory(mapper, info);
+        EventFactory factory = new EventFactory(mapper, blobAccessProvider, 
info);
         EventHandler handler = new FilteredHandler(
                 filter, new QueueingHandler(this, factory, aggregator, before, 
after));
         for (String path : basePaths) {

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java
 Wed Aug 22 08:51:41 2018
@@ -49,6 +49,7 @@ import org.apache.jackrabbit.commons.ite
 import org.apache.jackrabbit.commons.observation.ListenerTracker;
 import org.apache.jackrabbit.oak.api.ContentSession;
 import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.blob.BlobAccessProvider;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate;
 import org.apache.jackrabbit.oak.jcr.session.SessionContext;
@@ -97,6 +98,7 @@ public class ObservationManagerImpl impl
     private final int queueLength;
     private final CommitRateLimiter commitRateLimiter;
     private final PermissionProviderFactory permissionProviderFactory;
+    private final BlobAccessProvider blobAccessProvider;
 
     /**
      * Create a new instance based on a {@link ContentSession} that needs to 
implement
@@ -120,6 +122,7 @@ public class ObservationManagerImpl impl
         this.statisticManager = sessionContext.getStatisticManager();
         this.queueLength = queueLength;
         this.commitRateLimiter = commitRateLimiter;
+        this.blobAccessProvider = sessionContext.getBlobAccessProvider();
         this.permissionProviderFactory = new PermissionProviderFactory() {
             Set<Principal> principals = 
sessionDelegate.getAuthInfo().getPrincipals();
             @NotNull
@@ -161,7 +164,7 @@ public class ObservationManagerImpl impl
             // session. See OAK-1368.
             processor = new 
ChangeProcessor(sessionDelegate.getContentSession(), namePathMapper,
                     tracker, filterProvider, statisticManager, queueLength,
-                    commitRateLimiter);
+                    commitRateLimiter, blobAccessProvider);
             processors.put(listener, processor);
             processor.start(whiteboard);
         } else {

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
 Wed Aug 22 08:51:41 2018
@@ -65,7 +65,7 @@ public class QueryResultImpl implements
         this.sessionContext = sessionContext;
         this.sessionDelegate = sessionContext.getSessionDelegate();
         this.result = result;
-        this.valueFactory = new PartialValueFactory(sessionContext);
+        this.valueFactory = new PartialValueFactory(sessionContext, 
sessionContext.getBlobAccessProvider());
     }
 
     @Override

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java
 Wed Aug 22 08:51:41 2018
@@ -49,6 +49,7 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.commons.SimpleValueFactory;
 import org.apache.jackrabbit.oak.api.ContentRepository;
 import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.blob.BlobAccessProvider;
 import org.apache.jackrabbit.oak.api.jmx.SessionMBean;
 import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser;
 import org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate;
@@ -109,6 +110,7 @@ public class RepositoryImpl implements J
     private final DelegatingGCMonitor gcMonitor = new DelegatingGCMonitor();
     private final Registration gcMonitorRegistration;
     private final MountInfoProvider mountInfoProvider;
+    private final BlobAccessProvider blobAccessProvider;
 
     /**
      * {@link ThreadLocal} counter that keeps track of the save operations
@@ -157,6 +159,7 @@ public class RepositoryImpl implements J
         this.gcMonitorRegistration = whiteboard.register(GCMonitor.class, 
gcMonitor, emptyMap());
         this.fastQueryResultSize = fastQueryResultSize;
         this.mountInfoProvider = WhiteboardUtils.getService(whiteboard, 
MountInfoProvider.class);
+        this.blobAccessProvider = WhiteboardUtils.getService(whiteboard, 
BlobAccessProvider.class);
     }
 
     //---------------------------------------------------------< Repository 
>---
@@ -348,7 +351,7 @@ public class RepositoryImpl implements J
             Map<String, Object> attributes, SessionDelegate delegate, int 
observationQueueLength,
             CommitRateLimiter commitRateLimiter) {
         return new SessionContext(this, statisticManager, securityProvider, 
whiteboard, attributes,
-                delegate, observationQueueLength, commitRateLimiter, 
mountInfoProvider, fastQueryResultSize);
+                delegate, observationQueueLength, commitRateLimiter, 
mountInfoProvider, blobAccessProvider, fastQueryResultSize);
     }
 
     /**

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/PropertyImpl.java
 Wed Aug 22 08:51:41 2018
@@ -249,7 +249,7 @@ public class PropertyImpl extends ItemIm
             @NotNull
             @Override
             public Value perform() throws RepositoryException {
-                return new PartialValueFactory(sessionContext)
+                return new PartialValueFactory(sessionContext, 
sessionContext.getBlobAccessProvider())
                         .createValue(property.getSingleState());
             }
         });
@@ -262,7 +262,7 @@ public class PropertyImpl extends ItemIm
             @NotNull
             @Override
             public List<Value> perform() throws RepositoryException {
-                return new PartialValueFactory(sessionContext)
+                return new PartialValueFactory(sessionContext, 
sessionContext.getBlobAccessProvider())
                         .createValues(property.getMultiState());
             }
         }).toArray(NO_VALUES);

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java
 Wed Aug 22 08:51:41 2018
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.jcr.se
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Sets.newHashSet;
 import static com.google.common.collect.Sets.newTreeSet;
+import static 
org.apache.jackrabbit.oak.plugins.value.jcr.PartialValueFactory.DEFAULT_BLOB_ACCESS_PROVIDER;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -39,6 +40,7 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.api.stats.RepositoryStatistics.Type;
+import org.apache.jackrabbit.oak.api.blob.BlobAccessProvider;
 import org.apache.jackrabbit.oak.jcr.delegate.AccessControlManagerDelegator;
 import 
org.apache.jackrabbit.oak.jcr.delegate.JackrabbitAccessControlManagerDelegator;
 import org.apache.jackrabbit.oak.jcr.delegate.NodeDelegate;
@@ -63,9 +65,9 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
 import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
 import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter;
-import org.apache.jackrabbit.oak.stats.StatisticManager;
 import org.apache.jackrabbit.oak.stats.CounterStats;
 import org.apache.jackrabbit.oak.stats.MeterStats;
+import org.apache.jackrabbit.oak.stats.StatisticManager;
 import org.apache.jackrabbit.oak.stats.TimerStats;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -104,6 +106,7 @@ public class SessionContext implements N
     private UserManager userManager;
     private PrivilegeManager privilegeManager;
     private ObservationManagerImpl observationManager;
+    private BlobAccessProvider blobAccessProvider;
 
     /** Paths (tokens) of all open scoped locks held by this session. */
     private final Set<String> openScopedLocks = newTreeSet();
@@ -120,7 +123,7 @@ public class SessionContext implements N
              int observationQueueLength, CommitRateLimiter commitRateLimiter) {
         
         this(repository, statisticManager, securityProvider, whiteboard, 
attributes, delegate,
-            observationQueueLength, commitRateLimiter, null, false);
+            observationQueueLength, commitRateLimiter, null, null, false);
     }
 
     public SessionContext(
@@ -128,7 +131,8 @@ public class SessionContext implements N
             @NotNull SecurityProvider securityProvider, @NotNull Whiteboard 
whiteboard,
             @NotNull Map<String, Object> attributes, @NotNull final 
SessionDelegate delegate,
             int observationQueueLength, CommitRateLimiter commitRateLimiter,
-            MountInfoProvider mountInfoProvider, boolean fastQueryResultSize) {
+            MountInfoProvider mountInfoProvider, @Nullable BlobAccessProvider 
blobAccessProvider,
+            boolean fastQueryResultSize) {
         this.repository = checkNotNull(repository);
         this.statisticManager = statisticManager;
         this.securityProvider = checkNotNull(securityProvider);
@@ -138,13 +142,14 @@ public class SessionContext implements N
         this.observationQueueLength = observationQueueLength;
         this.commitRateLimiter = commitRateLimiter;
         this.mountInfoProvider = mountInfoProvider;
+        this.blobAccessProvider = blobAccessProvider == null ? 
DEFAULT_BLOB_ACCESS_PROVIDER : blobAccessProvider;
         SessionStats sessionStats = delegate.getSessionStats();
         sessionStats.setAttributes(attributes);
 
         this.namePathMapper = new NamePathMapperImpl(
                 delegate.getNamespaces(), delegate.getIdManager());
         this.valueFactory = new ValueFactoryImpl(
-                delegate.getRoot(), namePathMapper);
+                delegate.getRoot(), namePathMapper, this.blobAccessProvider);
         this.fastQueryResultSize = fastQueryResultSize;
     }
 
@@ -298,6 +303,11 @@ public class SessionContext implements N
         return observationManager;
     }
 
+    @NotNull
+    public BlobAccessProvider getBlobAccessProvider() {
+        return blobAccessProvider;
+    }
+
     public boolean hasEventListeners(){
         if (observationManager != null){
             return observationManager.getRegisteredEventListeners().hasNext();

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionImpl.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/version/VersionImpl.java
 Wed Aug 22 08:51:41 2018
@@ -115,7 +115,8 @@ public class VersionImpl extends NodeImp
     }
 
     private List<Value> getValues(PropertyDelegate p) throws 
InvalidItemStateException, ValueFormatException {
-        return new 
PartialValueFactory(sessionContext).createValues(p.getMultiState());
+        return new PartialValueFactory(sessionContext, 
sessionContext.getBlobAccessProvider())
+                .createValues(p.getMultiState());
     }
 
     @Override

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java?rev=1838617&r1=1838616&r2=1838617&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java
 Wed Aug 22 08:51:41 2018
@@ -16,9 +16,10 @@
  */
 package org.apache.jackrabbit.oak.jcr;
 
+import static org.junit.Assume.assumeTrue;
 import java.util.Collection;
+import java.util.Map;
 import java.util.Set;
-
 import javax.jcr.GuestCredentials;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
@@ -32,16 +33,21 @@ import org.apache.jackrabbit.oak.NodeSto
 import org.apache.jackrabbit.oak.commons.FixturesHelper;
 import org.apache.jackrabbit.oak.commons.FixturesHelper.Fixture;
 import org.apache.jackrabbit.oak.fixture.NodeStoreFixture;
+import org.apache.jackrabbit.oak.jcr.util.ComponentHolder;
 import 
org.apache.jackrabbit.oak.plugins.document.bundlor.BundlingConfigInitializer;
 import org.apache.jackrabbit.oak.query.QueryEngineSettings;
 import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
 import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
+import com.google.common.collect.Maps;
+
 /**
  * Abstract base class for repository tests providing methods for accessing
  * the repository, a session and nodes and properties from that session.
@@ -54,10 +60,12 @@ import org.junit.runners.Parameterized;
 public abstract class AbstractRepositoryTest {
 
     protected final NodeStoreFixture fixture;
+    private final boolean reuseNodeStore;
 
     private volatile NodeStore nodeStore;
     private volatile Repository repository;
     private volatile Session adminSession;
+    private volatile Session anonymousSession;
 
     /**
      * The system property "nsfixtures" can be used to provide a
@@ -66,35 +74,95 @@ public abstract class AbstractRepository
      */
     private static final Set<Fixture> FIXTURES = FixturesHelper.getFixtures();
 
-    protected AbstractRepositoryTest(NodeStoreFixture fixture) {
-        this.fixture = fixture;
-    }
+    /**
+     * If reuseNodeStore is on, this caches the NodeStore returned by each 
fixture
+     * and they'll be disposed only in @AfterClass instead of @After.
+     */
+    private static final Map<NodeStoreFixture, NodeStore> NODE_STORES = 
Maps.newConcurrentMap();
 
+    /**
+     * Default fixtures based on a list in the system property `nsfixtures`.
+     * To change the fixtures in a subclass, provide a static method with same 
@Parameterized
+     * annotation but different name that returns a different fixture list.
+     */
     @Parameterized.Parameters(name="{0}")
     public static Collection<Object[]> fixtures() {
         return NodeStoreFixtures.asJunitParameters(FIXTURES);
     }
 
+    /**
+     * Constructor enabling that a new NodeStore will be created from
+     * the NodeStoreFixture for each test (method).
+     *
+     * @param fixture the fixture, which gets passed in as junit parameter
+     */
+    protected AbstractRepositoryTest(NodeStoreFixture fixture) {
+        this(fixture, false);
+    }
+
+    /**
+     * Constructor giving a choice on NodeStore reuse across tests.
+     *
+     * @param fixture the fixture, which gets passed in as junit parameter
+     * @param reuseNodeStore if true, the NodeStore will be reused for all 
test methods of the
+     *                       given test class. if false, a new NodeStore will 
be created from
+     *                       the NodeStoreFixture for each test (method).
+     */
+    protected AbstractRepositoryTest(NodeStoreFixture fixture, boolean 
reuseNodeStore) {
+        this.fixture = fixture;
+        this.reuseNodeStore = reuseNodeStore;
+    }
+
+    @Before
+    public void ignoreIfFixtureUnavailable() {
+        assumeTrue("Skipping unavailable fixture: " + fixture.toString(), 
fixture.isAvailable());
+    }
+
     @After
     public void logout() {
-        // release session field
+        // release session fields
         if (adminSession != null) {
             adminSession.logout();
             adminSession = null;
         }
+        if (anonymousSession != null) {
+            anonymousSession.logout();
+            anonymousSession = null;
+        }
         // release repository field
         if (repository instanceof JackrabbitRepository) {
             ((JackrabbitRepository) repository).shutdown();
         }
         repository = null;
-        if (nodeStore != null) {
+        if (nodeStore != null && !reuseNodeStore) {
             fixture.dispose(nodeStore);
         }
     }
 
+    @AfterClass
+    public static void disposeNodeStores() {
+        // only dispose after the entire class
+        for (Map.Entry<NodeStoreFixture, NodeStore> e : 
NODE_STORES.entrySet()) {
+            e.getKey().dispose(e.getValue());
+        }
+        NODE_STORES.clear();
+    }
+
     protected Repository getRepository() throws RepositoryException {
         if (repository == null) {
-            nodeStore = createNodeStore(fixture);
+
+            if (reuseNodeStore) {
+                // see if there is an existing NodeStore from a previous test
+                nodeStore = NODE_STORES.get(fixture);
+                if (nodeStore == null) {
+                    nodeStore = createNodeStore(fixture);
+                }
+                NODE_STORES.put(fixture, nodeStore);
+            } else {
+                // always create a new NodeStore (default behavior)
+                nodeStore = createNodeStore(fixture);
+            }
+
             repository = createRepository(nodeStore);
         }
         return repository;
@@ -115,6 +183,28 @@ public abstract class AbstractRepository
         return jcr.withAsyncIndexing().with(qs);
     }
 
+    protected NodeStore getNodeStore() {
+        return nodeStore;
+    }
+
+    protected <T> T getNodeStoreComponent(Class<T> type) {
+        return getNodeStoreComponent(type.getName());
+    }
+
+    protected <T> T getNodeStoreComponent(String name) {
+        if (fixture instanceof ComponentHolder) {
+            return ((ComponentHolder) fixture).get(nodeStore, name);
+        }
+        return null;
+    }
+
+    protected Session getAnonymousSession() throws RepositoryException {
+        if (anonymousSession == null) {
+            anonymousSession = createAnonymousSession();
+        }
+        return anonymousSession;
+    }
+
     protected Session getAdminSession() throws RepositoryException {
         if (adminSession == null) {
             adminSession = createAdminSession();

Added: 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/AbstractBinaryAccessIT.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/AbstractBinaryAccessIT.java?rev=1838617&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/AbstractBinaryAccessIT.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/AbstractBinaryAccessIT.java
 Wed Aug 22 08:51:41 2018
@@ -0,0 +1,90 @@
+/*
+ * 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.oak.jcr.binary;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import javax.jcr.Repository;
+
+import org.apache.jackrabbit.core.data.DataStore;
+import org.apache.jackrabbit.oak.api.blob.BlobAccessProvider;
+import org.apache.jackrabbit.oak.fixture.NodeStoreFixture;
+import org.apache.jackrabbit.oak.jcr.AbstractRepositoryTest;
+import org.apache.jackrabbit.oak.jcr.Jcr;
+import 
org.apache.jackrabbit.oak.jcr.binary.fixtures.datastore.AzureDataStoreFixture;
+import 
org.apache.jackrabbit.oak.jcr.binary.fixtures.datastore.S3DataStoreFixture;
+import 
org.apache.jackrabbit.oak.jcr.binary.fixtures.nodestore.DocumentMemoryNodeStoreFixture;
+import 
org.apache.jackrabbit.oak.jcr.binary.fixtures.nodestore.SegmentMemoryNodeStoreFixture;
+import 
org.apache.jackrabbit.oak.plugins.blob.datastore.directaccess.ConfigurableDataRecordAccessProvider;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.spi.whiteboard.DefaultWhiteboard;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.junit.runners.Parameterized;
+
+/** Base test class for testing direct HTTP access to binaries. */
+public abstract class AbstractBinaryAccessIT extends AbstractRepositoryTest {
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<?> dataStoreFixtures() {
+        Collection<NodeStoreFixture> fixtures = new ArrayList<>();
+
+        S3DataStoreFixture s3 = new S3DataStoreFixture();
+        fixtures.add(new SegmentMemoryNodeStoreFixture(s3));
+        fixtures.add(new DocumentMemoryNodeStoreFixture(s3));
+
+        AzureDataStoreFixture azure = new AzureDataStoreFixture();
+        fixtures.add(new SegmentMemoryNodeStoreFixture(azure));
+        fixtures.add(new DocumentMemoryNodeStoreFixture(azure));
+
+        return fixtures;
+    }
+
+    protected AbstractBinaryAccessIT(NodeStoreFixture fixture, boolean 
reuseNodeStore) {
+        super(fixture, reuseNodeStore);
+    }
+
+    /**
+     * Adjust JCR repository creation to register BlobAccessProvider 
(BlobStore) in Whiteboard
+     * so it can be picked up by oak-jcr.
+     */
+    @Override
+    protected Repository createRepository(NodeStore nodeStore) {
+        Whiteboard wb = new DefaultWhiteboard();
+
+        BlobStore blobStore = getNodeStoreComponent(BlobStore.class);
+        if (blobStore != null && blobStore instanceof BlobAccessProvider) {
+            wb.register(BlobAccessProvider.class, (BlobAccessProvider) 
blobStore,
+                    Collections.emptyMap());
+
+        }
+
+        return initJcr(new Jcr(nodeStore).with(wb)).createRepository();
+    }
+
+    /** Return underlying DataStore configuration extension */
+    protected ConfigurableDataRecordAccessProvider 
getConfigurableHttpDataRecordProvider() {
+        DataStore dataStore = getNodeStoreComponent(DataStore.class);
+        if (dataStore != null && dataStore instanceof 
ConfigurableDataRecordAccessProvider) {
+            return (ConfigurableDataRecordAccessProvider) dataStore;
+        }
+        throw new AssertionError("issue with test setup, cannot retrieve 
underlying DataStore / ConfigurableDataRecordAccessProvider");
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/AbstractBinaryAccessIT.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/BinaryAccessDSGCIT.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/BinaryAccessDSGCIT.java?rev=1838617&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/BinaryAccessDSGCIT.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/BinaryAccessDSGCIT.java
 Wed Aug 22 08:51:41 2018
@@ -0,0 +1,290 @@
+/*
+ * 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.oak.jcr.binary;
+
+import static 
org.apache.jackrabbit.oak.jcr.binary.util.BinaryAccessTestUtils.getBinary;
+import static 
org.apache.jackrabbit.oak.jcr.binary.util.BinaryAccessTestUtils.httpGet;
+import static 
org.apache.jackrabbit.oak.jcr.binary.util.BinaryAccessTestUtils.isSuccessfulHttpPut;
+import static 
org.apache.jackrabbit.oak.jcr.binary.util.BinaryAccessTestUtils.putBinary;
+import static 
org.apache.jackrabbit.oak.jcr.binary.util.BinaryAccessTestUtils.storeBinaryAndRetrieve;
+import static 
org.apache.jackrabbit.oak.plugins.blob.datastore.SharedDataStoreUtils.SharedStoreRecordType.REPOSITORY;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+import javax.jcr.Binary;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.api.JackrabbitValueFactory;
+import org.apache.jackrabbit.api.binary.BinaryDownload;
+import org.apache.jackrabbit.api.binary.BinaryDownloadOptions;
+import org.apache.jackrabbit.api.binary.BinaryUpload;
+import org.apache.jackrabbit.core.data.DataStoreException;
+import org.apache.jackrabbit.oak.fixture.NodeStoreFixture;
+import 
org.apache.jackrabbit.oak.jcr.binary.fixtures.datastore.AzureDataStoreFixture;
+import 
org.apache.jackrabbit.oak.jcr.binary.fixtures.datastore.S3DataStoreFixture;
+import 
org.apache.jackrabbit.oak.jcr.binary.fixtures.nodestore.SegmentMemoryNodeStoreFixture;
+import org.apache.jackrabbit.oak.jcr.binary.util.Content;
+import org.apache.jackrabbit.oak.plugins.blob.MarkSweepGarbageCollector;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreBlobStore;
+import org.apache.jackrabbit.oak.segment.SegmentBlobReferenceRetriever;
+import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions;
+import org.apache.jackrabbit.oak.segment.file.FileStore;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
+import org.apache.jackrabbit.oak.spi.cluster.ClusterRepositoryInfo;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runners.Parameterized;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+public class BinaryAccessDSGCIT extends AbstractBinaryAccessIT {
+    private static final String TEST_ROOT = "testroot";
+    private static final long BINARY_SIZE = 1024*1024;
+
+    private static final String TRADITIONAL_UPLOAD_1 = "tu1";
+    private static final String TRADITIONAL_UPLOAD_2 = "tu2";
+    private static final String DIRECT_UPLOAD_1 = "du1";
+    private static final String DIRECT_UPLOAD_2 = "du2";
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<?> dataStoreFixtures() {
+        Collection<NodeStoreFixture> fixtures = new ArrayList<>();
+        fixtures.add(new SegmentMemoryNodeStoreFixture(new 
S3DataStoreFixture()));
+        fixtures.add(new SegmentMemoryNodeStoreFixture(new 
AzureDataStoreFixture()));
+        return fixtures;
+    }
+
+    public BinaryAccessDSGCIT(NodeStoreFixture fixture) {
+        // reuse NodeStore (and DataStore) across all tests in this class
+        super(fixture, true);
+    }
+
+    private Session session;
+    private JackrabbitValueFactory directUploader;
+
+    private MarkSweepGarbageCollector garbageCollector = null;
+    private ThreadPoolExecutor executor = null;
+
+    @Before
+    public void setup() throws RepositoryException {
+        session = getAdminSession();
+        directUploader = (JackrabbitValueFactory) session.getValueFactory();
+
+        if (session.getNode("/").hasNode(TEST_ROOT)) {
+            session.getNode("/" + TEST_ROOT).remove();
+            session.save();
+        }
+        session.getNode("/").addNode(TEST_ROOT);
+
+        
getConfigurableHttpDataRecordProvider().setDirectUploadURIExpirySeconds(60*5);
+        
getConfigurableHttpDataRecordProvider().setDirectDownloadURIExpirySeconds(60*5);
+    }
+
+    // For debugging.
+    private void printTree(Node root) throws RepositoryException {
+        printTree(root, 0);
+    }
+
+    // For debugging.
+    private void printTree(Node root, int level) throws RepositoryException {
+        for (int i=0; i<level; i++) {
+            System.out.print(" ");
+        }
+        System.out.println(root.getName());
+
+        NodeIterator iter = root.getNodes();
+        while (iter.hasNext()) {
+            printTree(iter.nextNode(), level+1);
+        }
+    }
+
+    private String toAbsolutePath(String leaf) {
+        return "/" + TEST_ROOT + "/" + leaf;
+    }
+
+    private Binary createDirectBinary(String path, Content content) throws 
RepositoryException, IOException {
+        BinaryUpload upload = 
directUploader.initiateBinaryUpload(content.size(), 1); // multi-part not 
needed for this
+        assertNotNull(upload);
+
+        int code = content.httpPUT(upload.getUploadURIs().iterator().next());
+        assertTrue(isSuccessfulHttpPut(code, 
getConfigurableHttpDataRecordProvider()));
+
+        Binary binary = 
directUploader.completeBinaryUpload(upload.getUploadToken());
+        putBinary(session, path, binary);
+
+        return getBinary(session, path);
+    }
+
+    private void verifyBinariesExistViaSession(Session session,
+                                               Map<String, Binary> binaries,
+                                               Map<String, Content> 
binaryContent)
+            throws RepositoryException, IOException {
+        for (Map.Entry<String, Binary> entry : binaries.entrySet()) {
+            Binary b = getBinary(session, toAbsolutePath(entry.getKey()));
+            assertEquals(b, entry.getValue());
+            binaryContent.get(entry.getKey()).assertEqualsWith(b.getStream());
+        }
+    }
+
+    private void verifyBinariesExistDirectly(Map<String, Binary> binaries, 
Map<String, Content> binaryContent)
+            throws RepositoryException, IOException {
+        for (Map.Entry<String, Binary> entry : binaries.entrySet()) {
+            assertTrue(entry.getValue() instanceof BinaryDownload);
+            URI uri = ((BinaryDownload) 
entry.getValue()).getURI(BinaryDownloadOptions.DEFAULT);
+            binaryContent.get(entry.getKey()).assertEqualsWith(httpGet(uri));
+        }
+    }
+
+    private void verifyBinariesDoNotExistDirectly(Map<String, Binary> 
deletedBinaries) throws RepositoryException {
+        for (Map.Entry<String, Binary> entry : deletedBinaries.entrySet()) {
+            assertTrue(entry.getValue() instanceof BinaryDownload);
+            URI uri = ((BinaryDownload) 
entry.getValue()).getURI(BinaryDownloadOptions.DEFAULT);
+            assertNull(uri);
+        }
+    }
+
+    private void compactFileStore() {
+        FileStore fileStore = getNodeStoreComponent(FileStore.class);
+        for (int i=0; 
i<SegmentGCOptions.defaultGCOptions().getRetainedGenerations(); i++) {
+            fileStore.compactFull();
+        }
+    }
+
+    private MarkSweepGarbageCollector getGarbageCollector()
+            throws DataStoreException, IOException {
+        DataStoreBlobStore blobStore = (DataStoreBlobStore) 
getNodeStoreComponent(BlobStore.class);
+        FileStore fileStore = getNodeStoreComponent(FileStore.class);
+        File fileStoreRoot = getNodeStoreComponent(FileStore.class.getName() + 
":root");
+        
+        if (null == garbageCollector) {
+            String repoId = 
ClusterRepositoryInfo.getOrCreateId(getNodeStore());
+            blobStore.addMetadataRecord(new ByteArrayInputStream(new byte[0]),
+                    REPOSITORY.getNameFromId(repoId));
+            if (null == executor) {
+                executor = (ThreadPoolExecutor) 
Executors.newFixedThreadPool(10);
+            }
+            garbageCollector = new MarkSweepGarbageCollector(
+                    new SegmentBlobReferenceRetriever(fileStore),
+                    blobStore,
+                    executor,
+                    fileStoreRoot.getAbsolutePath(),
+                    2048,
+                    0,
+                    repoId
+            );
+        }
+        return garbageCollector;
+    }
+
+    private int getBlobCount() throws Exception {
+        GarbageCollectableBlobStore ds = (GarbageCollectableBlobStore) 
getNodeStoreComponent(BlobStore.class);
+        Set<String> chunks = Sets.newHashSet();
+        Iterator<String> chunkIds = ds.getAllChunkIds(0);
+        while (chunkIds.hasNext()) {
+            chunks.add(chunkIds.next());
+        }
+        return chunks.size();
+    }
+
+    @Test
+    public void testGC() throws Exception {
+        Map<String, Content> binaryContent = Maps.newHashMap();
+        Map<String, Binary> binaries = Maps.newHashMap();
+
+        for (String key : Lists.newArrayList(TRADITIONAL_UPLOAD_1, 
TRADITIONAL_UPLOAD_2)) {
+            Content content = Content.createRandom(BINARY_SIZE);
+            binaryContent.put(key, content);
+            binaries.put(key, storeBinaryAndRetrieve(session, 
toAbsolutePath(key), content));
+        }
+        for (String key : Lists.newArrayList(DIRECT_UPLOAD_1, 
DIRECT_UPLOAD_2)) {
+            Content content = Content.createRandom(BINARY_SIZE);
+            binaryContent.put(key, content);
+            binaries.put(key, createDirectBinary(toAbsolutePath(key), 
content));
+        }
+        session.save();
+
+        // Test that all four binaries can be accessed
+        assertEquals(4, getBlobCount());
+        //  - Download all four via repo
+        verifyBinariesExistViaSession(session, binaries, binaryContent);
+        //  - Download directly
+        verifyBinariesExistDirectly(binaries, binaryContent);
+
+        // Delete one of the binaries uploaded via repo and one uploaded 
directly
+        Node testRoot = session.getNode("/" + TEST_ROOT);
+        List<String> deletedBinaryPaths = 
Lists.newArrayList(TRADITIONAL_UPLOAD_2, DIRECT_UPLOAD_2);
+        for (String path : deletedBinaryPaths) {
+            Node toRemove = testRoot.getNode(path);
+            toRemove.remove();
+        }
+        session.save();
+
+
+        // Verify that they are deleted from repo
+        for (String path : deletedBinaryPaths) {
+            assertFalse(session.nodeExists(toAbsolutePath(path)));
+        }
+
+        // Verify that all four binaries are still in data store
+        assertEquals(4, getBlobCount());
+
+
+        // Run DSGC
+        compactFileStore();
+        MarkSweepGarbageCollector garbageCollector = getGarbageCollector();
+        garbageCollector.collectGarbage(false);
+
+        // Verify that only two binaries remain in data store
+        assertEquals(2, getBlobCount());
+
+        // Verify that the two binaries remaining can still be accessed
+        Map<String, Binary> deletedBinaries = Maps.newHashMap();
+        for (String deletedPath : Lists.newArrayList(TRADITIONAL_UPLOAD_2, 
DIRECT_UPLOAD_2)) {
+            deletedBinaries.put(deletedPath, binaries.get(deletedPath));
+            binaries.remove(deletedPath);
+            binaryContent.remove(deletedPath);
+        }
+
+        verifyBinariesExistViaSession(session, binaries, binaryContent);
+        verifyBinariesExistDirectly(binaries, binaryContent);
+
+        verifyBinariesDoNotExistDirectly(deletedBinaries);
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/binary/BinaryAccessDSGCIT.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to