You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2013/04/22 12:58:51 UTC

svn commit: r1470448 [1/2] - in /sling/trunk/contrib/extensions/discovery/impl: ./ src/main/java/org/apache/sling/discovery/impl/ src/main/java/org/apache/sling/discovery/impl/cluster/voting/ src/main/java/org/apache/sling/discovery/impl/common/ src/ma...

Author: cziegeler
Date: Mon Apr 22 10:58:50 2013
New Revision: 1470448

URL: http://svn.apache.org/r1470448
Log:
SLING-2827 :  discovery.impl: a resource based implementation of the discovery.api . Apply patch from Stefan Egli 

Added:
    sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/helpers/AssertingTopologyEventListener.java   (with props)
Removed:
    sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/helpers/AssertingDiscoveryAware.java
Modified:
    sling/trunk/contrib/extensions/discovery/impl/pom.xml
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/Config.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/InfrastructurePropertyProvider.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/TopologyWebConsolePlugin.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHelper.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingView.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/View.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/resource/ResourceHelper.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/TopologyViewImpl.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/Announcement.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/AnnouncementFilter.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/AnnouncementRegistryImpl.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/ConnectorRegistry.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/ConnectorRegistryImpl.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorClient.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorClientInformation.java
    sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorServlet.java
    sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/ClusterTest.java
    sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/SingleInstanceTest.java
    sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/setup/Instance.java

Modified: sling/trunk/contrib/extensions/discovery/impl/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/pom.xml?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/pom.xml (original)
+++ sling/trunk/contrib/extensions/discovery/impl/pom.xml Mon Apr 22 10:58:50 2013
@@ -29,7 +29,7 @@
 
     <artifactId>org.apache.sling.discovery.impl</artifactId>
     <packaging>bundle</packaging>
-    <version>0.0.2-SNAPSHOT</version>
+    <version>0.0.6-SNAPSHOT</version>
 
     <name>Apache Sling Resource-Based Discovery Service</name>
     <description>Implementation of Apache Sling Discovery based on Sling Resource providing a ClusterView through resource-clustering (eg jackrabbit clustering) and a TopologyView through HTTP POST heartbeats announcing sub-topologies to each other.</description>
@@ -116,7 +116,7 @@
 		<dependency>
 			<groupId>org.apache.sling</groupId>
 			<artifactId>org.apache.sling.api</artifactId>
