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

Change-Id: I47e9db37eb5fc27ac19db2e4cb87774736b44685
diff --git a/drivers/bti/BUCK b/drivers/bti/BUCK
index 166fce9..791f198 100644
--- a/drivers/bti/BUCK
+++ b/drivers/bti/BUCK
@@ -6,6 +6,7 @@
 COMPILE_DEPS = [
     '//lib:CORE_DEPS',
     '//protocols/snmp/api:onos-snmp-api',
+    '//incubator/api:onos-incubator-api',
     '//lib:org.apache.servicemix.bundles.snmp4j',
     '//lib:snmp-core',
     '//lib:bti7000',
diff --git a/drivers/bti/src/main/java/org/onosproject/drivers/bti/Bti7000SnmpAlarmConsumer.java b/drivers/bti/src/main/java/org/onosproject/drivers/bti/Bti7000SnmpAlarmConsumer.java
new file mode 100644
index 0000000..2c30915
--- /dev/null
+++ b/drivers/bti/src/main/java/org/onosproject/drivers/bti/Bti7000SnmpAlarmConsumer.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2015-present Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.drivers.bti;
+
+import com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0.I_Device;
+import com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0._OidRegistry;
+import com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0.btisystems.btiproducts.bti7000.objects.conditions.ActAlarmTable;
+import com.btisystems.mibbler.mibs.bti7000.interfaces.btisystems.btiproducts.bti7000.objects.conditions.IActAlarmTable;
+import com.btisystems.pronx.ems.core.model.ClassRegistry;
+import com.btisystems.pronx.ems.core.model.IClassRegistry;
+import com.btisystems.pronx.ems.core.model.NetworkDevice;
+import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
+import com.google.common.collect.ImmutableList;
+import org.apache.commons.lang.StringUtils;
+import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmConsumer;
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEntityId;
+import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.snmp.SnmpController;
+import org.slf4j.Logger;
+import org.snmp4j.smi.OctetString;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.TimeZone;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * BTI 7000 specific implementation to provide a list of current alarms.
+ */
+public class Bti7000SnmpAlarmConsumer extends AbstractHandlerBehaviour implements AlarmConsumer {
+    private final Logger log = getLogger(getClass());
+    protected static final IClassRegistry CLASS_REGISTRY = new ClassRegistry(_OidRegistry.oidRegistry, I_Device.class);
+
+    static final int ALARM_SEVERITY_MINOR = 2;
+    static final int ALARM_SEVERITY_MAJOR = 3;
+    static final int ALARM_SEVERITY_CRITICAL = 4;
+
+
+    private Alarm.SeverityLevel mapAlarmSeverity(int intAlarmSeverity) {
+        Alarm.SeverityLevel mappedSeverity;
+        switch (intAlarmSeverity) {
+            case ALARM_SEVERITY_MINOR:
+                mappedSeverity = Alarm.SeverityLevel.MINOR;
+                break;
+            case ALARM_SEVERITY_MAJOR:
+                mappedSeverity = Alarm.SeverityLevel.MAJOR;
+                break;
+            case ALARM_SEVERITY_CRITICAL:
+                mappedSeverity = Alarm.SeverityLevel.CRITICAL;
+                break;
+            default:
+                mappedSeverity = Alarm.SeverityLevel.MINOR;
+                log.warn("Unexpected alarm severity: {}", intAlarmSeverity);
+        }
+        return mappedSeverity;
+    }
+
+    /**
+     * Converts an SNMP string representation into a {@link Date} object,
+     * and applies time zone conversion to provide the time on the local machine, ie PSM server.
+     *
+     * @param actAlarmDateAndTime MIB-II DateAndTime formatted. May optionally contain
+     *                            a timezone offset in 3 extra bytes
+     * @param sysInfoTimeZone     Must be supplied if actAlarmDateAndTime is just local time (with no timezone)
+     * @param swVersion           Must be supplied if actAlarmDateAndTime is just local time (with no timezone)
+     * @return adjusted {@link Date} or a simple conversion if other fields are null.
+     */
+    public static Date getLocalDateAndTime(String actAlarmDateAndTime, String sysInfoTimeZone,
+                                           String swVersion) {
+        if (StringUtils.isBlank(actAlarmDateAndTime)) {
+            return null;
+        }
+
+        GregorianCalendar decodedDateAndTimeCal = btiMakeCalendar(OctetString.fromHexString(actAlarmDateAndTime));
+        if ((sysInfoTimeZone == null) || (swVersion == null)) {
+            return decodedDateAndTimeCal.getTime();
+        }
+
+        TimeZone javaTimeZone = getTimeZone();
+        decodedDateAndTimeCal.setTimeZone(javaTimeZone);
+
+        GregorianCalendar localTime = new GregorianCalendar();
+        localTime.setTimeInMillis(decodedDateAndTimeCal.getTimeInMillis());
+
+        return localTime.getTime();
+    }
+
+    /**
+     * This method is similar to SNMP4J approach with some fixes for the 11-bytes version (ie the one with timezone
+     * offset).
+     * <p>
+     * For original makeCalendar refer @see http://www.snmp4j.org/agent/doc/org/snmp4j/agent/mo/snmp/DateAndTime.html
+     * <p>
+     * Creates a <code>GregorianCalendar</code> from a properly formatted SNMP4J DateAndTime <code>OctetString</code>.
+     *
+     * @param dateAndTimeValue an OctetString conforming to the DateAndTime TC.
+     * @return the corresponding <code>GregorianCalendar</code> instance.
+     */
+    public static GregorianCalendar btiMakeCalendar(OctetString dateAndTimeValue) {
+        int year = (dateAndTimeValue.get(0) & 0xFF) * 256
+                + (dateAndTimeValue.get(1) & 0xFF);
+        int month = (dateAndTimeValue.get(2) & 0xFF);
+        int date = (dateAndTimeValue.get(3) & 0xFF);
+        int hour = (dateAndTimeValue.get(4) & 0xFF);
+        int minute = (dateAndTimeValue.get(5) & 0xFF);
+        int second = (dateAndTimeValue.get(6) & 0xFF);
+        int deci = (dateAndTimeValue.get(7) & 0xFF);
+        GregorianCalendar gc =
+                new GregorianCalendar(year, month - 1, date, hour, minute, second);
+        gc.set(Calendar.MILLISECOND, deci * 100);
+
+        if (dateAndTimeValue.length() == 11) {
+            char directionOfOffset = (char) dateAndTimeValue.get(8);
+            int hoursOffset = directionOfOffset == '+'
+                    ? dateAndTimeValue.get(9) : -dateAndTimeValue.get(9);
+            org.joda.time.DateTimeZone offset =
+                    org.joda.time.DateTimeZone.forOffsetHoursMinutes(hoursOffset, dateAndTimeValue.get(10));
+            org.joda.time.DateTime dt =
+                    new org.joda.time.DateTime(year, month, date, hour, minute, second, offset);
+            return dt.toGregorianCalendar();
+        }
+        return gc;
+    }
+
+    private static TimeZone getTimeZone() {
+        return Calendar.getInstance().getTimeZone();
+    }
+
+    @Override
+    public List<Alarm> consumeAlarms() {
+        SnmpController controller = checkNotNull(handler().get(SnmpController.class));
+        ISnmpSession session;
+        List<Alarm> alarms = new ArrayList<>();
+        DeviceId deviceId = handler().data().deviceId();
+        try {
+            session = controller.getSession(deviceId);
+            log.debug("Getting alarms for BTI 7000 device at {}", deviceId);
+            NetworkDevice networkDevice = new NetworkDevice(CLASS_REGISTRY,
+                                                            session.getAddress().getHostAddress());
+            session.walkDevice(networkDevice, Collections.singletonList(
+                    CLASS_REGISTRY.getClassToOidMap().get(ActAlarmTable.class)));
+
+            IActAlarmTable deviceAlarms = (IActAlarmTable) networkDevice.getRootObject()
+                    .getEntity(CLASS_REGISTRY.getClassToOidMap().get(ActAlarmTable.class));
+            if ((deviceAlarms != null) && (deviceAlarms.getActAlarmEntry() != null)
+                    && (!deviceAlarms.getActAlarmEntry().isEmpty())) {
+
+                deviceAlarms.getActAlarmEntry().values().stream().forEach((alarm) -> {
+                    DefaultAlarm.Builder alarmBuilder = new DefaultAlarm.Builder(
+                            deviceId, alarm.getActAlarmDescription(),
+                            mapAlarmSeverity(alarm.getActAlarmSeverity()),
+                            getLocalDateAndTime(alarm.getActAlarmDateAndTime(), null, null).getTime())
+                            .forSource(AlarmEntityId.alarmEntityId("other:" + alarm.getActAlarmInstanceIdx()));
+                    alarms.add(alarmBuilder.build());
+                });
+
+            }
+            log.debug("Conditions retrieved: {}", deviceAlarms);
+
+        } catch (IOException ex) {
+            log.error("Error reading alarms for device {}.", deviceId, ex);
+            alarms.add(controller.buildWalkFailedAlarm(deviceId));
+
+        }
+
+        return ImmutableList.copyOf(alarms);
+    }
+}
diff --git a/drivers/bti/src/main/java/org/onosproject/drivers/bti/NetSnmpAlarmConsumer.java b/drivers/bti/src/main/java/org/onosproject/drivers/bti/NetSnmpAlarmConsumer.java
new file mode 100644
index 0000000..9a5c529
--- /dev/null
+++ b/drivers/bti/src/main/java/org/onosproject/drivers/bti/NetSnmpAlarmConsumer.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.drivers.bti;
+
+import com.btisystems.mibbler.mibs.netsnmp.netsnmp.I_Device;
+import com.btisystems.mibbler.mibs.netsnmp.netsnmp._OidRegistry;
+import com.btisystems.mibbler.mibs.netsnmp.netsnmp.mib_2.interfaces.IfTable;
+import com.btisystems.pronx.ems.core.model.ClassRegistry;
+import com.btisystems.pronx.ems.core.model.IClassRegistry;
+import com.btisystems.pronx.ems.core.model.NetworkDevice;
+import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
+import com.google.common.collect.ImmutableList;
+import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmConsumer;
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEntityId;
+import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.snmp.SnmpController;
+import org.slf4j.Logger;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Net SNMP specific implementation to provide a list of current alarms.
+ */
+public class NetSnmpAlarmConsumer extends AbstractHandlerBehaviour implements AlarmConsumer {
+    private final Logger log = getLogger(getClass());
+    protected static final IClassRegistry CLASS_REGISTRY =
+            new ClassRegistry(_OidRegistry.oidRegistry, I_Device.class);
+
+    @Override
+    public List<Alarm> consumeAlarms() {
+        SnmpController controller = checkNotNull(handler().get(SnmpController.class));
+        List<Alarm> alarms = new ArrayList<>();
+        ISnmpSession session;
+        DeviceId deviceId = handler().data().deviceId();
+        try {
+            session = controller.getSession(deviceId);
+
+            NetworkDevice networkDevice = new NetworkDevice(CLASS_REGISTRY,
+                                                            session.getAddress()
+                                                                    .getHostAddress());
+            session.walkDevice(networkDevice, Collections.singletonList(
+                    CLASS_REGISTRY.getClassToOidMap().get(IfTable.class)));
+
+            IfTable interfaceTable = (IfTable) networkDevice.getRootObject()
+                    .getEntity(CLASS_REGISTRY.getClassToOidMap().get(IfTable.class));
+            if (interfaceTable != null) {
+                interfaceTable.getEntries().values().stream().forEach((ifEntry) -> {
+                    if (ifEntry.getIfAdminStatus() == 1 && ifEntry.getIfOperStatus() == 2) {
+                        alarms.add(new DefaultAlarm.Builder(deviceId, "Link Down.",
+                                                            Alarm.SeverityLevel.CRITICAL,
+                                                            System.currentTimeMillis())
+                                           .forSource(AlarmEntityId
+                                                              .alarmEntityId("port:" + ifEntry.
+                                                                      getIfDescr())).build());
+                    }
+                    log.debug("Interface: " + ifEntry);
+                });
+            }
+        } catch (IOException ex) {
+            log.error("Error reading alarms for device {}.", deviceId, ex);
+            alarms.add(controller.buildWalkFailedAlarm(deviceId));
+        }
+        return ImmutableList.copyOf(alarms);
+    }
+}
diff --git a/drivers/bti/src/main/resources/bti-drivers.xml b/drivers/bti/src/main/resources/bti-drivers.xml
index e46ea58..33971c2 100644
--- a/drivers/bti/src/main/resources/bti-drivers.xml
+++ b/drivers/bti/src/main/resources/bti-drivers.xml
@@ -19,10 +19,14 @@
     <driver name="bti7000" manufacturer="bti" hwVersion="1.0.0" swVersion="1.0.0">
         <behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery"
                    impl="org.onosproject.drivers.bti.Bti7000DeviceDescriptor"/>
+        <behaviour api="org.onosproject.incubator.net.faultmanagement.alarm.AlarmConsumer"
+                   impl="org.onosproject.drivers.bti.Bti7000SnmpAlarmConsumer"/>
     </driver>
     <driver name="NetSnmp" manufacturer="bti" hwVersion="1.0.0" swVersion="1.0.0">
         <behaviour api="org.onosproject.net.device.DeviceDescriptionDiscovery"
                    impl="org.onosproject.drivers.bti.NetSnmpDeviceDescriptor"/>
+        <behaviour api="org.onosproject.incubator.net.faultmanagement.alarm.AlarmConsumer"
+                   impl="org.onosproject.drivers.bti.NetSnmpAlarmConsumer"/>
     </driver>
 </drivers>