import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Queue;
 import java.util.Random;
+import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.UUID;
 
         // create MD5 MessageDigest -- used to hash keywords
         try {
-            messageDigest = MessageDigest.getInstance("MD5");
+            // disabling sonar, as the digest is only used to hash keywords - it isn't
+            // used for security purposes
+            messageDigest = MessageDigest.getInstance("MD5");   // NOSONAR
         } catch (NoSuchAlgorithmException e) {
             throw new ExceptionInInitializerError(e);
         }
             logger.info("Bucket {} owner: {}->null",
                         index, bucket.getOwner());
             bucketChanges = true;
-            synchronized (bucket) {
-                bucket.setOwner(null);
-                bucket.setState(null);
-            }
+            bucket.nullifyOwner();
         }
         return bucketChanges;
     }
 
+    private synchronized void nullifyOwner() {
+        setOwner(null);
+        setState(null);
+    }
+
+    /**
+     * Gets the set of backups.
+     *
+     * @return the set of backups
+     */
+    public synchronized Set<Server> getBackups() {
+        /*
+         * For some reason, the junit tests break if Set.of() is used, so we'll stick with
+         * the long way for now.
+         */
+        Set<Server> backups = new HashSet<>();
+        backups.add(getPrimaryBackup());
+        backups.add(getSecondaryBackup());
+        return backups;
+    }
+
     private static boolean updatePrimaryBackup(DataInputStream dis, int index, Bucket bucket, boolean bucketChanges)
                     throws IOException {
         Server newPrimaryBackup =
      * is registered to listen for notifications of state transitions. Note
      * that all of these methods are running within the 'MainLoop' thread.
      */
-    private static class EventHandler implements Events {
+    private static class EventHandler extends Events {
         /**
          * {@inheritDoc}
          */
 
  * This interface is used to distribute notifications of various system
  * events, such as new 'Server' instances, or a server failing.
  */
-public interface Events {
+public class Events {
     // set of listeners receiving event notifications
-    static final Queue<Events> listeners =
+    private static final Queue<Events> listeners =
         new ConcurrentLinkedQueue<>();
 
     /**
      *
      * @param server this is the new server
      */
-    public default void newServer(Server server) {
+    public void newServer(Server server) {
+        // do nothing
     }
 
     /**
      *
      * @param server this is the server that failed
      */
-    public default void serverFailed(Server server) {
+    public void serverFailed(Server server) {
+        // do nothing
     }
 
     /**
      *
      * @param server this is the new lead server
      */
-    public default void newLeader(Server server) {
+    public void newLeader(Server server) {
+        // do nothing
     }
 
     /**
      *
      * @param server the lead server that failed
      */
-    public default void leaderFailed(Server server) {
+    public void leaderFailed(Server server) {
+        // do nothing
     }
 
     /**
      *
      * @param server the current leader, which has been confirmed
      */
-    public default void leaderConfirmed(Server server) {
+    public void leaderConfirmed(Server server) {
+        // do nothing
     }
 }
 
      * {@inheritDoc}
      */
     @Override
-    public boolean insertDrools(
-        final PolicySession session, final Object object) {
+    public boolean insertDrools(final PolicySession session, final Object object) { // NOSONAR
+        // sonar complained that the method always returns the same value. However,
+        // we prefer the code be structured this way, thus disabled sonar
 
         final String keyword = Keyword.lookupKeyword(object);
         if (keyword == null) {
 
      * is registered to listen for notifications of state transitions. Note
      * that all of these methods are running within the 'MainLoop' thread.
      */
-    private static class EventHandler implements Events {
+    private static class EventHandler extends Events {
         /**
          * {@inheritDoc}
          */
 
         Properties prop = new Properties();
 
         for (String arg : args) {
-            // arguments with an equals sign in them are a property definition;
+            // arguments with an equals sign in them are a property definition -
             // otherwise, they are a properties file name
 
             if (arg.contains("=")) {
 
 import org.onap.policy.common.utils.services.OrderedService;
 import org.onap.policy.common.utils.services.OrderedServiceImpl;
 
-public interface ServerPoolApi extends OrderedService {
+public abstract class ServerPoolApi implements OrderedService {
     /**
      * 'ServerPoolApi.impl.getList()' returns an ordered list of objects
      * implementing the 'ServerPoolApi' interface.
      */
-    public static OrderedServiceImpl<ServerPoolApi> impl =
+    public static final OrderedServiceImpl<ServerPoolApi> impl =
         new OrderedServiceImpl<>(ServerPoolApi.class);
 
     /**
      *
      * @return a Collection of classes implementing REST methods
      */
-    public default Collection<Class<?>> servletClasses() {
+    public Collection<Class<?>> servletClasses() {
         return Collections.emptyList();
     }
 
      *
      * @param bucket the bucket that needs restoring
      */
-    public default void restoreBucket(Bucket bucket) {
+    public void restoreBucket(Bucket bucket) {
+        // do nothing
     }
 
     /**
      * @param bucket the bucket containing the 'GlobalLocks' adjunct
      * @param globalLocks the 'GlobalLocks' adjunct
      */
-    public default void lockUpdate(Bucket bucket, TargetLock.GlobalLocks globalLocks) {
+    public void lockUpdate(Bucket bucket, TargetLock.GlobalLocks globalLocks) {
+        // do nothing
     }
 
     /**
      * @param isOwner 'true' if the current host owns the bucket
      * @param isBackup 'true' if the current host is a backup for the bucket
      */
-    public default void auditBucket(Bucket bucket, boolean isOwner, boolean isBackup) {
+    public void auditBucket(Bucket bucket, boolean isOwner, boolean isBackup) {
+        // do nothing
     }
 }
 
      * There is a single instance of class 'TargetLock.EventHandler', which is
      * registered to listen for notifications of state transitions.
      */
-    private static class EventHandler implements Events {
+    private static class EventHandler extends Events {
         /**
          * {@inheritDoc}
          */
 
  * backing up the data of selected Drools sessions and server-side 'TargetLock'
  * data on separate hosts.
  */
-public class Persistence implements PolicySessionFeatureApi, ServerPoolApi {
+public class Persistence extends ServerPoolApi implements PolicySessionFeatureApi {
     private static Logger logger = LoggerFactory.getLogger(Persistence.class);
 
     // HTTP query parameters
                           MediaType.APPLICATION_OCTET_STREAM_TYPE);
         final int count = lockCount;
 
-        // build list of backup servers
-        Set<Server> servers = new HashSet<>();
-        synchronized (bucket) {
-            servers.add(bucket.getPrimaryBackup());
-            servers.add(bucket.getSecondaryBackup());
-        }
-        sendLocksToBackupServers(bucketNumber, entity, count, servers);
+        sendLocksToBackupServers(bucketNumber, entity, count, bucket.getBackups());
     }
 
     private static void sendLocksToBackupServers(final int bucketNumber, final Entity<String> entity, final int count,