Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java?rev=1835837&r1=1835836&r2=1835837&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java
 Fri Jul 13 13:23:24 2018
@@ -21,40 +21,9 @@ package org.apache.jackrabbit.oak.segmen
 
 import static com.google.common.base.Strings.isNullOrEmpty;
 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.lookupConfigurationThenFramework;
-import static 
org.apache.jackrabbit.oak.plugins.blob.datastore.SharedDataStoreUtils.isShared;
 import static 
org.apache.jackrabbit.oak.segment.CachingSegmentReader.DEFAULT_STRING_CACHE_MB;
 import static 
org.apache.jackrabbit.oak.segment.CachingSegmentReader.DEFAULT_TEMPLATE_CACHE_MB;
 import static 
org.apache.jackrabbit.oak.segment.SegmentCache.DEFAULT_SEGMENT_CACHE_MB;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.BACKUP_DIRECTORY;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.COMPACTION_DISABLE_ESTIMATION;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.COMPACTION_FORCE_TIMEOUT;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.COMPACTION_RETRY_COUNT;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.COMPACTION_SIZE_DELTA_ESTIMATION;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.CUSTOM_BLOB_STORE;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.CUSTOM_SEGMENT_STORE;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.DEFAULT_BLOB_GC_MAX_AGE;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.DEFAULT_BLOB_SNAPSHOT_INTERVAL;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.GC_PROGRESS_LOG;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.MEMORY_THRESHOLD;
-import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.MODE;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.NODE_DEDUPLICATION_CACHE_SIZE;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.PAUSE_COMPACTION;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.PROP_BLOB_GC_MAX_AGE;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.PROP_BLOB_SNAPSHOT_INTERVAL;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.REPOSITORY_HOME_DIRECTORY;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.RETAINED_GENERATIONS;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.SEGMENT_CACHE_SIZE;
-import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.SIZE;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.STANDBY;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.STRING_CACHE_SIZE;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.STRING_DEDUPLICATION_CACHE_SIZE;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.TEMPLATE_CACHE_SIZE;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.TEMPLATE_DEDUPLICATION_CACHE_SIZE;
-import static 
org.apache.jackrabbit.oak.segment.SegmentNotFoundExceptionListener.IGNORE_SNFE;
 import static 
org.apache.jackrabbit.oak.segment.WriterCacheManager.DEFAULT_NODE_CACHE_SIZE_OSGi;
 import static 
org.apache.jackrabbit.oak.segment.WriterCacheManager.DEFAULT_STRING_CACHE_SIZE_OSGi;
 import static 
org.apache.jackrabbit.oak.segment.WriterCacheManager.DEFAULT_TEMPLATE_CACHE_SIZE_OSGi;
@@ -67,996 +36,511 @@ import static org.apache.jackrabbit.oak.
 import static 
org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.RETRY_COUNT_DEFAULT;
 import static 
org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.SIZE_DELTA_ESTIMATION_DEFAULT;
 import static 
org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.DEFAULT_MAX_FILE_SIZE;
-import static 
org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder;
 import static 
org.apache.jackrabbit.oak.spi.blob.osgi.SplitBlobStoreService.ONLY_STANDALONE_TARGET;
-import static 
org.apache.jackrabbit.oak.spi.cluster.ClusterRepositoryInfo.getOrCreateId;
 
-import java.io.ByteArrayInputStream;
-import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import com.google.common.base.Supplier;
 import com.google.common.io.Closer;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.ConfigurationPolicy;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.apache.felix.scr.annotations.ReferencePolicy;
-import org.apache.felix.scr.annotations.ReferencePolicyOption;
-import org.apache.jackrabbit.commons.SimpleValueFactory;
-import org.apache.jackrabbit.oak.api.Descriptors;
-import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean;
-import org.apache.jackrabbit.oak.api.jmx.CheckpointMBean;
-import org.apache.jackrabbit.oak.api.jmx.FileStoreBackupRestoreMBean;
-import org.apache.jackrabbit.oak.backup.impl.FileStoreBackupRestoreImpl;
-import org.apache.jackrabbit.oak.cache.CacheStats;
-import org.apache.jackrabbit.oak.cache.CacheStatsMBeanWrapper;
 import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard;
-import org.apache.jackrabbit.oak.plugins.blob.BlobGC;
-import org.apache.jackrabbit.oak.plugins.blob.BlobGCMBean;
-import org.apache.jackrabbit.oak.plugins.blob.BlobGarbageCollector;
-import org.apache.jackrabbit.oak.plugins.blob.BlobTrackingStore;
-import org.apache.jackrabbit.oak.plugins.blob.MarkSweepGarbageCollector;
-import org.apache.jackrabbit.oak.plugins.blob.SharedDataStore;
-import org.apache.jackrabbit.oak.plugins.blob.datastore.BlobIdTracker;
-import 
org.apache.jackrabbit.oak.plugins.blob.datastore.SharedDataStoreUtils.SharedStoreRecordType;
-import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions;
-import org.apache.jackrabbit.oak.segment.compaction.SegmentRevisionGC;
-import org.apache.jackrabbit.oak.segment.compaction.SegmentRevisionGCMBean;
-import org.apache.jackrabbit.oak.segment.file.FileStore;
-import org.apache.jackrabbit.oak.segment.file.FileStoreBuilder;
-import org.apache.jackrabbit.oak.segment.file.FileStoreGCMonitor;
-import org.apache.jackrabbit.oak.segment.file.FileStoreStatsMBean;
-import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException;
-import org.apache.jackrabbit.oak.segment.file.MetricsIOMonitor;
-import org.apache.jackrabbit.oak.segment.file.tar.SegmentTarReader;
 import 
org.apache.jackrabbit.oak.segment.spi.persistence.SegmentNodeStorePersistence;
-import org.apache.jackrabbit.oak.segment.util.RoleUtils;
 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.apache.jackrabbit.oak.spi.commit.ObserverTracker;
-import org.apache.jackrabbit.oak.spi.descriptors.GenericDescriptors;
-import org.apache.jackrabbit.oak.spi.gc.GCMonitor;
-import org.apache.jackrabbit.oak.spi.gc.GCMonitorTracker;
-import org.apache.jackrabbit.oak.spi.state.NodeStore;
-import org.apache.jackrabbit.oak.spi.state.RevisionGC;
-import org.apache.jackrabbit.oak.spi.state.RevisionGCMBean;
-import org.apache.jackrabbit.oak.spi.whiteboard.AbstractServiceTracker;
-import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
 import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
-import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardExecutor;
-import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils;
-import org.apache.jackrabbit.oak.stats.Clock;
 import org.apache.jackrabbit.oak.stats.StatisticsProvider;
-import org.osgi.framework.Constants;
+import org.osgi.framework.BundleContext;
 import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Deactivate;
+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.component.annotations.ReferencePolicyOption;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * An OSGi wrapper for the segment node store.
  */
