Author: amitj
Date: Wed Jun 24 04:25:58 2015
New Revision: 1687171

URL: http://svn.apache.org/r1687171
Log:
OAK-2962: SegmentNodeStoreService fails to handle empty strings in the OSGi 
configuration

Patch from Francesco Mari

Added:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/OsgiUtil.java
   (with props)
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/osgi/OsgiUtilTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/package-info.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreService.java

Added: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/OsgiUtil.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/OsgiUtil.java?rev=1687171&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/OsgiUtil.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/OsgiUtil.java
 Wed Jun 24 04:25:58 2015
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.osgi;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Utility methods to use in an OSGi environment.
+ */
+public class OsgiUtil {
+
+    private OsgiUtil() {
+        // Prevent instantiation.
+    }
+
+    /**
+     * Looks a property up by name in a component context. Returns {@code null}
+     * if the property is not found or if the property is found but it is an
+     * empty string.
+     *
+     * @param context Component context.
+     * @param name    Name of the property.
+     * @return The property value serialized as a string, or {@code null}.
+     */
+    public static String lookup(ComponentContext context, String name) {
+        return 
asString(checkNotNull(context).getProperties().get(checkNotNull(name)));
+    }
+
+    /**
+     * Looks a property up by name in the set of framework properties. Returns
+     * {@code null} if the property is not found or if the property is found 
but
+     * it is an empty string.
+     *
+     * @param context Component context.
+     * @param name    Name of the property.
+     * @return The property value serialized as a string, or {@code null}.
+     */
+    public static String lookup(BundleContext context, String name) {
+        return asString(checkNotNull(context).getProperty(checkNotNull(name)));
+    }
+
+    /**
+     * Looks a property up by name in the component context first, falling back
+     * in the framework properties if not found. Returns {@code null} if the
+     * property is not found or if the property is found but it is an empty
+     * string.
+     *
+     * @param context Component context.
+     * @param name    Name of the property.
+     * @return The property value serialized as a string, or {@code null}.
+     */
+    public static String fallbackLookup(ComponentContext context, String name) 
{
+        String fromComponent = lookup(context, name);
+
+        if (fromComponent != null) {
+            return fromComponent;
+        }
+
+        String fromFramework = lookup(context.getBundleContext(), name);
+
+        if (fromFramework != null) {
+            return fromFramework;
+        }
+
+        return null;
+    }
+
+    private static String asString(Object value) {
+        if (value == null) {
+            return null;
+        }
+
+        String string = value.toString().trim();
+
+        if (string.isEmpty()) {
+            return null;
+        }
+
+        return string;
+    }
+
+}

Propchange: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/OsgiUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/package-info.java?rev=1687171&r1=1687170&r2=1687171&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/package-info.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/package-info.java
 Wed Jun 24 04:25:58 2015
@@ -14,9 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.0")
+@Version("1.1")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.osgi;
 
 import aQute.bnd.annotation.Version;
-import aQute.bnd.annotation.Export;
\ No newline at end of file
+import aQute.bnd.annotation.Export;

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreService.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreService.java?rev=1687171&r1=1687170&r2=1687171&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreService.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreService.java
 Wed Jun 24 04:25:58 2015
@@ -21,6 +21,7 @@ import static java.util.Collections.empt
 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.fallbackLookup;
 import static 
org.apache.jackrabbit.oak.plugins.segment.compaction.CompactionStrategy.CLEANUP_DEFAULT;
 import static 
org.apache.jackrabbit.oak.plugins.segment.compaction.CompactionStrategy.CLONE_BINARIES_DEFAULT;
 import static 
