changed how ODTN OPENRoadm driver assigns ONOS port ids

Change-Id: I1094ca6c8854817f3157722c71704120480d490d
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmDeviceDescription.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmDeviceDescription.java
index 7a19fa9..bf54ebb 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmDeviceDescription.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/openroadm/OpenRoadmDeviceDescription.java
@@ -43,6 +43,7 @@
 import org.onosproject.net.intent.OpticalPathIntent;
 import org.onosproject.net.optical.device.OchPortHelper;
 import org.onosproject.net.optical.device.OmsPortHelper;
+import org.onosproject.netconf.DatastoreId;
 import org.onosproject.netconf.NetconfDevice;
 import org.onosproject.netconf.NetconfException;
 import org.onosproject.netconf.NetconfSession;
@@ -115,21 +116,33 @@
     }
 
     /**
-     * Builds a request to get Ports data (<circuit-packs>).
+     * Builds a request to get specific circuit pack data (by name).
      *
      * @return A string with the Netconf RPC
      */
-    private String getDeviceCircuitPacksBuilder() {
-        return getDeviceXmlNodeBuilder("<circuit-packs/>");
+    private String getDeviceCircuitPackByNameBuilder(String cpName) {
+        StringBuilder filter = new StringBuilder();
+        filter.append(OPENROADM_DEVICE_OPEN);
+        filter.append("<circuit-packs>");
+        filter.append(" <circuit-pack-name>");
+        filter.append(cpName);
+        filter.append(" </circuit-pack-name>");
+        filter.append("</circuit-packs>");
+        filter.append(OPENROADM_DEVICE_CLOSE);
+        return filteredGetBuilder(filter.toString());
     }
 
     /**
      * Builds a request to get External Links data (<external-link>).
      *
-     * @return A string with the Netconf RPC
+     * @return A string with the Netconf filter for the get-config operation.
      */
     private String getDeviceExternalLinksBuilder() {
-        return getDeviceXmlNodeBuilder("<external-link/>");
+        StringBuilder rb = new StringBuilder();
+        rb.append(OPENROADM_DEVICE_OPEN);
+        rb.append("<external-link/>");
+        rb.append(OPENROADM_DEVICE_CLOSE);
+        return rb.toString();
     }
 
     /**
@@ -344,8 +357,6 @@
     }
 
 
-
-
     /**
      * Get the external links as a list of XML hieriarchical configs.
      *  @param session the NETConf session to the OpenROADM device.
@@ -353,13 +364,13 @@
      */
     List<HierarchicalConfiguration> getExternalLinks(NetconfSession session) {
         try {
-            String reply = session.rpc(getDeviceExternalLinksBuilder()).get();
-            XMLConfiguration extLinksConf = //
+            String reply = session.getConfig(DatastoreId.RUNNING, getDeviceExternalLinksBuilder());
+            XMLConfiguration extLinksConf =
                 (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
             extLinksConf.setExpressionEngine(new XPathExpressionEngine());
             return extLinksConf.configurationsAt(
                     "/data/org-openroadm-device/external-link");
-        } catch (NetconfException | InterruptedException | ExecutionException e) {
+        } catch (NetconfException e) {
             log.error("[OPENROADM] {} exception getting external links", did());
             return ImmutableList.of();
         }
@@ -367,173 +378,441 @@
 
 
     /**
-     * Get the circuit packs from the device as a list of XML hierarchical configs.
-     *  @param session the NETConf session to the OpenROADM device.
-     *  @return a list of hierarchical conf. each one circuit pack.
+     * Get config and status info for a specific circuit pack as a
+     * list of XML hierarchical configs.
+     * @param session the NETConf session to the OpenROADM device.
+     * @param cpName the name of the requested circuit-pack
+     * @return the hierarchical conf. for the circuit pack.
      */
-    List<HierarchicalConfiguration> getCircuitPacks(NetconfSession session) {
+    HierarchicalConfiguration getCircuitPackByName(NetconfSession session, String cpName) {
         try {
-            String reply = session.rpc(getDeviceCircuitPacksBuilder()).get();
-            XMLConfiguration cpConf = //
+            String reply = session.rpc(getDeviceCircuitPackByNameBuilder(cpName)).get();
+            XMLConfiguration cpConf =
                 (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
             cpConf.setExpressionEngine(new XPathExpressionEngine());
-            return cpConf.configurationsAt(
+            List<HierarchicalConfiguration> cPacks = cpConf.configurationsAt(
                     "/data/org-openroadm-device/circuit-packs");
+            // <circuit-pack-name> is the key for the list.
+            // It shouldn't happen they are > 1
+            if (cPacks.size() > 1) {
+                log.warn("[OPENROADM] More than one circuit pack with the same name. Using first one");
+            }
+            return cPacks.get(0);
         } catch (NetconfException | InterruptedException | ExecutionException e) {
-            log.error("[OPENROADM] {} exception getting circuit packs", did());
+            log.error("[OPENROADM] {} exception getting circuit pack {}: {}", did(), cpName, e);
+            return null;
+        }
+    }
+
+
+    /**
+     * Get config and status info for the degrees from the device as a list
+     * of XML hierarchical configs.
+     *  @param session the NETConf session to the OpenROADM device.
+     *  @return a list of hierarchical conf. each one degree.
+     */
+    List<HierarchicalConfiguration> getDegrees(NetconfSession session) {
+        try {
+            String reply = session.rpc(getDeviceDegreesBuilder()).get();
+            XMLConfiguration conf =
+                (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+            conf.setExpressionEngine(new XPathExpressionEngine());
+            return conf.configurationsAt(
+                    "/data/org-openroadm-device/degree");
+        } catch (NetconfException | InterruptedException | ExecutionException e) {
+            log.error("[OPENROADM] {} exception getting degrees: {}", did(), e);
             return ImmutableList.of();
         }
     }
 
+
+    /**
+     * Get config and status info for the SRGs from the device as a list
+     * of XML hierarchical configs.
+     *  @param session the NETConf session to the OpenROADM device.
+     *  @return a list of hierarchical conf. each one SRG.
+     */
+    List<HierarchicalConfiguration> getSrgs(NetconfSession session) {
+        try {
+            String reply = session.rpc(getDeviceSharedRiskGroupsBuilder()).get();
+            XMLConfiguration conf =
+                (XMLConfiguration) XmlConfigParser.loadXmlString(reply);
+            conf.setExpressionEngine(new XPathExpressionEngine());
+            return conf.configurationsAt(
+                    "/data/org-openroadm-device/shared-risk-group");
+        } catch (NetconfException | InterruptedException | ExecutionException e) {
+            log.error("[OPENROADM] {} exception getting SRGs: {}", did(), e);
+            return ImmutableList.of();
+        }
+    }
+
+
     /**
      * Returns a list of PortDescriptions for the device.
      *
      * @return a list of descriptions.
      */
+    /*
+     * Assumptions: ROADM degree ports are Oms carrying 80 lambdas (should be
+     *              configurable)
+     *              ROADM SRG (client) ports are OCh carrying ODU4 (should be
+     *              configurable)
+     */
+
     @Override
-        public List<PortDescription> discoverPortDetails() {
-            NetconfSession session = getNetconfSession(did());
-            if (session == null) {
-                log.error("discoverPortDetails null session for {}", did());
-                return ImmutableList.of();
-            }
-            if (!getDevice().annotations().keys().contains("openroadm-node-id")) {
-                log.error("PortDiscovery before DeviceDiscovery, using netconf");
+    public List<PortDescription> discoverPortDetails() {
+        NetconfSession session = getNetconfSession(did());
+        if (session == null) {
+            log.error("discoverPortDetails null session for {}", did());
             return ImmutableList.of();
         }
-        String nodeId = getDevice().annotations().value("openroadm-node-id");
-        List<PortDescription> list = new ArrayList<PortDescription>();
-        List<HierarchicalConfiguration> circuitPacks = getCircuitPacks(session);
-        /*
-         * Iterate all the ports. We need to pass the whole circuitPacks list
-         * because some port data refers to ports in other circuit packs
-         * (reverse), in addition to pass the current circuit pack name, list of
-         * external ports etc
-         */
-        for (HierarchicalConfiguration c : circuitPacks) {
-            parsePorts(list, nodeId, // c contains the whole circuit pack
-                       c.getString("circuit-pack-name"), //
-                       c.configurationsAt(
-                         "ports[port-qual='roadm-external']"), // ext ports
-                       circuitPacks, getExternalLinks(session));
+        if (!getDevice().annotations().keys().contains("openroadm-node-id")) {
+            log.error("Unable to run PortDiscovery: missing openroadm-node-id annotation." +
+                      " Probable failure during DeviceDiscovery. Aborting!");
+        return ImmutableList.of();
         }
+
+        List<HierarchicalConfiguration> externalLinks = getExternalLinks(session);
+        List<PortDescription> list = new ArrayList<PortDescription>();
+        discoverDegreePorts(session, list, externalLinks);
+        discoverSrgPorts(session, list, externalLinks);
+        return list;
+    }
+
+   /**
+    * Parses degree (ROADM) port information.
+    *
+    * @param session the NETConf session to the OpenROADM device.
+    * @param list  List of port descriptions to append to.
+    * @param externalLinks Hierarchical configuration containing all the external
+    *        links.
+    * Port-id is obtained from degree-number and from the index contained
+    * in the <connection-ports> leaf.
+    * For OpenROADM Device model 2.2 both <degree-number> and <index> inside
+    * <connection-ports> are key for the related lists, so composing them
+    * assures identificator uniqueness.
+    * Degree IDs are chosen as 10 * degree-number + index to avoid overlapping
+    * with SRGs IDs.
+    * The above formula allows making a two-digit number starting from two
+    * one-digit numbers (actually, only port index needs to be single digit and
+    * this assumption is assured by what stated in the model:
+    *     OpenROADM Device model 2.2 (line 675):
+    *        (connection-ports) description "Port associated with degree: One if bi-directional; two if uni-directional"
+    * If my numbers are A and B, to have a number in the form AB (i.e. 11, 12, 21,
+    * 31, 42, ...) I have to multiply A by 10.
+    *
+    * Note that both bidirectional and unidirectional ports IDs are taken from
+    * the datastore.
+    * Ex. DEG1 bidirectional port
+    *          ONOS port ID: 11
+    *     DEG3 unidirectional port
+    *          ONOS port IDs: 31 and 32
+    */
+    private List<PortDescription>
+    discoverDegreePorts(NetconfSession session,
+                        List<PortDescription> list,
+                        List<HierarchicalConfiguration> externalLinks) {
+        int degreeNumber = 0;
+        String nodeId = getDevice().annotations().value(AnnotationKeys.OPENROADM_NODEID);
+        List<HierarchicalConfiguration> degrees = getDegrees(session);
+        for (HierarchicalConfiguration degree : degrees) {
+            degreeNumber = degree.getInt("degree-number", 0);
+            // From OpenROADM Device model 2.2: degree-number must be > 0
+            if (degreeNumber == 0) {
+                log.warn("[OPENROADM] Device {} <degree-number> MUST be > 0", did());
+                continue;
+            }
+
+            List<HierarchicalConfiguration> connectionPorts =
+                degree.configurationsAt("connection-ports");
+            for (HierarchicalConfiguration cport : connectionPorts) {
+                int portIndex = cport.getInt("index", 0);
+                long portNum = degreeNumber * 10 + portIndex;
+                PortNumber pNum = PortNumber.portNumber(portNum);
+                String cpName = cport.getString("circuit-pack-name", "");
+                String portName = cport.getString("port-name", "");
+                PortNumber reversepNum = findDegreeReversePort(degreeNumber, portIndex, connectionPorts);
+                HierarchicalConfiguration eLink = parseExternalLink(externalLinks, nodeId, cpName, portName);
+                HierarchicalConfiguration circuitPack = getCircuitPackByName(session, cpName);
+                List<HierarchicalConfiguration> cpPorts =
+                    circuitPack.configurationsAt("ports[port-name='" + portName + "']");
+                if (cpPorts.size() > 1) {
+                    log.warn("[OPENROADM] {}: more than one port with the same name. Using first one", did());
+                }
+                HierarchicalConfiguration port = cpPorts.get(0);
+                PortDescription pd = buildDegreePortDesc(nodeId, cpName, pNum, reversepNum, port, eLink);
+                if (pd != null) {
+                    list.add(pd);
+                }
+            }
+        }
+
+        return list;
+    }
+
+   /**
+    * Parses SRG (ROADM) port information.
+    *
+    * @param session the NETConf session to the OpenROADM device.
+    * @param list  List of port descriptions to append to.
+    * @param externalLinks Hierarchical configuration containing all the external
+    *        links.
+    *
+    * Port-id is obtained from srg-number and the number of the client
+    * port contained in the <logical-connection-point> leaf.
+    * OpenROADM Device Whitepaper for release 2.2, sect. 7.2.2.2.1:
+    *     "For the ROADM SRG add/drop port, the logical connection point should
+    *      be set to the format “SRG<n>-PP<m>”, where <n> is the SRG number
+    *      and <m> is the add/drop port pair identifier. For example SRG1
+    *      add/drop port #7 would have the logical connection point set to
+    *      SRG1-PP7".
+    * The method extract <m> following the sustring PP and use it in conjuncion
+    * with the degree-number taken from the <degree> branch (If the datastore is
+    * consistent this should be the same number in SRG<n>).
+    * To avoid overlapping with IDs assigned to degrees, the srg-number is multiplied
+    * by 1000. The to cover the uni-directional case (that needs two IDs, one per
+    * direction) the port index is multiplied by 10.
+    * Using 1000 as multiplier avoids overlapping with degree port IDs as long as
+    * the number of degree in the ROADM is less than 100. Current optical
+    * technologies don't allow ROADMs having such a high number of degrees.
+    *
+    * For unidirectional links the logical connection point is assumed to
+    * have the form DEGn-PPi[-TX/-RX] and to the RX link is assigned an ID
+    * following (+1) the TX one.
+    * Ex. SRG1 second port bidirectional link (SRG1-PP2)
+    *                      ONOS port ID: 1020
+    *     SRG2 third port, unidirectional link (SRG2-PP3-TX, SRG2-PP3-RX)
+    *                      ONOS port IDs: 2030 and 2031
+    */
+    private List<PortDescription>
+    discoverSrgPorts(NetconfSession session,
+                     List<PortDescription> list,
+                     List<HierarchicalConfiguration> externalLinks) {
+        int srgNumber = 0;
+        String nodeId = getDevice().annotations().value(AnnotationKeys.OPENROADM_NODEID);
+        List<HierarchicalConfiguration> srgs = getSrgs(session);
+        for (HierarchicalConfiguration s : srgs) {
+            srgNumber = s.getInt("srg-number", 0);
+            // From OpenROADM Device model 2.2: srg-number must be > 0
+            if (srgNumber == 0) {
+                log.warn("[OPENROADM] Device {} <srg-number> MUST be > 0", did());
+                continue;
+            }
+
+            List<HierarchicalConfiguration> srgCircuitPacks =
+                s.configurationsAt("circuit-packs");
+            for (HierarchicalConfiguration scp : srgCircuitPacks) {
+                String srgCpName = scp.getString("circuit-pack-name");
+                HierarchicalConfiguration cpConf = getCircuitPackByName(session, srgCpName);
+
+                List<HierarchicalConfiguration> ports = cpConf.configurationsAt("ports[port-qual='roadm-external']");
+                for (HierarchicalConfiguration p : ports) {
+                    String portName = p.getString("port-name");
+                    String lcp = p.getString("logical-connection-point", "unknown");
+                    int ppIndex = lcp.indexOf("PP");
+                    if (ppIndex == -1) {
+                        log.warn("[OPENROADM] {}: cannot find port index for circuit-pack {}", did(), srgCpName);
+                    } else {
+                        long portNum, revPortNum;
+                        String[] split = lcp.split("-");
+                        // 1000 is chosen as base value to avoid overlapping
+                        // with IDs for degree ports that have 10 as base value
+                        long basePort = srgNumber * 1000 + Long.parseLong(split[1].replace("PP", "")) * 10;
+                        if (split.length > 2) {
+                        // Unidirectional port
+                            portNum = basePort + (split[2].equals("RX") ? 1 : 0);
+                            revPortNum = basePort + (split[2].equals("RX") ? 0 : 1);
+                        } else {
+                        // Bidirectional port
+                            portNum = basePort;
+                            revPortNum = 0;
+                        }
+                        PortNumber pNum = PortNumber.portNumber(portNum);
+                        PortNumber reversepNum = PortNumber.portNumber(revPortNum);
+                        HierarchicalConfiguration eLink = parseExternalLink(externalLinks, nodeId, srgCpName, portName);
+                        PortDescription pd = buildSrgPortDesc(nodeId, srgCpName, pNum, reversepNum, p, eLink);
+                        if (pd != null) {
+                            list.add(pd);
+                        }
+                    }
+                }
+            }
+        }
+
         return list;
     }
 
     /**
-     * Parses port information.
+     * Locate (if present) the external link for a given <circuit-pack, port> pair
+     * within the Hierarchical Configuration.
      *
-     *  @param list  List of port descriptions to append to.
-     *  @param nodeId OpenROADM node identifier.
-     *  @param circuitPackName Name of the circuit pack the ports belong to
-     *  @param ports hierarchical conf containing all the ports for the circuit
-     * pack
-     *  @param circuitPacks all the circuit packs (to correlate data).
-     *  @param extLinks Hierarchical configuration containing all the ext.
-     * links.
+     * @param extLinks Hierarchical configuration containing all the external
+     *        links.
+     * @param nodeId The OpenRoadm nodeId of the current node.
+     * @param circuitPackName name of the circuit pack of the port.
+     * @param portName name of the port.
+     * @return the external link.
      */
-    protected void parsePorts(List<PortDescription> list, String nodeId,
-                              String circuitPackName,
-                              List<HierarchicalConfiguration> ports,
-                              List<HierarchicalConfiguration> circuitPacks,
-                              List<HierarchicalConfiguration> extLinks) {
-        checkNotNull(nodeId);
-        checkNotNull(circuitPackName);
-        for (HierarchicalConfiguration port : ports) {
-            try {
-                String portName = checkNotNull(port.getString("port-name"));
-                long portNum = Long.parseLong(port.getString("label"));
-                PortNumber pNum = PortNumber.portNumber(portNum);
-                PortNumber reversepNum = findReversePort(port, circuitPacks);
-                // To see if we have an external port
-                HierarchicalConfiguration eLink = null;
-                for (HierarchicalConfiguration extLink : extLinks) {
-                    String eln =
-                        checkNotNull(extLink.getString("external-link-name"));
-                    String esnid =
-                        checkNotNull(extLink.getString("source/node-id"));
-                    String escpn =
-                        checkNotNull(extLink.getString("source/circuit-pack-name"));
-                    String espn =
-                        checkNotNull(extLink.getString("source/port-name"));
-                    if (nodeId.equals(esnid) && circuitPackName.equals(escpn) &&
-                            portName.equals(espn)) {
-                        eLink = extLink;
-                    }
+    private HierarchicalConfiguration parseExternalLink(List<HierarchicalConfiguration> extLinks,
+                                                        String nodeId,
+                                                        String circuitPackName,
+                                                        String portName) {
+        HierarchicalConfiguration eLink = null;
+        try {
+            for (HierarchicalConfiguration extLink : extLinks) {
+                String eln =
+                    checkNotNull(extLink.getString("external-link-name"));
+                String esnid =
+                    checkNotNull(extLink.getString("source/node-id"));
+                String escpn =
+                    checkNotNull(extLink.getString("source/circuit-pack-name"));
+                String espn =
+                    checkNotNull(extLink.getString("source/port-name"));
+                if (nodeId.equals(esnid) && circuitPackName.equals(escpn) &&
+                        portName.equals(espn)) {
+                    eLink = extLink;
                 }
-                PortDescription pd = parsePortComponent(
-                        nodeId, circuitPackName, pNum, reversepNum, port, eLink);
-                if (pd != null) {
-                    list.add(pd);
-                }
-            } catch (NetconfException e) {
-                log.error("[OPENROADM] {} NetConf exception", did());
-                return;
             }
+        } catch (NullPointerException e) {
+            log.error("[OPENROADM] {} invalid external-links", did());
         }
+        return eLink;
     }
 
+
     /**
-     * Given a device port (external), return its patner/reverse port.
+     * Given a degree port (external), return its partner/reverse port.
      *
-     * @param thisPort the port for which we are looking for the reverse port.
-     * @param circuitPacks all the circuit packs (to correlate data).
+     * @param degreeNumber Number identifying the current degree.
+     * @param portIndex the index of the port (degree branch) for which we are
+     *        looking for the reverse port.
+     * @param connPorts list of connection-ports as hierarchical configuration.
      * @return the port number for the reverse port.
-     * @throws NetconfException .
      */
     protected PortNumber
-    findReversePort(HierarchicalConfiguration thisPort,
-                    List<HierarchicalConfiguration> circuitPacks)
-      throws NetconfException {
-        String partnerCircuitPackName =
-          checkNotNull(thisPort.getString("partner-port/circuit-pack-name"));
-        String partnerPortName =
-          checkNotNull(thisPort.getString("partner-port/port-name"));
-        for (HierarchicalConfiguration c : circuitPacks) {
-            if (!partnerCircuitPackName.equals(
-                  c.getString("circuit-pack-name"))) {
-                continue;
-            }
-            for (HierarchicalConfiguration thatPort :
-                 c.configurationsAt("ports[port-qual='roadm-external']")) {
-                String thatPortName = thatPort.getString("port-name");
-                if (partnerPortName.equals(thatPortName)) {
-                    long thatPortNum =
-                      Long.parseLong(thatPort.getString("label"));
-                    return PortNumber.portNumber(thatPortNum);
-                }
+    findDegreeReversePort(int degreeNumber, int portIndex,
+                          List<HierarchicalConfiguration> connPorts) {
+        // bidirectional port.
+        if (connPorts.size() == 1) {
+            return PortNumber.portNumber(0);
+        }
+
+        for (HierarchicalConfiguration cp : connPorts) {
+            int revPortIndex = cp.getInt("index", -1);
+            if (revPortIndex != portIndex) {
+                return PortNumber.portNumber(10 * degreeNumber + revPortIndex);
             }
         }
         // We should not reach here
-        throw new NetconfException("missing partner/reverse port info");
+        return PortNumber.portNumber(0);
     }
 
     /**
      * Parses a component XML doc into a PortDescription.
      * An OMS port description is constructed from XML parsed data.
      *
-     * @param port the port to parse
-     * @return PortDescription or null
+     * @param nodeId The OpenRoadm nodeId of the current node.
+     * @param circuitPackName name of circuit pack containing the port.
+     * @param pNum the portNumber of the port.
+     * @param reversepNum the portNumber of the partner port.
+     * @param port the hierarchical configuration of the port to parse
+     * @param extLink Hierarchical configuration for the external links.
+     * @return PortDescription or null.
      */
     private PortDescription
-    parsePortComponent(String nodeId, String circuitPackName, PortNumber pNum,
-                       PortNumber reversepNum, HierarchicalConfiguration port,
-                       HierarchicalConfiguration extLink) {
+    buildDegreePortDesc(String nodeId, String circuitPackName,
+                        PortNumber pNum, PortNumber reversepNum,
+                        HierarchicalConfiguration port,
+                        HierarchicalConfiguration extLink) {
+        DefaultAnnotations annotations = createPortAnnotations(nodeId,
+                                                               circuitPackName,
+                                                               pNum,
+                                                               reversepNum,
+                                                               port,
+                                                               extLink);
+
+               // Relationship : START and STOP Freq not being used (See
+               // LambdaQuery)
+        return OmsPortHelper.omsPortDescription(pNum,
+                                                true /* enabled */,
+                                                START_CENTER_FREQ,
+                                                STOP_CENTER_FREQ,
+                                                CHANNEL_SPACING.frequency(),
+                                                annotations);
+    }
+
+    /**
+     * Parses a component XML doc into a PortDescription.
+     * An Och port description is constructed from XML parsed data.
+     *
+     * @param nodeId The OpenRoadm nodeId of the current node.
+     * @param circuitPackName name of circuit pack containing the port.
+     * @param pNum the portNumber of the port.
+     * @param reversepNum the portNumber of the partner port.
+     * @param port the hierarchical configuration of the port to parse
+     * @param extLink Hierarchical configuration for the external links.
+     * @return PortDescription or null.
+     */
+    private PortDescription
+    buildSrgPortDesc(String nodeId, String circuitPackName,
+                     PortNumber pNum, PortNumber reversepNum,
+                     HierarchicalConfiguration port,
+                     HierarchicalConfiguration extLink) {
+        DefaultAnnotations annotations = createPortAnnotations(nodeId,
+                                                               circuitPackName,
+                                                               pNum,
+                                                               reversepNum,
+                                                               port,
+                                                               extLink);
+
+        OchSignal signalId =
+                  OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 3);
+        return OchPortHelper.ochPortDescription(pNum,
+                                                true /* enabled */,
+                                                OduSignalType.ODU4,
+                                                true /* tunable */,
+                                                signalId,
+                                                annotations);
+
+    }
+    /**
+     * Creates annotations for the port.
+     *
+     * @param nodeId The OpenRoadm nodeId of the current node.
+     * @param circuitPackName name of circuit pack containing the port.
+     * @param pNum the portNumber of the port.
+     * @param reversepNum the portNumber of the partner port.
+     * @param port the hierarchical configuration of the port to parse
+     * @param extLink Hierarchical configuration for the external links.
+     * @return DefaultAnnotation.
+     */
+    private DefaultAnnotations
+    createPortAnnotations(String nodeId,
+                          String circuitPackName,
+                          PortNumber pNum,
+                          PortNumber reversepNum,
+                          HierarchicalConfiguration port,
+                          HierarchicalConfiguration extLink) {
         Map<String, String> annotations = new HashMap<>();
+        String portName = port.getString("port-name");
         annotations.put(AnnotationKeys.OPENROADM_NODEID, nodeId);
         annotations.put(AnnotationKeys.OPENROADM_CIRCUIT_PACK_NAME,
                         circuitPackName);
-        annotations.put(AnnotationKeys.OPENROADM_PORT_NAME,
-                        port.getString("port-name"));
+        annotations.put(org.onosproject.net.AnnotationKeys.PORT_NAME, portName);
+        annotations.put(AnnotationKeys.OPENROADM_PORT_NAME, portName);
         annotations.put(AnnotationKeys.OPENROADM_PARTNER_CIRCUIT_PACK_NAME,
                         port.getString("partner-port/circuit-pack-name", ""));
         annotations.put(AnnotationKeys.OPENROADM_PARTNER_PORT_NAME,
                         port.getString("partner-port/port-name", ""));
         annotations.put(AnnotationKeys.OPENROADM_LOGICAL_CONNECTION_POINT,
                         port.getString("logical-connection-point", ""));
-        // Annotate the reverse port, this is needed for bidir intents.
-        annotations.put(OpticalPathIntent.REVERSE_PORT_ANNOTATION_KEY,
-                        Long.toString(reversepNum.toLong()));
+        // Annotate the reverse port, this is needed for bidir intents
+        // (Partner port is present in the datastore only for
+        // unidirectional ports).
+        if (reversepNum.toLong() != 0) {
+            annotations.put(OpticalPathIntent.REVERSE_PORT_ANNOTATION_KEY,
+                            Long.toString(reversepNum.toLong()));
+        }
 
         // for backwards compatibility
         annotations.put("logical-connection-point",
@@ -548,28 +827,6 @@
             annotations.put("openroadm-external-port-name", edpn);
         }
 
-        /*
-         * Declare the actual optical port:
-         * Assumptions: client ports are OCh, assumed to carry ODU4 (should be
-         * configurable)
-         */
-        if (port.getString("port-wavelength-type", "wavelength")
-              .equals("wavelength")) {
-            // OchSignal is needed for OchPortDescription constructor, but it's
-            // tunable
-            OchSignal signalId =
-              OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 3);
-            return OchPortHelper.ochPortDescription(
-              pNum, true /* enabled */, OduSignalType.ODU4, true /* tunable */,
-              signalId,
-              DefaultAnnotations.builder().putAll(annotations).build());
-        } else {
-            return OmsPortHelper.omsPortDescription(
-              pNum, true /* enabled */,
-              // Relationship : START and STOP Freq  not being used (See
-              // LambdaQuery)
-              START_CENTER_FREQ, STOP_CENTER_FREQ, CHANNEL_SPACING.frequency(),
-              DefaultAnnotations.builder().putAll(annotations).build());
-        }
+        return DefaultAnnotations.builder().putAll(annotations).build();
     }
 }