You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2015/01/11 08:58:33 UTC

karaf-cellar git commit: [KARAF-2168] Rename sync properties and usage

Repository: karaf-cellar
Updated Branches:
  refs/heads/cellar-2.3.x dc7ec5087 -> 5ed6e332c


[KARAF-2168] Rename sync properties and usage


Project: http://git-wip-us.apache.org/repos/asf/karaf-cellar/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf-cellar/commit/5ed6e332
Tree: http://git-wip-us.apache.org/repos/asf/karaf-cellar/tree/5ed6e332
Diff: http://git-wip-us.apache.org/repos/asf/karaf-cellar/diff/5ed6e332

Branch: refs/heads/cellar-2.3.x
Commit: 5ed6e332c49e3743030d1407db83e50d99ac05e6
Parents: dc7ec50
Author: Jean-Baptiste Onofré <jb...@apache.org>
Authored: Sun Jan 11 08:58:19 2015 +0100
Committer: Jean-Baptiste Onofré <jb...@apache.org>
Committed: Sun Jan 11 08:58:19 2015 +0100

----------------------------------------------------------------------
 assembly/src/main/resources/groups.cfg          | 41 ++++++++++-----
 assembly/src/main/resources/node.cfg            |  3 +-
 .../karaf/cellar/bundle/BundleSynchronizer.java | 51 +++++++++++++------
 .../config/ConfigurationSynchronizer.java       | 44 ++++++++++++-----
 .../apache/karaf/cellar/core/Synchronizer.java  | 15 ++++--
 .../karaf/cellar/event/LocalEventListener.java  | 29 ++++++++++-
 .../cellar/features/FeaturesSynchronizer.java   | 52 ++++++++++++++------
 .../hazelcast/CellarMembershipListener.java     |  5 +-
 .../cellar/hazelcast/HazelcastGroupManager.java |  5 +-
 .../management/internal/CellarMBeanImpl.java    |  5 +-
 .../karaf/cellar/obr/ObrUrlSynchronizer.java    | 52 +++++++++++++++-----
 .../apache/karaf/cellar/shell/SyncCommand.java  |  7 +--
 12 files changed, 219 insertions(+), 90 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/5ed6e332/assembly/src/main/resources/groups.cfg
----------------------------------------------------------------------
diff --git a/assembly/src/main/resources/groups.cfg b/assembly/src/main/resources/groups.cfg
index 4337320..1b9d592 100644
--- a/assembly/src/main/resources/groups.cfg
+++ b/assembly/src/main/resources/groups.cfg
@@ -3,6 +3,17 @@
 #
 groups = default
 
+#
+# Filtering of the bundles in the default cluster group
+#
+default.bundle.whitelist.inbound = *
+default.bundle.whitelist.outbound = *
+default.bundle.blacklist.inbound = *.xml
+default.bundle.blacklist.outbound = *.xml
+
+#
+# Filtering of the configurations in the default cluster group
+#
 default.config.whitelist.inbound = *
 default.config.whitelist.outbound = *
 default.config.blacklist.inbound = org.apache.felix.fileinstall*, \
@@ -17,20 +28,28 @@ default.config.blacklist.outbound = org.apache.felix.fileinstall*, \
                                     org.apache.karaf.shell, \
                                     org.ops4j.pax.logging, \
                                     org.ops4j.pax.web
-default.config.sync = true
 
+#
+# Filtering of the features in the default cluster group
+#
 default.features.whitelist.inbound = *
 default.features.whitelist.outbound = *
 default.features.blacklist.inbound = config,management,hazelcast,cellar*
 default.features.blacklist.outbound = config,management,hazelcast,cellar*
-default.features.sync = true
-default.features.repositories.sync = true
 