org.apache.jackrabbit.oak.plugins.segment.compaction.CompactionStrategy.FORCE_AFTER_FAIL_DEFAULT;
@@ -272,7 +273,7 @@ public class SegmentNodeStoreService ext
     @Activate
     private void activate(ComponentContext context) throws IOException {
         this.context = context;
-        this.customBlobStore = Boolean.parseBoolean(lookup(context, 
CUSTOM_BLOB_STORE));
+        this.customBlobStore = Boolean.parseBoolean(fallbackLookup(context, 
CUSTOM_BLOB_STORE));
 
         if (blobStore == null && customBlobStore) {
             log.info("BlobStore use enabled. SegmentNodeStore would be 
initialized when BlobStore would be available");
@@ -283,7 +284,7 @@ public class SegmentNodeStoreService ext
 
     public void registerNodeStore() throws IOException {
         if (registerSegmentStore()) {
-            boolean standby = toBoolean(lookup(context, STANDBY), false);
+            boolean standby = toBoolean(fallbackLookup(context, STANDBY), 
false);
             providerRegistration = context.getBundleContext().registerService(
                     SegmentStoreProvider.class.getName(), this, null);
             if (!standby) {
@@ -304,56 +305,56 @@ public class SegmentNodeStoreService ext
         Dictionary<?, ?> properties = context.getProperties();
         name = String.valueOf(properties.get(NAME));
 
-        String directory = lookup(context, DIRECTORY);
+        String directory = fallbackLookup(context, DIRECTORY);
         if (directory == null) {
             directory = "tarmk";
         }else{
             directory = FilenameUtils.concat(directory, "segmentstore");
         }
 
-        String mode = lookup(context, MODE);
+        String mode = fallbackLookup(context, MODE);
         if (mode == null) {
             mode = System.getProperty(MODE,
                     System.getProperty("sun.arch.data.model", "32"));
         }
 
-        String size = lookup(context, SIZE);
+        String size = fallbackLookup(context, SIZE);
         if (size == null) {
             size = System.getProperty(SIZE, "256");
         }
 
-        String cache = lookup(context, CACHE);
+        String cache = fallbackLookup(context, CACHE);
         if (cache == null) {
             cache = System.getProperty(CACHE);
         }
 
-        boolean pauseCompaction = toBoolean(lookup(context, PAUSE_COMPACTION),
+        boolean pauseCompaction = toBoolean(fallbackLookup(context, 
PAUSE_COMPACTION),
                 PAUSE_DEFAULT);
         boolean cloneBinaries = toBoolean(
-                lookup(context, COMPACTION_CLONE_BINARIES),
+                fallbackLookup(context, COMPACTION_CLONE_BINARIES),
                 CLONE_BINARIES_DEFAULT);
-        long cleanupTs = toLong(lookup(context, COMPACTION_CLEANUP_TIMESTAMP),
+        long cleanupTs = toLong(fallbackLookup(context, 
COMPACTION_CLEANUP_TIMESTAMP),
                 TIMESTAMP_DEFAULT);
-        int retryCount = toInteger(lookup(context, COMPACTION_RETRY_COUNT),
+        int retryCount = toInteger(fallbackLookup(context, 
COMPACTION_RETRY_COUNT),
                 RETRY_COUNT_DEFAULT);
-        boolean forceCommit = toBoolean(lookup(context, 
COMPACTION_FORCE_AFTER_FAIL),
+        boolean forceCommit = toBoolean(fallbackLookup(context, 
COMPACTION_FORCE_AFTER_FAIL),
                 FORCE_AFTER_FAIL_DEFAULT);
-        final int lockWaitTime = toInteger(lookup(context, 
COMPACTION_LOCK_WAIT_TIME),
+        final int lockWaitTime = toInteger(fallbackLookup(context, 
COMPACTION_LOCK_WAIT_TIME),
                 COMPACTION_LOCK_WAIT_TIME_DEFAULT);
-        boolean persistCompactionMap = toBoolean(lookup(context, 
PERSIST_COMPACTION_MAP),
+        boolean persistCompactionMap = toBoolean(fallbackLookup(context, 
PERSIST_COMPACTION_MAP),
                 PERSIST_COMPACTION_MAP_DEFAULT);
-        String cleanup = lookup(context, COMPACTION_CLEANUP);
+        String cleanup = fallbackLookup(context, COMPACTION_CLEANUP);
         if (cleanup == null) {
             cleanup = CLEANUP_DEFAULT.toString();
         }
 
-        String memoryThresholdS = lookup(context, COMPACTION_MEMORY_THRESHOLD);
+        String memoryThresholdS = fallbackLookup(context, 
COMPACTION_MEMORY_THRESHOLD);
         byte memoryThreshold = MEMORY_THRESHOLD_DEFAULT;
         if (memoryThresholdS != null) {
             memoryThreshold = Byte.valueOf(memoryThresholdS);
         }
 
-        final long blobGcMaxAgeInSecs = toLong(lookup(context, 
PROP_BLOB_GC_MAX_AGE), DEFAULT_BLOB_GC_MAX_AGE);
+        final long blobGcMaxAgeInSecs = toLong(fallbackLookup(context, 
PROP_BLOB_GC_MAX_AGE), DEFAULT_BLOB_GC_MAX_AGE);
 
         OsgiWhiteboard whiteboard = new 
OsgiWhiteboard(context.getBundleContext());
         gcMonitor = new GCMonitorTracker();
@@ -443,16 +444,6 @@ public class SegmentNodeStoreService ext
         return true;
     }
 
-    private static String lookup(ComponentContext context, String property) {
-        if (context.getProperties().get(property) != null) {
-            return context.getProperties().get(property).toString();
-        }
-        if (context.getBundleContext().getProperty(property) != null) {
-            return context.getBundleContext().getProperty(property);
-        }
-        return null;
-    }
-
     @Deactivate
     public synchronized void deactivate() {
         unregisterNodeStore();

Added: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/osgi/OsgiUtilTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/osgi/OsgiUtilTest.java?rev=1687171&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/osgi/OsgiUtilTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/osgi/OsgiUtilTest.java
 Wed Jun 24 04:25:58 2015
@@ -0,0 +1,202 @@
+/*
+ * 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.osgi;
+
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+
+import java.util.Dictionary;
+
+import static org.apache.jackrabbit.oak.osgi.OsgiUtil.fallbackLookup;
+import static org.apache.jackrabbit.oak.osgi.OsgiUtil.lookup;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+public class OsgiUtilTest {
+
+    @Test(expected = NullPointerException.class)
+    public void testComponentLookupWithNullContext() {
+        lookup((ComponentContext) null, "name");
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testComponentLookupWithNullName() {
+        lookup(mock(ComponentContext.class), null);
+    }
+
+    @Test
+    public void testComponentLookupWithNotFoundValue() {
+        Dictionary properties = mock(Dictionary.class);
+        doReturn(null).when(properties).get("name");
+
+        ComponentContext context = mock(ComponentContext.class);
+        doReturn(properties).when(context).getProperties();
+
+        assertNull(lookup(context, "name"));
+    }
+
+    @Test
+    public void testComponentLookupWithEmptyString() {
+        Dictionary properties = mock(Dictionary.class);
+        doReturn("").when(properties).get("name");
+
+        ComponentContext context = mock(ComponentContext.class);
+        doReturn(properties).when(context).getProperties();
+
+        assertNull(lookup(context, "name"));
+    }
+
+    @Test
+    public void testComponentLookupWithNonTrimmedString() {
+        Dictionary properties = mock(Dictionary.class);
+        doReturn("   ").when(properties).get("name");
+
+        ComponentContext context = mock(ComponentContext.class);
+        doReturn(properties).when(context).getProperties();
+
+        assertNull(lookup(context, "name"));
+    }
+
+    @Test
+    public void testComponentLookupWithNonStringValue() {
+        Dictionary properties = mock(Dictionary.class);
+        doReturn(42).when(properties).get("name");
+
+        ComponentContext context = mock(ComponentContext.class);
+        doReturn(properties).when(context).getProperties();
+
+        assertEquals("42", lookup(context, "name"));
+    }
+
+    @Test
+    public void testComponentLookupWithStringValue() {
+        Dictionary properties = mock(Dictionary.class);
+        doReturn("  value   ").when(properties).get("name");
+
+        ComponentContext context = mock(ComponentContext.class);
+        doReturn(properties).when(context).getProperties();
+
+        assertEquals("value", lookup(context, "name"));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testFrameworkLookupWithNullContext() {
+        lookup((BundleContext) null, "name");
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testFrameworkLookupWithNullName() {
+        lookup(mock(BundleContext.class), null);
+    }
+
+    @Test
+    public void testFrameworkLookupWithNotFoundValue() {
+        BundleContext context = mock(BundleContext.class);
+        doReturn(null).when(context).getProperty("name");
+
+        assertNull(lookup(context, "name"));
+    }
+
+    @Test
+    public void testFrameworkLookupWithEmptyString() {
+        BundleContext context = mock(BundleContext.class);
+        doReturn("").when(context).getProperty("name");
+
+        assertNull(lookup(context, "name"));
+    }
+
+    @Test
+    public void testFrameworkLookupWithNonTrimmedString() {
+        BundleContext context = mock(BundleContext.class);
+        doReturn("   ").when(context).getProperty("name");
+
+        assertNull(lookup(context, "name"));
+    }
+
+    @Test
+    public void testFrameworkLookupWith() {
+        BundleContext context = mock(BundleContext.class);
+        doReturn("  value   ").when(context).getProperty("name");
+
+        assertEquals("value", lookup(context, "name"));
+    }
+
+    @Test
+    public void testFallbackLookupWithNotFoundValue() {
+        Dictionary dictionary = mock(Dictionary.class);
+        doReturn(null).when(dictionary).get("name");
+
+        BundleContext bundleContext = mock(BundleContext.class);
+        doReturn(null).when(bundleContext).getProperty("name");
+
+        ComponentContext componentContext = mock(ComponentContext.class);
+        doReturn(dictionary).when(componentContext).getProperties();
+        doReturn(bundleContext).when(componentContext).getBundleContext();
+
+        assertNull(fallbackLookup(componentContext, "name"));
+    }
+
+    @Test
+    public void testFallbackLookupWithValueInComponent() {
+        Dictionary dictionary = mock(Dictionary.class);
+        doReturn("value").when(dictionary).get("name");
+
+        BundleContext bundleContext = mock(BundleContext.class);
+        doReturn(null).when(bundleContext).getProperty("name");
+
+        ComponentContext componentContext = mock(ComponentContext.class);
+        doReturn(dictionary).when(componentContext).getProperties();
+        doReturn(bundleContext).when(componentContext).getBundleContext();
+
+        assertEquals("value", fallbackLookup(componentContext, "name"));
+    }
+
+    @Test
+    public void testFallbackLookupWithValueInFramework() {
+        Dictionary dictionary = mock(Dictionary.class);
+        doReturn(null).when(dictionary).get("name");
+
+        BundleContext bundleContext = mock(BundleContext.class);
+        doReturn("value").when(bundleContext).getProperty("name");
+
+        ComponentContext componentContext = mock(ComponentContext.class);
+        doReturn(dictionary).when(componentContext).getProperties();
+        doReturn(bundleContext).when(componentContext).getBundleContext();
+
+        assertEquals("value", fallbackLookup(componentContext, "name"));
+    }
+
+    @Test
+    public void testFallbackLookupWithValueInComponentAndFramework() {
+        Dictionary dictionary = mock(Dictionary.class);
+        doReturn("value").when(dictionary).get("name");
+
+        BundleContext bundleContext = mock(BundleContext.class);
+        doReturn("ignored").when(bundleContext).getProperty("name");
+
+        ComponentContext componentContext = mock(ComponentContext.class);
+        doReturn(dictionary).when(componentContext).getProperties();
+        doReturn(bundleContext).when(componentContext).getBundleContext();
+
+        assertEquals("value", fallbackLookup(componentContext, "name"));
+    }
+
+}

Propchange: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/osgi/OsgiUtilTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to