Deprecating PortDiscovery in favour of DeviceDescritpionDiscovery

Change-Id: Ie9cff7937412c62c8a5a3b75b87a43952017f146
diff --git a/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaWaveserverDeviceDescription.java b/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaWaveserverDeviceDescription.java
new file mode 100644
index 0000000..69bbe9c
--- /dev/null
+++ b/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaWaveserverDeviceDescription.java
@@ -0,0 +1,187 @@
+/*
+ *
+ *  * Copyright 2016-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.ciena;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.CltSignalType;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.GridType;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalType;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.SparseAnnotations;
+import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceDescriptionDiscovery;
+import org.onosproject.net.device.PortDescription;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.protocol.rest.RestSBController;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
+import static org.onosproject.net.optical.device.OduCltPortHelper.oduCltPortDescription;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Discovers the ports from a Ciena WaveServer Rest device.
+ */
+public class CienaWaveserverDeviceDescription extends AbstractHandlerBehaviour
+        implements DeviceDescriptionDiscovery {
+
+    private final Logger log = getLogger(getClass());
+
+    private static final String SPEED = "speed";
+    private static final String GBPS = "Gbps";
+    private static final String PORT_ID = "port-id";
+    private static final String XML = "xml";
+    private static final String ENABLED = "enabled";
+    private static final String EMPTY_STRING = "";
+    private static final String NAME = "name";
+    private static final String ADMIN_STATE = "admin-state";
+
+    private static final ArrayList<String> LINESIDE_PORT_ID = Lists.newArrayList(
+            "4", "48");
+
+    private static final String GENERAL_PORT_REQUEST =
+            "ws-ports?config=true&format=xml&depth=unbounded";
+    private static final String SPECIFIC_PORT_PATH = "ws-ptps/ptp/";
+    private static final String SPECIFIC_PORT_CONFIG =
+            "/ptp-config?config=true&format=xml&depth=unbounded";
+    //HTTP strings
+//    private static final String GENERAL_PORT_REQUEST =
+//            "/yang-api/datastore/ws-ports?config=true&format=xml&depth=unbounded";
+//    private static final String SPECIFIC_PORT_PATH = "/yang-api/datastore/ws-ptps/ptp/";
+//    private static final String SPECIFIC_PORT_CONFIG =
+//            "/ptp-config?config=true&format=xml&depth=unbounded";
+
+    @Override
+    public DeviceDescription discoverDeviceDetails() {
+        log.info("No description to be added for device");
+        //TODO to be implemented if needed.
+        return null;
+    }
+
+    @Override
+    public List<PortDescription> discoverPortDetails() {
+        return getPorts();
+    }
+
+    private List<PortDescription> getPorts() {
+        List<PortDescription> ports = Lists.newArrayList();
+        DriverHandler handler = handler();
+        RestSBController controller = checkNotNull(handler.get(RestSBController.class));
+        DeviceId deviceId = handler.data().deviceId();
+
+
+        HierarchicalConfiguration config = XmlConfigParser.
+                loadXml(controller.get(deviceId, GENERAL_PORT_REQUEST, XML));
+        List<HierarchicalConfiguration> portsConfig =
+                parseWaveServerCienaPorts(config);
+        portsConfig.stream().forEach(sub -> {
+            String portId = sub.getString(PORT_ID);
+            String name = sub.getString(NAME);
+            if (LINESIDE_PORT_ID.contains(portId)) {
+                String txName = name + " Tx";
+                DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
+                        .set(AnnotationKeys.PORT_NAME, txName);
+                String wsportInfoRequest = SPECIFIC_PORT_PATH + portId +
+                        SPECIFIC_PORT_CONFIG;
+                ports.add(parseWaveServerCienaOchPorts(
+                        sub.getLong(PORT_ID),
+                        toGbps(Long.parseLong(sub.getString(SPEED).replace(GBPS, EMPTY_STRING)
+                                                      .replace(" ", EMPTY_STRING))),
+                        XmlConfigParser.loadXml(controller.get(deviceId, wsportInfoRequest, XML)),
+                        annotations.build()));
+                //adding corresponding opposite side port
+                String rxName = name.replace(".1", ".2") + " Rx";
+                ports.add(parseWaveServerCienaOchPorts(
+                        sub.getLong(PORT_ID) + 1,
+                        toGbps(Long.parseLong(sub.getString(SPEED).replace(GBPS, EMPTY_STRING)
+                                                      .replace(" ", EMPTY_STRING))),
+                        XmlConfigParser.loadXml(controller.get(deviceId, wsportInfoRequest, XML)),
+                        annotations.set(AnnotationKeys.PORT_NAME, rxName)
+                                .build()));
+            } else if (!portId.equals("5") && !portId.equals("49")) {
+                DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
+                        .set(AnnotationKeys.PORT_NAME, name);
+                //FIXME change when all optical types have two way information methods, see jira tickets
+                final int speed100GbpsinMbps = 100000;
+                CltSignalType cltType = toGbps(Long.parseLong(
+                        sub.getString(SPEED).replace(GBPS, EMPTY_STRING)
+                                .replace(" ", EMPTY_STRING))) == speed100GbpsinMbps ?
+                        CltSignalType.CLT_100GBE : null;
+                ports.add(oduCltPortDescription(PortNumber.portNumber(sub.getLong(PORT_ID)),
+                                                sub.getString(ADMIN_STATE).equals(ENABLED),
+                                                cltType, annotations.build()));
+            }
+        });
+        return ImmutableList.copyOf(ports);
+    }
+
+    public static List<HierarchicalConfiguration> parseWaveServerCienaPorts(HierarchicalConfiguration cfg) {
+        return cfg.configurationsAt("ws-ports.port-interface");
+    }
+
+    public static PortDescription parseWaveServerCienaOchPorts(long portNumber, long oduPortSpeed,
+                                                               HierarchicalConfiguration config,
+                                                               SparseAnnotations annotations) {
+        final List<String> tunableType = Lists.newArrayList("Performance-Optimized", "Accelerated");
+        final String transmitterPath = "ptp-config.transmitter-state";
+        final String tunablePath = "ptp-config.adv-config.tx-tuning-mode";
+        final String gridTypePath = "ptp-config.adv-config.wl-spacing";
+        final String frequencyPath = "ptp-config.adv-config.frequency";
+
+        boolean isEnabled = config.getString(transmitterPath).equals("enabled");
+        boolean isTunable = tunableType.contains(config.getString(tunablePath));
+
+        //FIXME change when all optical types have two way information methods, see jira tickets
+        final int speed100GbpsinMbps = 100000;
+        OduSignalType oduSignalType = oduPortSpeed == speed100GbpsinMbps ? OduSignalType.ODU4 : null;
+        GridType gridType = config.getString(gridTypePath).equals("FlexGrid") ? GridType.FLEX : null;
+        ChannelSpacing chSpacing = gridType == GridType.FLEX ? ChannelSpacing.CHL_6P25GHZ : null;
+
+        //Working in Ghz //(Nominal central frequency - 193.1)/channelSpacing = spacingMultiplier
+        final int baseFrequency = 193100;
+        int spacingMult = (int) (toGbps((Integer.parseInt(config.getString(frequencyPath)) -
+                baseFrequency)) / toGbpsFromHz(chSpacing.frequency().asHz())); //FIXME is there a better way ?
+
+        return ochPortDescription(PortNumber.portNumber(portNumber), isEnabled, oduSignalType, isTunable,
+                                  new OchSignal(gridType, chSpacing, spacingMult, 1), annotations);
+    }
+
+    //FIXME remove when all optical types have two way information methods, see jira tickets
+    private static long toGbps(long speed) {
+        return speed * 1000;
+    }
+
+    private static long toGbpsFromHz(long speed) {
+        return speed / 1000;
+    }
+}
+