-@Component(policy = ConfigurationPolicy.REQUIRE,
-        metatype = true,
-        label = "Oak Segment Tar NodeStore service",
-        description = "Apache Jackrabbit Oak NodeStore implementation based on 
the segment model. " +
-                "For configuration refer to 
http://jackrabbit.apache.org/oak/docs/osgi_config.html#SegmentNodeStore. " +
-                "Note that for system stability purpose it is advisable to not 
change these settings " +
-                "at runtime. Instead the config change should be done via file 
system based config " +
-                "file and this view should ONLY be used to determine which 
options are supported."
-)
+@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = SegmentNodeStoreService.Configuration.class)
 public class SegmentNodeStoreService {
 
     private static final Logger log = 
LoggerFactory.getLogger(SegmentNodeStoreService.class);
 
-    @Property(
-            label = "Repository Home Directory",
-            description = "Path on the file system where repository data will 
be stored. "
-                    + "Defaults to the value of the framework property 
'repository.home' or to 'repository' "
-                    + "if that is neither specified."
-    )
+    // TODO(frm) This is only exposed to tests. Should it be removed?
+    public static final String CUSTOM_BLOB_STORE = "customBlobStore";
+
+    // TODO(frm) This is only exposed to tests. Should it be removed?
     public static final String REPOSITORY_HOME_DIRECTORY = "repository.home";
 
-    @Property(
-            label = "Mode",
-            description = "TarMK mode (64 for memory mapped file access, 32 
for normal file access). " +
-                    "Default value is taken from the 'sun.arch.data.model' 
system property."
+    private static final long DEFAULT_BLOB_SNAPSHOT_INTERVAL = 12 * 60 * 60;
+
+    private static final long DEFAULT_BLOB_GC_MAX_AGE = 24 * 60 * 60;
+
+    @ObjectClassDefinition(
+        name = "Oak Segment Tar NodeStore service",
+        description = "Apache Jackrabbit Oak NodeStore implementation based on 
" +
+            "the segment model. For configuration refer to 
http://jackrabbit.apache.org/oak/docs/osgi_config.html#SegmentNodeStore. " +
+            "Note that for system stability purpose it is advisable to not " +
+            "change these settings at runtime. Instead the config change 
should " +
+            "be done via file system based config file and this view should 
ONLY " +
+            "be used to determine which options are supported."
     )
-    public static final String MODE = "tarmk.mode";
+    @interface Configuration {
+
+        @AttributeDefinition(
+            name = "Repository Home Directory",
+            description = "Path on the file system where repository data will 
be stored. "
+                + "Defaults to the value of the framework property 
'repository.home' or to 'repository' "
+                + "if that is neither specified."
+        )
+        String repository_home() default "repository";
 
-    @Property(
-            intValue = DEFAULT_MAX_FILE_SIZE,
-            label = "Maximum tar file size (MB)",
+        @AttributeDefinition(
+            name = "Mode",
+            description = "TarMK mode (64 for memory mapped file access, 32 
for normal file access). " +
+                "Default value is taken from the 'sun.arch.data.model' system 
property."
+        )
+        String tarmk_mode() default "";
+
+        @AttributeDefinition(
+            name = "Maximum tar file size (MB)",
             description = "The maximum size of the tar files in megabytes. " +
-                    "Default value is '" + DEFAULT_MAX_FILE_SIZE + "'."
-    )
-    public static final String SIZE = "tarmk.size";
+                "Default value is '" + DEFAULT_MAX_FILE_SIZE + "'."
+        )
+        int tarmk_size() default DEFAULT_MAX_FILE_SIZE;
 
-    @Property(
-            intValue = DEFAULT_SEGMENT_CACHE_MB,
-            label = "Segment cache size (MB)",
+        @AttributeDefinition(
+            name = "Segment cache size (MB)",
             description = "Cache size for storing most recently used segments 
in megabytes. " +
-                    "Default value is '" + DEFAULT_SEGMENT_CACHE_MB + "'."
-    )
-    public static final String SEGMENT_CACHE_SIZE = "segmentCache.size";
+                "Default value is '" + DEFAULT_SEGMENT_CACHE_MB + "'."
+        )
+        int segmentCache_size() default DEFAULT_SEGMENT_CACHE_MB;
 
-    @Property(
-            intValue = DEFAULT_STRING_CACHE_MB,
-            label = "String cache size (MB)",
+        @AttributeDefinition(
+            name = "String cache size (MB)",
             description = "Cache size for storing most recently used strings 
in megabytes. " +
-                    "Default value is '" + DEFAULT_STRING_CACHE_MB + "'."
-    )
-    public static final String STRING_CACHE_SIZE = "stringCache.size";
+                "Default value is '" + DEFAULT_STRING_CACHE_MB + "'."
+        )
+        int stringCache_size() default DEFAULT_STRING_CACHE_MB;
 
-    @Property(
-            intValue = DEFAULT_TEMPLATE_CACHE_MB,
-            label = "Template cache size (MB)",
+        @AttributeDefinition(
+            name = "Template cache size (MB)",
             description = "Cache size for storing most recently used templates 
in megabytes. " +
-                    "Default value is '" + DEFAULT_TEMPLATE_CACHE_MB + "'."
-    )
-    public static final String TEMPLATE_CACHE_SIZE = "templateCache.size";
+                "Default value is '" + DEFAULT_TEMPLATE_CACHE_MB + "'."
+        )
+        int templateCache_size() default DEFAULT_TEMPLATE_CACHE_MB;
 
-    @Property(
-            intValue = DEFAULT_STRING_CACHE_SIZE_OSGi,
-            label = "String deduplication cache size (#items)",
+        @AttributeDefinition(
+            name = "String deduplication cache size (#items)",
             description = "Maximum number of strings to keep in the 
deduplication cache. " +
-                    "Default value is '" + DEFAULT_STRING_CACHE_SIZE_OSGi + 
"'."
-    )
-    public static final String STRING_DEDUPLICATION_CACHE_SIZE = 
"stringDeduplicationCache.size";
+                "Default value is '" + DEFAULT_STRING_CACHE_SIZE_OSGi + "'."
+        )
+        int stringDeduplicationCache_size() default 
DEFAULT_STRING_CACHE_SIZE_OSGi;
 
-    @Property(
-            intValue = DEFAULT_TEMPLATE_CACHE_SIZE_OSGi,
-            label = "Template deduplication cache size (#items)",
+        @AttributeDefinition(
+            name = "Template deduplication cache size (#items)",
             description = "Maximum number of templates to keep in the 
deduplication cache. " +
-                    "Default value is '" + DEFAULT_TEMPLATE_CACHE_SIZE_OSGi + 
"'."
-    )
-    public static final String TEMPLATE_DEDUPLICATION_CACHE_SIZE = 
"templateDeduplicationCache.size";
+                "Default value is '" + DEFAULT_TEMPLATE_CACHE_SIZE_OSGi + "'."
+        )
+        int templateDeduplicationCache_size() default 
DEFAULT_TEMPLATE_CACHE_SIZE_OSGi;
 
-    @Property(
-            intValue = DEFAULT_NODE_CACHE_SIZE_OSGi,
-            label = "Node deduplication cache size (#items)",
+        @AttributeDefinition(
+            name = "Node deduplication cache size (#items)",
             description = "Maximum number of node to keep in the deduplication 
cache. If the supplied " +
-                    "value is not a power of 2, it will be rounded up to the 
next power of 2. " +
-                    "Default value is '" + DEFAULT_NODE_CACHE_SIZE_OSGi + "'."
-    )
-    public static final String NODE_DEDUPLICATION_CACHE_SIZE = 
"nodeDeduplicationCache.size";
+                "value is not a power of 2, it will be rounded up to the next 
power of 2. " +
+                "Default value is '" + DEFAULT_NODE_CACHE_SIZE_OSGi + "'."
+        )
+        int nodeDeduplicationCache_size() default DEFAULT_NODE_CACHE_SIZE_OSGi;
 
-    @Property(
-            boolValue = PAUSE_DEFAULT,
-            label = "Pause compaction",
+        @AttributeDefinition(
+            name = "Pause compaction",
             description = "When set to true the compaction phase is skipped 
during garbage collection. " +
-                    "Default value is '" + PAUSE_DEFAULT + "'."
-    )
-    public static final String PAUSE_COMPACTION = "pauseCompaction";
+                "Default value is '" + PAUSE_DEFAULT + "'."
+        )
+        boolean pauseCompaction() default PAUSE_DEFAULT;
 
-    @Property(
-            intValue = RETRY_COUNT_DEFAULT,
-            label = "Compaction retries",
+        @AttributeDefinition(
+            name = "Compaction retries",
             description = "Number of tries to compact concurrent commits on 
top of already " +
-                    "compacted commits. " +
-                    "Default value is '" + RETRY_COUNT_DEFAULT + "'."
-    )
-    public static final String COMPACTION_RETRY_COUNT = 
"compaction.retryCount";
+                "compacted commits. " +
+                "Default value is '" + RETRY_COUNT_DEFAULT + "'."
+        )
+        int compaction_retryCount() default RETRY_COUNT_DEFAULT;
 
-    @Property(
-            intValue = FORCE_TIMEOUT_DEFAULT,
-            label = "Force compaction timeout",
+        @AttributeDefinition(
+            name = "Force compaction timeout",
             description = "Number of seconds to attempt to force compact 
concurrent commits on top " +
-                    "of already compacted commits after the maximum number of 
retries has been " +
-                    "reached. Forced compaction tries to acquire an exclusive 
write lock on the " +
-                    "node store, blocking concurrent write access as long as 
the lock is held. " +
-                    "Default value is '" + FORCE_TIMEOUT_DEFAULT + "'."
-    )
-    public static final String COMPACTION_FORCE_TIMEOUT = 
"compaction.force.timeout";
+                "of already compacted commits after the maximum number of 
retries has been " +
+                "reached. Forced compaction tries to acquire an exclusive 
write lock on the " +
+                "node store, blocking concurrent write access as long as the 
lock is held. " +
+                "Default value is '" + FORCE_TIMEOUT_DEFAULT + "'."
+        )
+        int compaction_force_timeout() default FORCE_TIMEOUT_DEFAULT;
 
-    @Property(
-            longValue = SIZE_DELTA_ESTIMATION_DEFAULT,
-            label = "Garbage collection repository size threshold",
+        @AttributeDefinition(
+            name = "Garbage collection repository size threshold",
             description = "Garbage collection will be skipped unless the 
repository grew at least by " +
-                    "the number of bytes specified. " +
-                    "Default value is '" + SIZE_DELTA_ESTIMATION_DEFAULT + "'."
-    )
-    public static final String COMPACTION_SIZE_DELTA_ESTIMATION = 
"compaction.sizeDeltaEstimation";
+                "the number of bytes specified. " +
+                "Default value is '" + SIZE_DELTA_ESTIMATION_DEFAULT + "'."
+        )
+        long compaction_sizeDeltaEstimation() default 
SIZE_DELTA_ESTIMATION_DEFAULT;
 
-    @Property(
-            boolValue = DISABLE_ESTIMATION_DEFAULT,
-            label = "Disable estimation phase",
+        @AttributeDefinition(
+            name = "Disable estimation phase",
             description = "Disables the estimation phase allowing garbage 
collection to run unconditionally. " +
-                    "Default value is '" + DISABLE_ESTIMATION_DEFAULT + "'."
-    )
-    public static final String COMPACTION_DISABLE_ESTIMATION = 
"compaction.disableEstimation";
+                "Default value is '" + DISABLE_ESTIMATION_DEFAULT + "'."
+        )
+        boolean compaction_disableEstimation() default 
DISABLE_ESTIMATION_DEFAULT;
 
-    @Property(
-            intValue = RETAINED_GENERATIONS_DEFAULT,
-            label = "Compaction retained generations",
+        @AttributeDefinition(
+            name = "Compaction retained generations",
             description = "Number of segment generations to retain during 
garbage collection. " +
                 "The number of generations defaults to " + 
RETAINED_GENERATIONS_DEFAULT + " and " +
                 "can't be changed. This configuration option is considered 
deprecated " +
                 "and will be removed in the future."
-    )
-    public static final String RETAINED_GENERATIONS = 
"compaction.retainedGenerations";
+        )
+        int compaction_retainedGenerations() default 
RETAINED_GENERATIONS_DEFAULT;
 
-    @Property(
-            intValue = MEMORY_THRESHOLD_DEFAULT,
-            label = "Compaction memory threshold",
+        @AttributeDefinition(
+            name = "Compaction memory threshold",
             description = "Threshold of available heap memory in percent of 
total heap memory below " +
-                    "which the compaction phase is canceled. 0 disables heap 
memory monitoring. " +
-                    "Default value is '" + MEMORY_THRESHOLD_DEFAULT + "'."
-    )
-    public static final String MEMORY_THRESHOLD = "compaction.memoryThreshold";
+                "which the compaction phase is canceled. 0 disables heap 
memory monitoring. " +
+                "Default value is '" + MEMORY_THRESHOLD_DEFAULT + "'."
+        )
+        int compaction_memoryThreshold() default MEMORY_THRESHOLD_DEFAULT;
 
-    @Property(
-            longValue = GC_PROGRESS_LOG_DEFAULT,
-            label = "Compaction progress log",
+        @AttributeDefinition(
+            name = "Compaction progress log",
             description = "The number of nodes compacted after which a status 
message is logged. " +
-                    "-1 disables progress logging. " +
-                    "Default value is '" + GC_PROGRESS_LOG_DEFAULT + "'."
-    )
-    public static final String GC_PROGRESS_LOG = "compaction.progressLog";
+                "-1 disables progress logging. " +
+                "Default value is '" + GC_PROGRESS_LOG_DEFAULT + "'."
+        )
+        long compaction_progressLog() default GC_PROGRESS_LOG_DEFAULT;
 
-    @Property(
-            boolValue = false,
-            label = "Standby mode",
+        @AttributeDefinition(
+            name = "Standby mode",
             description = "Flag indicating this component will not register as 
a NodeStore but as a " +
-                    "NodeStoreProvider instead. "  +
-                    "Default value is 'false'."
-    )
-    public static final String STANDBY = "standby";
+                "NodeStoreProvider instead. " +
+                "Default value is 'false'."
+        )
+        boolean standby() default false;
 
-    @Property(boolValue = false,
-            label = "Custom blob store",
+        @AttributeDefinition(
+            name = "Custom blob store",
             description = "Boolean value indicating that a custom BlobStore is 
used for storing " +
-                    "large binary values."
-    )
-    public static final String CUSTOM_BLOB_STORE = "customBlobStore";
+                "large binary values."
+        )
+        boolean customBlobStore() default false;
 
-    @Property(boolValue = false,
-            label = "Custom segment store",
+        @AttributeDefinition(
+            name = "Custom segment store",
             description = "Boolean value indicating that a custom (non-tar) 
segment store is used"
-    )
-    public static final String CUSTOM_SEGMENT_STORE = "customSegmentStore";
+        )
+        boolean customSegmentStore() default false;
 
-    @Property(
-            label = "Backup directory",
+        @AttributeDefinition(
+            name = "Backup directory",
             description = "Directory (relative to current working directory) 
for storing repository backups. " +
-                    "Defaults to 'repository.home/segmentstore-backup'."
-    )
-    public static final String BACKUP_DIRECTORY = "repository.backup.dir";
+                "Defaults to 'repository.home/segmentstore-backup'."
+        )
+        String repository_backup_dir() default "";
+
+        @AttributeDefinition(
+            name = "Blob gc max age (in secs)",
+            description = "The blob garbage collection logic will only 
consider those blobs which " +
+                "are not accessed recently (currentTime - lastModifiedTime > 
blobGcMaxAgeInSecs). " +
+                "For example with the default setting only those blobs which 
have been created " +
+                "at least 24 hours ago will be considered for garbage 
collection. " +
+                "Default value is '" + DEFAULT_BLOB_GC_MAX_AGE + "'."
+        )
+        long blobGcMaxAgeInSecs() default DEFAULT_BLOB_GC_MAX_AGE;
+
+        @AttributeDefinition(
+            name = "Blob tracking snapshot interval",
+            description = "Interval in seconds in which snapshots of locally 
tracked blob ids are " +
+                "taken and synchronized with the blob store. This should be 
configured to be " +
+                "less than the frequency of blob garbage collection so that 
deletions during blob " +
+                "garbage collection can be accounted for in the next garbage 
collection execution. " +
+                "Default value is '" + DEFAULT_BLOB_SNAPSHOT_INTERVAL + "'."
+        )
+        long blobTrackSnapshotIntervalInSecs() default 
DEFAULT_BLOB_SNAPSHOT_INTERVAL;
+
+    }
 
     @Reference(
-            cardinality = ReferenceCardinality.OPTIONAL_UNARY,
-            policy = ReferencePolicy.STATIC,
-            policyOption = ReferencePolicyOption.GREEDY,
-            target = ONLY_STANDALONE_TARGET
+        cardinality = ReferenceCardinality.OPTIONAL,
+        policy = ReferencePolicy.STATIC,
+        policyOption = ReferencePolicyOption.GREEDY,
+        target = ONLY_STANDALONE_TARGET
     )
     private volatile BlobStore blobStore;
 
     @Reference(
-            cardinality = ReferenceCardinality.OPTIONAL_UNARY,
-            policy = ReferencePolicy.STATIC,
-            policyOption = ReferencePolicyOption.GREEDY
+        cardinality = ReferenceCardinality.OPTIONAL,
+        policy = ReferencePolicy.STATIC,
+        policyOption = ReferencePolicyOption.GREEDY
     )
     private volatile SegmentNodeStorePersistence segmentStore;
 
     @Reference
     private StatisticsProvider statisticsProvider = StatisticsProvider.NOOP;
