diff --git oak-core/pom.xml oak-core/pom.xml
index 66d41fe..bdf3f36 100644
--- oak-core/pom.xml
+++ oak-core/pom.xml
@@ -350,5 +350,21 @@
       <version>1.1.1</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.connect</artifactId>
+      <version>0.1.0</version>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>org.osgi</groupId>
+          <artifactId>org.osgi.core</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.osgi</groupId>
+          <artifactId>org.osgi.compendium</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
   </dependencies>
 </project>
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/OsgiWhiteboard.java oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/OsgiWhiteboard.java
index 222961a..4bf97d1 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/OsgiWhiteboard.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/OsgiWhiteboard.java
@@ -33,6 +33,7 @@ import java.util.SortedMap;
 import java.util.concurrent.atomic.AtomicReference;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
 import org.apache.jackrabbit.oak.spi.whiteboard.Tracker;
@@ -94,7 +95,7 @@ public class OsgiWhiteboard implements Whiteboard {
      * whenever services are added, modified or removed.
      */
     @Override
-    public <T> Tracker<T> track(final Class<T> type) {
+    public <T> Tracker<T> track(final Class<T> type, @Nullable final Runnable refreshCallback) {
         checkNotNull(type);
         final AtomicReference<List<T>> list =
                 new AtomicReference<List<T>>(Collections.<T>emptyList());
@@ -102,8 +103,16 @@ public class OsgiWhiteboard implements Whiteboard {
                 new ServiceTrackerCustomizer() {
                     private final Map<ServiceReference, T> services =
                             newHashMap();
-                    @Override @SuppressWarnings("unchecked")
-                    public synchronized Object addingService(
+                    @Override
+                    public Object addingService(ServiceReference reference) {
+                        Object result = addingService0(reference);
+                        if (result != null){
+                            invokeCallback();
+                        }
+                        return result;
+                    }
+                     @SuppressWarnings("unchecked")
+                    private synchronized Object addingService0(
                             ServiceReference reference) {
                         Object service = context.getService(reference);
                         if (type.isInstance(service)) {
@@ -115,8 +124,16 @@ public class OsgiWhiteboard implements Whiteboard {
                             return null;
                         }
                     }
-                    @Override @SuppressWarnings("unchecked")
-                    public synchronized void modifiedService(
+
+                    @Override
+                    public void modifiedService(
+                            ServiceReference reference, Object service) {
+                        modifiedService0(reference, service);
+                        invokeCallback();
+                    }
+
+                    @SuppressWarnings("unchecked")
+                    private synchronized void modifiedService0(
                             ServiceReference reference, Object service) {
                         // TODO: Figure out if the old reference instance
                         // would automatically reflect the updated properties.
@@ -126,8 +143,15 @@ public class OsgiWhiteboard implements Whiteboard {
                         services.put(reference, (T) service);
                         list.set(getServiceList(services));
                     }
+
                     @Override
-                    public synchronized void removedService(
+                    public void removedService(
+                            ServiceReference reference, Object service) {
+                        removedService0(reference, service);
+                        invokeCallback();
+                    }
+
+                    private synchronized void removedService0(
                             ServiceReference reference, Object service) {
                         services.remove(reference);
                         list.set(getServiceList(services));
@@ -136,6 +160,13 @@ public class OsgiWhiteboard implements Whiteboard {
                         // this method was invoked.
                         context.ungetService(reference);
                     }
+
+                    private void invokeCallback(){
+                        //Avoid invoking the callbacks from within the synchronized block
+                        if (refreshCallback != null){
+                            refreshCallback.run();
+                        }
+                    }
                 };
         final ServiceTracker tracker =
                 new ServiceTracker(context, type.getName(), customizer);
@@ -152,6 +183,11 @@ public class OsgiWhiteboard implements Whiteboard {
         };
     }
 
+    @Override
+    public <T> Tracker<T> track(Class<T> type) {
+        return track(type, null);
+    }
+
     /**
      * Utility method that sorts the service objects in the given map
      * according to their service rankings and returns the resulting list.
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/package-info.java oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/package-info.java
index 89473ab..c18f5fc 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/package-info.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/package-info.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("2.0")
+@Version("2.1.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.osgi;
 
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/DefaultWhiteboard.java oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/DefaultWhiteboard.java
index d5a4ad1..5d003cf 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/DefaultWhiteboard.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/DefaultWhiteboard.java
@@ -16,6 +16,13 @@
  */
 package org.apache.jackrabbit.oak.spi.whiteboard;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.common.collect.ImmutableSet;
+
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Lists.newArrayList;
@@ -23,13 +30,10 @@ import static com.google.common.collect.Maps.newHashMap;
 import static com.google.common.collect.Sets.newIdentityHashSet;
 import static java.util.Collections.emptyList;
 
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 public class DefaultWhiteboard implements Whiteboard {
 
     private final Map<Class<?>, Set<Object>> registry = newHashMap();
+    private final Map<Class<?>, Set<Runnable>> refreshCallbacks = newHashMap();
 
     private synchronized <T> void registered(Class<T> type, T service) {
         Set<Object> services = registry.get(type);
@@ -57,6 +61,37 @@ public class DefaultWhiteboard implements Whiteboard {
         }
     }
 
+    private synchronized void register(Class<?> type, Runnable callback){
+        Set<Runnable> callbacks = refreshCallbacks.get(type);
+        if (callbacks == null){
+            callbacks = newIdentityHashSet();
+            refreshCallbacks.put(type, callbacks);
+        }
+        callbacks.add(callback);
+    }
+
+    private synchronized void unregister(Class<?> type, Runnable callback){
+        Set<Runnable> callbacks = refreshCallbacks.get(type);
+        if (callbacks != null) {
+            callbacks.remove(callback);
+        }
+    }
+
+    private void invokeCallbacks(Class<?> type){
+        Set<Runnable> callbacks = Collections.emptySet();
+        synchronized (this){
+            Set<Runnable> registeredCbs = refreshCallbacks.get(type);
+            if (registeredCbs != null){
+                callbacks = ImmutableSet.copyOf(registeredCbs);
+            }
+        }
+
+        //Avoid invoking the callbacks from within the synchronized block
+        for (Runnable r : callbacks){
+            r.run();
+        }
+    }
+
     //--------------------------------------------------------< Whiteboard >--
 
     @Override
@@ -66,9 +101,11 @@ public class DefaultWhiteboard implements Whiteboard {
         checkNotNull(service);
         checkArgument(type.isInstance(service));
         registered(type, service);
+        invokeCallbacks(type);
         return new Registration() {
             @Override
             public void unregister() {
+                invokeCallbacks(type);
                 unregistered(type, service);
             }
         };
@@ -76,7 +113,15 @@ public class DefaultWhiteboard implements Whiteboard {
 
     @Override
     public <T> Tracker<T> track(final Class<T> type) {
+       return track(type, null);
+    }
+
+    @Override
+    public <T> Tracker<T> track(final Class<T> type, final Runnable refreshCallback) {
         checkNotNull(type);
+        if (refreshCallback != null) {
+            register(type, refreshCallback);
+        }
         return new Tracker<T>() {
             @Override
             public List<T> getServices() {
@@ -84,6 +129,9 @@ public class DefaultWhiteboard implements Whiteboard {
             }
             @Override
             public void stop() {
+                if (refreshCallback != null){
+                    unregister(type, refreshCallback);
+                }
             }
         };
     }
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/Whiteboard.java oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/Whiteboard.java
index 44c96c5..e1b86d6 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/Whiteboard.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/Whiteboard.java
@@ -18,6 +18,9 @@ package org.apache.jackrabbit.oak.spi.whiteboard;
 
 import java.util.Map;
 
+import aQute.bnd.annotation.ProviderType;
+
+@ProviderType
 public interface Whiteboard {
 
     /**
@@ -39,4 +42,14 @@ public interface Whiteboard {
      */
     <T> Tracker<T> track(Class<T> type);
 
+    /**
+     * Starts tracking services of the given type.
+     *
+     * @param type type of the services to track
+     * @param refreshCallback runnable which would be invoked in case
+     *                        there is some change in registered services
+     * @return service tracker
+     */
+    <T> Tracker<T> track(Class<T> type, Runnable refreshCallback);
+
 }
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/package-info.java oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/package-info.java
index 4e301d4..53c3d76 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/package-info.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/whiteboard/package-info.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.1.0")
+@Version("1.2.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.spi.whiteboard;
 
diff --git oak-core/src/test/java/org/apache/jackrabbit/oak/osgi/OsgiWhiteboardIT.java oak-core/src/test/java/org/apache/jackrabbit/oak/osgi/OsgiWhiteboardIT.java
new file mode 100644
index 0000000..8bd98e1
--- /dev/null
+++ oak-core/src/test/java/org/apache/jackrabbit/oak/osgi/OsgiWhiteboardIT.java
@@ -0,0 +1,68 @@
+/*
+ * 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 java.util.Hashtable;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.felix.connect.PojoServiceRegistryFactoryImpl;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.apache.jackrabbit.oak.spi.whiteboard.DefaultWhiteboardTest;
+import org.apache.jackrabbit.oak.spi.whiteboard.Tracker;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import static org.junit.Assert.assertEquals;
+
+public class OsgiWhiteboardIT extends DefaultWhiteboardTest {
+    private BundleContext bundleContext;
+
+    @Override
+    protected Whiteboard createWhiteBoard() throws Exception {
+        //Create registry with non existent bundle as we just want an
+        //empty serv
+        PojoServiceRegistry sr = new PojoServiceRegistryFactoryImpl()
+                .newPojoServiceRegistry(ImmutableMap.<String, Object>of(
+                        "pojosr.filter", "(|(Bundle-SymbolicName=foo.bar)"));
+        bundleContext = sr.getBundleContext();
+        return new OsgiWhiteboard(bundleContext);
+    }
+
+    @Test
+    public void modifiedCallback() throws Exception{
+        TestCallback cb = new TestCallback();
+        Tracker<TestClass> t = wb.track(TestClass.class, cb);
+
+        Hashtable<Object, Object> props = new Hashtable<Object, Object>();
+        props.put("foo", "bar");
+        ServiceRegistration reg = bundleContext.registerService(TestClass.class.getName(), new TestClass(), props);
+
+        assertEquals(1, cb.invocationCount);
+
+        props.put("foo", "cat");
+        reg.setProperties(props);
+        assertEquals("Callback should be invoked upon service property modification", 2, cb.invocationCount);
+
+        reg.unregister();
+        assertEquals(3, cb.invocationCount);
+    }
+}
diff --git oak-core/src/test/java/org/apache/jackrabbit/oak/spi/whiteboard/DefaultWhiteboardTest.java oak-core/src/test/java/org/apache/jackrabbit/oak/spi/whiteboard/DefaultWhiteboardTest.java
new file mode 100644
index 0000000..d443f1b
--- /dev/null
+++ oak-core/src/test/java/org/apache/jackrabbit/oak/spi/whiteboard/DefaultWhiteboardTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.spi.whiteboard;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static java.util.Collections.emptyMap;
+import static org.junit.Assert.assertEquals;
+
+public class DefaultWhiteboardTest {
+    protected Whiteboard wb;
+
+    @Before
+    public void setUp() throws Exception {
+        wb = createWhiteBoard();
+    }
+
+    @Test
+    public void register() throws Exception{
+        Registration r1 = wb.register(TestClass.class, new TestClass(), emptyMap());
+        assertEquals(1, WhiteboardUtils.getServices(wb, TestClass.class).size());
+
+        Registration r2 = wb.register(TestClass.class, new TestClass(), emptyMap());
+        assertEquals(2, WhiteboardUtils.getServices(wb, TestClass.class).size());
+
+        r1.unregister();
+        assertEquals(1, WhiteboardUtils.getServices(wb, TestClass.class).size());
+
+        r2.unregister();
+        assertEquals(0, WhiteboardUtils.getServices(wb, TestClass.class).size());
+    }
+
+    @Test
+    public void callback() throws Exception{
+        TestCallback cb = new TestCallback();
+        Tracker<TestClass> t = wb.track(TestClass.class, cb);
+
+        Registration r1 = wb.register(TestClass.class, new TestClass(), emptyMap());
+        assertEquals(1, cb.invocationCount);
+
+        Registration r2 = wb.register(TestClass.class, new TestClass(), emptyMap());
+        assertEquals(2, cb.invocationCount);
+
+        r1.unregister();
+        assertEquals(3, cb.invocationCount);
+
+        Registration r3 = wb.register(Object.class, new Object(), emptyMap());
+        assertEquals("No callback should happen for change in non related type", 3, cb.invocationCount);
+
+        r3.unregister();
+        assertEquals("No callback should happen for change in non related type", 3, cb.invocationCount);
+
+        r2.unregister();
+        assertEquals(4, cb.invocationCount);
+
+        t.stop();
+        Registration r4 = wb.register(TestClass.class, new TestClass(), emptyMap());
+        assertEquals("No callback should happen post tracker stop", 4, cb.invocationCount);
+
+    }
+
+    protected Whiteboard createWhiteBoard() throws Exception {
+        return new DefaultWhiteboard();
+    }
+
+    protected static final class TestClass {
+        public TestClass(){
+
+        }
+    }
+
+    protected static final class TestCallback implements Runnable {
+        public int invocationCount;
+
+        public TestCallback(){
+
+        }
+
+        @Override
+        public void run() {
+            invocationCount++;
+        }
+
+        public void reset(){
+            invocationCount = 0;
+        }
+    }
+}
\ No newline at end of file