-default.bundle.whitelist.inbound = *
-default.bundle.whitelist.outbound = *
-default.bundle.blacklist.inbound = *.xml
-default.bundle.blacklist.outbound = *.xml
-default.bundle.sync = true
-
-default.obr.urls.sync = true
-default.obr.bundles.sync = true
+#
+# The following properties define the behavior to use when the node joins the cluster (the usage of the bootstrap
+# synchronizer), per cluster group and per resource.
+# The following values are accepted:
+# disabled: means that the synchronizer is not used, meaning the node or the cluster are not updated at all
+# cluster: if the node is the first one in the cluster, it pushes its local state to the cluster, else it's not the
+#       first node of the cluster, the node will update its local state with the cluster one (meaning that the cluster
+#       is the master)
+# node: in this case, the node is the master, it means that the cluster state will be overwritten by the node state.
+#
+default.bundle.sync = cluster
+default.config.sync = cluster
+default.feature.sync = cluster
+default.feature.repositories.sync = cluster
+default.obr.urls.sync = cluster
+default.obr.bundles.sync = cluster
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/5ed6e332/assembly/src/main/resources/node.cfg
----------------------------------------------------------------------
diff --git a/assembly/src/main/resources/node.cfg b/assembly/src/main/resources/node.cfg
index 5db7ba9..024a548 100644
--- a/assembly/src/main/resources/node.cfg
+++ b/assembly/src/main/resources/node.cfg
@@ -4,12 +4,13 @@
 groups = default
 
 #
-# These properties define if the local event listeners (per resource)
+# The following properties define if the local event listeners (per resource)
 # A local listener listens for local events (like bundle install, etc) and broadcast this state change to the cluster
 #
 bundle.listener = false
 config.listener = false
 feature.listener = false
+event.listener = true;
 
 #
 # Cluster event producer

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/5ed6e332/bundle/src/main/java/org/apache/karaf/cellar/bundle/BundleSynchronizer.java
----------------------------------------------------------------------
diff --git a/bundle/src/main/java/org/apache/karaf/cellar/bundle/BundleSynchronizer.java b/bundle/src/main/java/org/apache/karaf/cellar/bundle/BundleSynchronizer.java
index 4413f54..ca0f182 100644
--- a/bundle/src/main/java/org/apache/karaf/cellar/bundle/BundleSynchronizer.java
+++ b/bundle/src/main/java/org/apache/karaf/cellar/bundle/BundleSynchronizer.java
@@ -47,10 +47,7 @@ public class BundleSynchronizer extends BundleSupport implements Synchronizer {
         Set<Group> groups = groupManager.listLocalGroups();
         if (groups != null && !groups.isEmpty()) {
             for (Group group : groups) {
-                if (isSyncEnabled(group)) {
-                    pull(group);
-                    push(group);
-                } else LOGGER.debug("CELLAR BUNDLE: sync is disabled for cluster group {}", group.getName());
+                sync(group);
             }
         }
     }
@@ -60,6 +57,30 @@ public class BundleSynchronizer extends BundleSupport implements Synchronizer {
     }
 
     /**
+     * Sync the node and cluster states, depending of the sync policy.
+     *
+     * @param group the target cluster group.
+     */
+    @Override
+    public void sync(Group group) {
+        String policy = getSyncPolicy(group);
+        if (policy != null && policy.equalsIgnoreCase("cluster")) {
+            LOGGER.debug("CELLAR BUNDLE: sync policy is set as 'cluster' for cluster group " + group.getName());
+            if (clusterManager.listNodesByGroup(group).size() == 1 && clusterManager.listNodesByGroup(group).contains(clusterManager.getNode())) {
+                LOGGER.debug("CELLAR BUNDLE: node is the first and only member of the group, pushing state");
+                push(group);
+            } else {
+                LOGGER.debug("CELLAR BUNDLE: pulling state");
+                pull(group);
+            }
+        }
+        if (policy != null && policy.equalsIgnoreCase("node")) {
+            LOGGER.debug("CELLAR BUNDLE: sync policy is set as 'cluster' for cluster group " + group.getName());
+            push(group);
+        }
+    }
+
+    /**
      * Pull the bundles states from a cluster group.
      *
      * @param group the cluster group where to get the bundles states.
@@ -95,7 +116,8 @@ public class BundleSynchronizer extends BundleSupport implements Synchronizer {
                                 } catch (BundleException e) {
                                     LOGGER.error("CELLAR BUNDLE: failed to pull bundle {}", id, e);
                                 }
-                            } else LOGGER.debug("CELLAR BUNDLE: bundle {} is marked BLOCKED INBOUND for cluster group {}", bundleLocation, groupName);
+                            } else
+                                LOGGER.debug("CELLAR BUNDLE: bundle {} is marked BLOCKED INBOUND for cluster group {}", bundleLocation, groupName);
                         }
                     }
                 }
@@ -180,7 +202,8 @@ public class BundleSynchronizer extends BundleSupport implements Synchronizer {
                             eventProducer.produce(event);
                         }
 
-                    } else LOGGER.debug("CELLAR BUNDLE: bundle {} is marked as BLOCKED OUTBOUND for cluster group {}", bundleLocation, groupName);
+                    } else
+                        LOGGER.debug("CELLAR BUNDLE: bundle {} is marked as BLOCKED OUTBOUND for cluster group {}", bundleLocation, groupName);
                 }
             } finally {
                 Thread.currentThread().setContextClassLoader(originalClassLoader);
@@ -189,28 +212,26 @@ public class BundleSynchronizer extends BundleSupport implements Synchronizer {
     }
 
     /**
-     * Check if the bundle sync flag is enabled for a cluster group.
+     * Get the bundle sync policy for the given cluster group.
      *
      * @param group the cluster group.
-     * @return true if the bundle sync flag is enabled, false else.
+     * @return the current bundle sync policy for the given cluster group.
      */
     @Override