-    
-    private Closer closer;
 
-    /**
-     * Blob modified before this time duration would be considered for Blob GC
-     */
-    static final long DEFAULT_BLOB_GC_MAX_AGE = 24 * 60 * 60;
-
-    @Property(longValue = DEFAULT_BLOB_GC_MAX_AGE,
-            label = "Blob gc max age (in secs)",
-            description = "The blob garbage collection logic will only 
consider those blobs which " +
-                    "are not accessed recently (currentTime - lastModifiedTime 
> blobGcMaxAgeInSecs). " +
-                    "For example with the default setting only those blobs 
which have been created " +
-                    "at least 24 hours ago will be considered for garbage 
collection. " +
-                    "Default value is '" + DEFAULT_BLOB_GC_MAX_AGE + "'."
-    )
-    public static final String PROP_BLOB_GC_MAX_AGE = "blobGcMaxAgeInSecs";
-
-    /**
-     * Default interval for taking snapshots of locally tracked blob ids.
-     */
-    static final long DEFAULT_BLOB_SNAPSHOT_INTERVAL = 12 * 60 * 60;
-
-    @Property(longValue = DEFAULT_BLOB_SNAPSHOT_INTERVAL,
-            label = "Blob tracking snapshot interval",
-            description = "Interval in seconds in which snapshots of locally 
tracked blob ids are " +
-                    "taken and synchronized with the blob store. This should 
be configured to be " +
-                    "less than the frequency of blob garbage collection so 
that deletions during blob " +
-                    "garbage collection can be accounted for in the next 
garbage collection execution. " +
-                    "Default value is '" + DEFAULT_BLOB_SNAPSHOT_INTERVAL + 
"'."
-    )
-    public static final String PROP_BLOB_SNAPSHOT_INTERVAL = 
"blobTrackSnapshotIntervalInSecs";
+    private final Closer closer = Closer.create();
 
     @Activate