-			<version>2.3.0</version>
+			<version>2.4.0</version>
             <scope>provided</scope>
 		</dependency>
         <dependency>

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/Config.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/Config.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/Config.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/Config.java Mon Apr 22 10:58:50 2013
@@ -43,24 +43,26 @@ public class Config {
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
     /** node used to keep instance information such as last heartbeat, properties, incoming announcements **/
-    private static final String CLUSTERINSTANCES_NODE = "/clusterInstances";
+    private static final String CLUSTERINSTANCES_NODE = "clusterInstances";
 
     /** node used to keep the currently established view **/
-    private static final String ESTABLISHED_VIEW_NODE = "/establishedView";
+    private static final String ESTABLISHED_VIEW_NODE = "establishedView";
 
     /** node used to keep the previously established view **/
-    private static final String PREVIOUS_VIEW_NODE = "/previousView";
+    private static final String PREVIOUS_VIEW_NODE = "previousView";
 
     /** node used to keep ongoing votings **/
-    private static final String ONGOING_VOTING_NODE = "/ongoingVotings";
+    private static final String ONGOING_VOTING_NODE = "ongoingVotings";
 
     public static final long DEFAULT_HEARTBEAT_TIMEOUT = 20;
-    @Property(label = "Heartbeat timeout (seconds)", description = "Configure the timeout (in seconds) after which an instance is considered dead/crashed, eg 20.")
+    public static final String DEFAULT_HEARTBEAT_TIMEOUT_STR = DEFAULT_HEARTBEAT_TIMEOUT+"";
+    @Property(label = "Heartbeat timeout (seconds)", description = "Configure the timeout (in seconds) after which an instance is considered dead/crashed, eg 20.", value=DEFAULT_HEARTBEAT_TIMEOUT_STR)
     public static final String HEARTBEAT_TIMEOUT_KEY = "heartbeatTimeout";
     private long heartbeatTimeout = DEFAULT_HEARTBEAT_TIMEOUT;
 
     public static final long DEFAULT_HEARTBEAT_INTERVAL = 15;
-    @Property(label = "Heartbeat interval (seconds)", description = "Configure the interval (in seconds) according to which the heartbeats are exchanged in the topology, eg 15.")
+    public static final String DEFAULT_HEARTBEAT_INTERVAL_STR = DEFAULT_HEARTBEAT_INTERVAL+"";
+    @Property(label = "Heartbeat interval (seconds)", description = "Configure the interval (in seconds) according to which the heartbeats are exchanged in the topology, eg 15.", value=DEFAULT_HEARTBEAT_INTERVAL_STR)
     public static final String HEARTBEAT_INTERVAL_KEY = "heartbeatInterval";
     private long heartbeatInterval = DEFAULT_HEARTBEAT_INTERVAL;
 
@@ -68,13 +70,13 @@ public class Config {
     public static final String TOPOLOGY_CONNECTOR_URL_KEY = "topologyConnectorUrl";
     private URL topologyConnectorUrl = null;
 
-    private static final String DEFAULT_TOPOLOGY_CONNECTOR_WHITELIST = "localhost,127.0.0.1";
-    @Property(label = "Topology Connector Whitelist", description = "comma separated list of ips and/or hostnames which are allowed to connect to /libs/sling/topology/connector")
+    private static final String[] DEFAULT_TOPOLOGY_CONNECTOR_WHITELIST = {"localhost","127.0.0.1"};
+    @Property(label = "Topology Connector Whitelist", description = "list of ips and/or hostnames which are allowed to connect to /libs/sling/topology/connector", value={"localhost","127.0.0.1"})
     public static final String TOPOLOGY_CONNECTOR_WHITELIST_KEY = "topologyConnectorWhitelist";
-    private String topologyConnectorWhitelist = DEFAULT_TOPOLOGY_CONNECTOR_WHITELIST;
+    private String[] topologyConnectorWhitelist = DEFAULT_TOPOLOGY_CONNECTOR_WHITELIST;
 
     private static final String DEFAULT_DISCOVERY_RESOURCE_PATH = "/var/discovery/impl";
-    @Property(label = "Discovery Resource Path", description = "Path of resource where to keep discovery information, e.g /var/discovery/impl")
+    @Property(label = "Discovery Resource Path", description = "Path of resource where to keep discovery information, e.g /var/discovery/impl", value=DEFAULT_DISCOVERY_RESOURCE_PATH)
     public static final String DISCOVERY_RESOURCE_PATH_KEY = "discoveryResourcePath";
     private String discoveryResourcePath = DEFAULT_DISCOVERY_RESOURCE_PATH;
 
@@ -100,25 +102,27 @@ public class Config {
                 this.heartbeatInterval);
         String topologyConnectorUrlStr = PropertiesUtil.toString(
                 properties.get(TOPOLOGY_CONNECTOR_URL_KEY), null);
-        try {
-            this.topologyConnectorUrl = new URL(topologyConnectorUrlStr);
-            logger.debug("configure: topologyConnectorUrl='{}''",
-                    this.topologyConnectorUrl);
-        } catch (MalformedURLException e) {
-            logger.error("configure: could not set topologyConnectorUrl: " + e,
-                    e);
+        if ( topologyConnectorUrlStr != null && topologyConnectorUrlStr.length() > 0 ) {
+            try {
+                this.topologyConnectorUrl = new URL(topologyConnectorUrlStr);
+                logger.debug("configure: topologyConnectorUrl='{}''",
+                        this.topologyConnectorUrl);
+            } catch (MalformedURLException e) {
+                logger.error("configure: could not set topologyConnectorUrl: " + e,
+                        e);
+            }
         }
-        this.topologyConnectorWhitelist = PropertiesUtil.toString(
+        this.topologyConnectorWhitelist = PropertiesUtil.toStringArray( 
                 properties.get(TOPOLOGY_CONNECTOR_WHITELIST_KEY),
                 DEFAULT_TOPOLOGY_CONNECTOR_WHITELIST);
         logger.debug("configure: topologyConnectorWhitelist='{}''",
                 this.topologyConnectorWhitelist);
-        
+
         this.discoveryResourcePath = PropertiesUtil.toString(
                 properties.get(DISCOVERY_RESOURCE_PATH_KEY),
                 "");
         while(this.discoveryResourcePath.endsWith("/")) {
-            this.discoveryResourcePath = this.discoveryResourcePath.substring(0, 
+            this.discoveryResourcePath = this.discoveryResourcePath.substring(0,
                     this.discoveryResourcePath.length()-1);
         }
         this.discoveryResourcePath = this.discoveryResourcePath + "/";
@@ -128,7 +132,7 @@ public class Config {
         }
         logger.debug("configure: discoveryResourcePath='{}''",
                 this.discoveryResourcePath);
-        
+
         this.leaderElectionRepositoryDescriptor = PropertiesUtil.toString(
                 properties.get(LEADER_ELECTION_REPOSITORY_DESCRIPTOR_NAME_KEY),
                 null);
@@ -168,10 +172,10 @@ public class Config {
      * @return a comma separated list of hostnames and/or ip addresses which are allowed as
      * remote hosts to open connections to the topology connector servlet
      */
-    public String getTopologyConnectorWhitelist() {
+    public String[] getTopologyConnectorWhitelist() {
         return topologyConnectorWhitelist;
     }
-    
+
     /**
      * Returns the resource path where cluster instance informations are stored.
      * @return the resource path where cluster instance informations are stored
@@ -179,7 +183,7 @@ public class Config {
     public String getClusterInstancesPath() {
         return discoveryResourcePath + CLUSTERINSTANCES_NODE;
     }
-    
+
     /**
      * Returns the resource path where the established view is stored.
      * @return the resource path where the established view is stored
@@ -187,7 +191,7 @@ public class Config {
     public String getEstablishedViewPath() {
         return discoveryResourcePath + ESTABLISHED_VIEW_NODE;
     }
-    
+
     /**
      * Returns the resource path where ongoing votings are stored.
      * @return the resource path where ongoing votings are stored
@@ -195,20 +199,20 @@ public class Config {
     public String getOngoingVotingsPath() {
         return discoveryResourcePath + ONGOING_VOTING_NODE;
     }
-    
+
     /**
-     * Returns the resource path where the previous view is stored. 
+     * Returns the resource path where the previous view is stored.
      * @return the resource path where the previous view is stored
      */
     public String getPreviousViewPath() {
         return discoveryResourcePath + PREVIOUS_VIEW_NODE;
     }
-    
+
     /**
      * Returns the repository descriptor key which is to be included in the
-     * cluster leader election - or null. 
+     * cluster leader election - or null.
      * <p>
-     * When set, the value (treated as a boolean) of the repository descriptor 
+     * When set, the value (treated as a boolean) of the repository descriptor
      * is prepended to the leader election id.
      * @return the repository descriptor key which is to be included in the
      * cluster leader election - or null

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java Mon Apr 22 10:58:50 2013
@@ -44,7 +44,7 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.discovery.ClusterView;
-import org.apache.sling.discovery.DiscoveryAware;
+import org.apache.sling.discovery.TopologyEventListener;
 import org.apache.sling.discovery.DiscoveryService;
 import org.apache.sling.discovery.InstanceDescription;
 import org.apache.sling.discovery.PropertyProvider;
@@ -78,8 +78,8 @@ public class DiscoveryServiceImpl implem
     @Reference
     private SlingSettingsService settingsService;
 
-    @Reference(cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC, referenceInterface = DiscoveryAware.class)
-    private DiscoveryAware[] discoveryAwares = new DiscoveryAware[0];
+    @Reference(cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC, referenceInterface = TopologyEventListener.class)
+    private TopologyEventListener[] eventListeners = new TopologyEventListener[0];
 
     /**
      * All property providers.
@@ -117,7 +117,7 @@ public class DiscoveryServiceImpl implem
     /** the slingId of the local instance **/
     private String slingId;
 
-    /** the old view previously valid and sent to the discoveryawares **/
+    /** the old view previously valid and sent to the TopologyEventListeners **/
     private TopologyViewImpl oldView = null;
 
     /**
@@ -144,17 +144,17 @@ public class DiscoveryServiceImpl implem
         heartbeatHandler.initialize(this,
                 clusterViewService.getIsolatedClusterViewId());
 
-        final DiscoveryAware[] registeredServices;
+        final TopologyEventListener[] registeredServices;
         synchronized (lock) {
             activated = true;
-            registeredServices = this.discoveryAwares;
+            registeredServices = this.eventListeners;
             doUpdateProperties();
 
         }
         TopologyViewImpl newView = (TopologyViewImpl) getTopology();
         TopologyEvent event = new TopologyEvent(Type.TOPOLOGY_INIT, null,
                 newView);
-        for (final DiscoveryAware da : registeredServices) {
+        for (final TopologyEventListener da : registeredServices) {
             da.handleTopologyEvent(event);
         }
         oldView = newView;
@@ -181,18 +181,18 @@ public class DiscoveryServiceImpl implem
     /**
      * bind a discovery aware
      */
-    protected void bindDiscoveryAware(final DiscoveryAware clusterAware) {
+    protected void bindTopologyEventListener(final TopologyEventListener clusterAware) {
 
-        logger.debug("bindDiscoveryAware: Binding DiscoveryAware {}",
+        logger.debug("bindTopologyEventListener: Binding TopologyEventListener {}",
                 clusterAware);
 
         boolean activated = false;
         synchronized (lock) {
-            List<DiscoveryAware> currentList = new ArrayList<DiscoveryAware>(
-                    Arrays.asList(discoveryAwares));
+            List<TopologyEventListener> currentList = new ArrayList<TopologyEventListener>(
+                    Arrays.asList(eventListeners));
             currentList.add(clusterAware);
-            this.discoveryAwares = currentList
-                    .toArray(new DiscoveryAware[currentList.size()]);
+            this.eventListeners = currentList
+                    .toArray(new TopologyEventListener[currentList.size()]);
             activated = this.activated;
         }
 
@@ -205,17 +205,17 @@ public class DiscoveryServiceImpl implem
     /**
      * Unbind a discovery aware
      */
-    protected void unbindDiscoveryAware(final DiscoveryAware clusterAware) {
+    protected void unbindTopologyEventListener(final TopologyEventListener clusterAware) {
 
-        logger.debug("unbindDiscoveryAware: Releasing DiscoveryAware {}",
+        logger.debug("unbindTopologyEventListener: Releasing TopologyEventListener {}",
                 clusterAware);
 
         synchronized (lock) {
-            List<DiscoveryAware> currentList = new ArrayList<DiscoveryAware>(
-                    Arrays.asList(discoveryAwares));
+            List<TopologyEventListener> currentList = new ArrayList<TopologyEventListener>(
+                    Arrays.asList(eventListeners));
             currentList.remove(clusterAware);
-            this.discoveryAwares = currentList
-                    .toArray(new DiscoveryAware[currentList.size()]);
+            this.eventListeners = currentList
+                    .toArray(new TopologyEventListener[currentList.size()]);
         }
     }
 
@@ -227,14 +227,14 @@ public class DiscoveryServiceImpl implem
         logger.debug("bindPropertyProvider: Binding PropertyProvider {}",
                 propertyProvider);
 
-        final DiscoveryAware[] awares;
+        final TopologyEventListener[] awares;
         synchronized (lock) {
             final ProviderInfo info = new ProviderInfo(propertyProvider, props);
             this.providerInfos.add(info);
             Collections.sort(this.providerInfos);
             this.doUpdateProperties();
             if (activated) {
-                awares = this.discoveryAwares;
+                awares = this.eventListeners;
             } else {
                 awares = null;
             }
@@ -277,13 +277,13 @@ public class DiscoveryServiceImpl implem
         logger.debug("unbindPropertyProvider: Releasing PropertyProvider {}",
                 propertyProvider);
 
-        final DiscoveryAware[] awares;
+        final TopologyEventListener[] awares;
         synchronized (lock) {
             final ProviderInfo info = new ProviderInfo(propertyProvider, props);
             this.providerInfos.remove(info);
             this.doUpdateProperties();
             if (activated) {
-                awares = this.discoveryAwares;
+                awares = this.eventListeners;
             } else {
                 awares = null;
             }
@@ -410,7 +410,7 @@ public class DiscoveryServiceImpl implem
 
     /**
      * Internal handle method which checks if anything in the topology has
-     * changed and informs the DiscoveryAwares if such a change occurred.
+     * changed and informs the TopologyEventListeners if such a change occurred.
      * <p>
      * All changes should go through this method. This method keeps track of
      * oldView/newView as well.
@@ -430,7 +430,7 @@ public class DiscoveryServiceImpl implem
             }
 
             oldView.markOld();
-            for (final DiscoveryAware da : discoveryAwares) {
+            for (final TopologyEventListener da : eventListeners) {
                 da.handleTopologyEvent(new TopologyEvent(difference, oldView,
                         newView));
             }
@@ -514,7 +514,7 @@ public class DiscoveryServiceImpl implem
      * Handle the fact that the topology has likely changed
      */
     public void handleTopologyChanged() {
-        logger.debug("handleTopologyChanged: informing the discoveryawares...");
+        logger.debug("handleTopologyChanged: informing the TopologyEventListeners...");
         handlePotentialTopologyChange();
     }
 

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/InfrastructurePropertyProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/InfrastructurePropertyProvider.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/InfrastructurePropertyProvider.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/InfrastructurePropertyProvider.java Mon Apr 22 10:58:50 2013
@@ -20,7 +20,6 @@ package org.apache.sling.discovery.impl;
 
 import java.util.Calendar;
 
-import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Properties;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
@@ -37,7 +36,7 @@ import org.osgi.service.component.Compon
  * allows to conclude when the properties were last read and propagated through
  * the topology
  */
-@Component
+// @Component - disable by default
 @Service(value = { PropertyProvider.class })
 @Properties({ @Property(name = PropertyProvider.PROPERTY_PROPERTIES, value = {
         "infrastructure.slingId", "infrastructure.slingHome",

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/TopologyWebConsolePlugin.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/TopologyWebConsolePlugin.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/TopologyWebConsolePlugin.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/TopologyWebConsolePlugin.java Mon Apr 22 10:58:50 2013
@@ -24,6 +24,7 @@ import java.net.URL;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Dictionary;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -47,13 +48,12 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.webconsole.AbstractWebConsolePlugin;
 import org.apache.felix.webconsole.WebConsoleConstants;
 import org.apache.sling.discovery.ClusterView;
-import org.apache.sling.discovery.DiscoveryAware;
-import org.apache.sling.discovery.DiscoveryService;
+import org.apache.sling.discovery.TopologyEventListener;
 import org.apache.sling.discovery.InstanceDescription;
 import org.apache.sling.discovery.InstanceFilter;
 import org.apache.sling.discovery.TopologyEvent;
-import org.apache.sling.discovery.TopologyView;
 import org.apache.sling.discovery.TopologyEvent.Type;
+import org.apache.sling.discovery.TopologyView;
 import org.apache.sling.discovery.impl.cluster.ClusterViewService;
 import org.apache.sling.discovery.impl.topology.announcement.Announcement;
 import org.apache.sling.discovery.impl.topology.announcement.AnnouncementRegistry;
@@ -71,10 +71,10 @@ import org.slf4j.LoggerFactory;
  * Simple webconsole which gives an overview of the topology visible by the
  * discovery service
  */
-@Service(value = { DiscoveryAware.class })
+@Service(value = { TopologyEventListener.class })
 @Component(immediate = true)
 @SuppressWarnings("serial")
-public class TopologyWebConsolePlugin extends AbstractWebConsolePlugin implements DiscoveryAware {
+public class TopologyWebConsolePlugin extends AbstractWebConsolePlugin implements TopologyEventListener {
 
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
@@ -84,9 +84,12 @@ public class TopologyWebConsolePlugin ex
     /** the url part where topology disconnects are posted to **/
     private static final String DISCONNECT = "/disconnect/";
 
+    /** the url part where topology explicit pings are posted to **/
+    private static final String PING = "/ping/";
+
     /** the truncated log of topology events, filtered by property change types. shown in webconsole **/
     private final List<String> propertyChangeLog = new LinkedList<String>();
-    
+
     /** the truncated log of topology events, shown in webconsole **/
     private final List<String> topologyLog = new LinkedList<String>();
 
@@ -105,8 +108,7 @@ public class TopologyWebConsolePlugin ex
     @Reference
     private ConnectorRegistry connectorRegistry;
 
-    @Reference
-    private DiscoveryService discoveryService;
+    private TopologyView currentView;
 
     @Override
     public String getLabel() {
@@ -117,12 +119,12 @@ public class TopologyWebConsolePlugin ex
     public String getTitle() {
         return "Topology Management";
     }
-    
+
     @Activate
     @Override
     public void activate(final BundleContext bundleContext) {
         super.activate(bundleContext);
-        logger.info("activate: activating...");
+        logger.debug("activate: activating...");
         Dictionary<String, Object> props = new Hashtable<String, Object>();
         props.put(
                 org.osgi.framework.Constants.SERVICE_DESCRIPTION,
@@ -162,7 +164,9 @@ public class TopologyWebConsolePlugin ex
         final PrintWriter pw = res.getWriter();
 
         if (pathInfo.equals("")) {
-            renderOverview(pw, discoveryService.getTopology());
+            if ( this.currentView != null ) {
+                renderOverview(pw,  currentView);
+            }
         } else {
             StringTokenizer st = new StringTokenizer(pathInfo, "/");
             final String nodeId = st.nextToken();
@@ -175,8 +179,10 @@ public class TopologyWebConsolePlugin ex
      */
     private void renderProperties(final PrintWriter pw, final String nodeId) {
         logger.debug("renderProperties: nodeId=" + nodeId);
-        Set<InstanceDescription> instances = discoveryService.getTopology()
-                .findInstances(new InstanceFilter() {
+        final TopologyView tv = this.currentView;
+        Set<InstanceDescription> instances = ( tv == null ? (Set<InstanceDescription>)Collections.EMPTY_SET :
+
+                tv.findInstances(new InstanceFilter() {
 
                     public boolean accept(InstanceDescription instance) {
                         String slingId = instance.getSlingId();
@@ -184,7 +190,7 @@ public class TopologyWebConsolePlugin ex
                                 + slingId);
                         return (slingId.equals(nodeId));
                     }
-                });
+                }));
 
         if (instances != null && instances.size() == 1) {
             InstanceDescription instance = instances.iterator().next();
@@ -307,19 +313,43 @@ public class TopologyWebConsolePlugin ex
      * Render a particular cluster (into table rows)
      */
     private void renderCluster(final PrintWriter pw, final ClusterView cluster, final boolean odd) {
-        Collection<Announcement> announcements = null;
+        final Collection<Announcement> announcements = announcementRegistry
+                .listAnnouncements(ListScope.AllInSameCluster);
+
         for (Iterator<InstanceDescription> it = cluster.getInstances()
                 .iterator(); it.hasNext();) {
-            InstanceDescription instanceDescription = it.next();
-            String oddEven = odd ? "odd" : "even";
-            pw.println("<tr class=\"" + oddEven + " ui-state-default\">");
-            boolean isLocal = instanceDescription.isLocal();
+            final InstanceDescription instanceDescription = it.next();
+            final boolean inLocalCluster = clusterViewService.contains(instanceDescription.getSlingId());
+            Announcement parentAnnouncement = null;
+            for (Iterator<Announcement> it2 = announcements.iterator(); it2
+                    .hasNext();) {
+                Announcement announcement = it2.next();
+                for (Iterator<InstanceDescription> it3 = announcement
+                        .listInstances().iterator(); it3.hasNext();) {
+                    InstanceDescription announcedInstance = it3.next();
+                    if (announcedInstance.getSlingId().equals(
+                            instanceDescription.getSlingId())) {
+                        parentAnnouncement = announcement;
+                        break;
+                    }
+                }
+            }
+
+            final String oddEven = odd ? "odd" : "even";
+            
+            if (inLocalCluster || (parentAnnouncement!=null)) {
+                pw.println("<tr class=\"" + oddEven + " ui-state-default\">");
+            } else {
+                pw.println("<tr class=\"" + oddEven + " ui-state-error\">");
+            }
+            final boolean isLocal = instanceDescription.isLocal();
             String slingId = instanceDescription.getSlingId();
             slingId = "<a href=\"/system/console/topology/" + slingId + "\">"
                     + slingId + "</a>";
             if (isLocal) {
                 slingId = "<b>" + slingId + "</b>";
             }
+
             pw.println("<td>" + slingId + "</td>");
             pw.println("<td>"
                     + (instanceDescription.getClusterView() == null ? "null"
@@ -329,29 +359,11 @@ public class TopologyWebConsolePlugin ex
             pw.println("<td>"
                     + (instanceDescription.isLeader() ? "<b>true</b>" : "false")
                     + "</td>");
-            if (clusterViewService.contains(instanceDescription.getSlingId())) {
+            if (inLocalCluster) {
                 pw.println("<td>local</td>");
                 pw.println("<td>n/a</td>");
             } else {
                 pw.println("<td>remote</td>");
-                if (announcements == null) {
-                    announcements = announcementRegistry
-                            .listAnnouncements(ListScope.AllInSameCluster);
-                }
-                Announcement parentAnnouncement = null;
-                for (Iterator<Announcement> it2 = announcements.iterator(); it2
-                        .hasNext();) {
-                    Announcement announcement = it2.next();
-                    for (Iterator<InstanceDescription> it3 = announcement
-                            .listInstances().iterator(); it3.hasNext();) {
-                        InstanceDescription announcedInstance = it3.next();
-                        if (announcedInstance.getSlingId().equals(
-                                instanceDescription.getSlingId())) {
-                            parentAnnouncement = announcement;
-                            break;
-                        }
-                    }
-                }
                 if (parentAnnouncement != null) {
                     pw.println("<td>" + parentAnnouncement.getOwnerId()
                             + "</td>");
@@ -380,6 +392,7 @@ public class TopologyWebConsolePlugin ex
         pw.println("<th class=\"header ui-widget-header\">Origin info</th>");
         pw.println("<th class=\"header ui-widget-header\">Persistent</th>");
         // pw.println("<th class=\"header ui-widget-header\">Fallback connector urls</th>");
+        pw.println("<th class=\"header ui-widget-header\">Trigger a heartbeat</th>");
         pw.println("<th class=\"header ui-widget-header\">Disconnect</th>");
         pw.println("</tr>");
         pw.println("</thead>");
@@ -391,17 +404,41 @@ public class TopologyWebConsolePlugin ex
                 .iterator(); it.hasNext();) {
             TopologyConnectorClientInformation topologyConnectorClient = it
                     .next();
-            String oddEven = odd ? "odd" : "even";
+            final String oddEven = odd ? "odd" : "even";
             odd = !odd;
-            pw.println("<tr class=\"" + oddEven + " ui-state-default\">");
+            final String remoteSlingId = topologyConnectorClient.getRemoteSlingId();
+            final boolean isConnected = topologyConnectorClient.isConnected() && remoteSlingId != null;
+            if (isConnected) {
+                pw.println("<tr class=\"" + oddEven + " ui-state-default\">");
+            } else {
+                pw.println("<tr class=\"" + oddEven + " ui-state-error\">");
+            }
             pw.println("<td>"
                     + topologyConnectorClient.getConnectorUrl().toString()
                     + "</td>");
-            String remoteSlingId = topologyConnectorClient.getRemoteSlingId();
-            if (topologyConnectorClient.isConnected() && remoteSlingId != null) {
+            if (isConnected) {
                 pw.println("<td>" + remoteSlingId + "</td>");
             } else {
-                pw.println("<td><b>not connected</b></td>");
+                final int statusCode = topologyConnectorClient.getStatusCode();
+                final String tooltipText;
+                switch(statusCode) {
+                case 401:
+                    tooltipText = "401: possible setup issue of discovery.impl on target instance";
+                    break;
+                case 404:
+                    tooltipText = "404: possible white list rejection by target instance";
+                    break;
+                case 409:
+                    tooltipText = "409: target instance complains that we're already in the same topology";
+                    break;
+                case -1:
+                    tooltipText = "-1: check error log. possible connection refused.";
+                    break;
+                default:
+                    tooltipText = null;
+                }
+                final String tooltip = tooltipText==null ? "" : (" title=\""+tooltipText+"\"");
+                pw.println("<td"+tooltip+"><b>not connected ("+statusCode+")</b></td>");
             }
             if (topologyConnectorClient.getOriginInfo() == OriginInfo.Config) {
                 pw.println("<td>");
@@ -434,11 +471,22 @@ public class TopologyWebConsolePlugin ex
             // pw.println("<td>" + fallbackConnectorUrls + "</td>");
             pw.println("<td>");
             final String id = topologyConnectorClient.getId();
-            pw.println("<form id=\"" + id
+            final String pingId = id+"-ping";
+            pw.println("<form id=\"" + pingId
+                    + "\" method=\"post\" action=\"/system/console/topology"
+                    + PING + id + "\">");
+            pw.println("<input type=\"hidden\" name=\"name\" value=\"value\" />");
+            pw.println(" <a onclick=\"document.getElementById('" + pingId
+                    + "').submit();\">click here to ping</a>");
+            pw.println("</form>");
+            pw.println("</td>");
+            final String disconnectId = topologyConnectorClient.getId()+"-disconnect";
+            pw.println("<td>");
+            pw.println("<form id=\"" + disconnectId
                     + "\" method=\"post\" action=\"/system/console/topology"
                     + DISCONNECT + id + "\">");
             pw.println("<input type=\"hidden\" name=\"name\" value=\"value\" />");
-            pw.println(" <a onclick=\"document.getElementById('" + id
+            pw.println(" <a onclick=\"document.getElementById('" + disconnectId
                     + "').submit();\">click here to disconnect</a>");
             pw.println("</form>");
             pw.println("</td>");
@@ -531,6 +579,13 @@ public class TopologyWebConsolePlugin ex
                 logger.error("doPost: 500: " + e);
                 resp.sendRedirect(root);
             }
+        } else if (pathInfo != null && pathInfo.startsWith(PING)) {
+            logger.debug("doPost: " + PING + " called with full info: "
+                    + pathInfo);
+            String id = pathInfo.substring(PING.length());
+            logger.debug("doPost: id=" + id);
+            connectorRegistry.pingOutgoingConnection(id);
+            resp.sendRedirect(root);
         } else if (pathInfo != null && pathInfo.startsWith(DISCONNECT)) {
             logger.debug("doPost: " + DISCONNECT + " called with full info: "
                     + pathInfo);
@@ -548,7 +603,7 @@ public class TopologyWebConsolePlugin ex
      * keep a truncated history of the log events for information purpose (to be shown in the webconsole)
      */
     public void handleTopologyEvent(final TopologyEvent event) {
-
+        this.currentView = event.getNewView();
         if (event.getType() == Type.PROPERTIES_CHANGED) {
 
             Set<InstanceDescription> newInstances = event.getNewView()

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java Mon Apr 22 10:58:50 2013
@@ -55,7 +55,7 @@ import org.slf4j.LoggerFactory;
  * accordingly
  */
 @Component(immediate = true)
-@Service(value = EventHandler.class)
+@Service(value = {EventHandler.class, VotingHandler.class})
 @Properties({
         @Property(name = Constants.SERVICE_DESCRIPTION, value = "New Voting Event Listener."),
         @Property(name = EventConstants.EVENT_TOPIC, value = {
@@ -129,7 +129,7 @@ public class VotingHandler implements Ev
     /**
      * Analyze any ongoing voting in the repository
      */
-    private void analyzeVotings(final ResourceResolver resourceResolver)
+    public void analyzeVotings(final ResourceResolver resourceResolver)
             throws RepositoryException {
         VotingView winningVote = VotingHelper.getWinningVoting(
                 resourceResolver, config);
@@ -298,7 +298,7 @@ public class VotingHandler implements Ev
                         + retiredView.getPath());
                 session.move(
                         retiredView.getPath(),
-                        config.getPreviousViewPath()
+                        previousViewsResource.getPath()
                                 + "/" + retiredView.getName());
             } else {
                 logger.debug("promote: retiring an erroneously additionally established node "

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHelper.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHelper.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHelper.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHelper.java Mon Apr 22 10:58:50 2013
@@ -54,7 +54,7 @@ public class VotingHelper {
         final Resource ongoingVotingsResource = resourceResolver
                 .getResource(ongoingVotingsPath);
         if (ongoingVotingsResource == null) {
-            logger.warn("listOpenNonWinningVotings: no ongoing votings parent resource found");
+            logger.info("listOpenNonWinningVotings: no ongoing votings parent resource found"); // TOOD - is this expected?
             return new ArrayList<VotingView>();
         }
         final Iterable<Resource> children = ongoingVotingsResource.getChildren();
@@ -77,6 +77,10 @@ public class VotingHelper {
             } else {
                 logger.debug("listOpenNonWinningVotings: found an invalid voting: "
                         + aChild
+                        + ", matches live: " + c.matchesLiveView(config)
+                        + ", is ongoing: " + c.isOngoingVoting(config)
+                        + ", has no votes: " + c.hasNoVotes()
+                        + ", is winning: " + c.isWinning()
                         + ", properties="
                         + ResourceHelper.getPropertiesForLogging(aChild));
             }
@@ -97,7 +101,7 @@ public class VotingHelper {
         Resource ongoingVotingsResource = resourceResolver
                 .getResource(ongoingVotingsPath);
         if (ongoingVotingsResource == null) {
-            logger.warn("getWinningVoting: no ongoing votings parent resource found");
+            logger.info("getWinningVoting: no ongoing votings parent resource found"); // TOOD - is this expected?
             return null;
         }
         Iterable<Resource> children = ongoingVotingsResource.getChildren();
@@ -119,7 +123,7 @@ public class VotingHelper {
     }
 
     /**
-     * Returns the voting for which the given slingId has vote yes or was the 
+     * Returns the voting for which the given slingId has vote yes or was the
      * initiator (which is equal to yes).
      * @param slingId the instance for which its yes vote should be looked up
      * @return the voting for which the given slingId has votes yes or was the

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingView.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingView.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingView.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingView.java Mon Apr 22 10:58:50 2013
@@ -127,7 +127,13 @@ public class VotingView extends View {
      * @return
      */
     public boolean isOngoingVoting(final Config config) {
-        final ValueMap properties = getResource().adaptTo(ValueMap.class);
+        ValueMap properties = null;
+        try{
+            properties = getResource().adaptTo(ValueMap.class);
+        } catch(RuntimeException e) {
+            logger.info("isOngoingVoting: could not get properties of "+getResource()+": "+e, e);
+            return false;
+        }
         if (properties == null) {
             // no properties, odd. then it's not a valid voting.
             return false;
@@ -149,7 +155,12 @@ public class VotingView extends View {
      * @return true if there are any no votes on this voting
      */
     public boolean hasNoVotes() {
-        final Iterator<Resource> it = getResource().getChild("members").getChildren()
+        Resource m = getResource().getChild("members");
+        if (m==null) {
+            // the vote is being created. wait.
+            return false;
+        }
+        final Iterator<Resource> it = m.getChildren()
                 .iterator();
         while (it.hasNext()) {
             Resource aMemberRes = it.next();
@@ -248,23 +259,32 @@ public class VotingView extends View {
      */
     public boolean isWinning() {
         final Resource members = getResource().getChild("members");
+        if (members==null) {
+            // the vote is being created. wait.
+            return false;
+        }
         final Iterable<Resource> children = members.getChildren();
         final Iterator<Resource> it = children.iterator();
         boolean isWinning = false;
         while (it.hasNext()) {
             Resource aMemberRes = it.next();
-            ValueMap properties = aMemberRes.adaptTo(ValueMap.class);
-            Boolean initiator = properties.get("initiator", Boolean.class);
-            Boolean vote = properties.get("vote", Boolean.class);
-            if (initiator != null && initiator) {
-                isWinning = true;
-                continue;
-            }
-            if (vote != null && vote) {
-                isWinning = true;
-                continue;
+            try{
+                ValueMap properties = aMemberRes.adaptTo(ValueMap.class);
+                Boolean initiator = properties.get("initiator", Boolean.class);
+                Boolean vote = properties.get("vote", Boolean.class);
+                if (initiator != null && initiator) {
+                    isWinning = true;
+                    continue;
+                }
+                if (vote != null && vote) {
+                    isWinning = true;
+                    continue;
+                }
+                return false;
+            } catch(RuntimeException re) {
+                logger.info("isWinning: Could not check vote due to "+re);
+                return false;
             }
-            return false;
         }
         return isWinning;
     }

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/View.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/View.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/View.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/View.java Mon Apr 22 10:58:50 2013
@@ -98,7 +98,7 @@ public class View {
      */
     public boolean matches(final Set<String> view) {
         final Set<String> viewCopy = new HashSet<String>(view);
-        final Resource members = resource.getChild("members");
+        final Resource members = getResource().getChild("members");
         if (members == null) {
             return false;
         }

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java Mon Apr 22 10:58:50 2013
@@ -40,6 +40,7 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.commons.scheduler.Scheduler;
 import org.apache.sling.discovery.impl.Config;
 import org.apache.sling.discovery.impl.DiscoveryServiceImpl;
+import org.apache.sling.discovery.impl.cluster.voting.VotingHandler;
 import org.apache.sling.discovery.impl.cluster.voting.VotingHelper;
 import org.apache.sling.discovery.impl.cluster.voting.VotingView;
 import org.apache.sling.discovery.impl.common.ViewHelper;
@@ -84,6 +85,9 @@ public class HeartbeatHandler implements
 
     @Reference
     private Config config;
+    
+    @Reference
+    private VotingHandler votingHandler;
 
     /** the discovery service reference is used to get properties updated before heartbeats are sent **/
     private DiscoveryServiceImpl discoveryService;
@@ -277,6 +281,12 @@ public class HeartbeatHandler implements
     private void doCheckView(final ResourceResolver resourceResolver)
             throws RepositoryException {
 
+        if (votingHandler==null) {
+            logger.info("doCheckView: votingHandler is null!");
+        } else {
+            votingHandler.analyzeVotings(resourceResolver);
+        }
+        
         final VotingView winningVoting = VotingHelper.getWinningVoting(
                 resourceResolver, config);
         int numOpenNonWinningVotes = VotingHelper.listOpenNonWinningVotings(

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/resource/ResourceHelper.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/resource/ResourceHelper.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/resource/ResourceHelper.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/common/resource/ResourceHelper.java Mon Apr 22 10:58:50 2013
@@ -68,7 +68,12 @@ public class ResourceHelper {
 
     /** Compile a stringbuffer containing the properties of a resource - used for logging **/
     public static StringBuffer getPropertiesForLogging(final Resource resource) {
-        final ValueMap valueMap = resource.adaptTo(ValueMap.class);
+        ValueMap valueMap;
+        try{
+            valueMap = resource.adaptTo(ValueMap.class);
+        } catch(RuntimeException re) {
+            return new StringBuffer("non-existing resource: "+resource+" ("+re.getMessage()+")");
+        }
         final Set<Entry<String, Object>> entrySet = valueMap.entrySet();
         final StringBuffer sb = new StringBuffer();
         for (Iterator<Entry<String, Object>> it = entrySet.iterator(); it

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/TopologyViewImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/TopologyViewImpl.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/TopologyViewImpl.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/TopologyViewImpl.java Mon Apr 22 10:58:50 2013
@@ -57,7 +57,7 @@ public class TopologyViewImpl implements
         }
     }
 
-    /** 
+    /**
      * Compare this topology with the given one and determine how they compare
      * @param other the other topology against which to compare
      * @return the type describing how these two compare
@@ -122,17 +122,23 @@ public class TopologyViewImpl implements
         return code;
     }
 
+    /**
+     * @see org.apache.sling.discovery.TopologyView#isCurrent()
+     */
     public boolean isCurrent() {
         return current;
     }
 
-    /** 
+    /**
      * Mark this topology as old
      */
     public void markOld() {
         this.current = false;
     }
 
+    /**
+     * @see org.apache.sling.discovery.TopologyView#getLocalInstance()
+     */
     public InstanceDescription getLocalInstance() {
         for (Iterator<InstanceDescription> it = instances.iterator(); it
                 .hasNext();) {
@@ -144,6 +150,9 @@ public class TopologyViewImpl implements
         return null;
     }
 
+    /**
+     * @see org.apache.sling.discovery.TopologyView#getInstances()
+     */
     public Set<InstanceDescription> getInstances() {
         return Collections.unmodifiableSet(instances);
     }
@@ -152,18 +161,24 @@ public class TopologyViewImpl implements
         if (instances == null) {
             return;
         }
-        for (Iterator<InstanceDescription> it = instances.iterator(); it
+        outerLoop: for (Iterator<InstanceDescription> it = instances.iterator(); it
                 .hasNext();) {
             InstanceDescription instanceDescription = it.next();
-            if (this.instances.contains(instanceDescription)) {
-                logger.error("addInstance: cannot add same instance twice: "
-                        + instanceDescription);
-            } else {
-                this.instances.add(instanceDescription);
+            for (Iterator<InstanceDescription> it2 = this.instances.iterator(); it2.hasNext();) {
+                InstanceDescription existingInstance = it2.next();
+                if (existingInstance.getSlingId().equals(instanceDescription.getSlingId())) {
+                    logger.error("addInstance: cannot add same instance twice: "
+                            + instanceDescription);
+                    continue outerLoop;
+                }
             }
+            this.instances.add(instanceDescription);
         }
     }
 
+    /**
+     * @see org.apache.sling.discovery.TopologyView#findInstances(org.apache.sling.discovery.InstanceFilter)
+     */
     public Set<InstanceDescription> findInstances(final InstanceFilter picker) {
         if (picker == null) {
             throw new IllegalArgumentException("picker must not be null");
@@ -179,6 +194,9 @@ public class TopologyViewImpl implements
         return result;
     }
 
+    /**
+     * @see org.apache.sling.discovery.TopologyView#getClusterViews()
+     */
     public Set<ClusterView> getClusterViews() {
         Set<ClusterView> result = new HashSet<ClusterView>();
         for (Iterator<InstanceDescription> it = instances.iterator(); it
@@ -192,4 +210,9 @@ public class TopologyViewImpl implements
         return new HashSet<ClusterView>(result);
     }
 
+    @Override
+    public String toString() {
+        return "TopologyViewImpl [current=" + current + ", instances="
+                + instances + "]";
+    }
 }

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/Announcement.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/Announcement.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/Announcement.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/Announcement.java Mon Apr 22 10:58:50 2013
@@ -18,7 +18,9 @@
  */
 package org.apache.sling.discovery.impl.topology.announcement;
 
+import java.util.Calendar;
 import java.util.Collection;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -78,6 +80,23 @@ public class Announcement {
     public Announcement(final String ownerId) {
         this.ownerId = ownerId;
     }
+    
+    @Override
+    public String toString() {
+        StringBuffer incomingList = new StringBuffer();
+        for (Iterator<Announcement> it = incomings.iterator(); it.hasNext();) {
+            Announcement anIncomingAnnouncement = it.next();
+            if (incomingList.length()!=0) {
+                incomingList.append(", ");
+            }
+            incomingList.append(anIncomingAnnouncement);
+        }
+        return "Announcement[ownerId="+getOwnerId()+
+                ", inherited="+isInherited()+
+                ", created="+new Date(created)+
+                ", originInfo="+getOriginInfo()+
+                ", incomings="+incomingList+"]";
+    }
 
     /** set the inherited flag - if true this means this announcement is the response of a topology connect **/
     public void setInherited(final boolean inherited) {

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/AnnouncementFilter.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/AnnouncementFilter.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/AnnouncementFilter.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/AnnouncementFilter.java Mon Apr 22 10:58:50 2013
@@ -23,7 +23,10 @@ package org.apache.sling.discovery.impl.
  **/
 public interface AnnouncementFilter {
 
-    /** Determine whether the given announcement can be accepte or not **/
-    boolean accept(Announcement announcement);
+    /**
+     * Check if the provided announcement, which was received by the provided
+     * slingId can be accepted or not.
+     **/
+    boolean accept(String receivingSlingId, Announcement announcement);
 
 }

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/AnnouncementRegistryImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/AnnouncementRegistryImpl.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/AnnouncementRegistryImpl.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/announcement/AnnouncementRegistryImpl.java Mon Apr 22 10:58:50 2013
@@ -30,6 +30,7 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
@@ -67,18 +68,14 @@ public class AnnouncementRegistryImpl im
             resourceResolver = resourceResolverFactory
                     .getAdministrativeResourceResolver(null);
 
-            final Resource announcementsResource = ResourceHelper
-                    .getOrCreateResource(
-                            resourceResolver,
-                            config.getClusterInstancesPath()
-                                    + "/"
-                                    + settingsService.getSlingId()
-                                    + "/announcements/" + ownerId);
-
-            if (announcementsResource != null) {
-                Node node = announcementsResource.adaptTo(Node.class);
-                node.remove();
-                node.getSession().save();
+            final String path = config.getClusterInstancesPath()
+                    + "/"
+                    + settingsService.getSlingId()
+                    + "/announcements/" + ownerId;
+            final Resource announcementsResource = resourceResolver.getResource(path);
+            if (announcementsResource!=null) {
+                resourceResolver.delete(announcementsResource);
+                resourceResolver.commit();
             }
 
         } catch (LoginException e) {
@@ -87,8 +84,8 @@ public class AnnouncementRegistryImpl im
                             + e, e);
             throw new RuntimeException("Could not log in to repository (" + e
                     + ")", e);
-        } catch (RepositoryException e) {
-            logger.error("unregisterAnnouncement: got a RepositoryException: "
+        } catch (PersistenceException e) {
+            logger.error("unregisterAnnouncement: got a PersistenceException: "
                     + e, e);
             throw new RuntimeException(
                     "Exception while talking to repository (" + e + ")", e);
@@ -273,7 +270,7 @@ public class AnnouncementRegistryImpl im
                     .iterator();
             Resource announcementsResource;
             while (it0.hasNext()) {
-                Resource aClusterInstanceResource = it0.next();
+                final Resource aClusterInstanceResource = it0.next();
                 announcementsResource = aClusterInstanceResource
                         .getChild("announcements");
                 if (announcementsResource == null) {
@@ -289,7 +286,11 @@ public class AnnouncementRegistryImpl im
                     topologyAnnouncement = Announcement.fromJSON(anAnnouncement
                             .adaptTo(ValueMap.class).get(
                                     "topologyAnnouncement", String.class));
-                    if (filter != null && !filter.accept(topologyAnnouncement)) {
+                    if (topologyAnnouncement.hasExpired(config)) {
+                        // dont propagate announcements that have expired
+                        continue;
+                    }
+                    if (filter != null && !filter.accept(aClusterInstanceResource.getName(), topologyAnnouncement)) {
                         continue;
                     }
                     target.addIncomingTopologyAnnouncement(topologyAnnouncement);

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/ConnectorRegistry.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/ConnectorRegistry.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/ConnectorRegistry.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/ConnectorRegistry.java Mon Apr 22 10:58:50 2013
@@ -43,4 +43,6 @@ public interface ConnectorRegistry {
     /** Unregister an outgoing topology connector identified by the given (connector) id **/
     boolean unregisterOutgoingConnection(String id);
 
+    /** Ping an outgoing topology connector identified by the given (connector) id **/
+    boolean pingOutgoingConnection(String id);
 }

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/ConnectorRegistryImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/ConnectorRegistryImpl.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/ConnectorRegistryImpl.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/ConnectorRegistryImpl.java Mon Apr 22 10:58:50 2013
@@ -115,6 +115,19 @@ public class ConnectorRegistryImpl imple
         }
     }
 
+    public boolean pingOutgoingConnection(final String id) {
+        if (id == null || id.length() == 0) {
+            throw new IllegalArgumentException("id must not be null");
+        }
+        synchronized (outgoingClientsMap) {
+            TopologyConnectorClient client = outgoingClientsMap.get(id);
+            if (client != null) {
+                client.ping();
+            }
+            return client != null;
+        }
+    }
+
     public void pingOutgoingConnections() {
         List<TopologyConnectorClient> outgoingTemplatesClone;
         synchronized (outgoingClientsMap) {

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorClient.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorClient.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorClient.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorClient.java Mon Apr 22 10:58:50 2013
@@ -20,6 +20,7 @@ package org.apache.sling.discovery.impl.
 
 import java.io.IOException;
 import java.net.URL;
+import java.util.Iterator;
 import java.util.UUID;
 
 import org.apache.commons.httpclient.Credentials;
@@ -29,9 +30,11 @@ import org.apache.commons.httpclient.Use
 import org.apache.commons.httpclient.auth.AuthScope;
 import org.apache.commons.httpclient.methods.PostMethod;
 import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.discovery.InstanceDescription;
 import org.apache.sling.discovery.impl.Config;
 import org.apache.sling.discovery.impl.cluster.ClusterViewService;
 import org.apache.sling.discovery.impl.topology.announcement.Announcement;
+import org.apache.sling.discovery.impl.topology.announcement.AnnouncementFilter;
 import org.apache.sling.discovery.impl.topology.announcement.AnnouncementRegistry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -68,6 +71,9 @@ public class TopologyConnectorClient imp
 
     /** the information about this server **/
     private final String serverInfo;
+    
+    /** the status code of the last post **/
+    private int lastStatusCode = -1;
 
     TopologyConnectorClient(final ClusterViewService clusterViewService,
             final AnnouncementRegistry announcementRegistry, final Config config,
@@ -119,7 +125,26 @@ public class TopologyConnectorClient imp
             topologyAnnouncement.setServerInfo(serverInfo);
             topologyAnnouncement.setLocalCluster(clusterViewService
                     .getClusterView());
-            announcementRegistry.addAllExcept(topologyAnnouncement, null);
+            announcementRegistry.addAllExcept(topologyAnnouncement, new AnnouncementFilter() {
+                
+                public boolean accept(final String receivingSlingId, final Announcement announcement) {
+                    // filter out announcements that are of old cluster instances
+                    // which I dont really have in my cluster view at the moment
+                    final Iterator<InstanceDescription> it = 
+                            clusterViewService.getClusterView().getInstances().iterator();
+                    while(it.hasNext()) {
+                        final InstanceDescription instance = it.next();
+                        if (instance.getSlingId().equals(receivingSlingId)) {
+                            // then I have the receiving instance in my cluster view
+                            // all fine then
+                            return true;
+                        }
+                    }
+                    // looks like I dont have the receiving instance in my cluster view
+                    // then I should also not propagate that announcement anywhere
+                    return false;
+                }
+            });
             final String p = topologyAnnouncement.asJSON();
 
             logger.debug("ping: topologyAnnouncement json is: " + p);
@@ -127,19 +152,24 @@ public class TopologyConnectorClient imp
             httpClient.executeMethod(method);
             logger.debug("ping: done. code=" + method.getStatusCode() + " - "
                     + method.getStatusText());
-            String responseBody = method.getResponseBodyAsString();
-            logger.debug("ping: response body=" + responseBody);
-            Announcement inheritedAnnouncement = Announcement
-                    .fromJSON(responseBody);
-            inheritedAnnouncement.setInherited(true);
-            if (!announcementRegistry
-                    .registerAnnouncement(inheritedAnnouncement)) {
-                logger.info("ping: connector response is from an instance which I already see in my topology"
-                        + inheritedAnnouncement);
+            lastStatusCode = method.getStatusCode();
+            if (method.getStatusCode()==200) {
+                String responseBody = method.getResponseBodyAsString();
+                logger.debug("ping: response body=" + responseBody);
+                Announcement inheritedAnnouncement = Announcement
+                        .fromJSON(responseBody);
+                inheritedAnnouncement.setInherited(true);
+                if (!announcementRegistry
+                        .registerAnnouncement(inheritedAnnouncement)) {
+                    logger.info("ping: connector response is from an instance which I already see in my topology"
+                            + inheritedAnnouncement);
+                    lastInheritedAnnouncement = null;
+                    return;
+                }
+                lastInheritedAnnouncement = inheritedAnnouncement;
+            } else {
                 lastInheritedAnnouncement = null;
-                return;
             }
-            lastInheritedAnnouncement = inheritedAnnouncement;
         } catch (URIException e) {
             logger.error("ping: Got URIException: " + e, e);
         } catch (IOException e) {
@@ -151,6 +181,10 @@ public class TopologyConnectorClient imp
         }
     }
 
+    public int getStatusCode() {
+        return lastStatusCode;
+    }
+    
     public URL getConnectorUrl() {
         return connectorUrl;
     }

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorClientInformation.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorClientInformation.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorClientInformation.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorClientInformation.java Mon Apr 22 10:58:50 2013
@@ -34,6 +34,9 @@ public interface TopologyConnectorClient
     /** the endpoint url where this connector is connecting to **/
     public URL getConnectorUrl();
 
+    /** return the http status code of the last post to the servlet, -1 if no post was ever done **/
+    public int getStatusCode();
+    
     /** whether or not this connector was able to successfully connect **/
     public boolean isConnected();
 

Modified: sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorServlet.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorServlet.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorServlet.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/main/java/org/apache/sling/discovery/impl/topology/connector/TopologyConnectorServlet.java Mon Apr 22 10:58:50 2013
@@ -22,7 +22,6 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.StringTokenizer;
 
 import javax.servlet.ServletException;
 
@@ -74,12 +73,11 @@ public class TopologyConnectorServlet ex
 
     protected void activate(final ComponentContext context) {
         whitelist.clear();
-        String whitelistStr = config.getTopologyConnectorWhitelist();
-        StringTokenizer st = new StringTokenizer(whitelistStr, ",");
-        while (st.hasMoreTokens()) {
-            String entry = st.nextToken().trim();
-            logger.info("activate: adding whitelist entry: " + entry);
-            whitelist.add(entry);
+        String[] whitelistConfig = config.getTopologyConnectorWhitelist();
+        for (int i = 0; i < whitelistConfig.length; i++) {
+            String aWhitelistEntry = whitelistConfig[i];
+            logger.info("activate: adding whitelist entry: " + aWhitelistEntry);
+            whitelist.add(aWhitelistEntry);
         }
     }
 
@@ -115,21 +113,21 @@ public class TopologyConnectorServlet ex
                     .getOwnerId())) {
                 logger.info("doPost: rejecting an announcement from an instance that is part of my cluster: "
                         + incomingTopologyAnnouncement);
-                response.sendError(500);
+                response.sendError(409);
                 return;
             }
             if (clusterViewService.containsAny(incomingTopologyAnnouncement
                     .listInstances())) {
                 logger.info("doPost: rejecting an announcement as it contains instance(s) that is/are part of my cluster: "
                         + incomingTopologyAnnouncement);
-                response.sendError(500);
+                response.sendError(409);
                 return;
             }
             if (!announcementRegistry
                     .registerAnnouncement(incomingTopologyAnnouncement)) {
                 logger.info("doPost: rejecting an announcement from an instance that I already see in my topology: "
                         + incomingTopologyAnnouncement);
-                response.sendError(500);
+                response.sendError(409);
                 return;
             }
 
@@ -140,7 +138,7 @@ public class TopologyConnectorServlet ex
             announcementRegistry.addAllExcept(replyAnnouncement,
                     new AnnouncementFilter() {
 
-                        public boolean accept(Announcement announcement) {
+                        public boolean accept(final String receivingSlingId, Announcement announcement) {
                             if (announcement.getPrimaryKey().equals(
                                     incomingTopologyAnnouncement
                                             .getPrimaryKey())) {

Modified: sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/ClusterTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/ClusterTest.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/ClusterTest.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/ClusterTest.java Mon Apr 22 10:58:50 2013
@@ -28,7 +28,7 @@ import java.util.UUID;
 import org.apache.sling.discovery.InstanceDescription;
 import org.apache.sling.discovery.TopologyEvent.Type;
 import org.apache.sling.discovery.impl.cluster.helpers.AcceptsMultiple;
-import org.apache.sling.discovery.impl.cluster.helpers.AssertingDiscoveryAware;
+import org.apache.sling.discovery.impl.cluster.helpers.AssertingTopologyEventListener;
 import org.apache.sling.discovery.impl.setup.Instance;
 import org.apache.sling.discovery.impl.setup.PropertyProviderImpl;
 import org.junit.After;
@@ -175,16 +175,16 @@ public class ClusterTest {
         assertEquals(2, instance2.getClusterViewService().getClusterView()
                 .getInstances().size());
 
-        AssertingDiscoveryAware assertingDiscoveryAware = new AssertingDiscoveryAware();
-        assertingDiscoveryAware.addExpected(Type.TOPOLOGY_INIT);
-        assertEquals(1, assertingDiscoveryAware.getRemainingExpectedCount());
-        instance1.bindDiscoveryAware(assertingDiscoveryAware);
-        assertEquals(0, assertingDiscoveryAware.getRemainingExpectedCount());
+        AssertingTopologyEventListener assertingTopologyEventListener = new AssertingTopologyEventListener();
+        assertingTopologyEventListener.addExpected(Type.TOPOLOGY_INIT);
+        assertEquals(1, assertingTopologyEventListener.getRemainingExpectedCount());
+        instance1.bindTopologyEventListener(assertingTopologyEventListener);
+        assertEquals(0, assertingTopologyEventListener.getRemainingExpectedCount());
 
         // startup instance 3
         AcceptsMultiple acceptsMultiple = new AcceptsMultiple(
                 Type.TOPOLOGY_CHANGING, Type.TOPOLOGY_CHANGED);
-        assertingDiscoveryAware.addExpected(acceptsMultiple);
+        assertingTopologyEventListener.addExpected(acceptsMultiple);
         instance3 = Instance.newClusterInstance("thirdInstance", instance1,
                 false);
         instance1.runHeartbeatOnce();

Modified: sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/SingleInstanceTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/SingleInstanceTest.java?rev=1470448&r1=1470447&r2=1470448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/SingleInstanceTest.java (original)
+++ sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/SingleInstanceTest.java Mon Apr 22 10:58:50 2013
@@ -32,7 +32,7 @@ import org.apache.sling.discovery.Cluste
 import org.apache.sling.discovery.InstanceDescription;
 import org.apache.sling.discovery.TopologyEvent;
 import org.apache.sling.discovery.TopologyEvent.Type;
-import org.apache.sling.discovery.impl.cluster.helpers.AssertingDiscoveryAware;
+import org.apache.sling.discovery.impl.cluster.helpers.AssertingTopologyEventListener;
 import org.apache.sling.discovery.impl.common.resource.EstablishedInstanceDescription;
 import org.apache.sling.discovery.impl.common.resource.IsolatedInstanceDescription;
 import org.apache.sling.discovery.impl.setup.Instance;
@@ -117,48 +117,48 @@ public class SingleInstanceTest {
     }
 
     @Test
-    public void testDiscoveryAwares() throws Throwable {
+    public void testTopologyEventListeners() throws Throwable {
         instance.runHeartbeatOnce();
         Thread.sleep(2000);
         instance.runHeartbeatOnce();
         Thread.sleep(2000);
 
-        AssertingDiscoveryAware assertingDiscoveryAware = new AssertingDiscoveryAware();
-        assertingDiscoveryAware.addExpected(Type.TOPOLOGY_INIT);
-        instance.bindDiscoveryAware(assertingDiscoveryAware);
-        assertEquals(0, assertingDiscoveryAware.getRemainingExpectedCount());
+        AssertingTopologyEventListener assertingTopologyEventListener = new AssertingTopologyEventListener();
+        assertingTopologyEventListener.addExpected(Type.TOPOLOGY_INIT);
+        instance.bindTopologyEventListener(assertingTopologyEventListener);
+        assertEquals(0, assertingTopologyEventListener.getRemainingExpectedCount());
 
         final String propertyName = UUID.randomUUID().toString();
         propertyValue = UUID.randomUUID().toString();
         PropertyProviderImpl pp = new PropertyProviderImpl();
         pp.setProperty(propertyName, propertyValue);
 
-        assertingDiscoveryAware.addExpected(Type.PROPERTIES_CHANGED);
+        assertingTopologyEventListener.addExpected(Type.PROPERTIES_CHANGED);
 
-        assertEquals(1, assertingDiscoveryAware.getRemainingExpectedCount());
+        assertEquals(1, assertingTopologyEventListener.getRemainingExpectedCount());
         assertEquals(0, pp.getGetCnt());
         instance.bindPropertyProvider(pp, propertyName);
-        assertEquals(0, assertingDiscoveryAware.getRemainingExpectedCount());
+        assertEquals(0, assertingTopologyEventListener.getRemainingExpectedCount());
         // we can only assume that the getProperty was called at least once - it
         // could be called multiple times though..
         assertTrue(pp.getGetCnt() > 0);
 
-        assertingDiscoveryAware.addExpected(Type.PROPERTIES_CHANGED);
+        assertingTopologyEventListener.addExpected(Type.PROPERTIES_CHANGED);
 
-        assertEquals(1, assertingDiscoveryAware.getRemainingExpectedCount());
+        assertEquals(1, assertingTopologyEventListener.getRemainingExpectedCount());
         pp.setGetCnt(0);
         propertyValue = UUID.randomUUID().toString();
         pp.setProperty(propertyName, propertyValue);
         assertEquals(0, pp.getGetCnt());
         instance.runHeartbeatOnce();
         Thread.sleep(2000);
-        assertEquals(0, assertingDiscoveryAware.getRemainingExpectedCount());
+        assertEquals(0, assertingTopologyEventListener.getRemainingExpectedCount());
         assertEquals(1, pp.getGetCnt());
 
         // a heartbeat repeat should not result in another call though
         instance.runHeartbeatOnce();
         Thread.sleep(2000);
-        assertEquals(0, assertingDiscoveryAware.getRemainingExpectedCount());
+        assertEquals(0, assertingTopologyEventListener.getRemainingExpectedCount());
         assertEquals(2, pp.getGetCnt());
 
     }
@@ -169,9 +169,9 @@ public class SingleInstanceTest {
                 .getClusterView();
         assertNotNull(initialClusterView);
 
-        AssertingDiscoveryAware ada = new AssertingDiscoveryAware();
+        AssertingTopologyEventListener ada = new AssertingTopologyEventListener();
         ada.addExpected(Type.TOPOLOGY_INIT);
-        instance.bindDiscoveryAware(ada);
+        instance.bindTopologyEventListener(ada);
         assertEquals(1, ada.getEvents().size());
         TopologyEvent initEvent = ada.getEvents().remove(0);
         assertNotNull(initEvent);

Added: sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/helpers/AssertingTopologyEventListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/helpers/AssertingTopologyEventListener.java?rev=1470448&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/helpers/AssertingTopologyEventListener.java (added)
+++ sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/helpers/AssertingTopologyEventListener.java Mon Apr 22 10:58:50 2013
@@ -0,0 +1,67 @@
+/*
+ * 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.sling.discovery.impl.cluster.helpers;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.sling.discovery.TopologyEvent;
+import org.apache.sling.discovery.TopologyEvent.Type;
+import org.apache.sling.discovery.TopologyEventListener;
+
+public class AssertingTopologyEventListener implements TopologyEventListener {
+    private final List<TopologyEventAsserter> expectedEvents = new LinkedList<TopologyEventAsserter>();
+
+    public AssertingTopologyEventListener() {
+    }
+
+    private List<TopologyEvent> events_ = new LinkedList<TopologyEvent>();
+
+    public void handleTopologyEvent(TopologyEvent event) {
+        TopologyEventAsserter asserter = null;
+        synchronized (expectedEvents) {
+            if (expectedEvents.size() == 0) {
+                throw new IllegalStateException(
+                        "no expected events anymore. But got: " + event);
+            }
+            asserter = expectedEvents.remove(0);
+        }
+        if (asserter == null) {
+            throw new IllegalStateException("this should not occur");
+        }
+        asserter.assertOk(event);
+        events_.add(event);
+    }
+
+    public List<TopologyEvent> getEvents() {
+        return events_;
+    }
+
+    public void addExpected(Type expectedType) {
+        addExpected(new AcceptsParticularTopologyEvent(expectedType));
+    }
+
+    public void addExpected(TopologyEventAsserter topologyEventAsserter) {
+        expectedEvents.add(topologyEventAsserter);
+    }
+
+    public int getRemainingExpectedCount() {
+        return expectedEvents.size();
+    }
+}
\ No newline at end of file

Propchange: sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/helpers/AssertingTopologyEventListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/helpers/AssertingTopologyEventListener.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/contrib/extensions/discovery/impl/src/test/java/org/apache/sling/discovery/impl/cluster/helpers/AssertingTopologyEventListener.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain