You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2024/09/09 15:49:05 UTC

(sling-org-apache-sling-discovery-impl) branch master updated: SLING-12424: Migrate discovery.impl to official OSGi annotations (#6)

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-discovery-impl.git


The following commit(s) were added to refs/heads/master by this push:
     new 9a7b4e1  SLING-12424: Migrate discovery.impl to official OSGi annotations (#6)
9a7b4e1 is described below

commit 9a7b4e1d6756aa196420363016f3833a24dd7737
Author: Marcel Reutegger <mr...@adobe.com>
AuthorDate: Mon Sep 9 17:49:01 2024 +0200

    SLING-12424: Migrate discovery.impl to official OSGi annotations (#6)
---
 bnd.bnd                                            |   3 +
 pom.xml                                            | 192 ++++----------------
 .../org/apache/sling/discovery/impl/Config.java    | 201 +++++----------------
 .../discovery/impl/DiscoveryServiceConfig.java     | 138 ++++++++++++++
 .../sling/discovery/impl/DiscoveryServiceImpl.java |  36 ++--
 .../discovery/impl/TopologyWebConsolePlugin.java   |  35 ++--
 .../impl/cluster/ClusterViewChangeListener.java    |   8 +-
 .../impl/cluster/ClusterViewServiceImpl.java       |   8 +-
 .../impl/cluster/voting/VotingHandler.java         |  12 +-
 .../impl/common/heartbeat/HeartbeatHandler.java    |  33 +++-
 .../discovery/impl/setup/VotingEventListener.java  |   5 +-
 11 files changed, 298 insertions(+), 373 deletions(-)

diff --git a/bnd.bnd b/bnd.bnd
new file mode 100644
index 0000000..e23702d
--- /dev/null
+++ b/bnd.bnd
@@ -0,0 +1,3 @@
+Import-Package:\
+    org.apache.felix.webconsole;resolution:=optional,\
+    *
diff --git a/pom.xml b/pom.xml
index 9704a2b..694370e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,13 +22,12 @@
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.apache.sling</groupId>
-        <artifactId>sling</artifactId>
-        <version>26</version>
+        <artifactId>sling-bundle-parent</artifactId>
+        <version>52</version>
         <relativePath />
     </parent>
 
     <artifactId>org.apache.sling.discovery.impl</artifactId>
-    <packaging>bundle</packaging>
     <version>1.2.13-SNAPSHOT</version>
 
     <name>Apache Sling Resource-Based Discovery Service</name>
@@ -41,80 +40,13 @@
     </scm>
 
     <properties>
-      <jackrabbit.version>2.20.16</jackrabbit.version>
+        <jackrabbit.version>2.20.16</jackrabbit.version>
         <!-- by default Slow tests are excluded - use -PincludeSlowTests to include them -->
         <sling.excluded.surefire.groups>org.apache.sling.commons.testing.junit.categories.Slow</sling.excluded.surefire.groups>
-        <!--
-            Explicitly set bundle required execution environment and
-            disable set-bundle-required-execution-environment execution
-            of maven-antrun-plugin. Allows building with Java 11.
-            Can be removed after upgrading to a recent Sling parent pom.
-            See also SLING-12419.
-        -->
-        <sling.java.version>8</sling.java.version>
-        <sling.bree>JavaSE-1.8</sling.bree>
-        <animal.sniffer.skip>true</animal.sniffer.skip>
-        <sling.animalSignatures.version>6</sling.animalSignatures.version>
     </properties>
 
     <build>
         <plugins>
-            <!--
-                START workarounds for Java 11+
-                Can be removed after upgrading to a recent Sling parent pom.
-                See also SLING-12419.
-            -->
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-antrun-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <!-- disable and explicitly set properties (SLING-12419) -->
-                        <id>set-bundle-required-execution-environment</id>
-                        <phase>none</phase>
-                    </execution>
-                </executions>
-            </plugin>
-            <!--
-                ianal-maven-plugin does not work with Java 11+,
-                but tools-maven-plugin does.
-            -->
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>ianal-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <phase>none</phase>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.geronimo.genesis.plugins</groupId>
-                <artifactId>tools-maven-plugin</artifactId>
-                <version>1.4</version>
-                <executions>
-                    <execution>
-                        <id>verify-legal-files</id>
-                        <goals>
-                            <goal>verify-legal-files</goal>
-                        </goals>
-                        <configuration>
-                            <!-- Fail the build if any artifacts are missing legal files -->
-                            <strict>true</strict>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <!-- END workarounds for Java 11+ -->
-            <!--
-                Use recent maven-bundle-plugin for Java 21 build on Windows.
-                Can be removed after upgrading to a recent Sling parent pom.
-            -->
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-source-plugin</artifactId>
-                <version>3.3.1</version>
-            </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-surefire-plugin</artifactId>
@@ -124,33 +56,6 @@
                     <excludedGroups>${sling.excluded.surefire.groups}</excludedGroups>
                 </configuration>
             </plugin>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-scr-plugin</artifactId>
-                <version>1.26.4</version>        
-            </plugin>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <!--  with 3.0.0 the following bundle dependency is failing
-                      on AEM 5.6.1 - thus switching back to 2.5.3 here:
-					javax.servlet,version=[2.6,3) - - Cannot be resolved
-					javax.servlet.http,version=[2.6,3) - - Cannot be resolved
-                -->
-                <version>2.5.3</version>
-                <extensions>true</extensions>
-                <configuration>
-                  <instructions>
-		            <Embed-Dependency>
-		              commons-net;inline=org/apache/commons/net/util/SubnetUtils*
-		            </Embed-Dependency>
-                <!-- remove when upgrading to bnd Maven plugin -->
-                <Provide-Capability><![CDATA[
-                  osgi.service;objectClass:List<String>="org.apache.sling.discovery.impl.Config,org.apache.sling.discovery.base.connectors.BaseConfig,org.apache.sling.discovery.commons.providers.spi.base.DiscoveryLiteConfig"
-                ]]></Provide-Capability>
-		          </instructions>
-		        </configuration>
-            </plugin>
         </plugins>
     </build>
     <profiles>
@@ -166,25 +71,40 @@
     </profiles>
     <dependencies>
         <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+	        <version>1.6.1</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.component.annotations</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>biz.aQute</groupId>
-            <artifactId>bndlib</artifactId>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.metatype.annotations</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-	        <version>1.6.1</version>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.framework</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
+            <artifactId>org.osgi.service.event</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
+            <artifactId>org.osgi.service.component</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.http</artifactId>
+            <scope>provided</scope>
         </dependency>
 		<dependency>
 			<groupId>org.apache.sling</groupId>
@@ -198,16 +118,10 @@
 			<version>2.0</version>
 			<scope>provided</scope>
 		</dependency>
-		<dependency>
-			<groupId>org.apache.jackrabbit</groupId>
-			<artifactId>oak-jackrabbit-api</artifactId>
-			<version>1.48.0</version>
-			<scope>provided</scope>
-		</dependency>
 		<dependency>
 			<groupId>org.apache.sling</groupId>
 			<artifactId>org.apache.sling.commons.osgi</artifactId>
-			<version>2.1.0</version>
+			<version>2.4.2</version>
 			<scope>provided</scope>
 		</dependency>
 		<dependency>
@@ -253,17 +167,11 @@
             <version>2.0.14</version>
             <scope>test</scope>
             <type>test-jar</type>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.commons.johnzon</artifactId>
-            <version>1.0.0</version>
-            <scope>test</scope>
         </dependency>
 		<dependency>
 			<groupId>org.apache.sling</groupId>
 			<artifactId>org.apache.sling.api</artifactId>
-			<version>2.5.0</version>
+			<version>2.7.0</version>
             <scope>provided</scope>
 		</dependency>
         <dependency>
@@ -286,30 +194,14 @@
 	    </dependency>
 		<dependency>
 			<groupId>javax.servlet</groupId>
-			<artifactId>servlet-api</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.httpcomponents</groupId>
-			<artifactId>httpclient-osgi</artifactId>
-			<version>4.3.5</version>
-			<scope>provided</scope>
-		</dependency>
-        <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-            <version>2.4</version>
+			<artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>commons-net</groupId>
-            <artifactId>commons-net</artifactId>
-            <version>3.3</version>
-            <scope>provided</scope>
-        </dependency>
+		</dependency>
       <!-- Testing -->
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>junit-addons</groupId>
@@ -317,16 +209,6 @@
             <version>1.4</version>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.jmock</groupId>
-            <artifactId>jmock-junit4</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-all</artifactId>
-            <version>1.9.5</version>
-            <scope>test</scope>
-        </dependency>
         <dependency>
         	<groupId>org.apache.sling</groupId>
         	<artifactId>org.apache.sling.commons.testing</artifactId>
@@ -375,6 +257,12 @@
             <version>10.14.2.0</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+            <scope>test</scope>
+        </dependency>
 
         <!-- using log4j under slf4j to allow fine-grained logging config (see src/test/resources/log4j.properties) -->
         <dependency>
@@ -409,8 +297,8 @@
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.testing.sling-mock</artifactId>
-            <version>1.2.0</version>
+            <artifactId>org.apache.sling.testing.sling-mock.junit4</artifactId>
+            <version>3.5.0</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
diff --git a/src/main/java/org/apache/sling/discovery/impl/Config.java b/src/main/java/org/apache/sling/discovery/impl/Config.java
index bb07c99..7ed5830 100644
--- a/src/main/java/org/apache/sling/discovery/impl/Config.java
+++ b/src/main/java/org/apache/sling/discovery/impl/Config.java
@@ -22,26 +22,34 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.commons.osgi.PropertiesUtil;
 import org.apache.sling.discovery.base.connectors.BaseConfig;
 import org.apache.sling.discovery.commons.providers.spi.base.DiscoveryLiteConfig;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.metatype.annotations.Designate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.sling.discovery.impl.DiscoveryServiceConfig.DEFAULT_BACKOFF_STABLE_FACTOR;
+import static org.apache.sling.discovery.impl.DiscoveryServiceConfig.DEFAULT_BACKOFF_STANDBY_FACTOR;
+import static org.apache.sling.discovery.impl.DiscoveryServiceConfig.DEFAULT_CONNECTION_TIMEOUT;
+import static org.apache.sling.discovery.impl.DiscoveryServiceConfig.DEFAULT_DISCOVERY_RESOURCE_PATH;
+import static org.apache.sling.discovery.impl.DiscoveryServiceConfig.DEFAULT_HEARTBEAT_INTERVAL;
+import static org.apache.sling.discovery.impl.DiscoveryServiceConfig.DEFAULT_HEARTBEAT_TIMEOUT;
+import static org.apache.sling.discovery.impl.DiscoveryServiceConfig.DEFAULT_MIN_EVENT_DELAY;
+import static org.apache.sling.discovery.impl.DiscoveryServiceConfig.DEFAULT_SO_TIMEOUT;
+import static org.apache.sling.discovery.impl.DiscoveryServiceConfig.DEFAULT_TOPOLOGY_CONNECTOR_WHITELIST;
+
 /**
  * Configuration object used as a central config point for the discovery service
  * implementation
  * <p>
  * The properties are described below under.
  */
-@Component(metatype = true, label="%config.name", description="%config.description")
-@Service(value = { Config.class, BaseConfig.class, DiscoveryLiteConfig.class })
+@Component(service = { Config.class, BaseConfig.class, DiscoveryLiteConfig.class })
+@Designate(ocd = DiscoveryServiceConfig.class)
 public class Config implements BaseConfig, DiscoveryLiteConfig {
 
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
@@ -64,126 +72,15 @@ public class Config implements BaseConfig, DiscoveryLiteConfig {
     /** resource used to keep ongoing votings **/
     private static final String ONGOING_VOTING_RESOURCE = "ongoingVotings";
 
-    /** Configure the timeout (in seconds) after which an instance is considered dead/crashed. */
-    public static final long DEFAULT_HEARTBEAT_TIMEOUT = 120;
-    @Property(longValue=DEFAULT_HEARTBEAT_TIMEOUT)
-    public static final String HEARTBEAT_TIMEOUT_KEY = "heartbeatTimeout";
     protected long heartbeatTimeout = DEFAULT_HEARTBEAT_TIMEOUT;
-
-    /** Configure the interval (in seconds) according to which the heartbeats are exchanged in the topology. */
-    public static final long DEFAULT_HEARTBEAT_INTERVAL = 30;
-    @Property(longValue=DEFAULT_HEARTBEAT_INTERVAL)
-    public static final String HEARTBEAT_INTERVAL_KEY = "heartbeatInterval";
     protected long heartbeatInterval = DEFAULT_HEARTBEAT_INTERVAL;
-
-    /** Configure the time (in seconds) which must be passed at minimum between sending TOPOLOGY_CHANGING/_CHANGED (avoid flooding). */
-    public static final int DEFAULT_MIN_EVENT_DELAY = 3;
-    @Property(intValue=DEFAULT_MIN_EVENT_DELAY)
-    public static final String MIN_EVENT_DELAY_KEY = "minEventDelay";
     protected int minEventDelay = DEFAULT_MIN_EVENT_DELAY;
-
-    /** Configure the socket connect timeout for topology connectors. */
-    public static final int DEFAULT_CONNECTION_TIMEOUT = 10;
-    @Property(intValue=DEFAULT_CONNECTION_TIMEOUT)
-    public static final String CONNECTION_TIMEOUT_KEY = "connectionTimeout";
     private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
-
-    /** Configure the socket read timeout (SO_TIMEOUT) for topology connectors. */
-    public static final int DEFAULT_SO_TIMEOUT = 10;
-    @Property(intValue=DEFAULT_SO_TIMEOUT)
-    public static final String SO_TIMEOUT_KEY = "soTimeout";
     private int soTimeout = DEFAULT_SO_TIMEOUT;
-
-    /** Name of the repository descriptor to be taken into account for leader election:
-        those instances have preference to become leader which have the corresponding descriptor value of 'false' */
-    @Property
-    public static final String LEADER_ELECTION_REPOSITORY_DESCRIPTOR_NAME_KEY = "leaderElectionRepositoryDescriptor";
-    
-    /**
-     * Whether or not (default false) the leaderElectionRepositoryDescriptor should be inverted (if that one
-     * is configured at all).
-     */
-    @Property(boolValue=false)
-    public static final String INVERT_REPOSITORY_DESCRIPTOR_NAME_KEY = "invertRepositoryDescriptor";
-    
-    /** URLs where to join a topology, eg http://localhost:4502/libs/sling/topology/connector */
-    @Property(cardinality=1024)
-    public static final String TOPOLOGY_CONNECTOR_URLS_KEY = "topologyConnectorUrls";
     private URL[] topologyConnectorUrls = {null};
-
-    /** 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(value={"localhost","127.0.0.1"})
-    public static final String TOPOLOGY_CONNECTOR_WHITELIST_KEY = "topologyConnectorWhitelist";
     private String[] topologyConnectorWhitelist = DEFAULT_TOPOLOGY_CONNECTOR_WHITELIST;
-
-    /** Path of resource where to keep discovery information, e.g /var/discovery/impl/ */
-    private static final String DEFAULT_DISCOVERY_RESOURCE_PATH = "/var/discovery/impl/";
-    @Property(value=DEFAULT_DISCOVERY_RESOURCE_PATH, propertyPrivate=true)
-    public static final String DISCOVERY_RESOURCE_PATH_KEY = "discoveryResourcePath";
     private String discoveryResourcePath = DEFAULT_DISCOVERY_RESOURCE_PATH;
-
-    /**
-     * If set to true, local-loops of topology connectors are automatically stopped when detected so.
-     */
-    @Property(boolValue=false)
-    private static final String AUTO_STOP_LOCAL_LOOP_ENABLED = "autoStopLocalLoopEnabled";
-
-    /**
-     * If set to true, request body will be gzipped - only works if counter-part accepts gzip-requests!
-     */
-    @Property(boolValue=false)
-    private static final String GZIP_CONNECTOR_REQUESTS_ENABLED = "gzipConnectorRequestsEnabled";
-
-    /**
-     * If set to true, hmac is enabled and the white list is disabled.
-     */
-    @Property(boolValue=false)
-    private static final String HMAC_ENABLED = "hmacEnabled";
-
-    /**
-     * If set to true, and the whitelist is disabled, messages will be encrypted.
-     */
-    @Property(boolValue=false)
-    private static final String ENCRYPTION_ENABLED = "enableEncryption";
-
-    /**
-     * The value fo the shared key, shared amongst all instances in the same cluster.
-     */
-    @Property
-    private static final String SHARED_KEY = "sharedKey";
-
-    /**
-     * The default lifetime of a HMAC shared key in ms. (4h)
-     */
-    private static final long DEFAULT_SHARED_KEY_INTERVAL = 3600*1000*4;
-
-    @Property(longValue=DEFAULT_SHARED_KEY_INTERVAL)
-    private static final String SHARED_KEY_INTERVAL = "hmacSharedKeyTTL";
-    
-    /**
-     * The property for defining the backoff factor for standby (loop) connectors
-     */
-    @Property
-    private static final String BACKOFF_STANDBY_FACTOR = "backoffStandbyFactor";
-    private static final int DEFAULT_BACKOFF_STANDBY_FACTOR = 5;
-    
-    /**
-     * The property for defining the maximum backoff factor for stable connectors
-     */
-    @Property
-    private static final String BACKOFF_STABLE_FACTOR = "backoffStableFactor";
-    private static final int DEFAULT_BACKOFF_STABLE_FACTOR = 5;
-    
-    /**
-     * when set to true and the syncTokenService (of discovery.commons) is available,
-     * then it is used
-     */
-    @Property(boolValue=true)
-    private static final String USE_SYNC_TOKEN_SERVICE_ENABLED = "useSyncTokenService";
-
     private String leaderElectionRepositoryDescriptor ;
-
     private boolean invertRepositoryDescriptor = false; /* default: false */
     
     /** True when auto-stop of a local-loop is enabled. Default is false. **/
@@ -227,50 +124,40 @@ public class Config implements BaseConfig, DiscoveryLiteConfig {
     private boolean useSyncTokenService = true;
     
     @Activate
-    protected void activate(final Map<String, Object> properties) {
+    protected void activate(final DiscoveryServiceConfig config) {
 		logger.debug("activate: config activated.");
-        configure(properties);
+        configure(config);
     }
 
-    protected void configure(final Map<String, Object> properties) {
-        this.heartbeatTimeout = PropertiesUtil.toLong(
-                properties.get(HEARTBEAT_TIMEOUT_KEY),
-                DEFAULT_HEARTBEAT_TIMEOUT);
+    protected void configure(final DiscoveryServiceConfig config) {
+        this.heartbeatTimeout = config.heartbeatTimeout();
         logger.debug("configure: heartbeatTimeout='{}'", this.heartbeatTimeout);
 
-        this.heartbeatInterval = PropertiesUtil.toLong(
-                properties.get(HEARTBEAT_INTERVAL_KEY),
-                DEFAULT_HEARTBEAT_INTERVAL);
+        this.heartbeatInterval = config.heartbeatInterval();
         logger.debug("configure: heartbeatInterval='{}'",
                 this.heartbeatInterval);
 
-        this.minEventDelay = PropertiesUtil.toInteger(
-                properties.get(MIN_EVENT_DELAY_KEY),
-                DEFAULT_MIN_EVENT_DELAY);
+        this.minEventDelay = config.minEventDelay();
         logger.debug("configure: minEventDelay='{}'",
                 this.minEventDelay);
         
-        this.connectionTimeout = PropertiesUtil.toInteger(
-                properties.get(CONNECTION_TIMEOUT_KEY),
-                DEFAULT_CONNECTION_TIMEOUT);
+        this.connectionTimeout = config.connectionTimeout();
         logger.debug("configure: connectionTimeout='{}'",
                 this.connectionTimeout);
         
-        this.soTimeout = PropertiesUtil.toInteger(
-                properties.get(SO_TIMEOUT_KEY),
-                DEFAULT_SO_TIMEOUT);
+        this.soTimeout = config.soTimeout();
         logger.debug("configure: soTimeout='{}'",
                 this.soTimeout);
         
         
         String[] topologyConnectorUrlsStr = PropertiesUtil.toStringArray(
-                properties.get(TOPOLOGY_CONNECTOR_URLS_KEY), null);
+                config.topologyConnectorUrls(), null);
         if (topologyConnectorUrlsStr!=null && topologyConnectorUrlsStr.length > 0) {
-            List<URL> urls = new LinkedList<URL>();
+            List<URL> urls = new LinkedList<>();
             for (int i = 0; i < topologyConnectorUrlsStr.length; i++) {
                 String anUrlStr = topologyConnectorUrlsStr[i];
                 try {
-                	if (anUrlStr!=null && anUrlStr.length()>0) {
+                	if (anUrlStr!=null && !anUrlStr.isEmpty()) {
 	                    URL url = new URL(anUrlStr);
 	                    logger.debug("configure: a topologyConnectorbUrl='{}'",
 	                            url);
@@ -281,7 +168,7 @@ public class Config implements BaseConfig, DiscoveryLiteConfig {
                             e);
                 }
             }
-            if (urls.size()>0) {
+            if (!urls.isEmpty()) {
                 this.topologyConnectorUrls = urls.toArray(new URL[urls.size()]);
                 logger.debug("configure: number of topologyConnectorUrls='{}''",
                         urls.size());
@@ -294,52 +181,46 @@ public class Config implements BaseConfig, DiscoveryLiteConfig {
             logger.debug("configure: no (valid) topologyConnectorUrls configured");
         }
         this.topologyConnectorWhitelist = PropertiesUtil.toStringArray(
-                properties.get(TOPOLOGY_CONNECTOR_WHITELIST_KEY),
+                config.topologyConnectorWhitelist(),
                 DEFAULT_TOPOLOGY_CONNECTOR_WHITELIST);
         logger.debug("configure: topologyConnectorWhitelist='{}'",
                 this.topologyConnectorWhitelist);
 
         this.discoveryResourcePath = PropertiesUtil.toString(
-                properties.get(DISCOVERY_RESOURCE_PATH_KEY),
+                config.discoveryResourcePath(),
                 "");
         while(this.discoveryResourcePath.endsWith("/")) {
             this.discoveryResourcePath = this.discoveryResourcePath.substring(0,
                     this.discoveryResourcePath.length()-1);
         }
         this.discoveryResourcePath = this.discoveryResourcePath + "/";
-        if (this.discoveryResourcePath==null || this.discoveryResourcePath.length()<=1) {
+        if (this.discoveryResourcePath.length()<=1) {
             // if the path is empty, or /, then use the default
             this.discoveryResourcePath = DEFAULT_DISCOVERY_RESOURCE_PATH;
         }
         logger.debug("configure: discoveryResourcePath='{}'",
                 this.discoveryResourcePath);
 
-        this.leaderElectionRepositoryDescriptor = PropertiesUtil.toString(
-                properties.get(LEADER_ELECTION_REPOSITORY_DESCRIPTOR_NAME_KEY),
-                null);
+        this.leaderElectionRepositoryDescriptor = config.leaderElectionRepositoryDescriptor();
         logger.debug("configure: leaderElectionRepositoryDescriptor='{}'",
                 this.leaderElectionRepositoryDescriptor);
         
-        this.invertRepositoryDescriptor = PropertiesUtil.toBoolean(
-                properties.get(INVERT_REPOSITORY_DESCRIPTOR_NAME_KEY),
-                false /* default: false*/);
+        this.invertRepositoryDescriptor = config.invertRepositoryDescriptor();
         logger.debug("configure: invertRepositoryDescriptor='{}'",
                 this.invertRepositoryDescriptor);
 
-        autoStopLocalLoopEnabled = PropertiesUtil.toBoolean(properties.get(AUTO_STOP_LOCAL_LOOP_ENABLED), false);
-        gzipConnectorRequestsEnabled = PropertiesUtil.toBoolean(properties.get(GZIP_CONNECTOR_REQUESTS_ENABLED), false);
+        autoStopLocalLoopEnabled = config.autoStopLocalLoopEnabled();
+        gzipConnectorRequestsEnabled = config.gzipConnectorRequestsEnabled();
         
-        hmacEnabled = PropertiesUtil.toBoolean(properties.get(HMAC_ENABLED), true);
-        encryptionEnabled = PropertiesUtil.toBoolean(properties.get(ENCRYPTION_ENABLED), false);
-        sharedKey = PropertiesUtil.toString(properties.get(SHARED_KEY), null);
-        keyInterval = PropertiesUtil.toLong(SHARED_KEY_INTERVAL, DEFAULT_SHARED_KEY_INTERVAL);
+        hmacEnabled = config.hmacEnabled();
+        encryptionEnabled = config.enableEncryption();
+        sharedKey = config.sharedKey();
+        keyInterval = config.hmacSharedKeyTTL();
         
-        backoffStandbyFactor = PropertiesUtil.toInteger(properties.get(BACKOFF_STANDBY_FACTOR), 
-                DEFAULT_BACKOFF_STANDBY_FACTOR);
-        backoffStableFactor = PropertiesUtil.toInteger(properties.get(BACKOFF_STABLE_FACTOR), 
-                DEFAULT_BACKOFF_STABLE_FACTOR);
+        backoffStandbyFactor = config.backoffStandbyFactor();
+        backoffStableFactor = config.backoffStableFactor();
         
-        useSyncTokenService = PropertiesUtil.toBoolean(properties.get(USE_SYNC_TOKEN_SERVICE_ENABLED), true);
+        useSyncTokenService = config.useSyncTokenServiceEnabled();
     }
 
     /**
diff --git a/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceConfig.java b/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceConfig.java
new file mode 100644
index 0000000..944d438
--- /dev/null
+++ b/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceConfig.java
@@ -0,0 +1,138 @@
+/*
+ * 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;
+
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+
+@ObjectClassDefinition(
+        localization = "OSGI-INF/l10n/metatype",
+        name = "%config.name",
+        description = "%config.description"
+)
+public @interface DiscoveryServiceConfig {
+
+    /** Configure the timeout (in seconds) after which an instance is considered dead/crashed. */
+    long DEFAULT_HEARTBEAT_TIMEOUT = 120;
+    @AttributeDefinition(name = "%heartbeatTimeout.name", description = "%heartbeatTimeout.description")
+    long heartbeatTimeout() default DEFAULT_HEARTBEAT_TIMEOUT;
+
+    /** Configure the interval (in seconds) according to which the heartbeats are exchanged in the topology. */
+    long DEFAULT_HEARTBEAT_INTERVAL = 30;
+    @AttributeDefinition(name = "%heartbeatInterval.name", description = "%heartbeatInterval.description")
+    long heartbeatInterval() default DEFAULT_HEARTBEAT_INTERVAL;
+
+    /** Configure the time (in seconds) which must be passed at minimum between sending TOPOLOGY_CHANGING/_CHANGED (avoid flooding). */
+    int DEFAULT_MIN_EVENT_DELAY = 3;
+    @AttributeDefinition(name = "%minEventDelay.name", description = "%minEventDelay.description")
+    int minEventDelay() default DEFAULT_MIN_EVENT_DELAY;
+
+    /** Configure the socket connect timeout for topology connectors. */
+    int DEFAULT_CONNECTION_TIMEOUT = 10;
+    @AttributeDefinition(name = "%connectionTimeout.name", description = "%connectionTimeout.description")
+    int connectionTimeout() default DEFAULT_CONNECTION_TIMEOUT;
+
+    /** Configure the socket read timeout (SO_TIMEOUT) for topology connectors. */
+    int DEFAULT_SO_TIMEOUT = 10;
+    @AttributeDefinition(name = "%soTimeout.name", description = "%soTimeout.description")
+    int soTimeout() default DEFAULT_SO_TIMEOUT;
+
+    /** Name of the repository descriptor to be taken into account for leader election:
+     those instances have preference to become leader which have the corresponding descriptor value of 'false' */
+    @AttributeDefinition(name = "%leaderElectionRepositoryDescriptor.name", description = "%leaderElectionRepositoryDescriptor.description")
+    String leaderElectionRepositoryDescriptor();
+
+    /**
+     * Whether or not (default false) the leaderElectionRepositoryDescriptor should be inverted (if that one
+     * is configured at all).
+     */
+    @AttributeDefinition(name = "%invertRepositoryDescriptor.name", description = "%invertRepositoryDescriptor.description")
+    boolean invertRepositoryDescriptor() default false;
+
+    /** URLs where to join a topology, eg http://localhost:4502/libs/sling/topology/connector */
+    @AttributeDefinition(name = "%topologyConnectorUrls.name", description = "%topologyConnectorUrls.description", cardinality=1024)
+    String[] topologyConnectorUrls() default {};
+
+    /** list of ips and/or hostnames which are allowed to connect to /libs/sling/topology/connector */
+    @AttributeDefinition(name = "%topologyConnectorWhitelist.name", description = "%topologyConnectorWhitelist.description")
+    String[] topologyConnectorWhitelist() default {"localhost", "127.0.0.1"};
+    String[] DEFAULT_TOPOLOGY_CONNECTOR_WHITELIST = {"localhost", "127.0.0.1"};
+
+    /** Path of resource where to keep discovery information, e.g /var/discovery/impl/ */
+    @AttributeDefinition(name = "%discoveryResourcePath.name", description = "%discoveryResourcePath.description")
+    String discoveryResourcePath() default DEFAULT_DISCOVERY_RESOURCE_PATH;
+    String DEFAULT_DISCOVERY_RESOURCE_PATH = "/var/discovery/impl/";
+
+    /**
+     * If set to true, local-loops of topology connectors are automatically stopped when detected so.
+     */
+    @AttributeDefinition(name = "%autoStopLocalLoopEnabled.name", description = "%autoStopLocalLoopEnabled.description")
+    boolean autoStopLocalLoopEnabled() default false;
+
+    /**
+     * If set to true, request body will be gzipped - only works if counter-part accepts gzip-requests!
+     */
+    @AttributeDefinition(name = "%gzipConnectorRequestsEnabled.name", description = "%gzipConnectorRequestsEnabled.description")
+    boolean gzipConnectorRequestsEnabled() default false;
+
+    /**
+     * If set to true, hmac is enabled and the white list is disabled.
+     */
+    @AttributeDefinition(name = "%hmacEnabled.name", description = "%hmacEnabled.description")
+    boolean hmacEnabled() default true;
+
+    /**
+     * If set to true, and the whitelist is disabled, messages will be encrypted.
+     */
+    @AttributeDefinition()
+    boolean enableEncryption() default false;
+
+    /**
+     * The value for the shared key, shared amongst all instances in the same cluster.
+     */
+    @AttributeDefinition(name = "%sharedKey.name", description = "%sharedKey.description")
+    String sharedKey();
+
+    /**
+     * The default lifetime of a HMAC shared key in ms. (4h)
+     */
+    long DEFAULT_SHARED_KEY_INTERVAL = 3600L*1000*4;
+    @AttributeDefinition(name = "%hmacSharedKeyTTL.name", description = "%hmacSharedKeyTTL.description")
+    long hmacSharedKeyTTL() default DEFAULT_SHARED_KEY_INTERVAL;
+
+    /**
+     * The property for defining the backoff factor for standby (loop) connectors
+     */
+    @AttributeDefinition(name = "%backoffStandbyFactor.name", description = "%backoffStandbyFactor.description")
+    int backoffStandbyFactor() default DEFAULT_BACKOFF_STANDBY_FACTOR;
+    int DEFAULT_BACKOFF_STANDBY_FACTOR = 5;
+
+    /**
+     * The property for defining the maximum backoff factor for stable connectors
+     */
+    @AttributeDefinition(name = "%backoffStableFactor.name", description = "%backoffStableFactor.description")
+    int backoffStableFactor() default DEFAULT_BACKOFF_STABLE_FACTOR;
+    int DEFAULT_BACKOFF_STABLE_FACTOR = 5;
+
+    /**
+     * when set to true and the syncTokenService (of discovery.commons) is available,
+     * then it is used
+     */
+    @AttributeDefinition(name = "%useSyncTokenServiceEnabled.name", description = "%useSyncTokenServiceEnabled.description")
+    boolean useSyncTokenServiceEnabled() default true;
+
+}
diff --git a/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java b/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java
index 3579a52..fb7cc86 100644
--- a/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java
+++ b/src/main/java/org/apache/sling/discovery/impl/DiscoveryServiceImpl.java
@@ -34,13 +34,6 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.locks.ReentrantLock;
 
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.apache.felix.scr.annotations.ReferencePolicy;
-import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.ModifiableValueMap;
 import org.apache.sling.api.resource.PersistenceException;
@@ -77,6 +70,12 @@ import org.apache.sling.settings.SlingSettingsService;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -85,11 +84,10 @@ import org.slf4j.LoggerFactory;
  * implementation for detecting changes in a cluster and only supports one
  * cluster (of which this instance is part of).
  */
-@Component(immediate = true)
-@Service(value = { DiscoveryService.class, DiscoveryServiceImpl.class })
+@Component(immediate = true, service = { DiscoveryService.class, DiscoveryServiceImpl.class })
 public class DiscoveryServiceImpl extends BaseDiscoveryService {
 
-    private final static Logger logger = LoggerFactory.getLogger(DiscoveryServiceImpl.class);
+    private static final Logger logger = LoggerFactory.getLogger(DiscoveryServiceImpl.class);
 
     /**
      * This ClusterSyncService just 'passes the call through', ie it doesn't actually
@@ -113,14 +111,10 @@ public class DiscoveryServiceImpl extends BaseDiscoveryService {
     @Reference
     private SlingSettingsService settingsService;
 
-    @Reference(cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC, referenceInterface = TopologyEventListener.class)
-    private TopologyEventListener[] eventListeners = new TopologyEventListener[0];
-
     /**
      * All property providers.
      */
-    @Reference(cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC, referenceInterface = PropertyProvider.class, updated = "updatedPropertyProvider")
-    private List<ProviderInfo> providerInfos = new ArrayList<ProviderInfo>();
+    private final List<ProviderInfo> providerInfos = new ArrayList<>();
 
     /** lock object used for synching bind/unbind and topology event sending **/
     private final Object lock = new Object();
@@ -166,7 +160,7 @@ public class DiscoveryServiceImpl extends BaseDiscoveryService {
 
     private final List<TopologyEventListener> pendingListeners = new LinkedList<TopologyEventListener>();
 
-    private TopologyEventListener changePropagationListener = new TopologyEventListener() {
+    private final TopologyEventListener changePropagationListener = new TopologyEventListener() {
 
         @Override
         public void handleTopologyEvent(TopologyEvent event) {
@@ -389,6 +383,11 @@ public class DiscoveryServiceImpl extends BaseDiscoveryService {
     /**
      * bind a topology event listener
      */
+    @Reference(name = "eventListeners",
+            service = TopologyEventListener.class,
+            cardinality = ReferenceCardinality.MULTIPLE,
+            policy = ReferencePolicy.DYNAMIC,
+            bind = "bindTopologyEventListener", unbind = "unbindTopologyEventListener")
     protected void bindTopologyEventListener(final TopologyEventListener eventListener) {
         viewStateManagerLock.lock();
         try{
@@ -425,6 +424,11 @@ public class DiscoveryServiceImpl extends BaseDiscoveryService {
     /**
      * Bind a new property provider.
      */
+    @Reference(name = "providerInfos",
+            service = PropertyProvider.class,
+            cardinality = ReferenceCardinality.MULTIPLE,
+            policy = ReferencePolicy.DYNAMIC,
+            bind = "bindPropertyProvider", unbind = "unbindPropertyProvider", updated = "updatedPropertyProvider")
     protected void bindPropertyProvider(final PropertyProvider propertyProvider,
                                         final Map<String, Object> props) {
         logger.debug("bindPropertyProvider: Binding PropertyProvider {}",
diff --git a/src/main/java/org/apache/sling/discovery/impl/TopologyWebConsolePlugin.java b/src/main/java/org/apache/sling/discovery/impl/TopologyWebConsolePlugin.java
index a6a6d30..8e0382a 100644
--- a/src/main/java/org/apache/sling/discovery/impl/TopologyWebConsolePlugin.java
+++ b/src/main/java/org/apache/sling/discovery/impl/TopologyWebConsolePlugin.java
@@ -38,13 +38,6 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Properties;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.Service;
 import org.apache.felix.webconsole.AbstractWebConsolePlugin;
 import org.apache.felix.webconsole.WebConsoleConstants;
 import org.apache.sling.discovery.ClusterView;
@@ -63,23 +56,31 @@ import org.apache.sling.discovery.base.connectors.ping.TopologyConnectorClientIn
 import org.apache.sling.discovery.commons.providers.spi.base.ClusterSyncHistory;
 import org.apache.sling.discovery.commons.providers.spi.base.SyncTokenService;
 import org.osgi.framework.BundleContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.propertytypes.ServiceDescription;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.felix.webconsole.WebConsoleConstants.PLUGIN_LABEL;
+import static org.apache.felix.webconsole.WebConsoleConstants.PLUGIN_TITLE;
+
 /**
  * Simple webconsole which gives an overview of the topology visible by the
  * discovery service
  */
-@Component
-@Service(value = { TopologyEventListener.class, Servlet.class })
-@Properties({
-    @Property(name=org.osgi.framework.Constants.SERVICE_DESCRIPTION,
-            value="Apache Sling Web Console Plugin to display Background servlets and ExecutionEngine status"),
-    @Property(name=WebConsoleConstants.PLUGIN_LABEL, value=TopologyWebConsolePlugin.LABEL),
-    @Property(name=WebConsoleConstants.PLUGIN_TITLE, value=TopologyWebConsolePlugin.TITLE),
-    @Property(name="felix.webconsole.category", value="Sling"),
-    @Property(name="felix.webconsole.configprinter.modes", value={"zip"})
-})
+@Component(
+        service = { TopologyEventListener.class, Servlet.class },
+        property = {
+                PLUGIN_LABEL + "=" + TopologyWebConsolePlugin.LABEL,
+                PLUGIN_TITLE + "=" + TopologyWebConsolePlugin.TITLE,
+                "felix.webconsole.category=Sling",
+                "felix.webconsole.configprinter.modes={zip}"
+        }
+)
+@ServiceDescription("Apache Sling Web Console Plugin to display Background servlets and ExecutionEngine status")
 @SuppressWarnings("serial")
 public class TopologyWebConsolePlugin extends AbstractWebConsolePlugin implements TopologyEventListener {
 
diff --git a/src/main/java/org/apache/sling/discovery/impl/cluster/ClusterViewChangeListener.java b/src/main/java/org/apache/sling/discovery/impl/cluster/ClusterViewChangeListener.java
index 83cce6c..b1b5473 100644
--- a/src/main/java/org/apache/sling/discovery/impl/cluster/ClusterViewChangeListener.java
+++ b/src/main/java/org/apache/sling/discovery/impl/cluster/ClusterViewChangeListener.java
@@ -21,10 +21,6 @@ package org.apache.sling.discovery.impl.cluster;
 import java.util.Dictionary;
 import java.util.Hashtable;
 
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Reference;
 import org.apache.sling.api.SlingConstants;
 import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.discovery.impl.Config;
@@ -34,6 +30,10 @@ import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.event.Event;
 import org.osgi.service.event.EventConstants;
 import org.osgi.service.event.EventHandler;
diff --git a/src/main/java/org/apache/sling/discovery/impl/cluster/ClusterViewServiceImpl.java b/src/main/java/org/apache/sling/discovery/impl/cluster/ClusterViewServiceImpl.java
index cf310e9..a190c48 100644
--- a/src/main/java/org/apache/sling/discovery/impl/cluster/ClusterViewServiceImpl.java
+++ b/src/main/java/org/apache/sling/discovery/impl/cluster/ClusterViewServiceImpl.java
@@ -18,9 +18,6 @@
  */
 package org.apache.sling.discovery.impl.cluster;
 
-import org.apache.felix.scr.annotations.Component;
-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.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
@@ -34,6 +31,8 @@ import org.apache.sling.discovery.impl.common.View;
 import org.apache.sling.discovery.impl.common.ViewHelper;
 import org.apache.sling.discovery.impl.common.resource.EstablishedClusterView;
 import org.apache.sling.settings.SlingSettingsService;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,8 +42,7 @@ import org.slf4j.LoggerFactory;
  * This class is a reader only - it accesses the repository to read the
  * currently established view
  */
-@Component
-@Service(value = {ClusterViewService.class, ClusterViewServiceImpl.class})
+@Component(service = {ClusterViewService.class, ClusterViewServiceImpl.class})
 public class ClusterViewServiceImpl implements ClusterViewService {
 
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
diff --git a/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java b/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java
index 1899f75..ed7ca3f 100644
--- a/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java
+++ b/src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java
@@ -29,11 +29,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.SlingConstants;
 import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.ModifiableValueMap;
@@ -49,6 +44,10 @@ import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.event.Event;
 import org.osgi.service.event.EventConstants;
 import org.osgi.service.event.EventHandler;
@@ -59,8 +58,7 @@ import org.slf4j.LoggerFactory;
  * The osgi event handler responsible for following any votings and vote
  * accordingly
  */
-@Component(immediate = true)
-@Service(value = {VotingHandler.class})
+@Component(immediate = true, service = {VotingHandler.class})
 public class VotingHandler implements EventHandler {
 
     public static enum VotingDetail {
diff --git a/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java b/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java
index e7c8585..ab24844 100644
--- a/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java
+++ b/src/main/java/org/apache/sling/discovery/impl/common/heartbeat/HeartbeatHandler.java
@@ -27,11 +27,6 @@ import java.util.UUID;
 
 import javax.jcr.Session;
 
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.apache.felix.scr.annotations.ReferencePolicy;
-import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.ModifiableValueMap;
 import org.apache.sling.api.resource.PersistenceException;
@@ -54,6 +49,11 @@ import org.apache.sling.discovery.impl.common.View;
 import org.apache.sling.discovery.impl.common.ViewHelper;
 import org.apache.sling.settings.SlingSettingsService;
 import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
 import org.osgi.service.http.HttpService;
 
 /**
@@ -63,11 +63,17 @@ import org.osgi.service.http.HttpService;
  * Local heartbeats are stored in the repository. Remote heartbeats are POSTs to
  * remote TopologyConnectorServlets.
  */
-@Component
-@Service(value = HeartbeatHandler.class)
-@Reference(referenceInterface=HttpService.class,
-           cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE,
-           policy=ReferencePolicy.DYNAMIC)
+@Component(service = {HeartbeatHandler.class},
+        reference = {
+                @Reference(name = "HttpService",
+                        service = HttpService.class,
+                        cardinality = ReferenceCardinality.MULTIPLE,
+                        policy = ReferencePolicy.DYNAMIC,
+                        bind = "bindHttpService",
+                        unbind = "unbindHttpService"
+                )
+        }
+)
 public class HeartbeatHandler extends BaseViewChecker {
 
     private static final String PROPERTY_ID_LAST_HEARTBEAT = "lastHeartbeat";
@@ -187,6 +193,13 @@ public class HeartbeatHandler extends BaseViewChecker {
         logger.info("doActivate: activated with runtimeId: {}, slingId: {}", runtimeId, slingId);
     }
 
+    @Override
+    protected void unbindHttpService(ServiceReference reference) {
+        // override super.unbindHttpService, otherwise bnd plugin
+        // complains about missing unbind method
+        super.unbindHttpService(reference);
+    }
+
     @Override
     protected void deactivate() {
         super.deactivate();
diff --git a/src/test/java/org/apache/sling/discovery/impl/setup/VotingEventListener.java b/src/test/java/org/apache/sling/discovery/impl/setup/VotingEventListener.java
index d76b241..e194df7 100644
--- a/src/test/java/org/apache/sling/discovery/impl/setup/VotingEventListener.java
+++ b/src/test/java/org/apache/sling/discovery/impl/setup/VotingEventListener.java
@@ -18,7 +18,8 @@
  */
 package org.apache.sling.discovery.impl.setup;
 
-import java.util.Properties;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 import javax.jcr.RepositoryException;
@@ -87,7 +88,7 @@ class VotingEventListener implements EventListener {
         try {
             while (!stopped && events.hasNext()) {
                 Event event = events.nextEvent();
-                Properties properties = new Properties();
+                Map<String, String> properties = new HashMap<>();
                 String topic;
                 if (event.getType() == Event.NODE_ADDED) {
                     topic = SlingConstants.TOPIC_RESOURCE_ADDED;