Author: mreutegg
Date: Mon Nov 27 09:12:21 2017
New Revision: 1816417

URL: http://svn.apache.org/viewvc?rev=1816417&view=rev
Log:
OAK-6917: Configuration presets for DocumentNodeStoreService

Added:
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfiguration.java
   (with props)
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfigurationTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/blob/DocumentBlobGCRegistrationTest.java
    
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/blob/DocumentBlobTrackerRegistrationTest.java
    
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentCachingDataStoreStatsTest.java
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Configuration.java
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceTest.java

Modified: 
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/blob/DocumentBlobGCRegistrationTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/blob/DocumentBlobGCRegistrationTest.java?rev=1816417&r1=1816416&r2=1816417&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/blob/DocumentBlobGCRegistrationTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/blob/DocumentBlobGCRegistrationTest.java
 Mon Nov 27 09:12:21 2017
@@ -55,7 +55,10 @@ public class DocumentBlobGCRegistrationT
         properties.put("repository.home", repoHome);
         properties.put("mongouri", MongoUtils.URL);
         properties.put("db", MongoUtils.DB);
-        service = context.registerInjectActivateService(new 
DocumentNodeStoreService(), properties);
+        MockOsgi.setConfigForPid(context.bundleContext(),
+                DocumentNodeStoreService.class.getName(), properties);
+        context.registerInjectActivateService(new 
DocumentNodeStoreService.Preset());
+        service = context.registerInjectActivateService(new 
DocumentNodeStoreService());
     }
 
     @Override

Modified: 
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/blob/DocumentBlobTrackerRegistrationTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/blob/DocumentBlobTrackerRegistrationTest.java?rev=1816417&r1=1816416&r2=1816417&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/blob/DocumentBlobTrackerRegistrationTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/blob/DocumentBlobTrackerRegistrationTest.java
 Mon Nov 27 09:12:21 2017
@@ -23,7 +23,9 @@ import java.util.Map;
 
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService;
 import org.apache.jackrabbit.oak.plugins.document.MongoUtils;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
 import org.junit.After;
+import org.junit.Before;
 import org.junit.BeforeClass;
 
 import static com.google.common.collect.Maps.newHashMap;
@@ -42,6 +44,11 @@ public class DocumentBlobTrackerRegistra
         assumeTrue(MongoUtils.isAvailable());
     }
 
+    @Before
+    public void registerPreset() {
+        context.registerInjectActivateService(new 
DocumentNodeStoreService.Preset());
+    }
+
     @After
     @Override
     public void tearDown() throws Exception {
@@ -57,7 +64,9 @@ public class DocumentBlobTrackerRegistra
         properties.put("repository.home", repoHome);
         properties.put("mongouri", MongoUtils.URL);
         properties.put("db", MongoUtils.DB);
-        service = context.registerInjectActivateService(new 
DocumentNodeStoreService(), properties);
+        MockOsgi.setConfigForPid(context.bundleContext(),
+                DocumentNodeStoreService.class.getName(), properties);
+        service = context.registerInjectActivateService(new 
DocumentNodeStoreService());
     }
 
     @Override

Modified: 
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentCachingDataStoreStatsTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentCachingDataStoreStatsTest.java?rev=1816417&r1=1816416&r2=1816417&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentCachingDataStoreStatsTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentCachingDataStoreStatsTest.java
 Mon Nov 27 09:12:21 2017
@@ -28,6 +28,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
 import org.apache.sling.testing.mock.osgi.ReferenceViolationException;
 import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
 import org.junit.After;
@@ -128,6 +129,9 @@ public class DocumentCachingDataStoreSta
         properties.put("db", MongoUtils.DB);
         properties.put("repository.home", repoHome);
         properties.put(DocumentNodeStoreService.CUSTOM_BLOB_STORE, 
customBlobStore);
+        MockOsgi.setConfigForPid(context.bundleContext(),
+                DocumentNodeStoreService.class.getName(), properties);
+        context.registerInjectActivateService(new 
DocumentNodeStoreService.Preset());
         documentNodeStoreService =
             context.registerInjectActivateService(new 
DocumentNodeStoreService(), properties);
     }

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Configuration.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Configuration.java?rev=1816417&r1=1816416&r2=1816417&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Configuration.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Configuration.java
 Mon Nov 27 09:12:21 2017
@@ -23,14 +23,17 @@ import org.osgi.service.metatype.annotat
 import org.osgi.service.metatype.annotations.ObjectClassDefinition;
 import org.osgi.service.metatype.annotations.Option;
 
+import static org.apache.jackrabbit.oak.plugins.document.Configuration.PID;
 import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_CACHE_SEGMENT_COUNT;
 import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_CACHE_STACK_MOVE_DISTANCE;
 import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_CHILDREN_CACHE_PERCENTAGE;
 import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_DIFF_CACHE_PERCENTAGE;
 import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_NODE_CACHE_PERCENTAGE;
 import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_PREV_DOC_CACHE_PERCENTAGE;
