Optical  topology provider for UC1

Change-Id: I1b25c9412b5180f9dce167f8700eb84baba70486
diff --git a/apps/optical/src/main/java/org/onlab/onos/optical/cfg/OpticalConfigProvider.java b/apps/optical/src/main/java/org/onlab/onos/optical/cfg/OpticalConfigProvider.java
new file mode 100644
index 0000000..86c1c0b
--- /dev/null
+++ b/apps/optical/src/main/java/org/onlab/onos/optical/cfg/OpticalConfigProvider.java
@@ -0,0 +1,338 @@
+package org.onlab.onos.optical.cfg;
+
+import static org.onlab.onos.net.DeviceId.deviceId;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.DefaultAnnotations;
+import org.onlab.onos.net.Device;
+import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.Link;
+import org.onlab.onos.net.MastershipRole;
+import org.onlab.onos.net.PortNumber;
+import org.onlab.onos.net.device.DefaultDeviceDescription;
+import org.onlab.onos.net.device.DeviceDescription;
+import org.onlab.onos.net.device.DeviceProvider;
+import org.onlab.onos.net.device.DeviceProviderRegistry;
+import org.onlab.onos.net.device.DeviceProviderService;
+import org.onlab.onos.net.link.DefaultLinkDescription;
+import org.onlab.onos.net.link.LinkProvider;
+import org.onlab.onos.net.link.LinkProviderRegistry;
+import org.onlab.onos.net.link.LinkProviderService;
+import org.onlab.onos.net.provider.AbstractProvider;
+import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.packet.ChassisId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * OpticalConfigProvider emulates the SB network provider for optical switches,
+ * optical links and any other state that needs to be configured for correct network
+ * operations.
+ *
+ */
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@Component(immediate = true)
+public class OpticalConfigProvider extends AbstractProvider implements DeviceProvider, LinkProvider {
+
+    protected static final Logger log = LoggerFactory
+            .getLogger(OpticalConfigProvider.class);
+
+    // TODO: fix hard coded file path later.
+    private static final String DEFAULT_CONFIG_FILE =
+            "/opt/onos/config/demo-3-roadm-2-ps.json";
+    private String configFileName = DEFAULT_CONFIG_FILE;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected LinkProviderRegistry linkProviderRegistry;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceProviderRegistry deviceProviderRegistry;
+
+    private static final String OPTICAL_ANNOTATION = "optical.";
+
+    private LinkProviderService linkProviderService;
+    private DeviceProviderService deviceProviderService;
+
+    private static final List<Roadm> RAW_ROADMS = new ArrayList<>();
+    private static final List<WdmLink> RAW_WDMLINKS = new ArrayList<>();
+    private static final List<PktOptLink> RAW_PKTOPTLINKS = new ArrayList<>();
+
+    private static final String ROADM = "Roadm";
+    private static final String WDM_LINK = "wdmLink";
+    private static final String PKT_OPT_LINK = "pktOptLink";
+
+    protected OpticalNetworkConfig opticalNetworkConfig;
+
+    public OpticalConfigProvider() {
+        super(new ProviderId("of", "org.onlab.onos.provider.opticalConfig", true));
+    }
+
+    @Activate
+    protected void activate() {
+        linkProviderService = linkProviderRegistry.register(this);
+        deviceProviderService = deviceProviderRegistry.register(this);
+        log.info("Starting optical network configuration process...");
+        log.info("Optical config file set to {}", configFileName);
+
+        loadOpticalConfig();
+        parseOpticalConfig();
+        publishOpticalConfig();
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        linkProviderRegistry.unregister(this);
+        linkProviderService = null;
+        deviceProviderRegistry.unregister(this);
+        deviceProviderService = null;
+        RAW_ROADMS.clear();
+        RAW_WDMLINKS.clear();
+        RAW_PKTOPTLINKS.clear();
+        log.info("Stopped");
+    }
+
+    private void loadOpticalConfig() {
+        ObjectMapper mapper = new ObjectMapper();
+        opticalNetworkConfig = new OpticalNetworkConfig();
+        try {
+            opticalNetworkConfig = mapper.readValue(new File(configFileName), OpticalNetworkConfig.class);
+        } catch (JsonParseException e) {
+            String err = String.format("JsonParseException while loading network "
+                    + "config from file: %s: %s", configFileName, e.getMessage());
+            log.error(err, e);
+        } catch (JsonMappingException e) {
+            String err = String.format(
+                    "JsonMappingException while loading network config "
+                            + "from file: %s: %s", configFileName, e.getMessage());
+            log.error(err, e);
+        } catch (IOException e) {
+            String err = String.format("IOException while loading network config "
+                    + "from file: %s %s", configFileName, e.getMessage());
+            log.error(err, e);
+        }
+    }
+
+    private void parseOpticalConfig() {
+        List<OpticalSwitchDescription> swList = opticalNetworkConfig.getOpticalSwitches();
+        List<OpticalLinkDescription> lkList = opticalNetworkConfig.getOpticalLinks();
+
+        for (OpticalSwitchDescription sw : swList) {
+            String swtype = sw.getType();
+            boolean allow = sw.isAllowed();
+           if (swtype.equals(ROADM) && allow) {
+               int regNum = 0;
+               Set<Map.Entry<String, JsonNode>> m = sw.params.entrySet();
+               for (Map.Entry<String, JsonNode> e : m) {
+                       String key = e.getKey();
+                       JsonNode j = e.getValue();
+                       if (key.equals("numRegen")) {
+                           regNum = j.asInt();
+                       }
+                }
+
+                Roadm newRoadm = new Roadm();
+                newRoadm.setName(sw.name);
+                newRoadm.setNodeId(sw.nodeDpid);
+                newRoadm.setLongtitude(sw.longitude);
+                newRoadm.setLatitude(sw.latitude);
+                newRoadm.setRegenNum(regNum);
+
+                RAW_ROADMS.add(newRoadm);
+                log.info(newRoadm.toString());
+            }
+           }
+
+        for (OpticalLinkDescription lk : lkList) {
+            String lktype = lk.getType();
+            switch (lktype) {
+            case WDM_LINK:
+                WdmLink newWdmLink = new WdmLink();
+                newWdmLink.setSrcNodeId(lk.getNodeDpid1());
+                newWdmLink.setSnkNodeId(lk.getNodeDpid2());
+                newWdmLink.setAdminWeight(1000); // default weight for each WDM link.
+                Set<Map.Entry<String, JsonNode>> m = lk.params.entrySet();
+                for (Map.Entry<String, JsonNode> e : m) {
+                    String key = e.getKey();
+                    JsonNode j = e.getValue();
+                    if (key.equals("nodeName1")) {
+                        newWdmLink.setSrcNodeName(j.asText());
+                    } else if (key.equals("nodeName2")) {
+                        newWdmLink.setSnkNodeName(j.asText());
+                    } else if (key.equals("port1")) {
+                        newWdmLink.setSrcPort(j.asInt());
+                    } else if (key.equals("port2")) {
+                        newWdmLink.setSnkPort(j.asInt());
+                    } else if (key.equals("distKms")) {
+                        newWdmLink.setDistance(j.asDouble());
+                    } else if (key.equals("numWaves")) {
+                        newWdmLink.setWavelengthNumber(j.asInt());
+                    } else {
+                        log.error("error found");
+                        // TODO add exception processing;
+                    }
+                }
+                RAW_WDMLINKS.add(newWdmLink);
+                log.info(newWdmLink.toString());
+
+                break;
+
+            case PKT_OPT_LINK:
+                PktOptLink newPktOptLink = new PktOptLink();
+                newPktOptLink.setSrcNodeId(lk.getNodeDpid1());
+                newPktOptLink.setSnkNodeId(lk.getNodeDpid2());
+                newPktOptLink.setAdminWeight(10); // default weight for each packet-optical link.
+                Set<Map.Entry<String, JsonNode>> ptm = lk.params.entrySet();
+                for (Map.Entry<String, JsonNode> e : ptm) {
+                    String key = e.getKey();
+                    JsonNode j = e.getValue();
+                    if (key.equals("nodeName1")) {
+                        newPktOptLink.setSrcNodeName(j.asText());
+                    } else if (key.equals("nodeName2")) {
+                        newPktOptLink.setSnkNodeName(j.asText());
+                    } else if (key.equals("port1")) {
+                        newPktOptLink.setSrcPort(j.asInt());
+                    } else if (key.equals("port2")) {
+                        newPktOptLink.setSnkPort(j.asInt());
+                    } else if (key.equals("bandWidth")) {
+                        newPktOptLink.setBandwdith(j.asDouble());
+                    } else {
+                        log.error("error found");
+                        // TODO add exception processing;
+                    }
+                }
+
+                RAW_PKTOPTLINKS.add(newPktOptLink);
+                log.info(newPktOptLink.toString());
+                break;
+            default:
+            }
+        }
+    }
+
+    private void publishOpticalConfig() {
+        if (deviceProviderService == null || linkProviderService == null) {
+            return;
+        }
+
+        // Discover the optical ROADM objects
+        Iterator<Roadm> iterWdmNode = RAW_ROADMS.iterator();
+        while (iterWdmNode.hasNext()) {
+            Roadm value = iterWdmNode.next();
+            DeviceId did = deviceId("of:" + value.getNodeId().replace(":", ""));
+            ChassisId cid = new ChassisId(value.getNodeId());
+            DefaultAnnotations extendedAttributes = DefaultAnnotations.builder()
+                    .set(OPTICAL_ANNOTATION + "switchType", "ROADM")
+                    .set(OPTICAL_ANNOTATION + "switchName", value.getName())
+                    .set(OPTICAL_ANNOTATION + "latitude", Double.toString(value.getLatitude()))
+                    .set(OPTICAL_ANNOTATION + "longtitude", Double.toString(value.getLongtitude()))
+                    .set(OPTICAL_ANNOTATION + "regNum", Integer.toString(value.getRegenNum()))
+                    .build();
+
+            DeviceDescription description =
+                    new DefaultDeviceDescription(did.uri(),
+                                                 Device.Type.SWITCH,
+                                                 "",
+                                                 "",
+                                                 "",
+                                                 "",
+                                                 cid,
+                                                 extendedAttributes);
+            deviceProviderService.deviceConnected(did, description);
+        }
+
+        // Discover the optical WDM link objects
+        Iterator<WdmLink> iterWdmlink = RAW_WDMLINKS.iterator();
+        while (iterWdmlink.hasNext()) {
+            WdmLink value = iterWdmlink.next();
+
+            DeviceId srcNodeId = deviceId("of:" + value.getSrcNodeId().replace(":", ""));
+            DeviceId snkNodeId = deviceId("of:" + value.getSnkNodeId().replace(":", ""));
+
+            PortNumber srcPort = PortNumber.portNumber(value.getSrcPort());
+            PortNumber snkPort = PortNumber.portNumber(value.getSnkPort());
+
+            ConnectPoint srcPoint = new ConnectPoint(srcNodeId, srcPort);
+            ConnectPoint snkPoint = new ConnectPoint(snkNodeId, snkPort);
+
+            DefaultAnnotations extendedAttributes = DefaultAnnotations.builder()
+                    .set(OPTICAL_ANNOTATION + "linkType", "WDM")
+                    .set(OPTICAL_ANNOTATION + "distance", Double.toString(value.getDistance()))
+                    .set(OPTICAL_ANNOTATION + "cost", Double.toString(value.getDistance()))
+                    .set(OPTICAL_ANNOTATION + "adminWeight", Double.toString(value.getAdminWeight()))
+                    .set(OPTICAL_ANNOTATION + "wavelengthNum", Integer.toString(value.getWavelengthNumber()))
+                    .build();
+
+            DefaultLinkDescription linkDescription =
+                    new DefaultLinkDescription(srcPoint,
+                                                 snkPoint,
+                                                 Link.Type.DIRECT,
+                                                 extendedAttributes);
+
+            linkProviderService.linkDetected(linkDescription);
+            log.info(String.format("WDM link: %s : %s",
+                    linkDescription.src().toString(), linkDescription.dst().toString()));
+        }
+
+        // Discover the packet optical link objects
+        Iterator<PktOptLink> iterPktOptlink = RAW_PKTOPTLINKS.iterator();
+        while (iterPktOptlink.hasNext()) {
+            PktOptLink value = iterPktOptlink.next();
+            DeviceId srcNodeId = deviceId("of:" + value.getSrcNodeId().replace(":", ""));
+            DeviceId snkNodeId = deviceId("of:" + value.getSnkNodeId().replace(":", ""));
+
+            PortNumber srcPort = PortNumber.portNumber(value.getSrcPort());
+            PortNumber snkPort = PortNumber.portNumber(value.getSnkPort());
+
+            ConnectPoint srcPoint = new ConnectPoint(srcNodeId, srcPort);
+            ConnectPoint snkPoint = new ConnectPoint(snkNodeId, snkPort);
+
+            DefaultAnnotations extendedAttributes = DefaultAnnotations.builder()
+                    .set(OPTICAL_ANNOTATION + "linkType", "PktOptLink")
+                    .set(OPTICAL_ANNOTATION + "bandwidth", Double.toString(value.getBandwidth()))
+                    .set(OPTICAL_ANNOTATION + "cost", Double.toString(value.getBandwidth()))
+                    .set(OPTICAL_ANNOTATION + "adminWeight", Double.toString(value.getAdminWeight()))
+                    .build();
+
+            DefaultLinkDescription linkDescription =
+                    new DefaultLinkDescription(srcPoint,
+                                                 snkPoint,
+                                                 Link.Type.DIRECT,
+                                                 extendedAttributes);
+
+            linkProviderService.linkDetected(linkDescription);
+            log.info(String.format("Packet-optical link: %s : %s",
+                    linkDescription.src().toString(), linkDescription.dst().toString()));
+        }
+
+    }
+
+    @Override
+    public void triggerProbe(Device device) {
+        // TODO We may want to consider re-reading config files and publishing them based on this event.
+    }
+
+    @Override
+    public void roleChanged(Device device, MastershipRole newRole) {
+        // TODO Auto-generated method stub.
+    }
+
+}