Adding Modulation to UI

Change-Id: I651dc44dd8f784962f4bc74bcbf246441a236707
diff --git a/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmManager.java b/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmManager.java
index e04bad9..7f1a559 100644
--- a/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmManager.java
+++ b/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmManager.java
@@ -24,11 +24,13 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Direction;
+import org.onosproject.net.ModulationScheme;
 import org.onosproject.net.OchSignal;
 import org.onosproject.net.OchSignalType;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.behaviour.LambdaQuery;
+import org.onosproject.net.behaviour.ModulationConfig;
 import org.onosproject.net.behaviour.PowerConfig;
 import org.onosproject.net.behaviour.protection.ProtectedTransportEndpointState;
 import org.onosproject.net.behaviour.protection.ProtectionConfigBehaviour;
@@ -239,7 +241,7 @@
             powerConfig.setTargetPower(portNumber, ochSignal, attenuation);
         } else {
             log.warn("Cannot set attenuation for channel index {} on device {}",
-                     ochSignal.spacingMultiplier(), deviceId);
+                    ochSignal.spacingMultiplier(), deviceId);
         }
     }
 
@@ -299,8 +301,43 @@
     }
 
     @Override
+    public ModulationScheme getModulation(DeviceId deviceId, PortNumber portNumber) {
+        checkNotNull(deviceId);
+        checkNotNull(portNumber);
+        Device device = deviceService.getDevice(deviceId);
+        Direction component = Direction.ALL;
+        if (device.is(ModulationConfig.class)) {
+            ModulationConfig<Object> modulationConfig = device.as(ModulationConfig.class);
+            Optional<ModulationScheme> scheme = modulationConfig.getModulationScheme(portNumber, component);
+            if (scheme.isPresent()) {
+                return scheme.get();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void setModulation(DeviceId deviceId, PortNumber portNumber, String modulation) {
+        checkNotNull(deviceId);
+        checkNotNull(portNumber);
+        Device device = deviceService.getDevice(deviceId);
+        Direction component = Direction.ALL;
+        if (device.is(ModulationConfig.class)) {
+            ModulationConfig<Object> modulationConfig = device.as(ModulationConfig.class);
+            long bitRate = 0;
+            if (modulation.equals(ModulationScheme.DP_QPSK.name())) {
+                bitRate = 100;
+            } else {
+                bitRate = 200;
+            }
+            modulationConfig.setModulationScheme(portNumber, component, bitRate);
+        }
+
+    }
+
+    @Override
     public FlowId createConnection(DeviceId deviceId, int priority, boolean isPermanent,
-                                 int timeout, PortNumber inPort, PortNumber outPort, OchSignal ochSignal) {
+                                   int timeout, PortNumber inPort, PortNumber outPort, OchSignal ochSignal) {
         checkNotNull(deviceId);
         checkNotNull(inPort);
         checkNotNull(outPort);
@@ -331,15 +368,15 @@
         flowRuleService.applyFlowRules(flowRule);
 
         log.info("Created connection from input port {} to output port {}",
-                 inPort.toLong(), outPort.toLong());
+                inPort.toLong(), outPort.toLong());
 
         return flowRule.id();
     }
 
     @Override
     public FlowId createConnection(DeviceId deviceId, int priority, boolean isPermanent,
-                                 int timeout, PortNumber inPort, PortNumber outPort,
-                                 OchSignal ochSignal, long attenuation) {
+                                   int timeout, PortNumber inPort, PortNumber outPort,
+                                   OchSignal ochSignal, long attenuation) {
         checkNotNull(deviceId);
         checkNotNull(inPort);
         checkNotNull(outPort);
diff --git a/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmPortViewMessageHandler.java b/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmPortViewMessageHandler.java
index dea83b0..f0d0183 100644
--- a/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmPortViewMessageHandler.java
+++ b/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmPortViewMessageHandler.java
@@ -25,12 +25,13 @@
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
-import org.onosproject.net.behaviour.protection.ProtectedTransportEndpointState;
-import org.onosproject.net.behaviour.protection.TransportEndpointState;
-import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.ModulationScheme;
 import org.onosproject.net.OchSignal;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.protection.ProtectedTransportEndpointState;
+import org.onosproject.net.behaviour.protection.TransportEndpointState;
+import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.intent.OpticalPathIntent;
 import org.onosproject.net.optical.OpticalAnnotations;
 import org.onosproject.ui.RequestHandler;
@@ -64,6 +65,8 @@
     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 ROADM_SET_MODULATION_REQ = "roadmSetModulationRequest";
+    private static final String ROADM_SET_MODULATION_RESP = "roadmSetModulationResponse";
     private static final String ROADM_SYNC_TARGET_POWER_REQ = "roadmSyncTargetPowerRequest";
     private static final String ROADM_SYNC_TARGET_POWER_RESP = "roadmSyncTargetPowerResp";
     private static final String ROADM_SHOW_ITEMS_REQ = "roadmShowPortItemsRequest";
@@ -82,12 +85,13 @@
     private static final String POWER_RANGE = "powerRange";
     private static final String CURRENT_POWER = "currentPower";
     private static final String TARGET_POWER = "targetPower";
+    private static final String MODULATION = "modulation";
     private static final String HAS_TARGET_POWER = "hasTargetPower";
     private static final String SERVICE_STATE = "serviceState";
 
     private static final String[] COLUMN_IDS = {
             ID, REVERSE_PORT, TYPE, NAME, ENABLED, MIN_FREQ, MAX_FREQ, GRID, POWER_RANGE,
-            CURRENT_POWER, SERVICE_STATE, TARGET_POWER, HAS_TARGET_POWER
+            CURRENT_POWER, SERVICE_STATE, TARGET_POWER, MODULATION, HAS_TARGET_POWER
     };
 
     private RoadmService roadmService;
@@ -108,8 +112,9 @@
                 new SetTargetPowerRequestHandler(),
                 new CreateShowItemsRequestHandler(),
                 new CreateOpsModeSetRequestHandler(),
-                new SyncTargetPowerRequestHandler()
-                );
+                new SyncTargetPowerRequestHandler(),
+                new SetModulationRequestHandler()
+        );
     }
 
     // Handler for sample table requests