-    public Boolean isSyncEnabled(Group group) {
-        Boolean result = Boolean.FALSE;
+    public String getSyncPolicy(Group group) {
         String groupName = group.getName();
 
         try {
-            Configuration configuration = configurationAdmin.getConfiguration(Configurations.GROUP);
+            Configuration configuration = configurationAdmin.getConfiguration(Configurations.GROUP, null);
             Dictionary<String, Object> properties = configuration.getProperties();
             if (properties != null) {
                 String propertyKey = groupName + Configurations.SEPARATOR + Constants.CATEGORY + Configurations.SEPARATOR + Configurations.SYNC;
-                String propertyValue = (String) properties.get(propertyKey);
-                result = Boolean.parseBoolean(propertyValue);
+                return properties.get(propertyKey).toString();
             }
         } catch (IOException e) {
-            LOGGER.warn("CELLAR BUNDLE: failed to check if sync is enabled", e);
+            LOGGER.error("CELLAR BUNDLE: error while retrieving the sync policy", e);
         }
-        return result;
+        return "disabled";
     }
 
     public EventProducer getEventProducer() {

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/5ed6e332/config/src/main/java/org/apache/karaf/cellar/config/ConfigurationSynchronizer.java
----------------------------------------------------------------------
diff --git a/config/src/main/java/org/apache/karaf/cellar/config/ConfigurationSynchronizer.java b/config/src/main/java/org/apache/karaf/cellar/config/ConfigurationSynchronizer.java
index c1804fa..6ee686f 100644
--- a/config/src/main/java/org/apache/karaf/cellar/config/ConfigurationSynchronizer.java
+++ b/config/src/main/java/org/apache/karaf/cellar/config/ConfigurationSynchronizer.java
@@ -48,10 +48,7 @@ public class ConfigurationSynchronizer extends ConfigurationSupport implements S
         Set<Group> groups = groupManager.listLocalGroups();
         if (groups != null && !groups.isEmpty()) {
             for (Group group : groups) {
-                if (isSyncEnabled(group)) {
-                    pull(group);
-                    push(group);
-                } else LOGGER.debug("CELLAR CONFIG: sync is disabled for cluster group {}", group.getName());
+                sync(group);
             }
         }
     }
@@ -61,6 +58,30 @@ public class ConfigurationSynchronizer extends ConfigurationSupport implements S
     }
 
     /**
+     * Sync node and cluster states, depending of the sync policy.
+     *
+     * @param group the target cluster group.
+     */
+    @Override
+    public void sync(Group group) {
+        String policy = getSyncPolicy(group);
+        if (policy != null && policy.equalsIgnoreCase("cluster")) {
+            LOGGER.debug("CELLAR CONFIG: sync policy is set as 'cluster' for cluster group " + group.getName());
+            if (clusterManager.listNodesByGroup(group).size() == 1 && clusterManager.listNodesByGroup(group).contains(clusterManager.getNode())) {
+                LOGGER.debug("CELLAR CONFIG: node is the first and only member of the group, pushing state");
+                push(group);
+            } else {
+                LOGGER.debug("CELLAR CONFIG: pulling state");
+                pull(group);
+            }
+        }
+        if (policy != null && policy.equalsIgnoreCase("node")) {
+            LOGGER.debug("CELLAR CONFIG: sync policy is set as 'cluster' for cluster group " + group.getName());
+            push(group);
+        }
+    }
+
+    /**
      * Pull the configurations from a cluster group to update the local ones.
      *
      * @param group the cluster group where to get the configurations.
@@ -152,27 +173,26 @@ public class ConfigurationSynchronizer extends ConfigurationSupport implements S
     }
 
     /**
-     * Check if configuration sync flag is enabled for a cluster group.
+     * Get the bundle sync policy for the given cluster group.
      *
      * @param group the cluster group.
-     * @return true if the configuration sync flag is enabled for the cluster group, false else.
+     * @return the current configuration sync policy for the given cluster group
      */
     @Override