-    public void activate(ComponentContext context) throws IOException {
-        Configuration configuration = new Configuration(context);
-        if (blobStore == null && configuration.hasCustomBlobStore()) {
-            log.info("BlobStore enabled. SegmentNodeStore will be initialized 
once the blob " +
-                    "store becomes available");
-            return;
-        }
-        if (segmentStore == null && configuration.hasCustomSegmentStore()) {
-            log.info("customSegmentStore enabled. SegmentNodeStore will be 
initialized once the custom segment " +
-                    "store becomes available");
-            return;
-        }
-        closer = Closer.create();
+    public void activate(ComponentContext context, Configuration 
configuration) throws IOException {
         OsgiWhiteboard whiteboard = new 
OsgiWhiteboard(context.getBundleContext());
-        registerSegmentStore(context, blobStore, segmentStore, 
statisticsProvider, closer, whiteboard, null, true);
+        registerSegmentStore(context, configuration, blobStore, segmentStore, 
statisticsProvider, closer, whiteboard, log);
     }
 
-    /**
-     * Configures and registers a new SegmentNodeStore instance together will
-     * all required components. Anything that must be disposed of (like
-     * registered services or MBeans) will be registered via the
-     * {@code registration} parameter.
-     *
-     * @param context            An instance of {@link ComponentContext}.
-     * @param blobStore          An instance of {@link BlobStore}. It can be
-     *                           {@code null}.
-     * @param segmentStore       An instance of {@link 
SegmentNodeStorePersistence}. It can be
-     *                           {@code null}.
-     * @param statisticsProvider An instance of {@link StatisticsProvider}.
-     * @param closer             An instance of {@link Closer}. It will be used
-     *                           to track every registered service or
-     *                           component.
-     * @param whiteboard         An instance of {@link Whiteboard}. It will be
-     *                           used to register services in the OSGi
-     *                           framework.
-     * @param role               The role of this component. It can be {@code
-     *                           null}.
-     * @param descriptors        Determines if repository descriptors related 
to
-     *                           discovery services should be registered.
-     * @return A configured {@link SegmentNodeStore}, or {@code null} if the
-     * setup failed.
-     * @throws IOException In case an unrecoverable error occurs.
-     */
-    static SegmentNodeStore registerSegmentStore(
-            @Nonnull ComponentContext context,
-            @Nullable BlobStore blobStore,
-            @Nullable SegmentNodeStorePersistence segmentStore,
-            @Nonnull StatisticsProvider statisticsProvider,
-            @Nonnull Closer closer,
-            @Nonnull Whiteboard whiteboard,
-            @Nullable String role,
-            boolean descriptors
+    private static SegmentNodeStore registerSegmentStore(
+        ComponentContext context,
+        Configuration configuration,
+        BlobStore blobStore,
+        SegmentNodeStorePersistence segmentStore,
+        StatisticsProvider statisticsProvider,
+        Closer closer,
+        Whiteboard whiteboard,
+        Logger logger
     ) throws IOException {
-        Configuration configuration = new Configuration(context, role);
-        Closeables closeables = new Closeables(closer);
-        Registrations registrations = new Registrations(whiteboard, role);
-
-        // Listen for GCMonitor services
-        GCMonitor gcMonitor = GCMonitor.EMPTY;
-
-        if (configuration.isPrimarySegmentStore()) {
-            GCMonitorTracker tracker = new GCMonitorTracker();
-            tracker.start(whiteboard);
-            closeables.add(tracker);
-            gcMonitor = tracker;
-        }
-
-        // Create the gc options
-        if (configuration.getCompactionGainThreshold() != null) {
-            log.warn("Detected deprecated flag 'compaction.gainThreshold'. "
-                    + "Please use 'compaction.sizeDeltaEstimation' instead and 
"
-                    + "'compaction.disableEstimation' to disable estimation.");
-        }
-        if (configuration.getRetainedGenerations() != 
RETAINED_GENERATIONS_DEFAULT) {
-            log.warn(
-                "The number of retained generations defaults to {} and can't 
be " +
-                    "changed. This configuration option is considered 
deprecated " +
-                    "and will be removed in the future.",
-                RETAINED_GENERATIONS_DEFAULT
-            );
-        }
-        SegmentGCOptions gcOptions = new 
SegmentGCOptions(configuration.getPauseCompaction(), 
configuration.getRetryCount(), configuration.getForceCompactionTimeout())
-                
.setGcSizeDeltaEstimation(configuration.getSizeDeltaEstimation())
-                .setMemoryThreshold(configuration.getMemoryThreshold())
-                .setEstimationDisabled(configuration.getDisableEstimation())
-                .setGCLogInterval(configuration.getGCProcessLog());
-        if (configuration.isStandbyInstance()) {
-            gcOptions.setRetainedGenerations(1);
-        }
-
-        // Build the FileStore
-        FileStoreBuilder builder = 
fileStoreBuilder(configuration.getSegmentDirectory())
-                .withSegmentCacheSize(configuration.getSegmentCacheSize())
-                .withStringCacheSize(configuration.getStringCacheSize())
-                .withTemplateCacheSize(configuration.getTemplateCacheSize())
-                
.withStringDeduplicationCacheSize(configuration.getStringDeduplicationCacheSize())
-                
.withTemplateDeduplicationCacheSize(configuration.getTemplateDeduplicationCacheSize())
-                
.withNodeDeduplicationCacheSize(configuration.getNodeDeduplicationCacheSize())
-                .withMaxFileSize(configuration.getMaxFileSize())
-                .withMemoryMapping(configuration.getMemoryMapping())
-                .withGCMonitor(gcMonitor)
-                .withIOMonitor(new MetricsIOMonitor(statisticsProvider))
-                .withIOLogging(LoggerFactory.getLogger(SegmentTarReader.class))
-                .withStatisticsProvider(statisticsProvider)
-                .withGCOptions(gcOptions);
-
-        if (configuration.hasCustomBlobStore() && blobStore != null) {
-            log.info("Initializing SegmentNodeStore with BlobStore [{}]", 
blobStore);
-            builder.withBlobStore(blobStore);
-        }
-
-        if (configuration.hasCustomSegmentStore() && segmentStore != null) {
-            log.info("Initializing SegmentNodeStore with custom persistence 
[{}]", segmentStore);
-            builder.withCustomPersistence(segmentStore);
-        }
-
-        if (configuration.isStandbyInstance()) {
-            builder.withSnfeListener(IGNORE_SNFE);
-        }
-
-        final FileStore store;
-        try {
-            store = builder.build();
-        } catch (InvalidFileStoreVersionException e) {
-            log.error("The storage format is not compatible with this version 
of Oak Segment Tar", e);
-            return null;
-        }
-        // store should be closed last
-        closeables.add(store);
-
-        // Listen for Executor services on the whiteboard
-
-        WhiteboardExecutor executor = new WhiteboardExecutor();
-        executor.start(whiteboard);
-        closeables.add(executor);
-
-        // Expose stats about the segment cache
-
-        CacheStatsMBean segmentCacheStats = 
addRoleToName(store.getSegmentCacheStats(), role);
-        closeables.add(registrations.registerMBean(
-                CacheStatsMBean.class,
-                segmentCacheStats,
-                CacheStats.TYPE,
-                segmentCacheStats.getName()
-        ));
-
-        // Expose stats about the string and template caches
-
-        CacheStatsMBean stringCacheStats = 
addRoleToName(store.getStringCacheStats(), role);
-        closeables.add(registrations.registerMBean(
-                CacheStatsMBean.class,
-                stringCacheStats,
-                CacheStats.TYPE,
-                stringCacheStats.getName()
-        ));
-
-        CacheStatsMBean templateCacheStats = 
addRoleToName(store.getTemplateCacheStats(), role);
-        closeables.add(registrations.registerMBean(
-                CacheStatsMBean.class,
-                templateCacheStats,
-                CacheStats.TYPE,
-                templateCacheStats.getName()
-        ));
-
-        WriterCacheManager cacheManager = builder.getCacheManager();
-        CacheStatsMBean stringDeduplicationCacheStats = 
addRoleToName(cacheManager.getStringCacheStats(), role);
-        if (stringDeduplicationCacheStats != null) {
-            closeables.add(registrations.registerMBean(
-                    CacheStatsMBean.class,
-                    stringDeduplicationCacheStats,
-                    CacheStats.TYPE,
-                    stringDeduplicationCacheStats.getName()
-            ));
-        }
-
-        CacheStatsMBean templateDeduplicationCacheStats = 
addRoleToName(cacheManager.getTemplateCacheStats(), role);
-        if (templateDeduplicationCacheStats != null) {
-            closeables.add(registrations.registerMBean(
-                    CacheStatsMBean.class,
-                    templateDeduplicationCacheStats,
-                    CacheStats.TYPE,
-                    templateDeduplicationCacheStats.getName()
-            ));
-        }
-
-        CacheStatsMBean nodeDeduplicationCacheStats = 
addRoleToName(cacheManager.getNodeCacheStats(), role);
-        if (nodeDeduplicationCacheStats != null) {
-            closeables.add(registrations.registerMBean(
-                    CacheStatsMBean.class,
-                    nodeDeduplicationCacheStats,
-                    CacheStats.TYPE,
-                    nodeDeduplicationCacheStats.getName()
-            ));
-        }
-
-        // Expose an MBean to managing and monitoring garbage collection
-        final FileStoreGCMonitor monitor = new 
FileStoreGCMonitor(Clock.SIMPLE);
-        closeables.add(registrations.register(
-                GCMonitor.class,
-                monitor
-        ));
-        if (!configuration.isStandbyInstance()) {
-            closeables.add(registrations.registerMBean(
-                    SegmentRevisionGC.class,
-                    new SegmentRevisionGCMBean(store, gcOptions, monitor),
-                    SegmentRevisionGC.TYPE,
-                    "Segment node store revision garbage collection"
-            ));
-        }
-
-        Runnable cancelGC = new Runnable() {
-
-            @Override
-            public void run() {
-                store.cancelGC();
-            }
-
-        };
-        Supplier<String> statusMessage = new Supplier<String>() {
-
-            @Override
-            public String get() {
-                return monitor.getStatus();
-            }
-
-        };
-        closeables.add(registrations.registerMBean(
-                RevisionGCMBean.class,
-                new RevisionGC(store.getGCRunner(), cancelGC, statusMessage, 
executor),
-                RevisionGCMBean.TYPE,
-                "Revision garbage collection"
-        ));
-
-        // Expose statistics about the FileStore
-
-        closeables.add(registrations.registerMBean(
-                FileStoreStatsMBean.class,
-                store.getStats(),
-                FileStoreStatsMBean.TYPE,
-                "FileStore statistics"
-        ));
-
-        // register segment node store
-
-        SegmentNodeStore.SegmentNodeStoreBuilder segmentNodeStoreBuilder = 
SegmentNodeStoreBuilders.builder(store).withStatisticsProvider(statisticsProvider);
-        if (configuration.isStandbyInstance() || 
!configuration.isPrimarySegmentStore()) {
-            segmentNodeStoreBuilder.dispatchChanges(false);
-        }
-        SegmentNodeStore segmentNodeStore = segmentNodeStoreBuilder.build();
-
-        if (configuration.isPrimarySegmentStore()) {
-            ObserverTracker observerTracker = new 
ObserverTracker(segmentNodeStore);
-            observerTracker.start(context.getBundleContext());
-            closeables.add(observerTracker);
-        }
-
-        if (configuration.isPrimarySegmentStore()) {
-            closeables.add(registrations.registerMBean(
-                    CheckpointMBean.class,
-                    new SegmentCheckpointMBean(segmentNodeStore),
-                    CheckpointMBean.TYPE,
-                    "Segment node store checkpoint management"
-            ));
-        }
-
-        if (descriptors) {
-            // ensure a clusterId is initialized
-            // and expose it as 'oak.clusterid' repository descriptor
-            GenericDescriptors clusterIdDesc = new GenericDescriptors();
-            clusterIdDesc.put(
-                    
ClusterRepositoryInfo.OAK_CLUSTERID_REPOSITORY_DESCRIPTOR_KEY,
-                    new 
SimpleValueFactory().createValue(getOrCreateId(segmentNodeStore)),
-                    true,
-                    false
-            );
-            closeables.add(registrations.register(Descriptors.class, 
clusterIdDesc));
-            // Register "discovery lite" descriptors
-            closeables.add(registrations.register(Descriptors.class, new 
SegmentDiscoveryLiteDescriptors(segmentNodeStore)));
-        }
-
-        // If a shared data store register the repo id in the data store
-        if (configuration.isPrimarySegmentStore() && isShared(blobStore)) {
-            SharedDataStore sharedDataStore = (SharedDataStore) blobStore;
-            try {
-                sharedDataStore.addMetadataRecord(new ByteArrayInputStream(new 
byte[0]), 
SharedStoreRecordType.REPOSITORY.getNameFromId(getOrCreateId(segmentNodeStore)));
-            } catch (Exception e) {
-                throw new IOException("Could not register a unique 
repositoryId", e);
-            }
-            if (blobStore instanceof BlobTrackingStore) {
-                BlobTrackingStore trackingStore = (BlobTrackingStore) 
blobStore;
-                if (trackingStore.getTracker() != null) {
-                    trackingStore.getTracker().close();
-                }
-                trackingStore.addTracker(new 
BlobIdTracker(configuration.getRepositoryHome(), 
getOrCreateId(segmentNodeStore), configuration.getBlobSnapshotInterval(), 
sharedDataStore));
-            }
-        }
+        return SegmentNodeStoreRegistrar.registerSegmentNodeStore(new 
SegmentNodeStoreRegistrar.Configuration() {
 
-        if (configuration.isPrimarySegmentStore() && blobStore instanceof 
GarbageCollectableBlobStore) {
-            BlobGarbageCollector gc = new MarkSweepGarbageCollector(
-                    new SegmentBlobReferenceRetriever(store),
-                    (GarbageCollectableBlobStore) blobStore,
-                    executor,
-                    TimeUnit.SECONDS.toMillis(configuration.getBlobGcMaxAge()),
-                    getOrCreateId(segmentNodeStore),
-                    whiteboard,
-                    statisticsProvider
-            );
-            closeables.add(registrations.registerMBean(
-                    BlobGCMBean.class,
-                    new BlobGC(gc, executor),
-                    BlobGCMBean.TYPE,
-                    "Segment node store blob garbage collection"
-            ));
-        }
-
-        // Expose an MBean for backup/restore operations
-
-        closeables.add(registrations.registerMBean(
-                FileStoreBackupRestoreMBean.class,
-                new FileStoreBackupRestoreImpl(
-                        segmentNodeStore,
-                        store.getRevisions(),
-                        store.getReader(),
-                        configuration.getBackupDirectory(),
-                        executor
-                ),
-                FileStoreBackupRestoreMBean.TYPE,
-                "Segment node store backup/restore"
-        ));
-
-        // Expose statistics about the SegmentNodeStore
-        
-        closeables.add(registrations.registerMBean(
-                SegmentNodeStoreStatsMBean.class,
-                segmentNodeStore.getStats(),
-                SegmentNodeStoreStatsMBean.TYPE,
-                "SegmentNodeStore statistics"
-        ));
-
-        if (configuration.isPrimarySegmentStore()) {
-            log.info("Primary SegmentNodeStore initialized");
-        } else {
-            log.info("Secondary SegmentNodeStore initialized, role={}", role);
-        }
-
-        // Register a factory service to expose the FileStore
-        closeables.add(registrations.register(
-                SegmentStoreProvider.class,
-                new DefaultSegmentStoreProvider(store)
-        ));
-
-        if (configuration.isStandbyInstance()) {
-            return segmentNodeStore;
-        }
-
-        if (configuration.isPrimarySegmentStore()) {
-            Map<String, Object> props = new HashMap<String, Object>();
-            props.put(Constants.SERVICE_PID, SegmentNodeStore.class.getName());
-            props.put("oak.nodestore.description", new String[] 
{"nodeStoreType=segment"});
-            closeables.add(registrations.register(NodeStore.class, 
segmentNodeStore, props));
-        }
+            int roundToNextPowerOfTwo(int size) {
+                return 1 << (32 - Integer.numberOfLeadingZeros(Math.max(0, 
size - 1)));
+            }
 
-        return segmentNodeStore;
-    }
+            String getMode() {
+                String mode = configuration.tarmk_mode();
+                if (isNullOrEmpty(mode)) {
+                    return System.getProperty("tarmk.mode", 
System.getProperty("sun.arch.data.model", "32"));
+                }
+                return mode;
+            }
 
-    @Deactivate
-    public void deactivate() {
-        closeQuietly(closer);
-        closer = null;
-    }
+            int getCacheSize(String name, int otherwise) {
+                Integer size = Integer.getInteger(name);
+                if (size != null) {
+                    return size;
+                }
+                return otherwise;
+            }
 
-    private static CacheStatsMBean addRoleToName(CacheStatsMBean 
cacheStatsMBean, String role) {
-        return new CacheStatsMBeanWrapper(cacheStatsMBean) {
             @Override
-            public String getName() {
-                return RoleUtils.maybeAppendRole(super.getName(), role);
+            public boolean isPrimarySegmentStore() {
+                return true;
             }
-        };
-    }
-}
-
-/**
- * Encapsulates a {@link Closer} and makes it easier to track the lifecycle
- * of entities that can be disposed.
- */
-class Closeables implements Closeable {
-
-    private final Closer closer;
-
-    Closeables(Closer closer) {
-        this.closer = closer;
-    }
-
-    void add(Closeable c) {
-        closer.register(c);
-    }
-
-    void add(final AbstractServiceTracker<?> t) {
-        add(new Closeable() {
 
             @Override
-            public void close() {
-                t.stop();
+            public boolean isSecondarySegmentStore() {
+                return false;
             }
 
-        });
-    }
-
-    void add(final Registration r) {
-        add(new Closeable() {
-
             @Override
-            public void close() {
-                r.unregister();
+            public boolean isStandbyInstance() {
+                return configuration.standby();
             }
 
-        });
-    }
-
-    void add(final ObserverTracker t) {
-        add(new Closeable() {
-
             @Override
-            public void close() {
-                t.stop();
+            public String getRole() {
+                return null;
             }
 
-        });
-    }
-
-    @Override
-    public void close() throws IOException {
-        closer.close();
-    }
-
-}
-
-/**
- * Allows simple access to the configuration of this component. Provides
- * default values for unspecified properties and type conversion.
- */
-class Configuration {
-
-    private static int roundToNextPowerOfTwo(int size) {
-        return 1 << (32 - Integer.numberOfLeadingZeros(Math.max(0, size - 1)));
-    }
-
-    private final ComponentContext context;
-
-    private final String role;
-
-    Configuration(ComponentContext context) {
-        this(context, null);
-    }
-
-    Configuration(ComponentContext context, String role) {
-        this.context = context;
-        this.role = role;
-    }
-
-    String property(String name) {
-        return lookupConfigurationThenFramework(context, name);
-    }
-
-    /**
-     * Chooses repository home directory name based on <b>repository.home</b>
-     * property, defaulting to <b>repository</b> if property is not set.
-     * 
-     * @return repository home directory name.
-     */
-    String getRepositoryHome() {
-        String root = property(REPOSITORY_HOME_DIRECTORY);
-        if (isNullOrEmpty(root)) {
-            return "repository";
-        }
-        return root;
-    }
-
-    /**
-     * Creates a new sub-directory relative to {@link #getRepositoryHome()} for
-     * storing segments.
-     * 
-     * @return directory for storing segments.
-     */
-    File getSegmentDirectory() {
-        return new File(getRepositoryHome(), appendRole("segmentstore"));
-    }
-
-    /**
-     * Creates a new sub-directory relative to {@link #getRepositoryHome()} 
for 
-     * storing repository backups.
-     * 
-     * @return directory for storing repository backups.
-     */
-    File getBackupDirectory() {
-        String backupDirectory = property(BACKUP_DIRECTORY);
-        if (backupDirectory != null) {
-            return new File(backupDirectory);
-        }
-        return new File(getRepositoryHome(), 
appendRole("segmentstore-backup"));
-    }
-
-    int getSegmentCacheSize() {
-        return toInteger(getCacheSize(SEGMENT_CACHE_SIZE), 
DEFAULT_SEGMENT_CACHE_MB);
-    }
-
-    int getStringCacheSize() {
-        return toInteger(getCacheSize(STRING_CACHE_SIZE), 
DEFAULT_STRING_CACHE_MB);
-    }
-
-    int getTemplateCacheSize() {
-        return toInteger(getCacheSize(TEMPLATE_CACHE_SIZE), 
DEFAULT_TEMPLATE_CACHE_MB);
-    }
-
-    int getStringDeduplicationCacheSize() {
-        return toInteger(getCacheSize(STRING_DEDUPLICATION_CACHE_SIZE), 
DEFAULT_STRING_CACHE_SIZE_OSGi);
-    }
-
-    int getTemplateDeduplicationCacheSize() {
-        return toInteger(getCacheSize(TEMPLATE_DEDUPLICATION_CACHE_SIZE), 
DEFAULT_TEMPLATE_CACHE_SIZE_OSGi);
-    }
-
-    int getNodeDeduplicationCacheSize() {
-        return 
roundToNextPowerOfTwo(toInteger(getCacheSize(NODE_DEDUPLICATION_CACHE_SIZE), 
DEFAULT_NODE_CACHE_SIZE_OSGi));
-    }
+            @Override
+            public int getRetainedGenerations() {
+                return configuration.compaction_retainedGenerations();
+            }
 
-    boolean getPauseCompaction() {
-        return toBoolean(property(PAUSE_COMPACTION), PAUSE_DEFAULT);
-    }
+            @Override
+            public int getDefaultRetainedGenerations() {
+                return RETAINED_GENERATIONS_DEFAULT;
+            }
 
-    int getRetryCount() {
-        return toInteger(property(COMPACTION_RETRY_COUNT), 
RETRY_COUNT_DEFAULT);
-    }
+            @Override
+            public boolean getPauseCompaction() {
+                return configuration.pauseCompaction();
+            }
 
-    int getForceCompactionTimeout() {
-        return toInteger(property(COMPACTION_FORCE_TIMEOUT), 
FORCE_TIMEOUT_DEFAULT);
-    }
+            @Override
+            public int getRetryCount() {
+                return configuration.compaction_retryCount();
+            }
 
-    int getRetainedGenerations() {
-        return toInteger(property(RETAINED_GENERATIONS), 
RETAINED_GENERATIONS_DEFAULT);
-    }
+            @Override
+            public int getForceCompactionTimeout() {
+                return configuration.compaction_force_timeout();
+            }
 
-    long getSizeDeltaEstimation() {
-        return toLong(property(COMPACTION_SIZE_DELTA_ESTIMATION), 
SIZE_DELTA_ESTIMATION_DEFAULT);
-    }
+            @Override
+            public long getSizeDeltaEstimation() {
+                return configuration.compaction_sizeDeltaEstimation();
+            }
 
-    int getMemoryThreshold() {
-        return toInteger(property(MEMORY_THRESHOLD), MEMORY_THRESHOLD_DEFAULT);
-    }
+            @Override
+            public int getMemoryThreshold() {
+                return configuration.compaction_memoryThreshold();
+            }
 
-    boolean getDisableEstimation() {
-        return toBoolean(property(COMPACTION_DISABLE_ESTIMATION), 
DISABLE_ESTIMATION_DEFAULT);
-    }
+            @Override
+            public boolean getDisableEstimation() {
+                return configuration.compaction_disableEstimation();
+            }
 
-    String getCompactionGainThreshold() {
-        return property("compaction.gainThreshold");
-    }
+            @Override
+            public long getGCProcessLog() {
+                return configuration.compaction_progressLog();
+            }
 
-    long getGCProcessLog() {
-        return toLong(property(GC_PROGRESS_LOG), GC_PROGRESS_LOG_DEFAULT);
-    }
+            @Override
+            public File getSegmentDirectory() {
+                return new File(getRepositoryHome(), "segmentstore");
+            }
 
-    int getMaxFileSize() {
-        return toInteger(property(SIZE), DEFAULT_MAX_FILE_SIZE);
-    }
+            @Override
+            public int getSegmentCacheSize() {
+                Integer size = Integer.getInteger("segmentCache.size");
+                if (size != null) {
+                    return size;
+                }
+                return configuration.segmentCache_size();
+            }
 
-    String getMode() {
-        String mode = property(MODE);
-        if (mode != null) {
-            return mode;
-        }
-        return System.getProperty(MODE, 
System.getProperty("sun.arch.data.model", "32"));
-    }
+            @Override
+            public int getStringCacheSize() {
+                return getCacheSize("stringCache.size", 
configuration.stringCache_size());
+            }
 
-    boolean getMemoryMapping() {
-        return getMode().equals("64");
-    }
+            @Override
+            public int getTemplateCacheSize() {
+                Integer size = Integer.getInteger("templateCache.size");
+                if (size != null) {
+                    return size;
+                }
+                return configuration.templateCache_size();
+            }
 
-    long getBlobSnapshotInterval() {
-        return toLong(property(PROP_BLOB_SNAPSHOT_INTERVAL), 
DEFAULT_BLOB_SNAPSHOT_INTERVAL);
-    }
+            @Override
+            public int getStringDeduplicationCacheSize() {
+                Integer size = 
Integer.getInteger("stringDeduplicationCache.size");
+                if (size != null) {
+                    return size;
+                }
+                return configuration.stringDeduplicationCache_size();
+            }
 
-    boolean isStandbyInstance() {
-        return toBoolean(property(STANDBY), false);
-    }
+            @Override
+            public int getTemplateDeduplicationCacheSize() {
+                Integer size = 
Integer.getInteger("templateDeduplicationCache.size");
+                if (size != null) {
+                    return size;
+                }
+                return configuration.templateDeduplicationCache_size();
+            }
 
-    boolean hasCustomBlobStore() {
-        return toBoolean(property(CUSTOM_BLOB_STORE), false);
-    }
+            @Override
+            public int getNodeDeduplicationCacheSize() {
+                Integer size = 
Integer.getInteger("nodeDeduplicationCache.size");
+                if (size != null) {
+                    return roundToNextPowerOfTwo(size);
+                }
+                return 
roundToNextPowerOfTwo(configuration.nodeDeduplicationCache_size());
+            }
 
-    boolean hasCustomSegmentStore() {
-        return toBoolean(property(CUSTOM_SEGMENT_STORE), false);
-    }
+            @Override
+            public int getMaxFileSize() {
+                return configuration.tarmk_size();
+            }
 
-    long getBlobGcMaxAge() {
-        return toLong(property(PROP_BLOB_GC_MAX_AGE), DEFAULT_BLOB_GC_MAX_AGE);
-    }
+            @Override
+            public boolean getMemoryMapping() {
+                return getMode().equals("64");
+            }
 
-    boolean isPrimarySegmentStore() {
-        return role == null;
-    }
+            @Override
+            public boolean hasCustomBlobStore() {
+                return configuration.customBlobStore();
+            }
 
-    private String appendRole(String name) {
-        if (role == null) {
-            return name;
-        } else {
-            return name + "-" + role;
-        }
-    }
+            @Override
+            public boolean hasCustomSegmentStore() {
+                return configuration.customSegmentStore();
+            }
 
-    private String getCacheSize(String propertyName) {
-        String cacheSize = property(propertyName);
-        if (cacheSize != null) {
-            return cacheSize;
-        }
-        return System.getProperty(propertyName);
-    }
+            @Override
+            public boolean registerDescriptors() {
+                return true;
+            }
 
-}
+            @Override
+            public String getRepositoryHome() {
+                return configuration.repository_home();
+            }
 
-/**
- * Performs registrations of services and MBean in a uniform way. Augments
- * the metadata of services and MBeans with an optionally provided role
- * name.
- */
-class Registrations {
+            @Override
+            public long getBlobSnapshotInterval() {
+                return configuration.blobTrackSnapshotIntervalInSecs();
+            }
 
-    private final Whiteboard whiteboard;
+            @Override
+            public long getBlobGcMaxAge() {
+                return configuration.blobGcMaxAgeInSecs();
+            }
 
-    private final String role;
+            @Override
+            public File getBackupDirectory() {
+                String backupDirectory = configuration.repository_backup_dir();
+                if (isNullOrEmpty(backupDirectory)) {
+                    return new File(getRepositoryHome(), 
"segmentstore-backup");
+                }
+                return new File(backupDirectory);
+            }
 
-    Registrations(Whiteboard whiteboard, String role) {
-        this.whiteboard = whiteboard;
-        this.role = role;
-    }
+            @Override
+            public Whiteboard getWhiteboard() {
+                return whiteboard;
+            }
 
-    <T> Registration registerMBean(Class<T> clazz, T bean, String type, String 
name) {
-        return registerMBean(clazz, bean, type, name, new HashMap<String, 
String>());
-    }
+            @Override
+            public Closer getCloser() {
+                return closer;
+            }
 
-    <T> Registration registerMBean(Class<T> clazz, T bean, String type, String 
name, Map<String, String> attributes) {
-        return WhiteboardUtils.registerMBean(whiteboard, clazz, bean, type, 
maybeAppendRole(name), maybePutRoleAttribute(attributes));
-    }
+            @Override
+            public Logger getLogger() {
+                return logger;
+            }
 
-    <T> Registration register(Class<T> clazz, T service) {
-        return register(clazz, service, new HashMap<String, Object>());
-    }
+            @Override
+            public StatisticsProvider getStatisticsProvider() {
+                return statisticsProvider;
+            }
 
-    <T> Registration register(Class<T> clazz, T service, Map<String, Object> 
properties) {
-        return whiteboard.register(clazz, service, 
maybePutRoleProperty(properties));
-    }
+            @Override
+            public BlobStore getBlobStore() {
+                return blobStore;
+            }
 
-    private String maybeAppendRole(String name) {
-        return RoleUtils.maybeAppendRole(name, role);
-    }
+            @Override
+            public SegmentNodeStorePersistence 
getSegmentNodeStorePersistence() {
+                return segmentStore;
+            }
 
-    private String jmxRole() {
-        return role.replaceAll(":", "-");
-    }
+            @Override
+            public BundleContext getBundleContext() {
+                return context.getBundleContext();
+            }
 
-    private Map<String, String> maybePutRoleAttribute(Map<String, String> 
attributes) {
-        if (role != null) {
-            attributes.put("role", jmxRole());
-        }
-        return attributes;
+        });
     }
 
-    private Map<String, Object> maybePutRoleProperty(Map<String, Object> 
attributes) {
-        if (role != null) {
-            attributes.put("role", role);
-        }
-        return attributes;
+    @Deactivate
+    public void deactivate() {
+        closeQuietly(closer);
     }
 
-}
+}
\ No newline at end of file

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreServiceDeprecationError.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreServiceDeprecationError.java?rev=1835837&r1=1835836&r2=1835837&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreServiceDeprecationError.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreServiceDeprecationError.java
 Fri Jul 13 13:23:24 2018
@@ -17,9 +17,9 @@
 
 package org.apache.jackrabbit.oak.segment.osgi;
 
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -30,8 +30,8 @@ import org.slf4j.LoggerFactory;
  * detected problem and hinting at a possible solution.
  */
 @Component(
-        policy = ConfigurationPolicy.REQUIRE,
-        configurationPid = 
"org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStoreService"
+    configurationPolicy = ConfigurationPolicy.REQUIRE,
+    configurationPid = 
"org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStoreService"
 )
 public class SegmentNodeStoreServiceDeprecationError {
 

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/StandbyStoreServiceDeprecationError.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/StandbyStoreServiceDeprecationError.java?rev=1835837&r1=1835836&r2=1835837&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/StandbyStoreServiceDeprecationError.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/osgi/StandbyStoreServiceDeprecationError.java
 Fri Jul 13 13:23:24 2018
@@ -16,9 +16,9 @@
  */
 package org.apache.jackrabbit.oak.segment.osgi;
 
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -29,8 +29,8 @@ import org.slf4j.LoggerFactory;
  * detected problem and hinting at a possible solution.
  */
 @Component(
-        policy = ConfigurationPolicy.REQUIRE,
-        configurationPid = 
"org.apache.jackrabbit.oak.plugins.segment.standby.store.StandbyStoreService"
+    configurationPolicy = ConfigurationPolicy.REQUIRE,
+    configurationPid = 
"org.apache.jackrabbit.oak.plugins.segment.standby.store.StandbyStoreService"
 )
 public class StandbyStoreServiceDeprecationError {
 

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java?rev=1835837&r1=1835836&r2=1835837&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java
 Fri Jul 13 13:23:24 2018
@@ -17,25 +17,15 @@
 
 package org.apache.jackrabbit.oak.segment.standby.store;
 
-import static java.lang.String.valueOf;
-import static org.apache.felix.scr.annotations.ReferencePolicy.STATIC;
-import static org.apache.felix.scr.annotations.ReferencePolicyOption.GREEDY;
+import static org.osgi.service.component.annotations.ReferencePolicy.STATIC;
+import static 
org.osgi.service.component.annotations.ReferencePolicyOption.GREEDY;
 
-import java.io.Closeable;
 import java.io.File;
 import java.util.Dictionary;
 import java.util.Hashtable;
 
 import com.google.common.base.StandardSystemProperty;
 import com.google.common.io.Closer;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.ConfigurationPolicy;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.PropertyOption;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.jackrabbit.oak.commons.PropertiesUtil;
 import org.apache.jackrabbit.oak.segment.SegmentStore;
 import org.apache.jackrabbit.oak.segment.SegmentStoreProvider;
 import org.apache.jackrabbit.oak.segment.file.FileStore;
@@ -43,71 +33,99 @@ import org.apache.jackrabbit.oak.segment
 import org.apache.jackrabbit.oak.segment.standby.server.StandbyServerSync;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+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 org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-@Property(name = "org.apache.sling.installer.configuration.persist", label = 
"Persist configuration", description = "Must be always disabled to avoid 
storing the configuration in the repository", boolValue = false)
-@Component(metatype = true, policy = ConfigurationPolicy.REQUIRE)
+@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = StandbyStoreService.Configuration.class)
 public class StandbyStoreService {
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
+    private static final Logger log = 
LoggerFactory.getLogger(StandbyStoreService.class);
 
-    private static final String MODE_PRIMARY = "primary";
-
-    private static final String MODE_STANDBY = "standby";
-
-    public static final String MODE_DEFAULT = MODE_PRIMARY;
-
-    @Property(options = {
-            @PropertyOption(name = MODE_PRIMARY, value = MODE_PRIMARY),
-            @PropertyOption(name = MODE_STANDBY, value = MODE_STANDBY)},
-            value = MODE_DEFAULT)
-    public static final String MODE = "mode";
-
-    public static final int PORT_DEFAULT = 8023;
-
-    @Property(intValue = PORT_DEFAULT)
-    public static final String PORT = "port";
-
-    public static final String PRIMARY_HOST_DEFAULT = "127.0.0.1";
-
-    @Property(value = PRIMARY_HOST_DEFAULT)
-    public static final String PRIMARY_HOST = "primary.host";
-
-    public static final int INTERVAL_DEFAULT = 5;
-
-    @Property(intValue = INTERVAL_DEFAULT)
-    public static final String INTERVAL = "interval";
-
-    public static final String[] ALLOWED_CLIENT_IP_RANGES_DEFAULT = new 
String[] {};
-
-    @Property(cardinality = Integer.MAX_VALUE)
-    public static final String ALLOWED_CLIENT_IP_RANGES = 
"primary.allowed-client-ip-ranges";
-
-    public static final boolean SECURE_DEFAULT = false;
-
-    @Property(boolValue = SECURE_DEFAULT)
-    public static final String SECURE = "secure";
-    
-    public static final int READ_TIMEOUT_DEFAULT = 60000;
-
-    @Property(intValue = READ_TIMEOUT_DEFAULT)
-    public static final String READ_TIMEOUT = "standby.readtimeout";
+    private static final int BLOB_CHUNK_SIZE = 
Integer.getInteger("oak.standby.blob.chunkSize", 1024 * 1024);
 
-    public static final boolean AUTO_CLEAN_DEFAULT = true;
+    @ObjectClassDefinition(
+        name = "Apache Jackrabbit Oak Segment Tar Cold Standby Service",
+        description = "Provides continuous backups of repositories based on 
Segment Tar"
+    )
+    @interface Configuration {
+
+        @AttributeDefinition(
+            name = "Persist configuration",
+            description = "Must be always disabled to avoid storing the 
configuration in the repository"
+        )
+        boolean org_apache_sling_installer_configuration_persist() default 
false;
+
+        @AttributeDefinition(
+            name = "Mode",
+            description = "TarMK Cold Standby mode (primary or standby)",
+            options = {
+                @Option(label = "primary", value = "primary"),
+                @Option(label = "standby", value = "standby")}
+        )
+        String mode() default "primary";
+
+        @AttributeDefinition(
+            name = "Port",
+            description = "TCP/IP port to use"
+        )
+        int port() default 8023;
+
+        @AttributeDefinition(
+            name = "Primary Host",
+            description = "Primary host (standby mode only)"
+        )
+        String primary_host() default "127.0.0.1";
+
+        @AttributeDefinition(
+            name = "Sync interval (seconds)",
+            description = "Sync interval in seconds (standby mode only)"
+        )
+        int interval() default 5;
+
+        @AttributeDefinition(
+            name = "Allowed IP-Ranges",
+            description = "Accept incoming requests for these host names and 
IP-ranges only (primary mode only)",
+            cardinality = Integer.MAX_VALUE
+        )
+        String[] primary_allowed$_$client$_$ip$_$ranges() default {};
+
+        @AttributeDefinition(
+            name = "Secure",
+            description = "Use secure connections"
+        )
+        boolean secure() default false;
+
+        @AttributeDefinition(
+            name = "Standby Read Timeout",
+            description = "Timeout for requests issued from the standby 
instance in milliseconds"
+        )
+        int standby_readtimeout() default 60000;
+
+        @AttributeDefinition(
+            name = "Standby Automatic Cleanup",
+            description = "Call the cleanup method when the root segment 
Garbage Collector (GC) generation number increases"
+        )
+        boolean standby_autoclean() default true;
 
-    @Property(boolValue = AUTO_CLEAN_DEFAULT)
-    public static final String AUTO_CLEAN = "standby.autoclean";
+    }
 
     @Reference(policy = STATIC, policyOption = GREEDY)
     private SegmentStoreProvider storeProvider = null;
-    
-    private static final int BLOB_CHUNK_SIZE = 
Integer.getInteger("oak.standby.blob.chunkSize", 1024 * 1024);
 
     private final Closer closer = Closer.create();
 
     @Activate
-    private void activate(ComponentContext context) {
+    private void activate(ComponentContext context, Configuration config) {
         SegmentStore segmentStore = storeProvider.getSegmentStore();
 
         if (!(segmentStore instanceof FileStore)) {
@@ -116,15 +134,15 @@ public class StandbyStoreService {
 
         FileStore fileStore = (FileStore) segmentStore;
 
-        String mode = valueOf(context.getProperties().get(MODE));
+        String mode = config.mode();
 
-        if (MODE_PRIMARY.equals(mode)) {
-            bootstrapMaster(context, fileStore);
+        if (mode.equals("primary")) {
+            bootstrapMaster(config, fileStore);
             return;
         }
 
-        if (MODE_STANDBY.equals(mode)) {
-            bootstrapSlave(context, fileStore);
+        if (mode.equals("standby")) {
+            bootstrapSlave(context, config, fileStore);
             return;
         }
 
@@ -136,11 +154,10 @@ public class StandbyStoreService {
         closer.close();
     }
 
-    private void bootstrapMaster(ComponentContext context, FileStore 
fileStore) {
-        Dictionary<?, ?> props = context.getProperties();
-        int port = PropertiesUtil.toInteger(props.get(PORT), PORT_DEFAULT);
-        String[] ranges = 
PropertiesUtil.toStringArray(props.get(ALLOWED_CLIENT_IP_RANGES), 
ALLOWED_CLIENT_IP_RANGES_DEFAULT);
-        boolean secure = PropertiesUtil.toBoolean(props.get(SECURE), 
SECURE_DEFAULT);
+    private void bootstrapMaster(Configuration config, FileStore fileStore) {
+        int port = config.port();
+        String[] ranges = config.primary_allowed$_$client$_$ip$_$ranges();
+        boolean secure = config.secure();
 
         StandbyServerSync standbyServerSync = new StandbyServerSync(port, 
fileStore, BLOB_CHUNK_SIZE, ranges, secure);
         closer.register(standbyServerSync);
@@ -149,14 +166,13 @@ public class StandbyStoreService {
         log.info("Started primary on port {} with allowed IP ranges {}", port, 
ranges);
     }
 
-    private void bootstrapSlave(ComponentContext context, FileStore fileStore) 
{
-        Dictionary<?, ?> props = context.getProperties();
-        int port = PropertiesUtil.toInteger(props.get(PORT), PORT_DEFAULT);
-        long interval = PropertiesUtil.toInteger(props.get(INTERVAL), 
INTERVAL_DEFAULT);
-        String host = PropertiesUtil.toString(props.get(PRIMARY_HOST), 
PRIMARY_HOST_DEFAULT);
-        boolean secure = PropertiesUtil.toBoolean(props.get(SECURE), 
SECURE_DEFAULT);
-        int readTimeout = PropertiesUtil.toInteger(props.get(READ_TIMEOUT), 
READ_TIMEOUT_DEFAULT);
-        boolean clean = PropertiesUtil.toBoolean(props.get(AUTO_CLEAN), 
AUTO_CLEAN_DEFAULT);
+    private void bootstrapSlave(ComponentContext context, Configuration 
config, FileStore fileStore) {
+        int port = config.port();
+        long interval = config.interval();
+        String host = config.primary_host();
+        boolean secure = config.secure();
+        int readTimeout = config.standby_readtimeout();
+        boolean clean = config.standby_autoclean();
 
         StandbyClientSync standbyClientSync = new StandbyClientSync(host, 
port, fileStore, secure, readTimeout, clean, new 
File(StandardSystemProperty.JAVA_IO_TMPDIR.value()));
         closer.register(standbyClientSync);
@@ -165,20 +181,9 @@ public class StandbyStoreService {
         dictionary.put("scheduler.period", interval);
         dictionary.put("scheduler.concurrent", false);
         ServiceRegistration registration = 
context.getBundleContext().registerService(Runnable.class.getName(), 
standbyClientSync, dictionary);
-        closer.register(asCloseable(registration));
+        closer.register(registration::unregister);
 
         log.info("Started standby on port {} with {}s sync frequency", port, 
interval);
     }
 
-    private static Closeable asCloseable(final ServiceRegistration r) {
-        return new Closeable() {
-
-            @Override
-            public void close() {
-                r.unregister();
-            }
-
-        };
-    }
-
 }

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactoryTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactoryTest.java?rev=1835837&r1=1835836&r2=1835837&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactoryTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreFactoryTest.java
 Fri Jul 13 13:23:24 2018
@@ -35,9 +35,9 @@ public class SegmentNodeStoreFactoryTest
     protected void registerSegmentNodeStoreService(boolean customBlobStore) {
         Map<String, Object> properties = newHashMap();
 
-        properties.put(SegmentNodeStoreFactory.ROLE, "some-role");
-        properties.put(SegmentNodeStoreFactory.CUSTOM_BLOB_STORE, 
customBlobStore);
-        properties.put(SegmentNodeStoreService.REPOSITORY_HOME_DIRECTORY, 
folder.getRoot().getAbsolutePath());
+        properties.put("role", "some-role");
+        properties.put("customBlobStore", customBlobStore);
+        properties.put("repository.home", folder.getRoot().getAbsolutePath());
 
         segmentNodeStoreFactory = context.registerInjectActivateService(new 
SegmentNodeStoreFactory(), properties);
     }

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/ComponentDescriptor.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/ComponentDescriptor.java?rev=1835837&r1=1835836&r2=1835837&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/ComponentDescriptor.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/ComponentDescriptor.java
 Fri Jul 13 13:23:24 2018
@@ -21,6 +21,7 @@ package org.apache.jackrabbit.oak.segmen
 
 import java.io.InputStream;
 
+import javax.print.attribute.HashPrintServiceAttributeSet;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 
@@ -47,6 +48,10 @@ class ComponentDescriptor {
         return element.hasAttribute(name) && 
element.getAttribute(name).equals(value);
     }
 
+    private static boolean hasNoAttribute(Element element, String name) {
+        return !element.hasAttribute(name);
+    }
+
     boolean hasName(String name) {
         return hasAttribute(root, "name", name);
     }
@@ -182,6 +187,8 @@ class ComponentDescriptor {
 
         private String unbind;
 
+        private String field;
+
         private HasReference(String name) {
             this.name = name;
         }
@@ -246,6 +253,11 @@ class ComponentDescriptor {
             return this;
         }
 
+        HasReference withField(String field) {
+            this.field = field;
+            return this;
+        }
+
         boolean check() {
             NodeList references = root.getElementsByTagName("reference");
             for (int i = 0; i < references.getLength(); i++) {
@@ -254,10 +266,10 @@ class ComponentDescriptor {
                     if (iface != null && !hasAttribute(reference, "interface", 
iface)) {
                         return false;
                     }
-                    if (cardinality != null && !hasAttribute(reference, 
"cardinality", cardinality)) {
+                    if (cardinality != null && 
!hasValidCardinality(reference)) {
                         return false;
                     }
-                    if (policy != null && !hasAttribute(reference, "policy", 
policy)) {
+                    if (policy != null && !hasValidPolicy(reference)) {
                         return false;
                     }
                     if (policyOption != null && !hasAttribute(reference, 
"policy-option", policyOption)) {
@@ -272,12 +284,29 @@ class ComponentDescriptor {
                     if (unbind != null && !hasAttribute(reference, "unbind", 
unbind)) {
                         return false;
                     }
+                    if (field != null && !hasAttribute(reference, "field", 
field)) {
+                        return false;
+                    }
                     return true;
                 }
             }
             return false;
         }
 
+        private boolean hasValidCardinality(Element reference) {
+            if (cardinality.equals("1..1") && hasNoAttribute(reference, 
"cardinality")) {
+                return true;
+            }
+            return hasAttribute(reference, "cardinality", cardinality);
+        }
+
+        private boolean hasValidPolicy(Element reference) {
+            if (policy.equals("static") && hasNoAttribute(reference, 
"policy")) {
+                return true;
+            }
+            return hasAttribute(reference, "policy", policy);
+        }
+
     }
 
     HasReference hasReference(String name) {

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreFactoryTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreFactoryTest.java?rev=1835837&r1=1835836&r2=1835837&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreFactoryTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreFactoryTest.java
 Fri Jul 13 13:23:24 2018
@@ -52,36 +52,32 @@ public class SegmentNodeStoreFactoryTest
             .withStaticPolicy()
             .withGreedyPolicyOption()
             .withTarget("(&(!(split.blobstore=old))(!(split.blobstore=new)))")
-            .withBind("bindBlobStore")
-            .withUnbind("unbindBlobStore")
+            .withField("blobStore")
             .check());
         assertTrue(cd.hasReference("segmentStore")
             
.withInterface("org.apache.jackrabbit.oak.segment.spi.persistence.SegmentNodeStorePersistence")
             .withOptionalUnaryCardinality()
             .withStaticPolicy()
             .withGreedyPolicyOption()
-            .withBind("bindSegmentStore")
-            .withUnbind("unbindSegmentStore")
+            .withField("segmentStore")
             .check());
         assertTrue(cd.hasReference("statisticsProvider")
             
.withInterface("org.apache.jackrabbit.oak.stats.StatisticsProvider")
             .withMandatoryUnaryCardinality()
             .withStaticPolicy()
-            .withBind("bindStatisticsProvider")
-            .withUnbind("unbindStatisticsProvider")
+            .withField("statisticsProvider")
             .check());
     }
 
     @Test
     public void testMetatypeInformation() throws Exception {
-        MetatypeInformation mi = 
MetatypeInformation.open(getClass().getResourceAsStream("/OSGI-INF/metatype/org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory.xml"));
+        MetatypeInformation mi = 
MetatypeInformation.open(getClass().getResourceAsStream("/OSGI-INF/metatype/org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory$Configuration.xml"));
         assertTrue(mi.hasDesignate()
-            
.withPid("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory")
             
.withFactoryPid("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory")
-            
.withReference("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory")
+            
.withReference("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory$Configuration")
             .check());
 
-        ObjectClassDefinition ocd = 
mi.getObjectClassDefinition("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory");
+        ObjectClassDefinition ocd = 
mi.getObjectClassDefinition("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory$Configuration");
         assertTrue(ocd.hasAttributeDefinition("role")
             .withStringType()
             .check());

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreMonitorServiceTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreMonitorServiceTest.java?rev=1835837&r1=1835836&r2=1835837&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreMonitorServiceTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/osgi/SegmentNodeStoreMonitorServiceTest.java
 Fri Jul 13 13:23:24 2018
@@ -33,25 +33,23 @@ public class SegmentNodeStoreMonitorServ
         assertTrue(cd.hasRequireConfigurationPolicy());
         assertTrue(cd.hasActivateMethod("activate"));
         
assertTrue(cd.hasImplementationClass("org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService"));
-        assertTrue(cd.hasProperty("commitsTrackerWriterGroups").check());
         assertTrue(cd.hasReference("snsStatsMBean")
             
.withInterface("org.apache.jackrabbit.oak.segment.SegmentNodeStoreStatsMBean")
             .withMandatoryUnaryCardinality()
             .withStaticPolicy()
-            .withBind("bindSnsStatsMBean")
-            .withUnbind("unbindSnsStatsMBean")
+            .withField("snsStatsMBean")
             .check());
     }
 
     @Test
     public void testMetatypeInformation() throws Exception {
-        MetatypeInformation mi = 
MetatypeInformation.open(getClass().getResourceAsStream("/OSGI-INF/metatype/org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService.xml"));
+        MetatypeInformation mi = 
MetatypeInformation.open(getClass().getResourceAsStream("/OSGI-INF/metatype/org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService$Configuration.xml"));
         assertTrue(mi.hasDesignate()
             
.withPid("org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService")
-            
.withReference("org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService")
+            
.withReference("org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService$Configuration")
             .check());
 
-        ObjectClassDefinition ocd = 
mi.getObjectClassDefinition("org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService");
+        ObjectClassDefinition ocd = 
mi.getObjectClassDefinition("org.apache.jackrabbit.oak.segment.SegmentNodeStoreMonitorService$Configuration");
         assertTrue(ocd.hasAttributeDefinition("commitsTrackerWriterGroups")
             .withStringType()
             .withCardinality("2147483647")


Reply via email to