@@ -155,6 +160,7 @@
                     .cell(POWER_RANGE, getPowerRange(deviceId, portNum))
                     .cell(CURRENT_POWER, getCurrentPower(deviceId, portNum))
                     .cell(SERVICE_STATE, getPortServiceState(deviceId, portNum))
+                    .cell(MODULATION, getModulation(deviceId, portNum))
                     .cell(TARGET_POWER, getTargetPower(deviceId, portNum))
                     .cell(HAS_TARGET_POWER, roadmService.hasPortTargetPower(deviceId, portNum));
         }
@@ -169,7 +175,7 @@
                 for (TransportEndpointState element : state.pathStates()) {
                     if (element.description().output().connectPoint().port().equals(portNumber)) {
                         return RoadmUtil.defaultString(element.attributes()
-                            .get(OpticalAnnotations.INPUT_PORT_STATUS), RoadmUtil.UNKNOWN);
+                                .get(OpticalAnnotations.INPUT_PORT_STATUS), RoadmUtil.UNKNOWN);
                     }
                 }
             }
@@ -177,6 +183,7 @@
         }
 
         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);
@@ -219,6 +226,17 @@
             Long targetPower = roadmService.getTargetPortPower(deviceId, portNumber);
             return RoadmUtil.objectToString(targetPower, RoadmUtil.UNKNOWN);
         }
+
+        // Returns modulation as a string, Unknown if modulation is expected but
+        // cannot be found
+        private String getModulation(DeviceId deviceId, PortNumber portNumber) {
+            Port port = deviceService.getPort(deviceId, portNumber);
+            ModulationScheme modulation = null;
+            if (port.type().equals(Port.Type.OCH)) {
+                modulation = roadmService.getModulation(deviceId, portNumber);
+            }
+            return RoadmUtil.objectToString(modulation, RoadmUtil.UNKNOWN);
+        }
     }
 
 