-    public Boolean isSyncEnabled(Group group) {
+    public String getSyncPolicy(Group group) {
         Boolean result = Boolean.FALSE;
         String groupName = group.getName();
         try {
-            Configuration configuration = configurationAdmin.getConfiguration(Configurations.GROUP);
+            Configuration configuration = configurationAdmin.getConfiguration(Configurations.GROUP, null);
             Dictionary<String, Object> properties = configuration.getProperties();
             if (properties != null) {
                 String propertyKey = groupName + Configurations.SEPARATOR + Constants.CATEGORY + Configurations.SEPARATOR + Configurations.SYNC;
-                String propertyValue = (String) properties.get(propertyKey);
-                result = Boolean.parseBoolean(propertyValue);
+                return properties.get(propertyKey).toString();
             }
         } catch (IOException e) {
-            LOGGER.error("CELLAR CONFIG: failed to check if sync is enabled", e);
+            LOGGER.error("CELLAR CONFIG: error while retrieving the sync policy", e);
         }
-        return result;
+        return "disabled";
     }
 
     public EventProducer getEventProducer() {

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/5ed6e332/core/src/main/java/org/apache/karaf/cellar/core/Synchronizer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/karaf/cellar/core/Synchronizer.java b/core/src/main/java/org/apache/karaf/cellar/core/Synchronizer.java
index 910e3d8..d5f0f72 100644
--- a/core/src/main/java/org/apache/karaf/cellar/core/Synchronizer.java
+++ b/core/src/main/java/org/apache/karaf/cellar/core/Synchronizer.java
@@ -33,11 +33,18 @@ public interface Synchronizer {
     public void pull(Group group);
 
     /**
-     * Check if the sync flag is enabled for a given cluster group.
+     * Sync the node and the cluster, depending of the sync policy.
      *
-     * @param group the cluster group where to check the sync flag.
-     * @return true if the sync flag is enabled, false else.
+     * @param group the target cluster group.
      */
-    public Boolean isSyncEnabled(Group group);
+    public void sync(Group group);
+
+    /**
+     * Get the sync policy for a given cluster group.
+     *
+     * @param group the cluster group.
+     * @return the current sync policy for the given cluster group.
+     */
+    public String getSyncPolicy(Group group);
 
 }

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/5ed6e332/event/src/main/java/org/apache/karaf/cellar/event/LocalEventListener.java
----------------------------------------------------------------------
diff --git a/event/src/main/java/org/apache/karaf/cellar/event/LocalEventListener.java b/event/src/main/java/org/apache/karaf/cellar/event/LocalEventListener.java
index feb1ae4..ceeebbd 100644
--- a/event/src/main/java/org/apache/karaf/cellar/event/LocalEventListener.java
+++ b/event/src/main/java/org/apache/karaf/cellar/event/LocalEventListener.java
@@ -13,16 +13,19 @@
  */
 package org.apache.karaf.cellar.event;
 
+import org.apache.karaf.cellar.core.Configurations;
 import org.apache.karaf.cellar.core.Group;
 import org.apache.karaf.cellar.core.control.SwitchStatus;
 import org.apache.karaf.cellar.core.event.EventProducer;
 import org.apache.karaf.cellar.core.event.EventType;
+import org.osgi.service.cm.Configuration;
 import org.osgi.service.event.Event;
 import org.osgi.service.event.EventHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.Serializable;
+import java.util.Dictionary;
 import java.util.Map;
 import java.util.Set;
 
@@ -35,6 +38,11 @@ public class LocalEventListener extends EventSupport implements EventHandler {
     @Override
     public void handleEvent(Event event) {
 
+        if (!isEnabled()) {
+            LOGGER.debug("CELLAR EVENT: local listener is disabled");
+            return;
+        }
+
         // ignore log entry event
         if (event.getTopic().startsWith("org/osgi/service/log/LogEntry"))
             return;
@@ -57,7 +65,7 @@ public class LocalEventListener extends EventSupport implements EventHandler {
 
                 // filter already processed events
                 if (hasEventProperty(event, Constants.EVENT_PROCESSED_KEY)) {
-                    if (event.getProperty(Constants.EVENT_PROCESSED_KEY).equals(Constants.EVENT_PROCESSED_VALUE)){
+                    if (event.getProperty(Constants.EVENT_PROCESSED_KEY).equals(Constants.EVENT_PROCESSED_VALUE)) {
                         LOGGER.debug("CELLAR EVENT: filtered out event {}", event.getTopic());
                         return;
                     }
@@ -82,6 +90,25 @@ public class LocalEventListener extends EventSupport implements EventHandler {
     }
 
     /**
+     * Check if the local config listener is enabled in the etc/org.apache.karaf.cellar.groups.cfg.
+     *
+     * @return true if enabled, false else.
+     */
+    private boolean isEnabled() {
+        try {
+            Configuration configuration = configurationAdmin.getConfiguration(Configurations.NODE, null);
+            Dictionary<String, Object> properties = configuration.getProperties();
+            if (properties != null) {
+                String value = properties.get(Constants.CATEGORY + Configurations.SEPARATOR + Configurations.LISTENER).toString();
+                return Boolean.parseBoolean(value);
+            }
+        } catch (Exception e) {
+            LOGGER.warn("CELLAR EVENT: can't check listener configuration", e);
+        }
+        return false;
+    }
+
+    /**
      * Initialization method.
      */
     public void init() {

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/5ed6e332/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSynchronizer.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSynchronizer.java b/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSynchronizer.java
index bd0d907..72ca64e 100644
--- a/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSynchronizer.java
+++ b/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSynchronizer.java
@@ -40,14 +40,10 @@ public class FeaturesSynchronizer extends FeaturesSupport implements Synchronize
 
     @Override
     public void init() {
-        super.init();
         Set<Group> groups = groupManager.listLocalGroups();
         if (groups != null && !groups.isEmpty()) {
             for (Group group : groups) {
-                if (isSyncEnabled(group)) {
-                    pull(group);
-                    push(group);
-                } else LOGGER.debug("CELLAR FEATURES_MAP: sync is disabled for cluster group {}", group.getName());
+                sync(group);
             }
         }
     }
@@ -58,6 +54,30 @@ public class FeaturesSynchronizer extends FeaturesSupport implements Synchronize
     }
 
     /**
+     * Sync node and cluster states, depending of the sync policy.
+     *
+     * @param group the target cluster group.
+     */
+    @Override
+    public void sync(Group group) {
+        String policy = getSyncPolicy(group);
+        if (policy != null && policy.equalsIgnoreCase("cluster")) {
+            LOGGER.debug("CELLAR FEATURE: sync policy is set as 'cluster' for cluster group " + group.getName());
+            if (clusterManager.listNodesByGroup(group).size() == 1 && clusterManager.listNodesByGroup(group).contains(clusterManager.getNode())) {
+                LOGGER.debug("CELLAR FEATURE: node is the first and only member of the group, pushing state");
+                push(group);
+            } else {
+                LOGGER.debug("CELLAR FEATURE: pulling state");
+                pull(group);
+            }
+        }
+        if (policy != null && policy.equalsIgnoreCase("node")) {
+            LOGGER.debug("CELLAR FEATURE: sync policy is set as 'cluster' for cluster group " + group.getName());
+            push(group);
+        }
+    }
+
+    /**
      * Pull features repositories and features status from a cluster group, and update the local status.
      *
      * @param group the cluster group where to pull.
@@ -112,7 +132,7 @@ public class FeaturesSynchronizer extends FeaturesSupport implements Synchronize
                                     LOGGER.debug("CELLAR FEATURES_MAP: installing feature {}/{}", info.getName(), info.getVersion());
                                     featuresService.installFeature(info.getName(), info.getVersion());
                                 } catch (Exception e) {
-                                    LOGGER.warn("CELLAR FEATURES_MAP: failed to install feature {}/{} ", new Object[]{ info.getName(), info.getVersion() }, e);
+                                    LOGGER.warn("CELLAR FEATURES_MAP: failed to install feature {}/{} ", new Object[]{info.getName(), info.getVersion()}, e);
                                 }
                                 // if feature has to be uninstalled locally
                             } else if (!clusterInstalled && locallyInstalled) {
@@ -120,10 +140,11 @@ public class FeaturesSynchronizer extends FeaturesSupport implements Synchronize
                                     LOGGER.debug("CELLAR FEATURES_MAP: un-installing feature {}/{}", info.getName(), info.getVersion());
                                     featuresService.uninstallFeature(info.getName(), info.getVersion());
                                 } catch (Exception e) {
-                                    LOGGER.warn("CELLAR FEATURES_MAP: failed to uninstall feature {}/{} ", new Object[]{ info.getName(), info.getVersion() }, e);
+                                    LOGGER.warn("CELLAR FEATURES_MAP: failed to uninstall feature {}/{} ", new Object[]{info.getName(), info.getVersion()}, e);
                                 }
                             }
-                        } else LOGGER.warn("CELLAR FEATURES_MAP: feature {} is marked BLOCKED INBOUND for cluster group {}", name, groupName);
+                        } else
+                            LOGGER.warn("CELLAR FEATURES_MAP: feature {} is marked BLOCKED INBOUND for cluster group {}", name, groupName);
                     }
                 }
             } finally {
@@ -141,7 +162,7 @@ public class FeaturesSynchronizer extends FeaturesSupport implements Synchronize
     public void push(Group group) {
         if (group != null) {
             String groupName = group.getName();
-            LOGGER.debug("CELLAR FEATURES_MAP: pushing features repositories and features in cluster group {}.",groupName);
+            LOGGER.debug("CELLAR FEATURES_MAP: pushing features repositories and features in cluster group {}.", groupName);
             clusterManager.getList(Constants.FEATURES_MAP + Configurations.SEPARATOR + groupName);
 
             ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
@@ -180,28 +201,27 @@ public class FeaturesSynchronizer extends FeaturesSupport implements Synchronize
     }
 
     /**
-     * Check if the features sync flag is enabled for a cluster group.
+     * Get the features sync policy for the given cluster group.
      *
      * @param group the cluster group.
-     * @return true if sync flag is enabled for the cluster group, false else.
+     * @return the current features sync policy for the given cluster group.
      */
     @Override
-    public Boolean isSyncEnabled(Group group) {
+    public String getSyncPolicy(Group group) {
         Boolean result = Boolean.FALSE;
         String groupName = group.getName();
 
         try {
-            Configuration configuration = configurationAdmin.getConfiguration(Configurations.GROUP);
+            Configuration configuration = configurationAdmin.getConfiguration(Configurations.GROUP, null);
             Dictionary<String, Object> properties = configuration.getProperties();
             if (properties != null) {
                 String propertyKey = groupName + Configurations.SEPARATOR + Constants.CATEGORY + Configurations.SEPARATOR + Configurations.SYNC;
-                String propertyValue = (String) properties.get(propertyKey);
-                result = Boolean.parseBoolean(propertyValue);
+                return properties.get(propertyKey).toString();
             }
         } catch (IOException e) {
             LOGGER.warn("CELLAR FEATURES_MAP: error while checking if sync is enabled", e);
         }
-        return result;
+        return "disabled";
     }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/5ed6e332/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/CellarMembershipListener.java
----------------------------------------------------------------------
diff --git a/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/CellarMembershipListener.java b/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/CellarMembershipListener.java
index 0eeafee..8ed412e 100644
--- a/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/CellarMembershipListener.java
+++ b/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/CellarMembershipListener.java
@@ -53,10 +53,7 @@ public class CellarMembershipListener extends HazelcastInstanceAware implements
                     if (groups != null && !groups.isEmpty()) {
                         for (Group group : groups) {
                             for (Synchronizer synchronizer : synchronizers) {
-                                if (synchronizer.isSyncEnabled(group)) {
-                                    synchronizer.pull(group);
-                                    synchronizer.push(group);
-                                }
+                                synchronizer.sync(group);
                             }
                         }
                     }

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/5ed6e332/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/HazelcastGroupManager.java
----------------------------------------------------------------------
diff --git a/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/HazelcastGroupManager.java b/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/HazelcastGroupManager.java
index e937ff6..8e413c3 100644
--- a/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/HazelcastGroupManager.java
+++ b/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/HazelcastGroupManager.java
@@ -397,9 +397,8 @@ public class HazelcastGroupManager implements GroupManager, EntryListener, Confi
                 if (serviceReferences != null && serviceReferences.length > 0) {
                     for (ServiceReference ref : serviceReferences) {
                         Synchronizer synchronizer = (Synchronizer) bundleContext.getService(ref);
-                        if (synchronizer != null && synchronizer.isSyncEnabled(group)) {
-                            synchronizer.pull(group);
-                            synchronizer.push(group);
+                        if (synchronizer != null) {
+                            synchronizer.sync(group);
                         }
                         bundleContext.ungetService(ref);
                     }

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/5ed6e332/management/src/main/java/org/apache/karaf/cellar/management/internal/CellarMBeanImpl.java
----------------------------------------------------------------------
diff --git a/management/src/main/java/org/apache/karaf/cellar/management/internal/CellarMBeanImpl.java b/management/src/main/java/org/apache/karaf/cellar/management/internal/CellarMBeanImpl.java
index b0caa9b..e97c2c0 100644
--- a/management/src/main/java/org/apache/karaf/cellar/management/internal/CellarMBeanImpl.java
+++ b/management/src/main/java/org/apache/karaf/cellar/management/internal/CellarMBeanImpl.java
@@ -95,10 +95,7 @@ public class CellarMBeanImpl extends StandardMBean implements CellarMBean {
                 if (serviceReferences != null && serviceReferences.length > 0) {
                     for (ServiceReference ref : serviceReferences) {
                         Synchronizer synchronizer = (Synchronizer) bundleContext.getService(ref);
-                        if (synchronizer.isSyncEnabled(group)) {
-                            synchronizer.pull(group);
-                            synchronizer.push(group);
-                        }
+                        synchronizer.sync(group);
                         bundleContext.ungetService(ref);
                     }
                 }

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/5ed6e332/obr/src/main/java/org/apache/karaf/cellar/obr/ObrUrlSynchronizer.java
----------------------------------------------------------------------
diff --git a/obr/src/main/java/org/apache/karaf/cellar/obr/ObrUrlSynchronizer.java b/obr/src/main/java/org/apache/karaf/cellar/obr/ObrUrlSynchronizer.java
index 7d9cf64..0cf6f04 100644
--- a/obr/src/main/java/org/apache/karaf/cellar/obr/ObrUrlSynchronizer.java
+++ b/obr/src/main/java/org/apache/karaf/cellar/obr/ObrUrlSynchronizer.java
@@ -36,14 +36,10 @@ public class ObrUrlSynchronizer extends ObrSupport implements Synchronizer {
 
     @Override
     public void init() {
-        super.init();
         Set<Group> groups = groupManager.listLocalGroups();
         if (groups != null && !groups.isEmpty()) {
             for (Group group : groups) {
-                if (isSyncEnabled(group)) {
-                    pull(group);
-                    push(group);
-                } else LOGGER.debug("CELLAR OBR: sync is disabled for group {}", group.getName());
+                sync(group);
             }
         }
     }
@@ -54,6 +50,30 @@ public class ObrUrlSynchronizer extends ObrSupport implements Synchronizer {
     }
 
     /**
+     * Sync node and cluster states, depending of the sync policy.
+     *
+     * @param group the target cluster group.
+     */
+    @Override
+    public void sync(Group group) {
+        String policy = getSyncPolicy(group);
+        if (policy != null && policy.equalsIgnoreCase("cluster")) {
+            LOGGER.debug("CELLAR OBR: sync policy is set as 'cluster' for cluster group " + group.getName());
+            if (clusterManager.listNodesByGroup(group).size() == 1 && clusterManager.listNodesByGroup(group).contains(clusterManager.getNode())) {
+                LOGGER.debug("CELLAR OBR: node is the first and only member of the group, pushing state");
+                push(group);
+            } else {
+                LOGGER.debug("CELLAR OBR: pulling state");
+                pull(group);
+            }
+        }
+        if (policy != null && policy.equalsIgnoreCase("node")) {
+            LOGGER.debug("CELLAR OBR: sync policy is set as 'cluster' for cluster group " + group.getName());
+            push(group);
+        }
+    }
+
+    /**
      * Pull the OBR URLs from a cluster group to update the local state.
      *
      * @param group the cluster group.
@@ -118,21 +138,27 @@ public class ObrUrlSynchronizer extends ObrSupport implements Synchronizer {
         }
     }
 
+    /**
+     * Get the OBR sync policy for the given cluster group.
+     *
+     * @param group the cluster group.
+     * @return the current OBR sync policy.
+     */
     @Override
-    public Boolean isSyncEnabled(Group group) {
+    public String getSyncPolicy(Group group) {
         Boolean result = Boolean.FALSE;
         String groupName = group.getName();
-
         try {
-            Configuration configuration = configurationAdmin.getConfiguration(Configurations.GROUP);
+            Configuration configuration = configurationAdmin.getConfiguration(Configurations.GROUP, null);
             Dictionary<String, Object> properties = configuration.getProperties();
-            String propertyKey = groupName + Configurations.SEPARATOR + Constants.URLS_CONFIG_CATEGORY + Configurations.SEPARATOR + Configurations.SYNC;
-            String propertyValue = (String) properties.get(propertyKey);
-            result = Boolean.parseBoolean(propertyValue);
+            if (properties != null) {
+                String propertyKey = groupName + Configurations.SEPARATOR + Constants.URLS_CONFIG_CATEGORY + Configurations.SEPARATOR + Configurations.SYNC;
+                return properties.get(propertyKey).toString();
+            }
         } catch (IOException e) {
-            LOGGER.error("CELLAR OBR: error while checking if sync is enabled", e);
+            LOGGER.error("CELLAR OBR: error while retrieving the sync policy", e);
         }
-        return result;
+        return "disabled";
     }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf-cellar/blob/5ed6e332/shell/src/main/java/org/apache/karaf/cellar/shell/SyncCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/karaf/cellar/shell/SyncCommand.java b/shell/src/main/java/org/apache/karaf/cellar/shell/SyncCommand.java
index c3e41d3..ba62510 100644
--- a/shell/src/main/java/org/apache/karaf/cellar/shell/SyncCommand.java
+++ b/shell/src/main/java/org/apache/karaf/cellar/shell/SyncCommand.java
@@ -34,12 +34,7 @@ public class SyncCommand extends ClusterCommandSupport {
                 if (serviceReferences != null && serviceReferences.length > 0) {
                     for (ServiceReference ref : serviceReferences) {
                         Synchronizer synchronizer = (Synchronizer) bundleContext.getService(ref);
-                        if (synchronizer.isSyncEnabled(group)) {
-                            System.out.print("    sync " + synchronizer.getClass() + " ...");
-                            synchronizer.pull(group);
-                            synchronizer.push(group);
-                            System.out.println("OK");
-                        }
+                        synchronizer.sync(group);
                         bundleContext.ungetService(ref);
                     }
                 }