change roadm app to support EDFA/ROADM/OPS devices, add OPS PowerConfig/LambdaQuery behaviour

Change-Id: Ieb6de727e766fdeb63740c0704f83fd11e44b935
diff --git a/apps/roadm/src/main/java/org/onosproject/roadm/RoadmPortViewMessageHandler.java b/apps/roadm/src/main/java/org/onosproject/roadm/RoadmPortViewMessageHandler.java
index 81fb581..2aa80f7 100644
--- a/apps/roadm/src/main/java/org/onosproject/roadm/RoadmPortViewMessageHandler.java
+++ b/apps/roadm/src/main/java/org/onosproject/roadm/RoadmPortViewMessageHandler.java
@@ -19,12 +19,13 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Range;
 import org.onlab.osgi.ServiceDirectory;
+import org.onlab.util.Frequency;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.DeviceId;
-import org.onosproject.net.optical.OpticalAnnotations;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.OchSignal;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceService;
 import org.onosproject.ui.RequestHandler;
 import org.onosproject.ui.UiConnection;
 import org.onosproject.ui.UiMessageHandler;
@@ -34,7 +35,12 @@
 import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
+import java.util.Set;
+
+import static org.onosproject.net.Device.Type;
 
 /**
  * Table-View message handler for ROADM port view.
@@ -44,17 +50,16 @@
     private static final String ROADM_PORT_DATA_REQ = "roadmPortDataRequest";
     private static final String ROADM_PORT_DATA_RESP = "roadmPortDataResponse";
     private static final String ROADM_PORTS = "roadmPorts";
-
     private static final String ROADM_SET_TARGET_POWER_REQ = "roadmSetTargetPowerRequest";
     private static final String ROADM_SET_TARGET_POWER_RESP = "roadmSetTargetPowerResponse";
-
-    private static final String NO_ROWS_MESSAGE = "No items found";
-
-    private static final String DEV_ID = "devId";
+    private static final String ROADM_SHOW_ITEMS_REQ = "roadmShowPortItemsRequest";
+    private static final String ROADM_SHOW_ITEMS_RESP = "roadmShowPortItemsResponse";
+    private static final String ROADM_SET_OPS_MODE_REQ = "roadmSetOpsModeRequest";
+    private static final String ROADM_SET_OPS_MODE_RESP = "roadmSetOpsModeResponse";
 
     private static final String ID = "id";
-    private static final String TYPE = "type";
     private static final String NAME = "name";
+    private static final String TYPE = "type";
     private static final String ENABLED = "enabled";
     private static final String MIN_FREQ = "minFreq";
     private static final String MAX_FREQ = "maxFreq";
@@ -63,53 +68,32 @@
     private static final String CURRENT_POWER = "currentPower";
     private static final String TARGET_POWER = "targetPower";
     private static final String HAS_TARGET_POWER = "hasTargetPower";
+    private static final String SERVICE_STATE = "serviceState";
 
     private static final String[] COLUMN_IDS = {
             ID, TYPE, NAME, ENABLED, MIN_FREQ, MAX_FREQ, GRID, INPUT_POWER_RANGE,
-            CURRENT_POWER, TARGET_POWER, HAS_TARGET_POWER,
+            CURRENT_POWER, SERVICE_STATE, TARGET_POWER, HAS_TARGET_POWER
     };
 
-    private static final String NA = "N/A";
-    private static final String UNKNOWN = "Unknown";
-
-    private static final long GHZ = 1_000_000_000L;
-    private static final long THZ = 1_000_000_000_000L;
-
-    private DeviceService deviceService;
     private RoadmService roadmService;
+    private DeviceService deviceService;
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
     @Override
     public void init(UiConnection connection, ServiceDirectory directory) {
         super.init(connection, directory);
-        deviceService = get(DeviceService.class);
         roadmService = get(RoadmService.class);
+        deviceService = get(DeviceService.class);
     }
 
     @Override
     protected Collection<RequestHandler> createRequestHandlers() {
-        return ImmutableSet.of(
-                new PortTableDataRequestHandler(),
-                new SetTargetPowerRequestHandler()
-        );
-    }
-
-    private String asGHz(String value) {
-        return String.valueOf(Double.valueOf(value) / GHZ);
-    }
-
-    private String asTHz(String value) {
-        return String.valueOf(Double.valueOf(value) / THZ);
-    }
-
-    private String annotation(Port port, String key, String defaultValue) {
-        String value = port.annotations().value(key);
-        return value != null ? value : defaultValue;
-    }
-
-    private String annotation(Port port, String key) {
-        return annotation(port, key, NA);
+        return ImmutableSet.of(new PortTableDataRequestHandler(),
+                new SetTargetPowerRequestHandler(),
+                new CreateShowItemsRequestHandler(),
+                new CreateOpsModeSetRequestHandler()
+                );
     }
 
     // Handler for sample table requests
@@ -126,13 +110,12 @@
 
         @Override
         protected String noRowsMessage(ObjectNode payload) {
-            return NO_ROWS_MESSAGE;
+            return RoadmUtil.NO_ROWS_MESSAGE;
         }
 
         @Override
         protected void populateTable(TableModel tm, ObjectNode payload) {
-            DeviceId deviceId = DeviceId.deviceId(string(payload, DEV_ID, "(none)"));
-
+            DeviceId deviceId = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
             if (deviceService.isAvailable(deviceId)) {
                 List<Port> ports = deviceService.getPorts(deviceId);
                 for (Port port : ports) {
@@ -142,53 +125,65 @@
         }
 
         private void populateRow(TableModel.Row row, Port port, DeviceId deviceId) {
-            row.cell(ID, port.number().toLong())
+            PortNumber portNum = port.number();
+            getFrequencyLimit(deviceId, portNum);
+            row.cell(ID, portNum.toLong())
                     .cell(TYPE, port.type())
                     .cell(ENABLED, port.isEnabled())
-                    .cell(NAME, annotation(port, AnnotationKeys.PORT_NAME))
-                    .cell(MIN_FREQ, asTHz(annotation(port, OpticalAnnotations.MIN_FREQ_HZ)))
-                    .cell(MAX_FREQ, asTHz(annotation(port, OpticalAnnotations.MAX_FREQ_HZ)))
-                    .cell(GRID, asGHz(annotation(port, OpticalAnnotations.GRID_HZ)))
-                    .cell(INPUT_POWER_RANGE, getInputPowerRange(deviceId, port.number()))
-                    .cell(CURRENT_POWER, getCurrentPower(deviceId, port.number()))
-                    .cell(TARGET_POWER, getTargetPower(deviceId, port.number()))
-                    .cell(HAS_TARGET_POWER, roadmService.hasPortTargetPower(deviceId, port.number()));
+                    .cell(NAME, RoadmUtil.getAnnotation(port.annotations(), AnnotationKeys.PORT_NAME))
+                    .cell(MIN_FREQ, RoadmUtil.asTHz(minFreq))
+                    .cell(MAX_FREQ, RoadmUtil.asTHz(maxFreq))
+                    .cell(GRID, RoadmUtil.asGHz(channelSpacing))
+                    .cell(INPUT_POWER_RANGE, getInputPowerRange(deviceId, portNum))
+                    .cell(CURRENT_POWER, getCurrentPower(deviceId, portNum))
+                    .cell(SERVICE_STATE, getPortServiceState(deviceId, portNum))
+                    .cell(TARGET_POWER, getTargetPower(deviceId, portNum))
+                    .cell(HAS_TARGET_POWER, roadmService.hasPortTargetPower(deviceId, portNum));
+        }
+
+        private String getPortServiceState(DeviceId deviceId, PortNumber portNumber) {
+            return RoadmUtil.defaultString(
+                    roadmService.getProtectionSwitchPortState(deviceId, portNumber),
+                    RoadmUtil.UNKNOWN);
+        }
+
+        private Frequency minFreq = null, maxFreq = null, channelSpacing = null;
+        // Gets min frequency, max frequency, channel spacing
+        private void getFrequencyLimit(DeviceId deviceId, PortNumber portNumber) {
+            Set<OchSignal> signals = roadmService.queryLambdas(deviceId, portNumber);
+            if (signals.isEmpty()) {
+                return;
+            }
+            Comparator<OchSignal> compare =
+                    (OchSignal a, OchSignal b) -> a.spacingMultiplier() - b.spacingMultiplier();
+            OchSignal minOch = Collections.min(signals, compare);
+            OchSignal maxOch = Collections.max(signals, compare);
+            minFreq = minOch.centralFrequency();
+            maxFreq = maxOch.centralFrequency();
+            channelSpacing = minOch.channelSpacing().frequency();
         }
 
         // Returns the input power range as a string, N/A if the port is not an
         // input port
         private String getInputPowerRange(DeviceId deviceId, PortNumber portNumber) {
-            Range<Long> range =
-                    roadmService.inputPortPowerRange(deviceId, portNumber);
-            if (range != null) {
-                return range.toString();
-            }
-            return NA;
+            Range<Long> range = roadmService.inputPortPowerRange(deviceId, portNumber);
+            return RoadmUtil.objectToString(range, RoadmUtil.NA);
         }
 
         // Returns the current power as a string, Unknown if no value can be found.
         private String getCurrentPower(DeviceId deviceId, PortNumber portNumber) {
-            Long currentPower =
-                    roadmService.getCurrentPortPower(deviceId, portNumber);
-            if (currentPower != null) {
-                return String.valueOf(currentPower);
-            }
-            return UNKNOWN;
+            Long currentPower = roadmService.getCurrentPortPower(deviceId, portNumber);
+            return RoadmUtil.objectToString(currentPower, RoadmUtil.UNKNOWN);
         }
 
         // Returns target power as a string, Unknown if target power is expected but
         // cannot be found, N/A if port does not have configurable target power
         private String getTargetPower(DeviceId deviceId, PortNumber portNumber) {
-            if (roadmService.hasPortTargetPower(deviceId, portNumber)) {
-                Long targetPower =
-                        roadmService.getTargetPortPower(deviceId, portNumber);
-                if (targetPower != null) {
-                    return String.valueOf(targetPower);
-                } else {
-                    return UNKNOWN;
-                }
+            if (!roadmService.hasPortTargetPower(deviceId, portNumber)) {
+                return RoadmUtil.NA;
             }
-            return NA;
+            Long targetPower = roadmService.getTargetPortPower(deviceId, portNumber);
+            return RoadmUtil.objectToString(targetPower, RoadmUtil.UNKNOWN);
         }
     }
 
@@ -196,9 +191,6 @@
     // Handler for setting port target power
     private final class SetTargetPowerRequestHandler extends RequestHandler {
 
-        private static final String VALID = "valid";
-        private static final String MESSAGE = "message";
-
         private static final String TARGET_POWER_ERR_MSG = "Target power range is %s.";
 
         private SetTargetPowerRequestHandler() {
@@ -207,29 +199,78 @@
 
         @Override
         public void process(ObjectNode payload) {
-            DeviceId deviceId = DeviceId.deviceId(string(payload, DEV_ID, "(none)"));
+            DeviceId deviceId = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
             PortNumber portNumber = PortNumber.portNumber(payload.get(ID).asLong());
-            long targetPower = payload.get(TARGET_POWER).asLong();
-            boolean validTargetPower;
-
-            Range<Long> range =
-                    roadmService.targetPortPowerRange(deviceId, portNumber);
-            if (range != null) {
-                validTargetPower = range.contains(targetPower);
-
-                if (validTargetPower) {
-                    roadmService.setTargetPortPower(deviceId, portNumber, targetPower);
-                }
-
-                ObjectNode rootNode = objectNode();
-                rootNode.put(ID, payload.get(ID).asText());
-                rootNode.put(VALID, validTargetPower);
-                rootNode.put(MESSAGE, String.format(TARGET_POWER_ERR_MSG, range.toString()));
-                sendMessage(ROADM_SET_TARGET_POWER_RESP, rootNode);
-
-            } else {
+            Range<Long> range = roadmService.targetPortPowerRange(deviceId, portNumber);
+            if (range == null) {
                 log.warn("Unable to determine target power range for device {}", deviceId);
+                return;
             }
+            Long targetPower = payload.get(TARGET_POWER).asLong();
+            boolean validTargetPower = range.contains(targetPower);
+            if (validTargetPower) {
+                roadmService.setTargetPortPower(deviceId, portNumber, targetPower);
+            }
+            ObjectNode rootNode = objectNode();
+            rootNode.put(ID, payload.get(ID).asText());
+            rootNode.put(RoadmUtil.VALID, validTargetPower);
+            rootNode.put(RoadmUtil.MESSAGE, String.format(TARGET_POWER_ERR_MSG, range.toString()));
+            sendMessage(ROADM_SET_TARGET_POWER_RESP, rootNode);
+        }
+    }
+
+    private final class CreateShowItemsRequestHandler extends RequestHandler {
+        private static final String SHOW_TARGET_POWER = "showTargetPower";
+        private static final String SHOW_SERVICE_STATE = "showServiceState";
+        private static final String SHOW_FLOW_ICON = "showFlowIcon";
+
+        private CreateShowItemsRequestHandler() {
+            super(ROADM_SHOW_ITEMS_REQ);
+        }
+
+        @Override
+        public void process(ObjectNode payload) {
+            DeviceId did = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
+            Type devType = deviceService.getDevice(did).type();
+            // Build response
+            ObjectNode node = objectNode();
+            node.put(SHOW_TARGET_POWER, devType != Type.FIBER_SWITCH);
+            node.put(SHOW_SERVICE_STATE, devType == Type.FIBER_SWITCH);
+            node.put(SHOW_FLOW_ICON, devType == Type.ROADM);
+            sendMessage(ROADM_SHOW_ITEMS_RESP, node);
+        }
+    }
+
+    private final class CreateOpsModeSetRequestHandler extends RequestHandler {
+        private static final String OPS_SWITCH_INDEX = "index";
+        private static final String DEVICE_INVALID_ERR_MSG = "Apply failed: device is offline or unavailable.";
+        private static final String TYPE_INVALID_ERR_MSG = "Apply failed: invalid device type.";
+
+        private CreateOpsModeSetRequestHandler() {
+            super(ROADM_SET_OPS_MODE_REQ);
+        }
+
+        @Override
+        public void process(ObjectNode payload) {
+            DeviceId did = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
+            ObjectNode node = objectNode();
+            if (!deviceService.isAvailable(did)) {
+                node.put(RoadmUtil.VALID, false);
+                node.put(RoadmUtil.MESSAGE, DEVICE_INVALID_ERR_MSG);
+                sendMessage(ROADM_SET_OPS_MODE_RESP, node);
+                return;
+            }
+            Type devType = deviceService.getDevice(did).type();
+            if (devType != Type.FIBER_SWITCH) {
+                node.put(RoadmUtil.VALID, false);
+                node.put(RoadmUtil.MESSAGE, TYPE_INVALID_ERR_MSG);
+                sendMessage(ROADM_SET_OPS_MODE_RESP, node);
+                return;
+            }
+            // get virtual port and switch port from payload
+            roadmService.setProtectionSwitchWorkingPath(did, (int) number(payload, OPS_SWITCH_INDEX));
+            node.put(RoadmUtil.VALID, true);
+            sendMessage(ROADM_SET_OPS_MODE_RESP, node);
         }
     }
 }