@@ -257,6 +275,7 @@
     private final class SyncTargetPowerRequestHandler extends RequestHandler {
 
         private static final String SYNCED_TARGET_POWER = "Synced target power is %s.";
+
         private SyncTargetPowerRequestHandler() {
             super(ROADM_SYNC_TARGET_POWER_REQ);
         }
@@ -275,6 +294,29 @@
         }
     }
 
+    // Handler for setting port modulation
+    private final class SetModulationRequestHandler extends RequestHandler {
+
+        private static final String TARGET_MODULATION_MSG = "Target modulation is %s.";
+
+        private SetModulationRequestHandler() {
+            super(ROADM_SET_MODULATION_REQ);
+        }
+
+        @Override
+        public void process(ObjectNode payload) {
+            DeviceId deviceId = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
+            PortNumber portNumber = PortNumber.portNumber(payload.get(ID).asLong());
+            String modulation = payload.get(MODULATION).asText();
+            roadmService.setModulation(deviceId, portNumber, modulation);
+            ObjectNode rootNode = objectNode();
+            rootNode.put(ID, payload.get(ID).asText());
+            rootNode.put(RoadmUtil.VALID, modulation);
+            rootNode.put(RoadmUtil.MESSAGE, String.format(TARGET_MODULATION_MSG, modulation));
+            sendMessage(ROADM_SET_MODULATION_RESP, rootNode);
+        }
+    }
+
     // Protection switch operation type and path index
     private static final String OPS_ARRAY_INDEX = "index";
     private static final String OPS_ARRAY_OPERATION = "operation";
@@ -322,18 +364,18 @@
                 String groupName = states.keySet().size() == 1 ? "" : String.format(OPS_GROUP_FMT, ++groupIndex);
                 // Add AUTOMATIC operation.
                 nodes.add(new ObjectNode(JsonNodeFactory.instance)
-                          .put(OPS_ARRAY_INDEX, ACTIVE_UNKNOWN)
-                          .put(OPS_ARRAY_OPERATION, OPS_OPT_AUTO)
-                          .put(OPS_ARRAY_NAME, String.format("%s%s", groupName, OPS_OPT_AUTO)));
+                        .put(OPS_ARRAY_INDEX, ACTIVE_UNKNOWN)
+                        .put(OPS_ARRAY_OPERATION, OPS_OPT_AUTO)
+                        .put(OPS_ARRAY_NAME, String.format("%s%s", groupName, OPS_OPT_AUTO)));
                 // Add FORCE and MANUAL operations for every path.
                 for (String opt : OPS_NON_AUTO_OPTS) {
                     int pathIndex = 0;
                     for (TransportEndpointState state : states.get(identifier).pathStates()) {
                         nodes.add(new ObjectNode(JsonNodeFactory.instance)
-                                  .put(OPS_ARRAY_INDEX, pathIndex++)
-                                  .put(OPS_ARRAY_OPERATION, opt)
-                                  .put(OPS_ARRAY_NAME,
-                                       String.format("%s%s %s", groupName, opt, state.id().id().toUpperCase())));
+                                .put(OPS_ARRAY_INDEX, pathIndex++)
+                                .put(OPS_ARRAY_OPERATION, opt)
+                                .put(OPS_ARRAY_NAME,
+                                        String.format("%s%s %s", groupName, opt, state.id().id().toUpperCase())));
                     }
                 }
             }
diff --git a/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmService.java b/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmService.java
index c9e65d8..d116391 100644
--- a/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmService.java
+++ b/apps/roadm/app/src/main/java/org/onosproject/roadm/RoadmService.java
@@ -18,6 +18,7 @@
 import com.google.common.collect.Range;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.ModulationScheme;
 import org.onosproject.net.OchSignal;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.behaviour.protection.ProtectedTransportEndpointState;