+import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_UPDATE_LIMIT;
 
 @ObjectClassDefinition(
+        pid = {PID},
         name = "Apache Jackrabbit Oak Document NodeStore Service",
         description = "NodeStore implementation based on Document model. For 
configuration option refer " +
                 "to 
http://jackrabbit.apache.org/oak/docs/osgi_config.html#DocumentNodeStore. Note 
that for system " +
@@ -38,6 +41,11 @@ import static org.apache.jackrabbit.oak.
                 "should be done via file system based config file and this 
view should ONLY be used to determine which " +
                 "options are supported")
 @interface Configuration {
+
+    String PID = 
"org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService";
+
+    String PRESET_PID = PID + "Preset";
+
     @AttributeDefinition(
             name = "Mongo URI",
             description = "Mongo connection URI used to connect to Mongo. 
Refer to " +
@@ -121,7 +129,7 @@ import static org.apache.jackrabbit.oak.
             name = "Custom BlobStore",
             description = "Boolean value indicating that a custom BlobStore is 
to be used. " +
                     "By default, for MongoDB, MongoBlobStore is used; for RDB, 
RDBBlobStore is used.")
-    boolean customBlobStore() default false;
+    boolean customBlobStore() default 
DocumentNodeStoreService.DEFAULT_CUSTOM_BLOB_STORE;
 
 
     @AttributeDefinition(
@@ -141,7 +149,7 @@ import static org.apache.jackrabbit.oak.
             name = "Pre-fetch external changes",
             description = "Boolean value indicating if external changes should 
" +
                     "be pre-fetched in a background thread.")
-    boolean prefetchExternalChanges() default false;
+    boolean prefetchExternalChanges() default 
DocumentNodeStoreService.DEFAULT_PREFETCH_EXTERNAL_CHANGES;
 
     @AttributeDefinition(
             name = "NodeStoreProvider role",
@@ -168,7 +176,7 @@ import static org.apache.jackrabbit.oak.
                     "expression triggers a GC run every night at 2 AM: '" +
                     DocumentNodeStoreService.CLASSIC_RGC_EXPR + "'."
     )
-    String versionGCExpression() default "";
+    String versionGCExpression() default 
DocumentNodeStoreService.DEFAULT_VER_GC_EXPRESSION;
 
     @AttributeDefinition(
             name = "Time limit for a Version GC run (in sec)",
@@ -225,7 +233,7 @@ import static org.apache.jackrabbit.oak.
             name = "DocumentNodeStore update.limit",
             description = "Number of content updates that need to happen 
before " +
                     "the updates are automatically purged to the private 
branch.")
-    int updateLimit();
+    int updateLimit() default DEFAULT_UPDATE_LIMIT;
 
     @AttributeDefinition(
             name = "Persistent Cache Includes",

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java?rev=1816417&r1=1816416&r2=1816417&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
 Mon Nov 27 09:12:21 2017
@@ -22,6 +22,7 @@ import static com.google.common.base.Sup
 import static com.google.common.base.Suppliers.ofInstance;
 import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
 import static 
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_JOURNAL_GC_MAX_AGE_MILLIS;
+import static 
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreServiceConfiguration.PROP_UPDATE_LIMIT;
 import static 
org.apache.jackrabbit.oak.plugins.document.util.MongoConnection.readConcernLevel;
 
 import java.io.InputStream;
@@ -145,7 +146,7 @@ public class DocumentMK {
      * Number of content updates that need to happen before the updates
      * are automatically purged to the private branch.
      */
-    static final int UPDATE_LIMIT = Integer.getInteger("update.limit", 100000);
+    static final int UPDATE_LIMIT = Integer.getInteger("update.limit", 
Builder.DEFAULT_UPDATE_LIMIT);
 
     /**
      * The node store.
@@ -561,6 +562,7 @@ public class DocumentMK {
         public static final int DEFAULT_DIFF_CACHE_PERCENTAGE = 30;
         public static final int DEFAULT_CACHE_SEGMENT_COUNT = 16;
         public static final int DEFAULT_CACHE_STACK_MOVE_DISTANCE = 16;
+        public static final int DEFAULT_UPDATE_LIMIT = 100000;
         private DocumentNodeStore nodeStore;
         private Supplier<DocumentStore> documentStoreSupplier = ofInstance(new 
MemoryDocumentStore());
         private String mongoUri;

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java?rev=1816417&r1=1816416&r2=1816417&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
 Mon Nov 27 09:12:21 2017
@@ -22,16 +22,8 @@ import static com.google.common.base.Pre
 import static com.google.common.collect.Lists.newArrayList;
 import static java.util.Collections.emptyList;
 import static org.apache.jackrabbit.oak.commons.IOUtils.closeQuietly;
-import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toBoolean;
-import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toInteger;
 import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toLong;
-import static 
org.apache.jackrabbit.oak.osgi.OsgiUtil.lookupFrameworkThenConfiguration;
-import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_CACHE_SEGMENT_COUNT;
-import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_CACHE_STACK_MOVE_DISTANCE;
-import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_CHILDREN_CACHE_PERCENTAGE;
-import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_DIFF_CACHE_PERCENTAGE;
 import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_MEMORY_CACHE_SIZE;
-import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_NODE_CACHE_PERCENTAGE;
 import static 
org.apache.jackrabbit.oak.plugins.document.NodeDocument.MODIFIED_IN_SECS_RESOLUTION;
 import static 
org.apache.jackrabbit.oak.spi.blob.osgi.SplitBlobStoreService.ONLY_STANDALONE_TARGET;
 import static 
org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean;
@@ -70,7 +62,6 @@ import org.apache.jackrabbit.oak.api.jmx
 import org.apache.jackrabbit.oak.api.jmx.CheckpointMBean;
 import org.apache.jackrabbit.oak.api.jmx.PersistentCacheStatsMBean;
 import org.apache.jackrabbit.oak.cache.CacheStats;
-import org.apache.jackrabbit.oak.commons.PropertiesUtil;
 import 
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.VersionGCStats;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.apache.jackrabbit.oak.spi.commit.ObserverTracker;
@@ -112,6 +103,7 @@ import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
@@ -120,7 +112,6 @@ import org.osgi.service.component.annota
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.osgi.service.component.annotations.ReferencePolicy;
-import org.osgi.service.metatype.annotations.Designate;
 import org.quartz.CronExpression;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -130,8 +121,7 @@ import org.slf4j.LoggerFactory;
  */
 @Component(
         configurationPolicy = ConfigurationPolicy.REQUIRE,
-        service = {})
-@Designate(ocd = Configuration.class)
+        configurationPid = {Configuration.PID})
 public class DocumentNodeStoreService {
 
     private static final long MB = 1024 * 1024;
@@ -142,16 +132,18 @@ public class DocumentNodeStoreService {
     static final boolean DEFAULT_SO_KEEP_ALIVE = false;
     static final String DEFAULT_PERSISTENT_CACHE = "cache,binary=0";
     static final String DEFAULT_JOURNAL_CACHE = "diff-cache";
+    static final boolean DEFAULT_CUSTOM_BLOB_STORE = false;
     public static final String CONTINUOUS_RGC_EXPR = "*/5 * * * * ?";
     public static final String CLASSIC_RGC_EXPR = "0 0 2 * * ?";
     public static final long DEFAULT_RGC_TIME_LIMIT_SECS = 3*60*60; // default 
is 3 hours
-    private static final String PREFIX = "oak.documentstore.";
     private static final String DESCRIPTION = "oak.nodestore.description";
     static final long DEFAULT_JOURNAL_GC_INTERVAL_MILLIS = 5*60*1000; // 
default is 5min
     static final long DEFAULT_JOURNAL_GC_MAX_AGE_MILLIS = 24*60*60*1000; // 
default is 24hours
+    static final boolean DEFAULT_PREFETCH_EXTERNAL_CHANGES = false;
     private static final String DEFAULT_PROP_HOME = "./repository";
     static final long DEFAULT_MAX_REPLICATION_LAG = 6 * 60 * 60;
     static final boolean DEFAULT_BUNDLING_DISABLED = false;
+    static final String DEFAULT_VER_GC_EXPRESSION = "";
 
     /**
      * Revisions older than this time would be garbage collected
@@ -169,55 +161,12 @@ public class DocumentNodeStoreService {
      */
     static final long DEFAULT_BLOB_SNAPSHOT_INTERVAL = 12 * 60 * 60;
 
-    /**
-     * Name of framework property to configure Mongo Connection URI
-     */
-    private static final String FWK_PROP_URI = "oak.mongo.uri";
-
-    /**
-     * Name of framework property to configure Mongo Database name
-     * to use
-     */
-    private static final String FWK_PROP_DB = "oak.mongo.db";
-
-    /**
-     * Name of framework property to configure socket keep-alive for MongoDB
-     */
-    private static final String FWK_PROP_SO_KEEP_ALIVE = 
"oak.mongo.socketKeepAlive";
-
-
     // property name constants - values can come from framework properties or 
OSGi config
-    private static final String PROP_URI = "mongouri";
-    private static final String PROP_DB = "db";
-    static final String PROP_SO_KEEP_ALIVE = "socketKeepAlive";
-    private static final String PROP_CACHE = "cache";
-    private static final String PROP_NODE_CACHE_PERCENTAGE = 
"nodeCachePercentage";
-    private static final String PROP_PREV_DOC_CACHE_PERCENTAGE = 
"prevDocCachePercentage";
-    private static final String PROP_CHILDREN_CACHE_PERCENTAGE = 
"childrenCachePercentage";
-    private static final String PROP_DIFF_CACHE_PERCENTAGE = 
"diffCachePercentage";
-    private static final String PROP_CACHE_SEGMENT_COUNT = "cacheSegmentCount";
-    private static final String PROP_CACHE_STACK_MOVE_DISTANCE = 
"cacheStackMoveDistance";
-    private static final String PROP_BLOB_CACHE_SIZE = "blobCacheSize";
-    private static final String PROP_PERSISTENT_CACHE = "persistentCache";
-    private static final String PROP_JOURNAL_CACHE = "journalCache";
-    public static final String PROP_PREFETCH_EXTERNAL_CHANGES = 
"prefetchExternalChanges";
-    private static final String PROP_JOURNAL_GC_MAX_AGE_MILLIS = 
"journalGCMaxAge";
     public static final String CUSTOM_BLOB_STORE = "customBlobStore";
-    public static final String PROP_VER_GC_MAX_AGE = "versionGcMaxAgeInSecs";
-    public static final String PROP_VER_GC_EXPRESSION = "versionGCExpression";
-    public static final String PROP_VER_GC_TIME_LIMIT = 
"versionGCTimeLimitInSecs";
     public static final String PROP_REV_RECOVERY_INTERVAL = 
"lastRevRecoveryJobIntervalInSecs";
-    public static final String PROP_BLOB_GC_MAX_AGE = "blobGcMaxAgeInSecs";
-    public static final String PROP_BLOB_SNAPSHOT_INTERVAL = 
"blobTrackSnapshotIntervalInSecs";
-    private static final String PROP_HOME = "repository.home";
-    public static final String PROP_REPLICATION_LAG = 
"maxReplicationLagInSecs";
     public static final String PROP_DS_TYPE = "documentStoreType";
-    private static final String PROP_BUNDLING_DISABLED = "bundlingDisabled";
-    public static final String PROP_UPDATE_LIMIT = "updateLimit";
-    public static final String PROP_ROLE = "role";
-    private static final String PROP_JOURNAL_GC_INTERVAL_MILLIS = 
"journalGCInterval";
 
-    private static enum DocumentStoreType {
+    private enum DocumentStoreType {
         MONGO, RDB;
 
         static DocumentStoreType fromString(String type) {
@@ -248,30 +197,35 @@ public class DocumentNodeStoreService {
     private ComponentContext context;
     private Whiteboard whiteboard;
     private long deactivationTimestamp = 0;
-    private long maxReplicationLagInSecs;
 
     @Reference
     private StatisticsProvider statisticsProvider;
 
+    @Reference
+    private ConfigurationAdmin configurationAdmin;
+
+    @Reference(service = Preset.class)
+    private Preset preset;
+
     private boolean customBlobStore;
 
     private ServiceRegistration blobStoreReg;
 
     private BlobStore defaultBlobStore;
 
-    private volatile Configuration config;
+    private Configuration config;
 
     @Activate
     protected void activate(ComponentContext context, Configuration config) 
throws Exception {
         closer = Closer.create();
-        this.config = config;
+        this.config = DocumentNodeStoreServiceConfiguration.create(context,
+                configurationAdmin, preset.configuration, config);
         this.context = context;
         whiteboard = new OsgiWhiteboard(context.getBundleContext());
         executor = new WhiteboardExecutor();
         executor.start(whiteboard);
-        maxReplicationLagInSecs = config.maxReplicationLagInSecs();
-        customBlobStore = toBoolean(prop(CUSTOM_BLOB_STORE), false);
-        documentStoreType = 
DocumentStoreType.fromString(config.documentStoreType());
+        customBlobStore = this.config.customBlobStore();
+        documentStoreType = 
DocumentStoreType.fromString(this.config.documentStoreType());
 
         registerNodeStoreIfPossible();
     }
@@ -294,37 +248,21 @@ public class DocumentNodeStoreService {
     }
 
     private void registerNodeStore() throws IOException {
-        String uri = PropertiesUtil.toString(prop(PROP_URI, FWK_PROP_URI), 
DEFAULT_URI);
-        String db = PropertiesUtil.toString(prop(PROP_DB, FWK_PROP_DB), 
DEFAULT_DB);
-        boolean soKeepAlive = 
PropertiesUtil.toBoolean(prop(PROP_SO_KEEP_ALIVE, FWK_PROP_SO_KEEP_ALIVE), 
DEFAULT_SO_KEEP_ALIVE);
-
-        int cacheSize = toInteger(prop(PROP_CACHE), DEFAULT_CACHE);
-        int nodeCachePercentage = toInteger(prop(PROP_NODE_CACHE_PERCENTAGE), 
DEFAULT_NODE_CACHE_PERCENTAGE);
-        int prevDocCachePercentage = 
toInteger(prop(PROP_PREV_DOC_CACHE_PERCENTAGE), DEFAULT_NODE_CACHE_PERCENTAGE);
-        int childrenCachePercentage = 
toInteger(prop(PROP_CHILDREN_CACHE_PERCENTAGE), 
DEFAULT_CHILDREN_CACHE_PERCENTAGE);
-        int diffCachePercentage = toInteger(prop(PROP_DIFF_CACHE_PERCENTAGE), 
DEFAULT_DIFF_CACHE_PERCENTAGE);
-        int blobCacheSize = toInteger(prop(PROP_BLOB_CACHE_SIZE), 
DEFAULT_BLOB_CACHE_SIZE);
-        String persistentCache = getPath(PROP_PERSISTENT_CACHE, 
DEFAULT_PERSISTENT_CACHE);
-        String journalCache = getPath(PROP_JOURNAL_CACHE, 
DEFAULT_JOURNAL_CACHE);
-        int cacheSegmentCount = toInteger(prop(PROP_CACHE_SEGMENT_COUNT), 
DEFAULT_CACHE_SEGMENT_COUNT);
-        int cacheStackMoveDistance = 
toInteger(prop(PROP_CACHE_STACK_MOVE_DISTANCE), 
DEFAULT_CACHE_STACK_MOVE_DISTANCE);
-        boolean bundlingDisabled = toBoolean(prop(PROP_BUNDLING_DISABLED), 
DEFAULT_BUNDLING_DISABLED);
-        boolean prefetchExternalChanges = 
toBoolean(prop(PROP_PREFETCH_EXTERNAL_CHANGES), false);
-        int updateLimit = toInteger(prop(PROP_UPDATE_LIMIT), 
DocumentMK.UPDATE_LIMIT);
-        long journalGCMaxAge = 
toLong(context.getProperties().get(PROP_JOURNAL_GC_MAX_AGE_MILLIS), 
DEFAULT_JOURNAL_GC_MAX_AGE_MILLIS);
+        String persistentCache = resolvePath(config.persistentCache(), 
DEFAULT_PERSISTENT_CACHE);
+        String journalCache = resolvePath(config.journalCache(), 
DEFAULT_JOURNAL_CACHE);
         DocumentMK.Builder mkBuilder =
                 new DocumentMK.Builder().
                 setStatisticsProvider(statisticsProvider).
-                memoryCacheSize(cacheSize * MB).
+                memoryCacheSize(config.cache() * MB).
                 memoryCacheDistribution(
-                        nodeCachePercentage,
-                        prevDocCachePercentage,
-                        childrenCachePercentage, 
-                        diffCachePercentage).
-                setCacheSegmentCount(cacheSegmentCount).
-                setCacheStackMoveDistance(cacheStackMoveDistance).
-                setBundlingDisabled(bundlingDisabled).
-                        
setJournalPropertyHandlerFactory(journalPropertyHandlerFactory).
+                        config.nodeCachePercentage(),
+                        config.prevDocCachePercentage(),
+                        config.childrenCachePercentage(),
+                        config.diffCachePercentage()).
+                setCacheSegmentCount(config.cacheSegmentCount()).
+                setCacheStackMoveDistance(config.cacheStackMoveDistance()).
+                setBundlingDisabled(config.bundlingDisabled()).
+                
setJournalPropertyHandlerFactory(journalPropertyHandlerFactory).
                 setLeaseCheck(!ClusterNodeInfo.DEFAULT_LEASE_CHECK_DISABLED /* 
OAK-2739: enabled by default */).
                 setLeaseFailureHandler(new LeaseFailureHandler() {
                     
@@ -347,9 +285,9 @@ public class DocumentNodeStoreService {
                         }
                     }
                 }).
-                setPrefetchExternalChanges(prefetchExternalChanges).
-                setUpdateLimit(updateLimit).
-                setJournalGCMaxAge(journalGCMaxAge).
+                setPrefetchExternalChanges(config.prefetchExternalChanges()).
+                setUpdateLimit(config.updateLimit()).
+                setJournalGCMaxAge(config.journalGCMaxAge()).
                 setNodeCachePredicate(createCachePredicate());
 
         if (!Strings.isNullOrEmpty(persistentCache)) {
@@ -382,6 +320,10 @@ public class DocumentNodeStoreService {
                 log.info("Connected to datasource {}", dataSource);
             }
         } else {
+            String uri = config.mongouri();
+            String db = config.db();
+            boolean soKeepAlive = config.socketKeepAlive();
+
             MongoClientURI mongoURI = new MongoClientURI(uri);
 
             if (log.isInfoEnabled()) {
@@ -389,14 +331,14 @@ public class DocumentNodeStoreService {
                 // might contain passwords
                 log.info("Starting DocumentNodeStore with host={}, db={}, 
cache size (MB)={}, persistentCache={}, " +
                                 "journalCache={}, blobCacheSize (MB)={}, 
maxReplicationLagInSecs={}",
-                        mongoURI.getHosts(), db, cacheSize, persistentCache,
-                        journalCache, blobCacheSize, maxReplicationLagInSecs);
+                        mongoURI.getHosts(), db, config.cache(), 
persistentCache,
+                        journalCache, config.blobCacheSize(), 
config.maxReplicationLagInSecs());
                 log.info("Mongo Connection details {}", 
MongoConnection.toString(mongoURI.getOptions()));
             }
 
-            mkBuilder.setMaxReplicationLag(maxReplicationLagInSecs, 
TimeUnit.SECONDS);
+            mkBuilder.setMaxReplicationLag(config.maxReplicationLagInSecs(), 
TimeUnit.SECONDS);
             mkBuilder.setSocketKeepAlive(soKeepAlive);
-            mkBuilder.setMongoDB(uri, db, blobCacheSize);
+            mkBuilder.setMongoDB(uri, db, config.blobCacheSize());
 
             log.info("Connected to database '{}'", db);
         }
@@ -453,17 +395,14 @@ public class DocumentNodeStoreService {
             }
 
             if (blobStore instanceof BlobTrackingStore) {
-                final long trackSnapshotInterval = 
toLong(prop(PROP_BLOB_SNAPSHOT_INTERVAL),
-                    DEFAULT_BLOB_SNAPSHOT_INTERVAL);
-                String root = getRepositoryHome();
-
                 BlobTrackingStore trackingStore = (BlobTrackingStore) 
blobStore;
                 if (trackingStore.getTracker() != null) {
                     trackingStore.getTracker().close();
                 }
                 ((BlobTrackingStore) blobStore).addTracker(
-                    new BlobIdTracker(root, repoId, trackSnapshotInterval, 
(SharedDataStore)
-                        blobStore));
+                    new BlobIdTracker(getRepositoryHome(), repoId,
+                            config.blobTrackSnapshotIntervalInSecs(),
+                            (SharedDataStore) blobStore));
             }
         }
 
@@ -545,7 +484,7 @@ public class DocumentNodeStoreService {
     }
 
     private boolean isNodeStoreProvider() {
-        return prop(PROP_ROLE) != null;
+        return !Strings.isNullOrEmpty(config.role());
     }
 
     private boolean isContinuousRevisionGC() {
@@ -562,8 +501,8 @@ public class DocumentNodeStoreService {
         } else {
             defaultExpr = "";
         }
-        String expr = PropertiesUtil.toString(prop(PROP_VER_GC_EXPRESSION), 
"");
-        if (expr.isEmpty()) {
+        String expr = config.versionGCExpression();
+        if (Strings.isNullOrEmpty(expr)) {
             expr = defaultExpr;
         }
         // validate expression
@@ -579,14 +518,11 @@ public class DocumentNodeStoreService {
     }
 
     private void registerNodeStoreProvider(final NodeStore ns) {
-        Dictionary<String, Object> props = new Hashtable<String, Object>();
-        props.put(NodeStoreProvider.ROLE, prop(PROP_ROLE));
-        nodeStoreReg = 
context.getBundleContext().registerService(NodeStoreProvider.class.getName(), 
new NodeStoreProvider() {
-                    @Override
-                    public NodeStore getNodeStore() {
-                        return ns;
-                    }
-                },
+        Dictionary<String, Object> props = new Hashtable<>();
+        props.put(NodeStoreProvider.ROLE, config.role());
+        nodeStoreReg = context.getBundleContext().registerService(
+                NodeStoreProvider.class.getName(),
+                (NodeStoreProvider) () -> ns,
                 props);
         log.info("Registered NodeStoreProvider backed by DocumentNodeStore");
     }
@@ -737,35 +673,15 @@ public class DocumentNodeStoreService {
 
     private void registerJMXBeans(final DocumentNodeStore store, 
DocumentMK.Builder mkBuilder) throws
             IOException {
-        addRegistration(
-                registerMBean(whiteboard,
-                        CacheStatsMBean.class,
-                        store.getNodeCacheStats(),
-                        CacheStatsMBean.TYPE,
-                        store.getNodeCacheStats().getName()));
-        addRegistration(
-                registerMBean(whiteboard,
-                        CacheStatsMBean.class,
-                        store.getNodeChildrenCacheStats(),
-                        CacheStatsMBean.TYPE,
-                        store.getNodeChildrenCacheStats().getName())
-        );
+        registerCacheStatsMBean(store.getNodeCacheStats());
+        registerCacheStatsMBean(store.getNodeChildrenCacheStats());
         for (CacheStats cs : store.getDiffCacheStats()) {
-            addRegistration(
-                    registerMBean(whiteboard,
-                            CacheStatsMBean.class, cs,
-                            CacheStatsMBean.TYPE, cs.getName()));
+            registerCacheStatsMBean(cs);
         }
         DocumentStore ds = store.getDocumentStore();
         if (ds.getCacheStats() != null) {
             for (CacheStats cacheStats : ds.getCacheStats()) {
-                addRegistration(
-                        registerMBean(whiteboard,
-                                CacheStatsMBean.class,
-                                cacheStats,
-                                CacheStatsMBean.TYPE,
-                                cacheStats.getName())
-                );
+                registerCacheStatsMBean(cacheStats);
             }
         }
 
@@ -786,13 +702,7 @@ public class DocumentNodeStoreService {
         );
 
         if (mkBuilder.getBlobStoreCacheStats() != null) {
-            addRegistration(
-                    registerMBean(whiteboard,
-                            CacheStatsMBean.class,
-                            mkBuilder.getBlobStoreCacheStats(),
-                            CacheStatsMBean.TYPE,
-                            mkBuilder.getBlobStoreCacheStats().getName())
-            );
+            registerCacheStatsMBean(mkBuilder.getBlobStoreCacheStats());
         }
 
         if (mkBuilder.getDocumentStoreStatsCollector() instanceof 
DocumentStoreStatsMBean) {
@@ -817,9 +727,8 @@ public class DocumentNodeStoreService {
             );
         }
 
-
-        final long versionGcMaxAgeInSecs = toLong(prop(PROP_VER_GC_MAX_AGE), 
DEFAULT_VER_GC_MAX_AGE);
-        final long blobGcMaxAgeInSecs = toLong(prop(PROP_BLOB_GC_MAX_AGE), 
DEFAULT_BLOB_GC_MAX_AGE);
+        final long versionGcMaxAgeInSecs = config.versionGcMaxAgeInSecs();
+        final long blobGcMaxAgeInSecs = config.blobGcMaxAgeInSecs();
 
         if (store.getBlobStore() instanceof GarbageCollectableBlobStore) {
             BlobGarbageCollector gc = 
store.createBlobGarbageCollector(blobGcMaxAgeInSecs, 
@@ -859,6 +768,11 @@ public class DocumentNodeStoreService {
         }
     }
 
+    private void registerCacheStatsMBean(CacheStats cacheStats) {
+        addRegistration(registerMBean(whiteboard, CacheStatsMBean.class,
+                cacheStats, CacheStatsMBean.TYPE, cacheStats.getName()));
+    }
+
     private void registerLastRevRecoveryJob(final DocumentNodeStore nodeStore) 
{
         long leaseTime = 
toLong(context.getProperties().get(PROP_REV_RECOVERY_INTERVAL),
                 ClusterNodeInfo.DEFAULT_LEASE_UPDATE_INTERVAL_MILLIS);
@@ -868,12 +782,10 @@ public class DocumentNodeStoreService {
     }
 
     private void registerJournalGC(final DocumentNodeStore nodeStore) {
-        long journalGCInterval = 
toLong(context.getProperties().get(PROP_JOURNAL_GC_INTERVAL_MILLIS),
-                DEFAULT_JOURNAL_GC_INTERVAL_MILLIS);
         addRegistration(scheduleWithFixedDelay(whiteboard,
                 new JournalGCJob(nodeStore),
                 jobPropertiesFor(JournalGCJob.class),
-                TimeUnit.MILLISECONDS.toSeconds(journalGCInterval),
+                TimeUnit.MILLISECONDS.toSeconds(config.journalGCInterval()),
                 true/*runOnSingleClusterNode*/, true /*use dedicated pool*/));
     }
 
@@ -884,26 +796,18 @@ public class DocumentNodeStoreService {
         }
         Map<String, Object> props = jobPropertiesFor(RevisionGCJob.class);
         props.put("scheduler.expression", expr);
-        long versionGcMaxAgeInSecs = toLong(prop(PROP_VER_GC_MAX_AGE), 
DEFAULT_VER_GC_MAX_AGE);
-        long versionGCTimeLimitInSecs = toLong(prop(PROP_VER_GC_TIME_LIMIT), 
DEFAULT_RGC_TIME_LIMIT_SECS);
+        long versionGcMaxAgeInSecs = config.versionGcMaxAgeInSecs();
+        long versionGCTimeLimitInSecs = config.versionGCTimeLimitInSecs();
         addRegistration(scheduleWithFixedDelay(whiteboard,
                 new RevisionGCJob(nodeStore, versionGcMaxAgeInSecs,
                         versionGCTimeLimitInSecs),
                 props, MODIFIED_IN_SECS_RESOLUTION, true, true));
     }
 
-    private String prop(String propName) {
-        return prop(propName, PREFIX + propName);
-    }
-
-    private String prop(String propName, String fwkPropName) {
-        return lookupFrameworkThenConfiguration(context, propName, 
fwkPropName);
-    }
-
-    private String getPath(String propName, String defaultValue) {
-        String path = PropertiesUtil.toString(prop(propName), defaultValue);
-        if (Strings.isNullOrEmpty(path)) {
-            return path;
+    private String resolvePath(String value, String defaultValue) {
+        String path = value;
+        if (Strings.isNullOrEmpty(value)) {
+            path = defaultValue;
         }
         if ("-".equals(path)) {
             // disable this path configuration
@@ -914,7 +818,7 @@ public class DocumentNodeStoreService {
     }
 
     private String getRepositoryHome() {
-        String repoHome = prop(PROP_HOME, PROP_HOME);
+        String repoHome = config.repository_home();
         if (Strings.isNullOrEmpty(repoHome)) {
             repoHome = DEFAULT_PROP_HOME;
         }
@@ -1058,4 +962,17 @@ public class DocumentNodeStoreService {
         props.put("scheduler.name", clazz.getName());
         return props;
     }
+
+    @Component(
+            service = Preset.class,
+            configurationPid = Configuration.PRESET_PID)
+    public static class Preset {
+
+        Configuration configuration;
+
+        @Activate
+        void activate(Configuration configuration) {
+            this.configuration = configuration;
+        }
+    }
 }

Added: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfiguration.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfiguration.java?rev=1816417&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfiguration.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfiguration.java
 Mon Nov 27 09:12:21 2017
@@ -0,0 +1,203 @@
+/*
+ * 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.plugins.document;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.apache.jackrabbit.oak.osgi.OsgiUtil;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.ComponentContext;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Configuration for the {@link DocumentNodeStoreService}. Access is provided
+ * via {@link Configuration}, while internally the implementation considers
+ * entries in the following sequence:
+ * <ul>
+ *     <li>Framework/system properties, potentially with mapped names. See
+ *          {@link #frameworkPropertyNameFor(String)}.</li>
+ *     <li>OSGi configuration for {@link DocumentNodeStoreService} with
+ *          {@link Configuration#PID} if the property is set via the
+ *          OSGi Configuration Admin.</li>
+ *     <li>OSGi configuration with {@link Configuration#PRESET_PID}. The
+ *          default value for a configuration entry will be provided if the
+ *          OSGi Configuration Admin does not have an entry as a preset.</li>
+ * </ul>
+ */
+final class DocumentNodeStoreServiceConfiguration {
+
+    /**
+     * Default framework property name prefix.
+     */
+    private static final String DEFAULT_FWK_PREFIX = "oak.documentstore.";
+
+    /**
+     * Name of framework property to configure Mongo Connection URI
+     */
+    private static final String FWK_PROP_URI = "oak.mongo.uri";
+
+    /**
+     * Name of framework property to configure Mongo Database name
+     * to use
+     */
+    private static final String FWK_PROP_DB = "oak.mongo.db";
+
+    /**
+     * Name of framework property to configure socket keep-alive for MongoDB
+     */
+    private static final String FWK_PROP_SO_KEEP_ALIVE = 
"oak.mongo.socketKeepAlive";
+
+    /**
+     * Name of the framework property to configure the update limit.
+     */
+    private static final String FWK_PROP_UPDATE_LIMIT = "update.limit";
+
+    private static final String PROP_DB = "db";
+    private static final String PROP_URI = "mongouri";
+    private static final String PROP_HOME = "repository.home";
+    static final String PROP_SO_KEEP_ALIVE = "socketKeepAlive";
+    static final String PROP_UPDATE_LIMIT = "updateLimit";
+
+    /**
+     * Special mapping of property names to framework properties. All other
+     * property names are mapped to framework properties by prefixing them with
+     * {@link #DEFAULT_FWK_PREFIX}.
+     */
+    private static final Map<String, String> FWK_PROP_MAPPING = 
ImmutableMap.of(
+            PROP_DB, FWK_PROP_DB,
+            PROP_URI, FWK_PROP_URI,
+            PROP_HOME, PROP_HOME,
+            PROP_SO_KEEP_ALIVE, FWK_PROP_SO_KEEP_ALIVE,
+            PROP_UPDATE_LIMIT, FWK_PROP_UPDATE_LIMIT
+    );
+
+    private DocumentNodeStoreServiceConfiguration() {
+    }
+
+    static Configuration create(ComponentContext context,
+                                ConfigurationAdmin configurationAdmin,
+                                Configuration preset,
+                                Configuration configuration)
+            throws IOException {
+        return (Configuration) Proxy.newProxyInstance(
+                DocumentNodeStoreServiceConfiguration.class.getClassLoader(),
+                new Class[]{Configuration.class},
+                new ConfigurationHandler(context, configurationAdmin, preset, 
configuration)
+        );
+    }
+
+    private static String frameworkPropertyNameFor(String propertyName) {
+        String fwkPropName = FWK_PROP_MAPPING.get(propertyName);
+        if (fwkPropName == null) {
+            fwkPropName = DEFAULT_FWK_PREFIX + propertyName;
+        }
+        return fwkPropName;
+    }
+
+    private static final class ConfigurationHandler implements 
InvocationHandler {
+
+        private final ComponentContext context;
+
+        /**
+         * The preset configuration.
+         */
+        private final Configuration preset;
+
+        /**
+         * The configuration taking precedence over the preset.
+         */
+        private final Configuration configuration;
+
+        private final Set<String> configurationKeys;
+
+        ConfigurationHandler(ComponentContext context,
+                             ConfigurationAdmin configurationAdmin,
+                             Configuration preset,
+                             Configuration configuration) throws IOException {
+            this.context = checkNotNull(context);
+            this.preset = checkNotNull(preset);
+            this.configuration = checkNotNull(configuration);
+            this.configurationKeys = 
getConfigurationKeys(checkNotNull(configurationAdmin));
+        }
+
+        private static Set<String> getConfigurationKeys(ConfigurationAdmin 
configurationAdmin)
+                throws IOException {
+            Set<String> keys = new HashSet<>();
+            org.osgi.service.cm.Configuration c = 
configurationAdmin.getConfiguration(Configuration.PID);
+            for (Object k : Collections.list(c.getProperties().keys())) {
+                keys.add(k.toString());
+            }
+            return keys;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args)
+                throws Throwable {
+            String name = method.getName().replaceAll("_", ".");
+            Configuration c;
+            if (configurationKeys.contains(name)) {
+                c = configuration;
+            } else {
+                c = preset;
+            }
+            Object value = method.invoke(c);
+            // check if this is overridden by a framework property
+            String frameworkProp = OsgiUtil.lookup(
+                    context.getBundleContext(), 
frameworkPropertyNameFor(name));
+            if (frameworkProp != null) {
+                value = tryCoerce(frameworkProp, method.getReturnType(), 
value);
+            }
+            return value;
+        }
+
+        private Object tryCoerce(String value, Class<?> type, Object 
defaultValue) {
+            Object obj;
+            if (type == Boolean.class || type == boolean.class) {
+                obj = Boolean.parseBoolean(value);
+            } else if (type == Integer.class || type == int.class) {
+                try {
+                    obj = Integer.parseInt(value);
+                } catch (NumberFormatException e) {
+                    obj = defaultValue;
+                }
+            } else if (type == Long.class || type == long.class) {
+                try {
+                    obj = Long.parseLong(value);
+                } catch (NumberFormatException e) {
+                    obj = defaultValue;
+                }
+            } else if (type == String.class) {
+                obj = value;
+            } else {
+                obj = defaultValue;
+            }
+            return obj;
+        }
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfiguration.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfigurationTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfigurationTest.java?rev=1816417&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfigurationTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfigurationTest.java
 Mon Nov 27 09:12:21 2017
@@ -0,0 +1,168 @@
+/*
+ * 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.plugins.document;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Hashtable;
+
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.Rule;
+import org.junit.Test;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class DocumentNodeStoreServiceConfigurationTest {
+
+    @Rule
+    public final OsgiContext context = new OsgiContext();
+
+    private ConfigurationAdmin configAdmin = 
context.getService(ConfigurationAdmin.class);
+
+    private TestConfig configuration = new TestConfig(Configuration.PID);
+
+    private TestConfig preset = new TestConfig(Configuration.PRESET_PID);
+
+    @Test
+    public void defaultValues() throws Exception {
+        Configuration config = createConfiguration();
+        assertEquals(DocumentNodeStoreService.DEFAULT_URI, config.mongouri());
+        assertEquals(DocumentNodeStoreService.DEFAULT_DB, config.db());
+        assertEquals(DocumentNodeStoreService.DEFAULT_SO_KEEP_ALIVE, 
config.socketKeepAlive());
+        assertEquals(DocumentNodeStoreService.DEFAULT_CACHE, config.cache());
+        assertEquals(DocumentMK.Builder.DEFAULT_NODE_CACHE_PERCENTAGE, 
config.nodeCachePercentage());
+        assertEquals(DocumentMK.Builder.DEFAULT_PREV_DOC_CACHE_PERCENTAGE, 
config.prevDocCachePercentage());
+        assertEquals(DocumentMK.Builder.DEFAULT_CHILDREN_CACHE_PERCENTAGE, 
config.childrenCachePercentage());
+        assertEquals(DocumentMK.Builder.DEFAULT_DIFF_CACHE_PERCENTAGE, 
config.diffCachePercentage());
+        assertEquals(DocumentMK.Builder.DEFAULT_CACHE_SEGMENT_COUNT, 
config.cacheSegmentCount());
+        assertEquals(DocumentMK.Builder.DEFAULT_CACHE_STACK_MOVE_DISTANCE, 
config.cacheStackMoveDistance());
+        assertEquals(DocumentNodeStoreService.DEFAULT_BLOB_CACHE_SIZE, 
config.blobCacheSize());
+        assertEquals(DocumentNodeStoreService.DEFAULT_PERSISTENT_CACHE, 
config.persistentCache());
+        assertEquals(DocumentNodeStoreService.DEFAULT_JOURNAL_CACHE, 
config.journalCache());
+        assertEquals(DocumentNodeStoreService.DEFAULT_CUSTOM_BLOB_STORE, 
config.customBlobStore());
+        
assertEquals(DocumentNodeStoreService.DEFAULT_JOURNAL_GC_INTERVAL_MILLIS, 
config.journalGCInterval());
+        
assertEquals(DocumentNodeStoreService.DEFAULT_JOURNAL_GC_MAX_AGE_MILLIS, 
config.journalGCMaxAge());
+        
assertEquals(DocumentNodeStoreService.DEFAULT_PREFETCH_EXTERNAL_CHANGES, 
config.prefetchExternalChanges());
+        assertEquals(null, config.role());
+        assertEquals(DocumentNodeStoreService.DEFAULT_VER_GC_MAX_AGE, 
config.versionGcMaxAgeInSecs());
+        assertEquals(DocumentNodeStoreService.DEFAULT_VER_GC_EXPRESSION, 
config.versionGCExpression());
+        assertEquals(DocumentNodeStoreService.DEFAULT_RGC_TIME_LIMIT_SECS, 
config.versionGCTimeLimitInSecs());
+        assertEquals(DocumentNodeStoreService.DEFAULT_BLOB_GC_MAX_AGE, 
config.blobGcMaxAgeInSecs());
+        assertEquals(DocumentNodeStoreService.DEFAULT_BLOB_SNAPSHOT_INTERVAL, 
config.blobTrackSnapshotIntervalInSecs());
+        assertEquals(null, config.repository_home());
+        assertEquals(DocumentNodeStoreService.DEFAULT_MAX_REPLICATION_LAG, 
config.maxReplicationLagInSecs());
+        assertEquals("MONGO", config.documentStoreType());
+        assertEquals(DocumentNodeStoreService.DEFAULT_BUNDLING_DISABLED, 
config.bundlingDisabled());
+        assertEquals(DocumentMK.Builder.DEFAULT_UPDATE_LIMIT, 
config.updateLimit());
+        assertEquals(Arrays.asList("/"), 
Arrays.asList(config.persistentCacheIncludes()));
+    }
+
+    @Test
+    public void presetMongoURI() throws Exception {
+        String uri = "mongodb://localhost:27017/test";
+        addConfigurationEntry(preset, "mongouri", uri);
+        Configuration config = createConfiguration();
+        assertEquals(uri, config.mongouri());
+    }
+
+    @Test
+    public void presetSocketKeepAlive() throws Exception {
+        boolean keepAlive = !DocumentNodeStoreService.DEFAULT_SO_KEEP_ALIVE;
+        addConfigurationEntry(preset, "socketKeepAlive", keepAlive);
+        Configuration config = createConfiguration();
+        assertEquals(keepAlive, config.socketKeepAlive());
+    }
+
+    @Test
+    public void presetUpdateLimit() throws Exception {
+        int updateLimit = DocumentMK.Builder.DEFAULT_UPDATE_LIMIT / 2;
+        addConfigurationEntry(preset, "updateLimit", updateLimit);
+        Configuration config = createConfiguration();
+        assertEquals(updateLimit, config.updateLimit());
+    }
+
+    @Test
+    public void presetPersistentCacheIncludes() throws Exception {
+        String[] includes = new String[]{"/foo", "/bar"};
+        addConfigurationEntry(preset, "persistentCacheIncludes", includes);
+        Configuration config = createConfiguration();
+        assertTrue(Arrays.equals(includes, config.persistentCacheIncludes()));
+    }
+
+    @Test
+    public void presetOverridden() throws Exception {
+        String db = "test";
+        addConfigurationEntry(preset, "db", "foo");
+        addConfigurationEntry(configuration, "db", db);
+        Configuration config = createConfiguration();
+        assertEquals(db, config.db());
+    }
+
+    @Test
+    public void presetResetToDefault() throws Exception {
+        String db = "test";
+        addConfigurationEntry(preset, "db", db);
+        addConfigurationEntry(configuration, "db", 
DocumentNodeStoreService.DEFAULT_DB);
+        Configuration config = createConfiguration();
+        assertEquals(DocumentNodeStoreService.DEFAULT_DB, config.db());
+    }
+
+    private Configuration createConfiguration() throws IOException {
+        return DocumentNodeStoreServiceConfiguration.create(
+                context.componentContext(), configAdmin,
+                preset.asConfiguration(),
+                configuration.asConfiguration());
+    }
+
+    private void addConfigurationEntry(TestConfig config, String key, Object 
value)
+            throws IOException {
+        config.put(key, value);
+        org.osgi.service.cm.Configuration c = 
configAdmin.getConfiguration(config.servicePid);
+        c.update(new Hashtable(config));
+    }
+
+    private static class TestConfig extends HashMap<String, Object> {
+
+        final String servicePid;
+
+        TestConfig(String servicePid) {
+            this.servicePid = servicePid;
+        }
+
+        Configuration asConfiguration() {
+            return (Configuration) Proxy.newProxyInstance(
+                    
DocumentNodeStoreServiceConfigurationTest.class.getClassLoader(),
+                    new Class[]{Configuration.class},
+                    this::getProperty);
+        }
+
+        private Object getProperty(Object proxy, Method method, Object[] args) 
{
+            Object value = get(method.getName().replaceAll("_", "."));
+            if (value == null) {
+                value = method.getDefaultValue();
+            }
+            return value;
+        }
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfigurationTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceTest.java?rev=1816417&r1=1816416&r2=1816417&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceTest.java
 Mon Nov 27 09:12:21 2017
@@ -34,10 +34,12 @@ import org.apache.sling.testing.mock.osg
 import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 
+import static org.apache.jackrabbit.oak.plugins.document.Configuration.PID;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -56,12 +58,15 @@ public class DocumentNodeStoreServiceTes
 
     private final DocumentNodeStoreService service = new 
DocumentNodeStoreService();
 
+    private final DocumentNodeStoreService.Preset preset = new 
DocumentNodeStoreService.Preset();
+
     private String repoHome;
 
     @Before
     public void setUp() throws  Exception {
         assumeTrue(MongoUtils.isAvailable());
         context.registerService(StatisticsProvider.class, 
StatisticsProvider.NOOP);
+        context.registerInjectActivateService(preset);
         MockOsgi.injectServices(service, context.bundleContext());
         repoHome = target.newFolder().getAbsolutePath();
     }
@@ -123,7 +128,8 @@ public class DocumentNodeStoreServiceTes
 
     @Test
     public void journalPropertyTracker() throws Exception {
-        MockOsgi.activate(service, context.bundleContext(), 
newConfig(repoHome));
+        MockOsgi.setConfigForPid(context.bundleContext(), PID, 
newConfig(repoHome));
+        MockOsgi.activate(service, context.bundleContext());
         DocumentNodeStore store = context.getService(DocumentNodeStore.class);
         assertEquals(0, 
store.getJournalPropertyHandlerFactory().getServiceCount());
 
@@ -134,8 +140,9 @@ public class DocumentNodeStoreServiceTes
     @Test
     public void setUpdateLimit() throws Exception {
         Map<String, Object> config = newConfig(repoHome);
-        config.put(DocumentNodeStoreService.PROP_UPDATE_LIMIT, 17);
-        MockOsgi.activate(service, context.bundleContext(), config);
+        config.put(DocumentNodeStoreServiceConfiguration.PROP_UPDATE_LIMIT, 
17);
+        MockOsgi.setConfigForPid(context.bundleContext(), PID, config);
+        MockOsgi.activate(service, context.bundleContext());
         DocumentNodeStore store = context.getService(DocumentNodeStore.class);
         assertEquals(17, store.getUpdateLimit());
     }
@@ -143,8 +150,9 @@ public class DocumentNodeStoreServiceTes
     @Test
     public void keepAlive() throws Exception {
         Map<String, Object> config = newConfig(repoHome);
-        config.put(DocumentNodeStoreService.PROP_SO_KEEP_ALIVE, true);
-        MockOsgi.activate(service, context.bundleContext(), config);
+        config.put(DocumentNodeStoreServiceConfiguration.PROP_SO_KEEP_ALIVE, 
true);
+        MockOsgi.setConfigForPid(context.bundleContext(), PID, config);
+        MockOsgi.activate(service, context.bundleContext());
         DocumentNodeStore store = context.getService(DocumentNodeStore.class);
         MongoDocumentStore mds = getMongoDocumentStore(store);
         DB db = MongoDocumentStoreTestHelper.getDB(mds);
@@ -154,7 +162,8 @@ public class DocumentNodeStoreServiceTes
     @Test
     public void continuousRGCDefault() throws Exception {
         Map<String, Object> config = newConfig(repoHome);
-        MockOsgi.activate(service, context.bundleContext(), config);
+        MockOsgi.setConfigForPid(context.bundleContext(), PID, config);
+        MockOsgi.activate(service, context.bundleContext());
         boolean jobScheduled = false;
         for (Runnable r : context.getServices(Runnable.class, 
"(scheduler.expression=\\*/5 \\* \\* \\* \\* ?)")) {
             jobScheduled |= 
r.getClass().equals(DocumentNodeStoreService.RevisionGCJob.class);
@@ -165,7 +174,8 @@ public class DocumentNodeStoreServiceTes
     @Test
     public void continuousRGCJobAsSupplier() throws Exception {
         Map<String, Object> config = newConfig(repoHome);
-        MockOsgi.activate(service, context.bundleContext(), config);
+        MockOsgi.setConfigForPid(context.bundleContext(), PID, config);
+        MockOsgi.activate(service, context.bundleContext());
         Runnable rgcJob = null;
         for (Runnable r : context.getServices(Runnable.class, null)) {
             if 
(r.getClass().equals(DocumentNodeStoreService.RevisionGCJob.class)) {
@@ -181,7 +191,8 @@ public class DocumentNodeStoreServiceTes
     public void persistentCacheExclude() throws Exception{
         Map<String, Object> config = newConfig(repoHome);
         config.put("persistentCacheIncludes", new String[] {"/a/b", "/c/d ", 
null});
-        MockOsgi.activate(service, context.bundleContext(), config);
+        MockOsgi.setConfigForPid(context.bundleContext(), PID, config);
+        MockOsgi.activate(service, context.bundleContext());
 
         DocumentNodeStore dns = context.getService(DocumentNodeStore.class);
         assertTrue(dns.getNodeCachePredicate().apply("/a/b/c"));
@@ -190,6 +201,42 @@ public class DocumentNodeStoreServiceTes
         assertFalse(dns.getNodeCachePredicate().apply("/x"));
     }
 
+    @Ignore("SLING-7233")
+    @Test
+    public void preset() throws Exception {
+        MockOsgi.setConfigForPid(context.bundleContext(),
+                Configuration.PRESET_PID,
+                DocumentNodeStoreServiceConfiguration.PROP_SO_KEEP_ALIVE, 
true);
+        MockOsgi.activate(preset, context.bundleContext());
+
+        MockOsgi.setConfigForPid(context.bundleContext(), PID, 
newConfig(repoHome));
+        MockOsgi.activate(service, context.bundleContext());
+
+        DocumentNodeStore store = context.getService(DocumentNodeStore.class);
+        MongoDocumentStore mds = getMongoDocumentStore(store);
+        DB db = MongoDocumentStoreTestHelper.getDB(mds);
+        assertTrue(db.getMongo().getMongoOptions().isSocketKeepAlive());
+    }
+
+    @Test
+    public void presetOverride() throws Exception {
+        MockOsgi.setConfigForPid(context.bundleContext(),
+                Configuration.PRESET_PID,
+                DocumentNodeStoreServiceConfiguration.PROP_SO_KEEP_ALIVE, 
true);
+        MockOsgi.activate(preset, context.bundleContext());
+
+        Map<String, Object> config = newConfig(repoHome);
+        config.put(DocumentNodeStoreServiceConfiguration.PROP_SO_KEEP_ALIVE, 
false);
+        MockOsgi.setConfigForPid(context.bundleContext(), PID, config);
+
+        MockOsgi.activate(service, context.bundleContext());
+
+        DocumentNodeStore store = context.getService(DocumentNodeStore.class);
+        MongoDocumentStore mds = getMongoDocumentStore(store);
+        DB db = MongoDocumentStoreTestHelper.getDB(mds);
+        assertFalse(db.getMongo().getMongoOptions().isSocketKeepAlive());
+    }
+
     private static MongoDocumentStore getMongoDocumentStore(DocumentNodeStore 
s) {
         try {
             Field f = s.getClass().getDeclaredField("nonLeaseCheckingStore");
@@ -223,7 +270,8 @@ public class DocumentNodeStoreServiceTes
                                  Map<String, Object> config) {
         assertFalse(new File(expectedPath).exists());
 
-        MockOsgi.activate(service, context.bundleContext(), config);
+        MockOsgi.setConfigForPid(context.bundleContext(), PID, config);
+        MockOsgi.activate(service, context.bundleContext());
 
         assertNotNull(context.getService(NodeStore.class));
         // must exist after service was activated
@@ -249,8 +297,8 @@ public class DocumentNodeStoreServiceTes
     private void assertNoCachePath(String unexpectedPath,
                                    Map<String, Object> config) {
         assertFalse(new File(unexpectedPath).exists());
-
-        MockOsgi.activate(service, context.bundleContext(), config);
+        MockOsgi.setConfigForPid(context.bundleContext(), PID, config);
+        MockOsgi.activate(service, context.bundleContext());
 
         assertNotNull(context.getService(NodeStore.class));
         // must not exist after service was activated


Reply via email to