[ONOS-4260]Alarm and fault managment application refactoring according to ONOS architecture

Change-Id: I47e9db37eb5fc27ac19db2e4cb87774736b44685
diff --git a/apps/faultmanagement/fmcli/src/main/java/org/onosproject/faultmanagement/alarms/cli/GetAllAlarmsCounts.java b/apps/faultmanagement/fmcli/src/main/java/org/onosproject/faultmanagement/alarms/cli/GetAllAlarmsCounts.java
index 9f8973a..578cee9 100644
--- a/apps/faultmanagement/fmcli/src/main/java/org/onosproject/faultmanagement/alarms/cli/GetAllAlarmsCounts.java
+++ b/apps/faultmanagement/fmcli/src/main/java/org/onosproject/faultmanagement/alarms/cli/GetAllAlarmsCounts.java
@@ -35,9 +35,9 @@
         printCounts(alarmCounts);
     }
 
-    static void printCounts(Map<Alarm.SeverityLevel, Long> alarmCounts) {
+    void printCounts(Map<Alarm.SeverityLevel, Long> alarmCounts) {
         alarmCounts.entrySet().stream().forEach((countEntry) -> {
-            System.out.println(String.format("%s, %d",
+            print(String.format("%s, %d",
                     countEntry.getKey(), countEntry.getValue()));
 
         });
diff --git a/apps/faultmanagement/fmcli/src/main/java/org/onosproject/faultmanagement/alarms/cli/GetDeviceAlarmsCounts.java b/apps/faultmanagement/fmcli/src/main/java/org/onosproject/faultmanagement/alarms/cli/GetDeviceAlarmsCounts.java
index bf0ae56..0d62c39 100644
--- a/apps/faultmanagement/fmcli/src/main/java/org/onosproject/faultmanagement/alarms/cli/GetDeviceAlarmsCounts.java
+++ b/apps/faultmanagement/fmcli/src/main/java/org/onosproject/faultmanagement/alarms/cli/GetDeviceAlarmsCounts.java
@@ -38,7 +38,14 @@
         Map<Alarm.SeverityLevel, Long> alarmCounts = AbstractShellCommand.get(AlarmService.class).
                 getAlarmCounts(DeviceId.deviceId(deviceId));
         // Deliberately using same formatting for both ...
-        GetAllAlarmsCounts.printCounts(alarmCounts);
+        printCounts(alarmCounts);
     }
 
+    void printCounts(Map<Alarm.SeverityLevel, Long> alarmCounts) {
+        alarmCounts.entrySet().stream().forEach((countEntry) -> {
+            print(String.format("%s, %d",
+                                countEntry.getKey(), countEntry.getValue()));
+
+        });
+    }
 }
diff --git a/apps/faultmanagement/fmgui/src/main/java/org/onosproject/faultmanagement/alarms/gui/AlarmTopovMessageHandler.java b/apps/faultmanagement/fmgui/src/main/java/org/onosproject/faultmanagement/alarms/gui/AlarmTopovMessageHandler.java
index 162cf7d..3268343 100644
--- a/apps/faultmanagement/fmgui/src/main/java/org/onosproject/faultmanagement/alarms/gui/AlarmTopovMessageHandler.java
+++ b/apps/faultmanagement/fmgui/src/main/java/org/onosproject/faultmanagement/alarms/gui/AlarmTopovMessageHandler.java
@@ -42,7 +42,7 @@
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmService;
 
 /**
- * Skeletal ONOS UI Topology-Overlay message handler.
+ * FaultManagement UI Topology-Overlay message handler.
  */
 public class AlarmTopovMessageHandler extends UiMessageHandler {
 
diff --git a/apps/faultmanagement/fmmgr/pom.xml b/apps/faultmanagement/fmmgr/pom.xml
index 07a2910..3e1f3bd 100644
--- a/apps/faultmanagement/fmmgr/pom.xml
+++ b/apps/faultmanagement/fmmgr/pom.xml
@@ -45,11 +45,6 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onos-snmp-provider-alarm</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.compendium</artifactId>
             <version>5.0.0</version>
diff --git a/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/AlarmsManager.java b/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/AlarmsManager.java
index 90ccaff..c7f724e 100644
--- a/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/AlarmsManager.java
+++ b/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/AlarmsManager.java
@@ -15,95 +15,79 @@
  */
 package org.onosproject.faultmanagement.impl;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import java.util.Dictionary;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.stream.Collectors;
+import com.google.common.collect.ImmutableSet;
 import org.apache.commons.collections.CollectionUtils;
 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.Modified;
-import org.apache.felix.scr.annotations.Property;
-import static org.onlab.util.Tools.nullIsNotFound;
-
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.util.ItemNotFoundException;
 import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEntityId;
-import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEvent;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmId;
-import org.onosproject.incubator.net.faultmanagement.alarm.AlarmListener;
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProvider;
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProviderRegistry;
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProviderService;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmService;
+import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
-import org.slf4j.Logger;
-import static org.slf4j.LoggerFactory.getLogger;
-import org.apache.felix.scr.annotations.Service;
-import static org.onlab.util.Tools.get;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.IdGenerator;
-import org.onosproject.core.CoreService;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.onlab.util.ItemNotFoundException;
-import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProvider;
-import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
-import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.provider.AbstractProviderRegistry;
+import org.onosproject.net.provider.AbstractProviderService;
 import org.osgi.service.component.ComponentContext;
-import static java.util.concurrent.TimeUnit.SECONDS;
+import org.slf4j.Logger;
 
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicLong;
-import static org.onlab.util.Tools.groupedThreads;
-import org.onosproject.net.Device;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsNotFound;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * Implementation of the Alarm service.
  */
 @Component(immediate = true)
 @Service
-public class AlarmsManager implements AlarmService {
-
-    // For subscribing to device-related events
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected CoreService coreService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected DeviceService deviceService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected AlarmProvider alarmProvider;
+public class AlarmsManager
+        extends AbstractProviderRegistry<AlarmProvider, AlarmProviderService>
+        implements AlarmService, AlarmProviderRegistry {
 
     private final Logger log = getLogger(getClass());
-    private ApplicationId appId;
-    private IdGenerator idGenerator;
 
-    private ScheduledExecutorService alarmPollExecutor;
-
-    // dummy data
     private final AtomicLong alarmIdGenerator = new AtomicLong(0);
 
+    // TODO Later should must be persisted to disk or database
+    protected final Map<AlarmId, Alarm> alarms = new ConcurrentHashMap<>();
+
+    private static final String NOT_SUPPORTED_YET = "Not supported yet.";
+
+    @Activate
+    public void activate(ComponentContext context) {
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate(ComponentContext context) {
+        alarms.clear();
+        log.info("Stopped");
+    }
+
+    @Modified
+    public boolean modified(ComponentContext context) {
+        log.info("Modified");
+        return true;
+    }
+
     private AlarmId generateAlarmId() {
         return AlarmId.alarmId(alarmIdGenerator.incrementAndGet());
     }
 
-    private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 120;
-    @Property(name = "alarmPollFrequencySeconds", intValue = DEFAULT_POLL_FREQUENCY_SECONDS,
-            label = "Frequency (in seconds) for polling alarm from devices")
-    private int alarmPollFrequencySeconds = DEFAULT_POLL_FREQUENCY_SECONDS;
-
-    // TODO implement purging of old alarms.
-    private static final int DEFAULT_CLEAR_FREQUENCY_SECONDS = 500;
-    @Property(name = "clearedAlarmPurgeSeconds", intValue = DEFAULT_CLEAR_FREQUENCY_SECONDS,
-            label = "Frequency (in seconds) for deleting cleared alarms")
-    private int clearedAlarmPurgeFrequencySeconds = DEFAULT_CLEAR_FREQUENCY_SECONDS;
-
-    // TODO Later should must be persisted to disk or database
-    private final Map<AlarmId, Alarm> alarms = new ConcurrentHashMap<>();
-
     @Override
     public Alarm updateBookkeepingFields(AlarmId id, boolean isAcknowledged, String assignedUser) {
 
@@ -120,7 +104,6 @@
     }
 
     public Alarm clear(AlarmId id) {
-
         Alarm found = alarms.get(id);
         if (found == null) {
             log.warn("id {} cant be cleared as it is already gone.", id);
@@ -133,33 +116,25 @@
 
     @Override
     public Map<Alarm.SeverityLevel, Long> getAlarmCounts(DeviceId deviceId) {
-
         return getAlarms(deviceId).stream().collect(
                 Collectors.groupingBy(Alarm::severity, Collectors.counting()));
-
     }
 
     @Override
     public Map<Alarm.SeverityLevel, Long> getAlarmCounts() {
-
         return getAlarms().stream().collect(
                 Collectors.groupingBy(Alarm::severity, Collectors.counting()));
     }
 
-
-    private static final String NOT_SUPPORTED_YET = "Not supported yet.";
-
     @Override
     public Alarm getAlarm(AlarmId alarmId) {
-        return nullIsNotFound(
-                alarms.get(
-                        checkNotNull(alarmId, "Alarm Id cannot be null")),
-                "Alarm is not found");
+        return nullIsNotFound(alarms.get(checkNotNull(alarmId, "Alarm Id cannot be null")),
+                              "Alarm is not found");
     }
 
     @Override
     public Set<Alarm> getAlarms() {
-        return new HashSet<>(alarms.values());
+        return ImmutableSet.copyOf(alarms.values());
     }
 
     @Override
@@ -198,122 +173,21 @@
 
     @Override
     public Set<Alarm> getAlarmsForLink(ConnectPoint src, ConnectPoint dst) {
-        //TODO
         throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
     }
 
     @Override
     public Set<Alarm> getAlarmsForFlow(DeviceId deviceId, long flowId) {
-        //TODO
         throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
     }
 
-    private final AlarmListener alarmListener = new InternalAlarmListener();
-
-    private class InternalAlarmListener implements AlarmListener {
-
-        @Override
-        public void event(AlarmEvent event) {
-            log.debug("AlarmsManager. InternalAlarmListener received {}", event);
-            try {
-
-                switch (event.type()) {
-                    case DEVICE_DISCOVERY:
-                        DeviceId deviceId = checkNotNull(event.getDeviceRefreshed(), "Listener cannot be null");
-                        log.info("New alarm set for {} received!", deviceId);
-                        updateAlarms(event.subject(), deviceId);
-                        break;
-
-                    case NOTIFICATION:
-                        throw new IllegalArgumentException(
-                                "Alarm Notifications (Traps) not expected or implemented yet. Received =" + event);
-                    default:
-                        break;
-                }
-            } catch (Exception e) {
-                log.warn("Failed to process {}", event, e);
-            }
-        }
-    }
-
-    @Activate
-    public void activate(ComponentContext context) {
-        appId = coreService.registerApplication("org.onosproject.faultmanagement.alarms");
-        idGenerator = coreService.getIdGenerator("alarm-ids");
-        log.info("Started with appId={}", appId);
-
-        alarmProvider.addAlarmListener(alarmListener);
-
-        probeActiveDevices();
-
-        boolean result = modified(context);
-        log.info("modified result = {}", result);
-
-        alarmPollExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/fm", "alarms-poll-%d"));
-        alarmPollExecutor.scheduleAtFixedRate(new PollAlarmsTask(),
-                alarmPollFrequencySeconds, alarmPollFrequencySeconds, SECONDS);
-
-    }
-
-    /**
-     * Auxiliary task to keep alarms up to date. IN future release alarm-notifications will be used as an optimization
-     * so we dont have to wait until polling to detect changes. Furthermore with simple polling flapping alarms may be
-     * missed.
-     */
-    private final class PollAlarmsTask implements Runnable {
-
-        @Override
-        public void run() {
-            if (Thread.currentThread().isInterrupted()) {
-                log.info("Interrupted, quitting");
-                return;
-            }
-            try {
-                probeActiveDevices();
-            } catch (RuntimeException e) {
-                log.error("Exception thrown during alarm synchronization process", e);
-            }
-        }
-    }
-
-    private void probeActiveDevices() {
-        Iterable<Device> devices = deviceService.getAvailableDevices();
-        log.info("Refresh alarms for all available devices={} ...", devices);
-        for (Device d : devices) {
-            log.info("Lets tell alarm provider to refresh alarms for {} ...", d.id());
-            alarmProvider.triggerProbe(d.id());
-        }
-    }
-
-    @Deactivate
-    public void deactivate(ComponentContext context) {
-        log.info("Deactivate ...");
-        alarmProvider.removeAlarmListener(alarmListener);
-
-        if (alarmPollExecutor != null) {
-            alarmPollExecutor.shutdownNow();
-        }
-        alarms.clear();
-        log.info("Stopped");
-    }
-
-    @Modified
-    public boolean modified(ComponentContext context) {
-        log.info("context={}", context);
-        if (context == null) {
-            log.info("No configuration file");
-            return false;
-        }
-        Dictionary<?, ?> properties = context.getProperties();
-        String clearedAlarmPurgeSeconds = get(properties, "clearedAlarmPurgeSeconds");
-
-        log.info("Settings: clearedAlarmPurgeSeconds={}", clearedAlarmPurgeSeconds);
-
-        return true;
+    @Override
+    protected AlarmProviderService createProviderService(AlarmProvider provider) {
+        return new InternalAlarmProviderService(provider);
     }
 
     // Synchronised to prevent duplicate NE alarms being raised
-    synchronized void updateAlarms(Set<Alarm> discoveredSet, DeviceId deviceId) {
+    protected synchronized void updateAlarms(DeviceId deviceId, Set<Alarm> discoveredSet) {
         Set<Alarm> storedSet = getActiveAlarms(deviceId);
         log.trace("currentNeAlarms={}. discoveredAlarms={}", storedSet, discoveredSet);
 
@@ -324,16 +198,31 @@
 
         storedSet.stream().filter(
                 (stored) -> (!discoveredSet.contains(stored))).forEach((stored) -> {
-                    log.info("Alarm will be cleared as it is not on the element. Cleared alarm: {}.", stored);
-                    clear(stored.id());
-                });
+            log.debug("Alarm will be cleared as it is not on the element. Cleared alarm: {}.", stored);
+            clear(stored.id());
+        });
 
         discoveredSet.stream().filter(
                 (discovered) -> (!storedSet.contains(discovered))).forEach((discovered) -> {
-            log.info("Alarm will be raised as it is missing. New alarm: {}.", discovered);
+            log.info("New alarm raised as it is missing. New alarm: {}.", discovered);
             AlarmId id = generateAlarmId();
             alarms.put(id, new DefaultAlarm.Builder(discovered).withId(id).build());
         });
     }
 
+    private class InternalAlarmProviderService
+            extends AbstractProviderService<AlarmProvider>
+            implements AlarmProviderService {
+
+        InternalAlarmProviderService(AlarmProvider provider) {
+            super(provider);
+
+
+        }
+
+        @Override
+        public void updateAlarmList(DeviceId deviceId, Collection<Alarm> alarms) {
+            updateAlarms(deviceId, ImmutableSet.copyOf(alarms));
+        }
+    }
 }
diff --git a/apps/faultmanagement/fmmgr/src/test/java/org/onosproject/faultmanagement/impl/AlarmsManagerTest.java b/apps/faultmanagement/fmmgr/src/test/java/org/onosproject/faultmanagement/impl/AlarmsManagerTest.java
index e943c56..7bc1b77 100644
--- a/apps/faultmanagement/fmmgr/src/test/java/org/onosproject/faultmanagement/impl/AlarmsManagerTest.java
+++ b/apps/faultmanagement/fmmgr/src/test/java/org/onosproject/faultmanagement/impl/AlarmsManagerTest.java
@@ -15,100 +15,32 @@
  */
 package org.onosproject.faultmanagement.impl;
 
-import com.google.common.collect.Sets;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
+import com.google.common.collect.ImmutableSet;
+import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
-import static org.junit.Assert.*;
+import org.junit.rules.ExpectedException;
 import org.onlab.util.ItemNotFoundException;
-import org.onosproject.net.DeviceId;
-import static org.hamcrest.Matchers.containsString;
 import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
-import static org.onosproject.incubator.net.faultmanagement.alarm.Alarm.SeverityLevel.*;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEntityId;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmId;
 import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
+import org.onosproject.net.DeviceId;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.incubator.net.faultmanagement.alarm.Alarm.SeverityLevel.CLEARED;
+import static org.onosproject.incubator.net.faultmanagement.alarm.Alarm.SeverityLevel.CRITICAL;
+
+/**
+ * Alarm manager test suite.
+ */
 public class AlarmsManagerTest {
 
-    @Test
-    public void testGettersWhenNoAlarms() {
-        AlarmsManager am = new AlarmsManager();
-        assertTrue("No alarms", am.getAlarms().isEmpty());
-        assertTrue("No active alarms", am.getActiveAlarms().isEmpty());
-        assertTrue("No alarms gives empty map per unknown device", am.getAlarmCounts(DeviceId.NONE).keySet().isEmpty());
-        assertTrue("No alarms gives empty map", am.getAlarmCounts().keySet().isEmpty());
-
-        assertEquals("Zero alarms for that device", 0, am.getAlarms(DeviceId.NONE).size());
-        assertEquals("Zero major alarms", 0, am.getAlarms(Alarm.SeverityLevel.MAJOR).size());
-
-        try {
-            assertEquals("no alarms", 0, am.getAlarm(null));
-        } catch (NullPointerException ex) {
-            assertThat(ex.getMessage(),
-                    containsString("cannot be null"));
-        }
-
-        try {
-            assertEquals("no alarms", 0, am.getAlarm(AlarmId.alarmId(1)));
-        } catch (ItemNotFoundException ex) {
-            assertThat(ex.getMessage(),
-                    containsString("not found"));
-        }
-    }
-
-    @Test
-    public void testAlarmUpdates() {
-        AlarmsManager am = new AlarmsManager();
-        assertTrue("no alarms", am.getAlarms().isEmpty());
-
-        am.updateAlarms(new HashSet<>(), DEVICE_ID);
-        assertTrue("still no alarms", am.getAlarms().isEmpty());
-        Map<Alarm.SeverityLevel, Long> zeroAlarms = new CountsMapBuilder().create();
-        assertEquals(zeroAlarms, am.getAlarmCounts());
-        assertEquals(zeroAlarms, am.getAlarmCounts(DEVICE_ID));
-
-        am.updateAlarms(Sets.newHashSet(ALARM_B, ALARM_A), DEVICE_ID);
-        verifyGettingSetsOfAlarms(am, 2, 2);
-        Map<Alarm.SeverityLevel, Long> critical2 = new CountsMapBuilder().with(CRITICAL, 2L).create();
-        assertEquals(critical2, am.getAlarmCounts());
-        assertEquals(critical2, am.getAlarmCounts(DEVICE_ID));
-
-        am.updateAlarms(Sets.newHashSet(ALARM_A), DEVICE_ID);
-        verifyGettingSetsOfAlarms(am, 2, 1);
-        Map<Alarm.SeverityLevel, Long> critical1cleared1 =
-                new CountsMapBuilder().with(CRITICAL, 1L).with(CLEARED, 1L).create();
-        assertEquals(critical1cleared1, am.getAlarmCounts());
-        assertEquals(critical1cleared1, am.getAlarmCounts(DEVICE_ID));
-
-        // No change map when same alarms sent
-        am.updateAlarms(Sets.newHashSet(ALARM_A), DEVICE_ID);
-        verifyGettingSetsOfAlarms(am, 2, 1);
-        assertEquals(critical1cleared1, am.getAlarmCounts());
-        assertEquals(critical1cleared1, am.getAlarmCounts(DEVICE_ID));
-
-        am.updateAlarms(Sets.newHashSet(ALARM_A, ALARM_A_WITHSRC), DEVICE_ID);
-        verifyGettingSetsOfAlarms(am, 3, 2);
-        Map<Alarm.SeverityLevel, Long> critical2cleared1 =
-                new CountsMapBuilder().with(CRITICAL, 2L).with(CLEARED, 1L).create();
-        assertEquals(critical2cleared1, am.getAlarmCounts());
-        assertEquals(critical2cleared1, am.getAlarmCounts(DEVICE_ID));
-
-        am.updateAlarms(Sets.newHashSet(), DEVICE_ID);
-        verifyGettingSetsOfAlarms(am, 3, 0);
-        assertEquals(new CountsMapBuilder().with(CLEARED, 3L).create(), am.getAlarmCounts(DEVICE_ID));
-
-        assertEquals("No alarms for unknown devices", zeroAlarms, am.getAlarmCounts(DeviceId.NONE));
-        assertEquals("No alarms for unknown devices", zeroAlarms, am.getAlarmCounts(DeviceId.deviceId("junk:junk")));
-
-    }
-
-    private void verifyGettingSetsOfAlarms(AlarmsManager am, int expectedTotal, int expectedActive) {
-        assertEquals("Wrong total", expectedTotal, am.getAlarms().size());
-        assertEquals("Wrong active count", expectedActive, am.getActiveAlarms().size());
-    }
     private static final DeviceId DEVICE_ID = DeviceId.deviceId("foo:bar");
     private static final DefaultAlarm ALARM_A = new DefaultAlarm.Builder(
             DEVICE_ID, "aaa", Alarm.SeverityLevel.CRITICAL, 0).build();
@@ -119,6 +51,101 @@
     private static final DefaultAlarm ALARM_B = new DefaultAlarm.Builder(
             DEVICE_ID, "bbb", Alarm.SeverityLevel.CRITICAL, 0).build();
 
+    private AlarmsManager am;
+
+    @Rule
+    public final ExpectedException exception = ExpectedException.none();
+
+    @Before
+    public void setUp() throws Exception {
+        am = new AlarmsManager();
+    }
+
+    @Test
+    public void deactivate() throws Exception {
+        am.updateAlarms(DEVICE_ID, ImmutableSet.of(ALARM_B, ALARM_A));
+        verifyGettingSetsOfAlarms(am, 2, 2);
+        am.deactivate(null);
+        assertEquals("Alarms should be purged", 0, am.alarms.size());
+    }
+
+    @Test
+    public void testGettersWhenNoAlarms() {
+
+        assertTrue("No alarms should be present", am.getAlarms().isEmpty());
+        assertTrue("No active alarms should be present", am.getActiveAlarms().isEmpty());
+        assertTrue("The map should be empty per unknown device",
+                   am.getAlarmCounts(DeviceId.NONE).keySet().isEmpty());
+        assertTrue("The counts should be empty", am.getAlarmCounts().keySet().isEmpty());
+
+        assertEquals("Incorrect number of alarms for unknown device",
+                     0, am.getAlarms(DeviceId.NONE).size());
+        assertEquals("Incorrect number of major alarms for unknown device",
+                     0, am.getAlarms(Alarm.SeverityLevel.MAJOR).size());
+
+        exception.expect(NullPointerException.class);
+        am.getAlarm(null);
+
+        exception.expect(ItemNotFoundException.class);
+        am.getAlarm(AlarmId.alarmId(1));
+    }
+
+    @Test
+    public void testAlarmUpdates() {
+
+        assertTrue("No alarms should be present", am.getAlarms().isEmpty());
+        am.updateAlarms(DEVICE_ID, ImmutableSet.of());
+        assertTrue("No alarms should be present", am.getAlarms().isEmpty());
+        Map<Alarm.SeverityLevel, Long> zeroAlarms = new CountsMapBuilder().create();
+        assertEquals("No alarms count should be present", zeroAlarms, am.getAlarmCounts());
+        assertEquals("No alarms count should be present", zeroAlarms, am.getAlarmCounts(DEVICE_ID));
+
+        am.updateAlarms(DEVICE_ID, ImmutableSet.of(ALARM_B, ALARM_A));
+        verifyGettingSetsOfAlarms(am, 2, 2);
+        Map<Alarm.SeverityLevel, Long> critical2 = new CountsMapBuilder().with(CRITICAL, 2L).create();
+        assertEquals("A critical should be present", critical2, am.getAlarmCounts());
+        assertEquals("A critical should be present", critical2, am.getAlarmCounts(DEVICE_ID));
+
+        am.updateAlarms(DEVICE_ID, ImmutableSet.of(ALARM_A));
+        verifyGettingSetsOfAlarms(am, 2, 1);
+        Map<Alarm.SeverityLevel, Long> critical1cleared1 =
+                new CountsMapBuilder().with(CRITICAL, 1L).with(CLEARED, 1L).create();
+        assertEquals("A critical should be present and cleared", critical1cleared1,
+                     am.getAlarmCounts());
+        assertEquals("A critical should be present and cleared", critical1cleared1,
+                     am.getAlarmCounts(DEVICE_ID));
+
+        // No change map when same alarms sent
+        am.updateAlarms(DEVICE_ID, ImmutableSet.of(ALARM_A));
+        verifyGettingSetsOfAlarms(am, 2, 1);
+        assertEquals("Map should not be changed for same alarm", critical1cleared1,
+                     am.getAlarmCounts());
+        assertEquals("Map should not be changed for same alarm", critical1cleared1,
+                     am.getAlarmCounts(DEVICE_ID));
+
+        am.updateAlarms(DEVICE_ID, ImmutableSet.of(ALARM_A, ALARM_A_WITHSRC));
+        verifyGettingSetsOfAlarms(am, 3, 2);
+        Map<Alarm.SeverityLevel, Long> critical2cleared1 =
+                new CountsMapBuilder().with(CRITICAL, 2L).with(CLEARED, 1L).create();
+        assertEquals("A critical should be present", critical2cleared1, am.getAlarmCounts());
+        assertEquals("A critical should be present", critical2cleared1, am.getAlarmCounts(DEVICE_ID));
+
+        am.updateAlarms(DEVICE_ID, ImmutableSet.of());
+        verifyGettingSetsOfAlarms(am, 3, 0);
+        assertEquals(new CountsMapBuilder().with(CLEARED, 3L).create(), am.getAlarmCounts(DEVICE_ID));
+
+        assertEquals("The counts should be empty for unknown devices", zeroAlarms,
+                     am.getAlarmCounts(DeviceId.NONE));
+        assertEquals("The counts should be empty for unknown devices", zeroAlarms,
+                     am.getAlarmCounts(DeviceId.deviceId("junk:junk")));
+
+    }
+
+    private void verifyGettingSetsOfAlarms(AlarmsManager am, int expectedTotal, int expectedActive) {
+        assertEquals("Incorrect total alarms", expectedTotal, am.getAlarms().size());
+        assertEquals("Incorrect active alarms count", expectedActive, am.getActiveAlarms().size());
+    }
+
     private static class CountsMapBuilder {
 
         private final Map<Alarm.SeverityLevel, Long> map = new HashMap<>();
diff --git a/apps/faultmanagement/fmweb/src/main/java/org/onosproject/faultmanagement/web/AlarmsWebResource.java b/apps/faultmanagement/fmweb/src/main/java/org/onosproject/faultmanagement/web/AlarmsWebResource.java
index 8c3268c..ef875cd 100644
--- a/apps/faultmanagement/fmweb/src/main/java/org/onosproject/faultmanagement/web/AlarmsWebResource.java
+++ b/apps/faultmanagement/fmweb/src/main/java/org/onosproject/faultmanagement/web/AlarmsWebResource.java
@@ -46,7 +46,7 @@
 @Path("alarms")
 public class AlarmsWebResource extends AbstractWebResource {
 
-    public static final String ALARM_NOT_FOUND = "Alarm is not found";
+    private static final String ALARM_NOT_FOUND = "Alarm is not found";
 
     private final Logger log = getLogger(getClass());
 
@@ -63,7 +63,7 @@
             @DefaultValue("") @QueryParam("devId") String devId
     ) {
 
-        log.info("Requesting all alarms, includeCleared={}", includeCleared);
+        log.debug("Requesting all alarms, includeCleared={}", includeCleared);
         AlarmService service = get(AlarmService.class);
 
         Iterable<Alarm> alarms;
@@ -90,7 +90,7 @@
     @Path("{id}")
     @Produces(MediaType.APPLICATION_JSON)
     public Response getAlarm(@PathParam("id") String id) {
-        log.info("HTTP GET alarm for id={}", id);
+        log.debug("HTTP GET alarm for id={}", id);
 
         AlarmId alarmId = toAlarmId(id);
         Alarm alarm = get(AlarmService.class).getAlarm(alarmId);
@@ -113,11 +113,11 @@
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
     public Response update(@PathParam("alarm_id") String alarmIdPath, InputStream stream) {
-        log.info("PUT NEW ALARM at /{}", alarmIdPath);
+        log.debug("PUT NEW ALARM at /{}", alarmIdPath);
 
         try {
             ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
-            log.info("jsonTree={}", jsonTree);
+            log.debug("jsonTree={}", jsonTree);
 
             Alarm alarm = new AlarmCodec().decode(jsonTree, this);
 
@@ -139,7 +139,7 @@
         }
     }
 
-    private static AlarmId toAlarmId(String id) {
+    private AlarmId toAlarmId(String id) {
         try {
             return AlarmId.alarmId(Long.parseLong(id));
         } catch (NumberFormatException ex) {