@@ -159,6 +160,24 @@
     Set<OchSignal> queryLambdas(DeviceId deviceId, PortNumber portNumber);
 
     /**
+     * Set modulation for a port if the port has configurable modulation.
+     *
+     * @param deviceId DeviceId of the device to configure
+     * @param portNumber PortNumber of the port to configure
+     * @param modulation value to set modulation to
+     */
+    void setModulation(DeviceId deviceId, PortNumber portNumber, String modulation);
+
+    /**
+     * Get modulation for a port if the port has configurable modulation.
+     *
+     * @param deviceId DeviceId of the device to configure
+     * @param portNumber PortNumber of the port to configure
+     * @return modulation scheme
+     */
+    ModulationScheme getModulation(DeviceId deviceId, PortNumber portNumber);
+
+    /**
      * Creates a new internal connection on a device without attenuation. This does
      * not check that the connection is actually valid (e.g. an input port to an
      * output port).
diff --git a/apps/roadm/web/roadm-gui/projects/roadm-gui-lib/src/lib/port/port.component.html b/apps/roadm/web/roadm-gui/projects/roadm-gui-lib/src/lib/port/port.component.html
index 812bfed..79e2fb5 100644
--- a/apps/roadm/web/roadm-gui/projects/roadm-gui-lib/src/lib/port/port.component.html
+++ b/apps/roadm/web/roadm-gui/projects/roadm-gui-lib/src/lib/port/port.component.html
@@ -70,6 +70,7 @@
                     <td colId="minFreq">Min Freq (GHz)</td>
                     <td colId="maxFreq">Max Freq (GHz)</td>
                     <td colId="grid">Grid (GHz)</td>
+                    <td colId="modulation">Modulation</td>
                     <td colId="powerRange">Power Range (dBm)</td>
                     <td colId="currentPower">Current Power (dBm)</td>
                     <td colId="targetPower">Target Power (dBm)</td>
@@ -94,6 +95,15 @@
                     <td [ngClass]="(isDelta() ? 'delta' : '')">{{port.type=='OCH'?port.minFreq:""}}</td>
                     <td [ngClass]="(isDelta() ? 'delta' : '')">{{port.type=='OCH'?port.maxFreq:""}}</td>
                     <td [ngClass]="(isDelta() ? 'delta' : '')">{{port.type=='OCH'?port.grid:""}}</td>
+                    <td [ngClass]="(isDelta() ? 'delta' : '')">
+                        <form [formGroup]="modulationForm" (ngSubmit)="submitModulation(devId, port.id)" *ngIf="port.type=='OCH'">
+                            <select [(ngModel)]="port.modulation" formControlName="newModulation">
+                                <option value="dp_qpsk">qpsk</option>
+                                <option value="dp_16qam">16qam</option>
+                            </select>
+                            <button type="submit">Submit</button>
+                        </form>
+                    </td>
                     <td [ngClass]="(isDelta() ? 'delta' : '')">{{port.powerRange}}</td>
                     <td [ngClass]="(isDelta() ? 'delta' : '')">{{port.currentPower}}</td>
                     <td [ngClass]="(isDelta() ? 'delta' : '')">
diff --git a/apps/roadm/web/roadm-gui/projects/roadm-gui-lib/src/lib/port/port.component.ts b/apps/roadm/web/roadm-gui/projects/roadm-gui-lib/src/lib/port/port.component.ts
index d1a2a21..869c256 100644
--- a/apps/roadm/web/roadm-gui/projects/roadm-gui-lib/src/lib/port/port.component.ts
+++ b/apps/roadm/web/roadm-gui/projects/roadm-gui-lib/src/lib/port/port.component.ts
@@ -47,6 +47,7 @@
     powerRange: string;
     currentPower: string;
     targetPower: string;
+    modulation: string;
     hasTargetPower: string;
     serviceState: string;
 }
@@ -78,8 +79,10 @@
     toggleState: FilterToggleState;
 
     powerForm: FormGroup;
+    modulationForm: FormGroup;
     SET_POWER_REQ = 'roadmSetTargetPowerRequest';
     SET_POWER_RESP = 'roadmSetTargetPowerResponse';
+    SET_MODULATION = 'roadmSetModulationRequest';
 
     restorePrefsConfig; // Function
 
@@ -128,7 +131,10 @@
         this.powerForm = new FormGroup({
             newPower: new FormControl(''),
         });
-        this.log.debug('Create Form');
+        this.modulationForm = new FormGroup({
+            newModulation: new FormControl(''),
+        });
+        this.log.debug('Create Forms');
     }
 
     ngOnDestroy() {
@@ -207,6 +213,15 @@
         });
     }
 
+    submitModulation(devId, port) {
+        this.log.debug('Set Modulation of port ', port, 'in device ', devId, 'as value ', this.modulationForm.value['newModulation']);
+        this.wss.sendEvent(this.SET_MODULATION, {
+            'modulation': this.modulationForm.value['newModulation'],
+            'devId': devId,
+            'id': port,
+        });
+    }
+
     powerConfigCb(data) {
         if (!data.valid) {
             const info = 'The power config operation is failed. The reason is: \n' + data.message;
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniModulationConfig.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniModulationConfig.java
index a271132..0149566 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniModulationConfig.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniModulationConfig.java
@@ -205,7 +205,7 @@
                     .append("</filter>")
                     .append("</get>")
                     .append(RPC_CLOSE_TAG);
-            log.info("RPC Call for Getting Modulation : \n {}", rpcReq.toString());
+            log.debug("RPC Call for Getting Modulation : \n {}", rpcReq.toString());
             XMLConfiguration xconf = NetconfSessionUtility.executeRpc(session, rpcReq.toString());
             try {
                 HierarchicalConfiguration config =
@@ -420,9 +420,11 @@
                     .append(RPC_CLOSE_TAG);
             log.info("RPC call for Setting Modulation : {}", rpcReq.toString());
             XMLConfiguration xconf = NetconfSessionUtility.executeRpc(session, rpcReq.toString());
-
-            // The successful reply should be "<rpc-reply ...><ok /></rpc-reply>"
-            if (!xconf.getRoot().getChild(0).getName().equals("ok")) {
+            if (xconf == null) {
+                log.error("The <edit-config> operation to set target-modulation of Port({}:{}) is failed.",
+                        port.toString(), component.toString());
+            } else if (!xconf.getRoot().getChild(0).getName().equals("ok")) {
+                    // The successful reply should be "<rpc-reply ...><ok /></rpc-reply>"
                 response = false;
                 log.error("The <edit-config> operation to set target-modulation of Port({}:{}) is failed.",
                         port.toString(), component.toString());
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/util/NetconfSessionUtility.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/util/NetconfSessionUtility.java
index 786c999..6c9500c 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/util/NetconfSessionUtility.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/util/NetconfSessionUtility.java
@@ -48,7 +48,7 @@
      */
     public static NetconfSession getNetconfSession(DeviceId deviceId,
                                                    NetconfController controller) {
-        log.info("Inside getNetconfSession () method for device : {}", deviceId);
+        log.debug("Inside getNetconfSession () method for device : {}", deviceId);
         NetconfDevice ncdev = controller.getDevicesMap().get(deviceId);
         if (ncdev == null) {
             log.trace("No netconf device, returning null session");
@@ -77,7 +77,7 @@
         } catch (InterruptedException ie) {
             log.error("Interrupted Exception: {}.", ie);
         } catch (ExecutionException ee) {
-            log.error("Concurrent Exception while executing Netconf operation: {}.", ee);
+            log.error("Concurrent Exception while executing Netconf operation: {}.", ee.getCause());
         }
         return null;
     }
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
index 041dce2..2e7e643 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
@@ -261,7 +261,7 @@
             }
 
         } catch (Error | Exception e) {
-            log.warn("Unable to parse GUI message {} due to {}", data, e);
+            log.warn("Unable to parse GUI message {} due to", data, e);
             log.debug("Boom!!!", e);
         }
     }