Updating CassiniDriver according to testing with IPI

Change-Id: Ia183f0a9ef432909aafa5480ee5b740425aa1832
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniFlowRuleProgrammable.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniFlowRuleProgrammable.java
index fee9499..db46d8d 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniFlowRuleProgrammable.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniFlowRuleProgrammable.java
@@ -20,8 +20,8 @@
 
 import com.google.common.collect.ImmutableList;
 import org.onlab.util.Frequency;
-import org.onosproject.drivers.odtn.impl.FlowRuleParser;
 import org.onosproject.drivers.odtn.impl.DeviceConnectionCache;
+import org.onosproject.drivers.odtn.impl.FlowRuleParser;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
@@ -184,12 +184,15 @@
                         + " </oc-opt-term:optical-channel>"
                         + "</component>"
                         + "</components>");
-
-        boolean ok =
-                session.editConfig(DatastoreId.RUNNING, null, sb.toString());
+        log.info("Optical Channel Frequency {}", sb.toString());
+        boolean ok = session.editConfig(DatastoreId.CANDIDATE, null, sb.toString());
         if (!ok) {
             throw new NetconfException("error writing channel frequency");
         }
+        ok = session.commit();
+        if (!ok) {
+            throw new NetconfException("error committing channel frequency");
+        }
     }
 
     /**
@@ -205,7 +208,7 @@
 
     /**
      * Apply the flowrule.
-     *
+     * <p>
      * Note: only bidirectional are supported as of now,
      * given OpenConfig note (below). In consequence, only the
      * TX rules are actually mapped to netconf ops.
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 163bfb5..a271132 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
@@ -209,7 +209,7 @@
             XMLConfiguration xconf = NetconfSessionUtility.executeRpc(session, rpcReq.toString());
             try {
                 HierarchicalConfiguration config =
-                        xconf.configurationAt("data/components/component/optical-channel/config");
+                        xconf.configurationAt("components/component/optical-channel/config");
 
                 String modulationScheme = String.valueOf(config.getString("modulation"));
 
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniModulationOcNos.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniModulationOcNos.java
index 5daf5cc..53b56db 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniModulationOcNos.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniModulationOcNos.java
@@ -35,8 +35,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -60,10 +58,10 @@
 
 
     enum BitRate {
-        GBPS_200(20000000),      // 200 Gbps
-        GBPS_100(10000000),        // 100 Gbps
-        GBPS_40(4000000),          // 40 Gbps
-        GBPS_10(1000000);          // 10 Gbps
+        GBPS_200(200),      // 200 Gbps
+        GBPS_100(100),        // 100 Gbps
+        GBPS_40(40),          // 40 Gbps
+        GBPS_10(10);          // 10 Gbps
 
         private final long value;
 
@@ -228,12 +226,6 @@
 
         CassiniModulationOcNos cassini;
 
-        List<PortNumber> getPorts(Object component) {
-            // FIXME
-            log.warn("Not Implemented Yet!");
-            return new ArrayList<PortNumber>();
-        }
-
         /*
          * mirror method in the internal class.
          * @param port port
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniModulationOpenConfig.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniModulationOpenConfig.java
index bcb055f..5592041 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniModulationOpenConfig.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniModulationOpenConfig.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-present Open Networking Foundation
+ * Copyright 2019-present Open Networking Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@
 import org.onosproject.net.behaviour.ModulationConfig;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.netconf.DatastoreId;
 import org.onosproject.netconf.NetconfController;
 import org.onosproject.netconf.NetconfDevice;
 import org.onosproject.netconf.NetconfException;
@@ -35,8 +36,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -60,10 +59,10 @@
 
 
     enum BitRate {
-        GBPS_200(20000000),      // 200 Gbps
-        GBPS_100(10000000),        // 100 Gbps
-        GBPS_40(4000000),          // 40 Gbps
-        GBPS_10(1000000);          // 10 Gbps
+        GBPS_200(200),      // 200 Gbps
+        GBPS_100(100),        // 100 Gbps
+        GBPS_40(40),          // 40 Gbps
+        GBPS_10(10);          // 10 Gbps
 
         private final long value;
 
@@ -229,12 +228,6 @@
 
         CassiniModulationOpenConfig cassini;
 
-        List<PortNumber> getPorts(Object component) {
-            // FIXME
-            log.warn("Not Implemented Yet!");
-            return new ArrayList<PortNumber>();
-        }
-
         /*
          * mirror method in the internal class.
          * @param port port
@@ -257,7 +250,7 @@
             XMLConfiguration xconf = cassini.executeRpc(session, rpcReq.toString());
             try {
                 HierarchicalConfiguration config =
-                        xconf.configurationAt("data/components/component/optical-channel/config");
+                        xconf.configurationAt("components/component/optical-channel/config");
 
                 String modulationScheme = String.valueOf(config.getString("modulation"));
                 /*Used for Internal Testing */
@@ -387,7 +380,7 @@
             StringBuilder rpcReq = new StringBuilder();
             rpcReq.append(RPC_TAG_NETCONF_BASE)
                     .append("<edit-config>")
-                    .append("<target><running/></target>")
+                    .append("<target><" + DatastoreId.CANDIDATE + "/></target>")
                     .append("<config>")
                     .append(editConfig)
                     .append("</config>")
@@ -402,9 +395,13 @@
                 log.error("The <edit-config> operation to set target-modulation of Port({}:{}) is failed.",
                         port.toString(), component.toString());
             }
+            try {
+                session.commit();
+            } catch (NetconfException e) {
+                response = false;
+                log.error("error committing modulation changes");
+            }
             return response;
         }
     }
-
-
 }
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDeviceDiscovery.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDeviceDiscovery.java
index eeb885f..ebc1c65 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDeviceDiscovery.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDeviceDiscovery.java
@@ -18,32 +18,30 @@
 
 package org.onosproject.drivers.odtn;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableList;
 import org.apache.commons.configuration.HierarchicalConfiguration;
 import org.apache.commons.configuration.XMLConfiguration;
 import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
 import org.onlab.packet.ChassisId;
 import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port.Type;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalType;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DefaultDeviceDescription;
-import org.onosproject.net.device.DefaultPortDescription;
-import org.onosproject.net.device.DefaultPortDescription.Builder;
 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.optical.device.OchPortHelper;
 import org.onosproject.netconf.NetconfController;
 import org.onosproject.netconf.NetconfDevice;
 import org.onosproject.netconf.NetconfSession;
 import org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery;
-import org.onosproject.net.OchSignal;
-import org.onosproject.net.optical.device.OchPortHelper;
-import org.onosproject.net.OduSignalType;
-import org.onosproject.net.ChannelSpacing;
 import org.slf4j.Logger;
 
 import java.util.HashMap;
@@ -51,35 +49,27 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
+import static com.google.common.base.Preconditions.checkNotNull;
 import static org.slf4j.LoggerFactory.getLogger;
 
 
 /**
  * Driver Implementation of the DeviceDescrption discovery for OpenConfig
  * terminal devices.
- *
  */
 public class CassiniTerminalDeviceDiscovery
-    extends AbstractHandlerBehaviour
-    implements OdtnDeviceDescriptionDiscovery, DeviceDescriptionDiscovery {
+        extends AbstractHandlerBehaviour
+        implements OdtnDeviceDescriptionDiscovery, DeviceDescriptionDiscovery {
 
     private static final String RPC_TAG_NETCONF_BASE =
-        "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
+            "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
 
     private static final String RPC_CLOSE_TAG = "</rpc>";
 
-    private static final String OC_PLATFORM_TYPES_TRANSCEIVER =
-        "oc-platform-types:TRANSCEIVER";
-
-    private static final String OC_PLATFORM_TYPES_PORT =
-        "oc-platform-types:PORT";
-
     private static final String OC_TRANSPORT_TYPES_OPTICAL_CHANNEL =
-        "oc-opt-types:OPTICAL_CHANNEL";
+            "OPTICAL_CHANNEL";
 
     private static final Logger log = getLogger(CassiniTerminalDeviceDiscovery.class);
 
@@ -88,7 +78,6 @@
      * Returns the NetconfSession with the device for which the method was called.
      *
      * @param deviceId device indetifier
-     *
      * @return The netconf session or null
      */
     private NetconfSession getNetconfSession(DeviceId deviceId) {
@@ -130,35 +119,23 @@
     }
 
 
-    /**
-     * Builds a request to get Device Components, config and operational data.
-     *
-     * @return A string with the Netconf RPC for a get with subtree rpcing based on
-     *    /components/
-     */
-    private String getTerminalDeviceBuilder() {
-        return filteredGetBuilder("<terminal-device xmlns='http://openconfig.net/yang/terminal-device'/>");
-    }
-
-
     @Override
     public DeviceDescription discoverDeviceDetails() {
         return new DefaultDeviceDescription(handler().data().deviceId().uri(),
-                                            Device.Type.TERMINAL_DEVICE,
-                                            "EDGECORE",
-                                            "Cassini",
-                                            "OcNOS",
-                                            "",
-                                            new ChassisId("1"));
+                Device.Type.TERMINAL_DEVICE,
+                "EDGECORE",
+                "Cassini",
+                "OcNOS",
+                "",
+                new ChassisId("1"));
     }
 
 
-
     /**
      * Returns a list of PortDescriptions for the device.
      *
      * @return a list of descriptions.
-     *
+     * <p>
      * The RPC reply follows the following pattern:
      * //CHECKSTYLE:OFF
      * <pre>{@code
@@ -184,134 +161,124 @@
                 log.error("discoverPortDetails called with null session for {}", did());
                 return ImmutableList.of();
             }
+            CompletableFuture<CharSequence> fut1 = session.asyncGet();
+            String rpcReplyTest = fut1.get().toString();
 
-            CompletableFuture<String> fut = session.rpc(getTerminalDeviceBuilder());
-            String rpcReply = fut.get();
-
-            XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(rpcReply);
+            XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(rpcReplyTest);
             xconf.setExpressionEngine(new XPathExpressionEngine());
 
-            HierarchicalConfiguration logicalChannels = xconf.configurationAt("data/terminal-device/logical-channels");
-            return parseLogicalChannels(logicalChannels);
+            HierarchicalConfiguration logicalChannels = xconf.configurationAt("components");
+            return discoverPorts(logicalChannels);
         } catch (Exception e) {
             log.error("Exception discoverPortDetails() {}", did(), e);
             return ImmutableList.of();
         }
     }
 
-
-
-
     /**
-     * Parses transceiver information from OpenConfig XML configuration.
+     * Parses port information from OpenConfig XML configuration.
      *
-     * @param terminalDevice the XML document with components root.
+     * @param cfg tree where the root node is {@literal <data>}
      * @return List of ports
-     *
-     * //CHECKSTYLE:OFF
-     * <pre>{@code
-     *   <components xmlns="http://openconfig.net/yang/platform">
-     *     <component>....
-     *     </component>
-     *     <component>....
-     *     </component>
-     *   </components>
-     * }</pre>
-     * //CHECKSTYLE:ON
      */
-    protected List<PortDescription> parseLogicalChannels(HierarchicalConfiguration terminalDevice) {
-        return terminalDevice.configurationsAt("channel")
-            .stream()
-            .filter(channel -> !channel.getString("index", "unknown").equals("unknown"))
-            .map(channel -> {
-                try {
-                    // Pass the root document for cross-reference
-                    return parseLogicalChannel(channel);
-                } catch (Exception e) {
-                    return null;
-                }
-                })
-            .filter(Objects::nonNull)
-            .collect(Collectors.toList());
+    @VisibleForTesting
+    private List<PortDescription> discoverPorts(HierarchicalConfiguration cfg) {
+        // If we want to use XPath
+        cfg.setExpressionEngine(new XPathExpressionEngine());
+        // converting components into PortDescription.
+        List<HierarchicalConfiguration> components = cfg.configurationsAt("component");
+        return components.stream()
+                .map(this::toPortDescriptionInternal)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
     }
 
+    /**
+     * Converts Component subtree to PortDescription.
+     *
+     * @param component subtree to parse
+     * @return PortDescription or null if component is not an ONOS Port
+     */
+    private PortDescription toPortDescriptionInternal(HierarchicalConfiguration component) {
+        Map<String, String> annotations = new HashMap<>();
+         /*
+        <components xmlns="http://openconfig.net/yang/platform">
+             <component>
+                <name>oc1/0</name>
+                 <config>
+                    <name>oc1/0</name>
+                 </config>
+                 <state>
+                    <name>oc1/0</name>
+                 <type>OPTICAL_CHANNEL</type>
+                <id/>
+                <description/>
+                <mfg-name/>
+                <hardware-version/>
+                <firmware-version/>
+                <software-version/>
+                <serial-no/>
+                <part-no/>
+                <removable>true</removable>
+                <empty>false</empty>
+                <parent/>
+                <temperature>
+                <instant>0.0</instant>
+                <avg>0.0</avg>
+                <min>0.0</min>
+                <max>0.0</max>
+                <interval>0</interval>
+                <min-time>0</min-time>
+                <max-time>0</max-time>
+                <alarm-status>true</alarm-status>
+                <alarm-threshold>0</alarm-threshold>
+                </temperature>
+                <memory>
+                    <available>0</available>
+                    <utilized>0</utilized>
+                </memory>
+                <allocated-power>0</allocated-power>
+                <used-power>0</used-power>
+            </state>
+            <optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+                <config>
+                    <line-port>port-10101</line-port>
+                </config>
+            <state>
+                <output-power/>
+                <input-power/>
+            </state>
+            </optical-channel>
+        </component>
+        */
+        String name = component.getString("name");
+        String type = component.getString("state/type");
+        checkNotNull(name, "name not found");
+        checkNotNull(type, "state/type not found");
+        annotations.put(OdtnDeviceDescriptionDiscovery.OC_NAME, name);
+        annotations.put(OdtnDeviceDescriptionDiscovery.OC_TYPE, type);
 
-     /**
-      * Parses a component XML doc into a PortDescription.
-      *
-      * @param channel subtree to parse. It must be a component ot type PORT.
-      *  case we need to check transceivers or optical channels.
-      *
-      * @return PortDescription or null if component does not have onos-index
-      */
-     private PortDescription parseLogicalChannel(
-             HierarchicalConfiguration channel) {
+        //TODO this currently support only line-side ports through parsing of optical channels.
+        if (type.equals(OC_TRANSPORT_TYPES_OPTICAL_CHANNEL)) {
+            String portName = component.getString("optical-channel/config/line-port");
+            String portIndex = portName.split("-")[1];
+            annotations.putIfAbsent("name", portName);
+            annotations.putIfAbsent(PORT_TYPE, OdtnPortType.LINE.value());
+            annotations.putIfAbsent(ONOS_PORT_INDEX, portIndex);
+            annotations.putIfAbsent(CONNECTION_ID, "connection-" + portIndex);
 
-         HierarchicalConfiguration config = channel.configurationAt("config");
-         String logicalChannelIndex = config.getString("index");
-         String description = config.getString("description");
-         String rateClass = config.getString("rate-class");
-         log.info("Parsing Component {} type {} rate {}", logicalChannelIndex, description, rateClass);
+            OchSignal signalId = OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1);
+            return OchPortHelper.ochPortDescription(
+                    PortNumber.portNumber(Long.parseLong(portIndex)),
+                    true,
+                    OduSignalType.ODU4, // TODO Client signal to be discovered
+                    true,
+                    signalId,
+                    DefaultAnnotations.builder().putAll(annotations).build());
 
-         Map<String, String> annotations = new HashMap<>();
-         annotations.put(OdtnDeviceDescriptionDiscovery.OC_LOGICAL_CHANNEL, logicalChannelIndex);
-         annotations.put(OdtnDeviceDescriptionDiscovery.OC_NAME, description);
-
-         // Store all properties as port properties
-
-         Pattern clientPattern = Pattern.compile("xe(\\d*)/1"); // e.g. xe1/1
-         Pattern linePattern = Pattern.compile("oe(\\d*)/(\\d*)"); // e.g. oe1
-         Matcher clientMatch = clientPattern.matcher(description);
-         Matcher lineMatch = linePattern.matcher(description);
-
-         Pattern portSpeedPattern = Pattern.compile("TRIB_RATE_([0-9.]*)G");
-         Matcher portSpeedMatch = portSpeedPattern.matcher(rateClass);
-
-
-         Builder builder = DefaultPortDescription.builder();
-
-         if (portSpeedMatch.find()) {
-             Long speed = Long.parseLong(portSpeedMatch.group(1));
-             builder.portSpeed(speed * 1000);
-         }
-
-         if (clientMatch.find()) {
-             Long num = Long.parseLong(clientMatch.group(1));
-             Long portNum = 100 + num;
-             String connectionId = "connection:" + num.toString();
-
-             annotations.putIfAbsent(PORT_TYPE, OdtnPortType.CLIENT.value());
-             annotations.putIfAbsent(ONOS_PORT_INDEX, portNum.toString());
-             annotations.putIfAbsent(CONNECTION_ID, connectionId);
-
-             builder.withPortNumber(PortNumber.portNumber(portNum));
-             builder.type(Type.PACKET);
-
-             builder.annotations(DefaultAnnotations.builder().putAll(annotations).build());
-             return builder.build();
-
-         } else if (lineMatch.find()) {
-             Long num = (Long.parseLong(lineMatch.group(1)) - 1) * 2 + Long.parseLong(lineMatch.group(2));
-             Long portNum = 200 + num;
-             String connectionId = "connection:" + num.toString();
-
-             annotations.putIfAbsent(PORT_TYPE, OdtnPortType.LINE.value());
-             annotations.putIfAbsent(ONOS_PORT_INDEX, portNum.toString());
-             annotations.putIfAbsent(CONNECTION_ID, connectionId);
-
-             OchSignal signalId = OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1);
-             return OchPortHelper.ochPortDescription(
-                     PortNumber.portNumber(portNum),
-                     true,
-                     OduSignalType.ODU4, // TODO Client signal to be discovered
-                     true,
-                     signalId,
-                     DefaultAnnotations.builder().putAll(annotations).build());
-
-         } else {
-             log.warn("Unexpected component description: {}", description);
-             return null;
-         }
-
-     }
+        } else {
+            log.debug("Unknown port component type {}", type);
+            return null;
+        }
+    }
 }
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDeviceDiscoveryOld.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDeviceDiscoveryOld.java
new file mode 100644
index 0000000..19b247e
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDeviceDiscoveryOld.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ *
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+
+package org.onosproject.drivers.odtn;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
+import org.onlab.packet.ChassisId;
+import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalType;
+import org.onosproject.net.Port.Type;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DefaultDeviceDescription;
+import org.onosproject.net.device.DefaultPortDescription;
+import org.onosproject.net.device.DefaultPortDescription.Builder;
+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.optical.device.OchPortHelper;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery;
+import org.slf4j.Logger;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+
+/**
+ * Driver Implementation of the DeviceDescrption discovery for OpenConfig
+ * terminal devices.
+ *
+ */
+public class CassiniTerminalDeviceDiscoveryOld
+    extends AbstractHandlerBehaviour
+    implements OdtnDeviceDescriptionDiscovery, DeviceDescriptionDiscovery {
+
+    private static final String RPC_TAG_NETCONF_BASE =
+        "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
+
+    private static final String RPC_CLOSE_TAG = "</rpc>";
+
+    private static final String OC_PLATFORM_TYPES_TRANSCEIVER =
+        "oc-platform-types:TRANSCEIVER";
+
+    private static final String OC_PLATFORM_TYPES_PORT =
+        "oc-platform-types:PORT";
+
+    private static final String OC_TRANSPORT_TYPES_OPTICAL_CHANNEL =
+        "oc-opt-types:OPTICAL_CHANNEL";
+
+    private static final Logger log = getLogger(CassiniTerminalDeviceDiscoveryOld.class);
+
+
+    /**
+     * Returns the NetconfSession with the device for which the method was called.
+     *
+     * @param deviceId device indetifier
+     *
+     * @return The netconf session or null
+     */
+    private NetconfSession getNetconfSession(DeviceId deviceId) {
+        NetconfController controller = handler().get(NetconfController.class);
+        NetconfDevice ncdev = controller.getDevicesMap().get(deviceId);
+        if (ncdev == null) {
+            log.trace("No netconf device, returning null session");
+            return null;
+        }
+        return ncdev.getSession();
+    }
+
+
+    /**
+     * Get the deviceId for which the methods apply.
+     *
+     * @return The deviceId as contained in the handler data
+     */
+    private DeviceId did() {
+        return handler().data().deviceId();
+    }
+
+
+    /**
+     * Construct a String with a Netconf filtered get RPC Message.
+     *
+     * @param filter A valid XML tree with the filter to apply in the get
+     * @return a String containing the RPC XML Document
+     */
+    private String filteredGetBuilder(String filter) {
+        StringBuilder rpc = new StringBuilder(RPC_TAG_NETCONF_BASE);
+        rpc.append("<get>");
+        rpc.append("<filter type='subtree'>");
+        rpc.append(filter);
+        rpc.append("</filter>");
+        rpc.append("</get>");
+        rpc.append(RPC_CLOSE_TAG);
+        return rpc.toString();
+    }
+
+
+    /**
+     * Builds a request to get Device Components, config and operational data.
+     *
+     * @return A string with the Netconf RPC for a get with subtree rpcing based on
+     *    /components/
+     */
+    private String getTerminalDeviceBuilder() {
+        return filteredGetBuilder("<terminal-device xmlns='http://openconfig.net/yang/terminal-device'/>");
+    }
+
+
+    @Override
+    public DeviceDescription discoverDeviceDetails() {
+        return new DefaultDeviceDescription(handler().data().deviceId().uri(),
+                                            Device.Type.TERMINAL_DEVICE,
+                                            "EDGECORE",
+                                            "Cassini",
+                                            "OcNOS",
+                                            "",
+                                            new ChassisId("1"));
+    }
+
+
+
+    /**
+     * Returns a list of PortDescriptions for the device.
+     *
+     * @return a list of descriptions.
+     *
+     * The RPC reply follows the following pattern:
+     * //CHECKSTYLE:OFF
+     * <pre>{@code
+     * <?xml version="1.0" encoding="UTF-8"?>
+     * <rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="7">
+     * <data>
+     *   <components xmlns="http://openconfig.net/yang/platform">
+     *     <component>....
+     *     </component>
+     *     <component>....
+     *     </component>
+     *   </components>
+     * </data>
+     * </rpc-reply>
+     * }</pre>
+     * //CHECKSTYLE:ON
+     */
+    @Override
+    public List<PortDescription> discoverPortDetails() {
+        try {
+            NetconfSession session = getNetconfSession(did());
+            if (session == null) {
+                log.error("discoverPortDetails called with null session for {}", did());
+                return ImmutableList.of();
+            }
+
+            CompletableFuture<String> fut = session.rpc(getTerminalDeviceBuilder());
+            String rpcReply = fut.get();
+
+            XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(rpcReply);
+            xconf.setExpressionEngine(new XPathExpressionEngine());
+
+            HierarchicalConfiguration logicalChannels = xconf.configurationAt("data/terminal-device/logical-channels");
+            return parseLogicalChannels(logicalChannels);
+        } catch (Exception e) {
+            log.error("Exception discoverPortDetails() {}", did(), e);
+            return ImmutableList.of();
+        }
+    }
+
+
+
+
+    /**
+     * Parses transceiver information from OpenConfig XML configuration.
+     *
+     * @param terminalDevice the XML document with components root.
+     * @return List of ports
+     *
+     * //CHECKSTYLE:OFF
+     * <pre>{@code
+     *   <components xmlns="http://openconfig.net/yang/platform">
+     *     <component>....
+     *     </component>
+     *     <component>....
+     *     </component>
+     *   </components>
+     * }</pre>
+     * //CHECKSTYLE:ON
+     */
+    protected List<PortDescription> parseLogicalChannels(HierarchicalConfiguration terminalDevice) {
+        return terminalDevice.configurationsAt("channel")
+            .stream()
+            .filter(channel -> !channel.getString("index", "unknown").equals("unknown"))
+            .map(channel -> {
+                try {
+                    // Pass the root document for cross-reference
+                    return parseLogicalChannel(channel);
+                } catch (Exception e) {
+                    return null;
+                }
+                })
+            .filter(Objects::nonNull)
+            .collect(Collectors.toList());
+    }
+
+
+     /**
+      * Parses a component XML doc into a PortDescription.
+      *
+      * @param channel subtree to parse. It must be a component ot type PORT.
+      *  case we need to check transceivers or optical channels.
+      *
+      * @return PortDescription or null if component does not have onos-index
+      */
+     private PortDescription parseLogicalChannel(
+             HierarchicalConfiguration channel) {
+
+         HierarchicalConfiguration config = channel.configurationAt("config");
+         String logicalChannelIndex = config.getString("index");
+         String description = config.getString("description");
+         String rateClass = config.getString("rate-class");
+         log.info("Parsing Component {} type {} rate {}", logicalChannelIndex, description, rateClass);
+
+         Map<String, String> annotations = new HashMap<>();
+         annotations.put(OdtnDeviceDescriptionDiscovery.OC_LOGICAL_CHANNEL, logicalChannelIndex);
+         annotations.put(OdtnDeviceDescriptionDiscovery.OC_NAME, description);
+
+         // Store all properties as port properties
+
+         Pattern clientPattern = Pattern.compile("xe(\\d*)/1"); // e.g. xe1/1
+         Pattern linePattern = Pattern.compile("oe(\\d*)/(\\d*)"); // e.g. oe1
+         Matcher clientMatch = clientPattern.matcher(description);
+         Matcher lineMatch = linePattern.matcher(description);
+
+         Pattern portSpeedPattern = Pattern.compile("TRIB_RATE_([0-9.]*)G");
+         Matcher portSpeedMatch = portSpeedPattern.matcher(rateClass);
+
+
+         Builder builder = DefaultPortDescription.builder();
+
+         if (portSpeedMatch.find()) {
+             Long speed = Long.parseLong(portSpeedMatch.group(1));
+             builder.portSpeed(speed * 1000);
+         }
+
+         if (clientMatch.find()) {
+             Long num = Long.parseLong(clientMatch.group(1));
+             Long portNum = 100 + num;
+             String connectionId = "connection:" + num.toString();
+
+             annotations.putIfAbsent(PORT_TYPE, OdtnPortType.CLIENT.value());
+             annotations.putIfAbsent(ONOS_PORT_INDEX, portNum.toString());
+             annotations.putIfAbsent(CONNECTION_ID, connectionId);
+
+             builder.withPortNumber(PortNumber.portNumber(portNum));
+             builder.type(Type.PACKET);
+
+             builder.annotations(DefaultAnnotations.builder().putAll(annotations).build());
+             return builder.build();
+
+         } else if (lineMatch.find()) {
+             Long num = (Long.parseLong(lineMatch.group(1)) - 1) * 2 + Long.parseLong(lineMatch.group(2));
+             Long portNum = 200 + num;
+             String connectionId = "connection:" + num.toString();
+
+             annotations.putIfAbsent(PORT_TYPE, OdtnPortType.LINE.value());
+             annotations.putIfAbsent(ONOS_PORT_INDEX, portNum.toString());
+             annotations.putIfAbsent(CONNECTION_ID, connectionId);
+
+             OchSignal signalId = OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1);
+             return OchPortHelper.ochPortDescription(
+                     PortNumber.portNumber(portNum),
+                     true,
+                     OduSignalType.ODU4, // TODO Client signal to be discovered
+                     true,
+                     signalId,
+                     DefaultAnnotations.builder().putAll(annotations).build());
+
+         } else {
+             log.warn("Unexpected component description: {}", description);
+             return null;
+         }
+
+     }
+}
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDevicePowerConfig.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDevicePowerConfig.java
index 564686e..33dc66b 100644
--- a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDevicePowerConfig.java
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDevicePowerConfig.java
@@ -29,6 +29,7 @@
 import org.onosproject.net.behaviour.PowerConfig;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.netconf.DatastoreId;
 import org.onosproject.netconf.NetconfController;
 import org.onosproject.netconf.NetconfDevice;
 import org.onosproject.netconf.NetconfException;
@@ -240,7 +241,7 @@
             XMLConfiguration xconf = cassini.executeRpc(session, rpcReq.toString());
             try {
                 HierarchicalConfiguration config =
-                        xconf.configurationAt("data/components/component/optical-channel/config");
+                        xconf.configurationAt("components/component/optical-channel/state");
                 long power = Float.valueOf(config.getString("target-output-power")).longValue();
                 return Optional.of(power);
             } catch (IllegalArgumentException e) {
@@ -261,18 +262,24 @@
             StringBuilder rpcReq = new StringBuilder();
             rpcReq.append(RPC_TAG_NETCONF_BASE)
                     .append("<edit-config>")
-                    .append("<target><running/></target>")
+                    .append("<target><" + DatastoreId.CANDIDATE + "/></target>")
                     .append("<config>")
                     .append(editConfig)
                     .append("</config>")
                     .append("</edit-config>")
                     .append(RPC_CLOSE_TAG);
+            log.info("Setting power {}", rpcReq.toString());
             XMLConfiguration xconf = cassini.executeRpc(session, rpcReq.toString());
             // The successful reply should be "<rpc-reply ...><ok /></rpc-reply>"
             if (!xconf.getRoot().getChild(0).getName().equals("ok")) {
                 log.error("The <edit-config> operation to set target-output-power of Port({}:{}) is failed.",
                         port.toString(), component.toString());
             }
+            try {
+                session.commit();
+            } catch (NetconfException e) {
+                log.error("error committing channel power");
+            }
         }
 
         /**
@@ -286,7 +293,7 @@
                                     cassini, port, "<output-power><instant/></output-power>");
             try {
                 HierarchicalConfiguration config =
-                        xconf.configurationAt("data/components/component/optical-channel/state/output-power");
+                        xconf.configurationAt("components/component/optical-channel/state/output-power");
                 long currentPower = Float.valueOf(config.getString("instant")).longValue();
                 return Optional.of(currentPower);
             } catch (IllegalArgumentException e) {
@@ -305,7 +312,7 @@
                     cassini, port, "<input-power><instant/></input-power>");
             try {
                 HierarchicalConfiguration config =
-                        xconf.configurationAt("data/components/component/optical-channel/state/input-power");
+                        xconf.configurationAt("components/component/optical-channel/state/input-power");
                 long currentPower = Float.valueOf(config.getString("instant")).longValue();
                 return Optional.of(currentPower);
             } catch (IllegalArgumentException e) {
@@ -314,32 +321,15 @@
         }
 
         Optional<Range<Long>> getTargetPowerRange(PortNumber port, Object component) {
-            XMLConfiguration xconf = getOpticalChannelState(
-                    cassini, port, "<target-power-range/>");
-            try {
-                HierarchicalConfiguration config =
-                        xconf.configurationAt("data/components/component/optical-channel/state/target-power-range");
-                long targetMin = Float.valueOf(config.getString("min")).longValue();
-                long targetMax = Float.valueOf(config.getString("max")).longValue();
+                long targetMin = -30;
+                long targetMax = 1;
                 return Optional.of(Range.open(targetMin, targetMax));
-            } catch (IllegalArgumentException e) {
-                return Optional.empty();
-            }
-
         }
 
         Optional<Range<Long>> getInputPowerRange(PortNumber port, Object component) {
-            XMLConfiguration xconf = getOpticalChannelState(
-                    cassini, port, "<input-power-range/>");
-            try {
-                HierarchicalConfiguration config =
-                        xconf.configurationAt("data/components/component/optical-channel/state/input-power-range");
-                long inputMin = Float.valueOf(config.getString("min")).longValue();
-                long inputMax = Float.valueOf(config.getString("max")).longValue();
-                return Optional.of(Range.open(inputMin, inputMax));
-            } catch (IllegalArgumentException e) {
-                return Optional.empty();
-            }
+            long targetMin = -30;
+            long targetMax = 1;
+            return Optional.of(Range.open(targetMin, targetMax));
         }
 
         List<PortNumber> getPorts(Object component) {
diff --git a/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDevicePowerConfigExt.java b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDevicePowerConfigExt.java
new file mode 100644
index 0000000..0029fff
--- /dev/null
+++ b/drivers/odtn-driver/src/main/java/org/onosproject/drivers/odtn/CassiniTerminalDevicePowerConfigExt.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ *
+ * This work was partially supported by EC H2020 project METRO-HAUL (761727).
+ */
+
+package org.onosproject.drivers.odtn;
+
+import com.google.common.collect.Range;
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.PowerConfig;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Driver Implementation of the PowerConfig for OpenConfig terminal devices.
+ *
+ */
+public class CassiniTerminalDevicePowerConfigExt<T>
+        extends AbstractHandlerBehaviour implements PowerConfig<T> {
+
+    private static final String RPC_TAG_NETCONF_BASE =
+            "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
+
+    private static final String RPC_CLOSE_TAG = "</rpc>";
+
+    private static final long NO_POWER = -50;
+
+    private static final Logger log = getLogger(CassiniTerminalDevicePowerConfigExt.class);
+
+    private ComponentType state = ComponentType.DIRECTION;
+
+    /**
+     * Returns the NetconfSession with the device for which the method was called.
+     *
+     * @param deviceId device indetifier
+     *
+     * @return The netconf session or null
+     */
+    private NetconfSession getNetconfSession(DeviceId deviceId) {
+        NetconfController controller = handler().get(NetconfController.class);
+        NetconfDevice ncdev = controller.getDevicesMap().get(deviceId);
+        if (ncdev == null) {
+            log.trace("No netconf device, returning null session");
+            return null;
+        }
+        return ncdev.getSession();
+    }
+
+    /**
+     * Get the deviceId for which the methods apply.
+     *
+     * @return The deviceId as contained in the handler data
+     */
+    private DeviceId did() {
+        return handler().data().deviceId();
+    }
+
+    /**
+     * Execute RPC request.
+     * @param session Netconf session
+     * @param message Netconf message in XML format
+     * @return XMLConfiguration object
+     */
+    private XMLConfiguration executeRpc(NetconfSession session, String message) {
+        try {
+            CompletableFuture<String> fut = session.rpc(message);
+            String rpcReply = fut.get();
+            XMLConfiguration xconf = (XMLConfiguration) XmlConfigParser.loadXmlString(rpcReply);
+            xconf.setExpressionEngine(new XPathExpressionEngine());
+            return xconf;
+        } catch (NetconfException ne) {
+            log.error("Exception on Netconf protocol: {}.", ne);
+        } catch (InterruptedException ie) {
+            log.error("Interrupted Exception: {}.", ie);
+        } catch (ExecutionException ee) {
+            log.error("Concurrent Exception while executing Netconf operation: {}.", ee);
+        }
+        return null;
+    }
+
+    /**
+     * Get the target-output-power value on specific optical-channel.
+     * @param port the port
+     * @param component the port component. It should be 'oc-name' in the Annotations of Port.
+     *                  'oc-name' could be mapped to '/component/name' in openconfig yang.
+     * @return target power value
+     */
+    @Override
+    public Optional<Long> getTargetPower(PortNumber port, T component) {
+        checkState(component);
+        return state.getTargetPower(port, component);
+    }
+
+    @Override
+    public void setTargetPower(PortNumber port, T component, long power) {
+        checkState(component);
+        state.setTargetPower(port, component, power);
+    }
+
+    @Override
+    public Optional<Long> currentPower(PortNumber port, T component) {
+        checkState(component);
+        return state.currentPower(port, component);
+    }
+
+    @Override
+    public Optional<Long> currentInputPower(PortNumber port, T component) {
+        checkState(component);
+        return state.currentInputPower(port, component);
+    }
+
+    @Override
+    public Optional<Range<Long>> getTargetPowerRange(PortNumber port, T component) {
+        checkState(component);
+        return state.getTargetPowerRange(port, component);
+    }
+
+    @Override
+    public Optional<Range<Long>> getInputPowerRange(PortNumber port, T component) {
+        checkState(component);
+        return state.getInputPowerRange(port, component);
+    }
+
+    @Override
+    public List<PortNumber> getPorts(T component) {
+        checkState(component);
+        return state.getPorts(component);
+    }
+
+
+    /**
+     * Set the ComponentType to invoke proper methods for different template T.
+     * @param component the component.
+     */
+    void checkState(Object component) {
+        String clsName = component.getClass().getName();
+        switch (clsName) {
+            case "org.onosproject.net.Direction":
+                state = ComponentType.DIRECTION;
+                break;
+            case "org.onosproject.net.OchSignal":
+                state = ComponentType.OCHSIGNAL;
+                break;
+            default:
+                log.error("Cannot parse the component type {}.", clsName);
+                log.info("The component content is {}.", component.toString());
+        }
+        state.cassini = this;
+    }
+
+    /**
+     * Component type.
+     */
+    enum ComponentType {
+
+        /**
+         * Direction.
+         */
+        DIRECTION() {
+            @Override
+            public Optional<Long> getTargetPower(PortNumber port, Object component) {
+                return super.getTargetPower(port, component);
+            }
+            @Override
+            public void setTargetPower(PortNumber port, Object component, long power) {
+                super.setTargetPower(port, component, power);
+            }
+        },
+
+        /**
+         * OchSignal.
+         */
+        OCHSIGNAL() {
+            @Override
+            public Optional<Long> getTargetPower(PortNumber port, Object component) {
+                return super.getTargetPower(port, component);
+            }
+
+            @Override
+            public void setTargetPower(PortNumber port, Object component, long power) {
+                super.setTargetPower(port, component, power);
+            }
+        };
+
+
+
+        CassiniTerminalDevicePowerConfigExt cassini;
+
+        /**
+         * mirror method in the internal class.
+         * @param port port
+         * @param component component
+         * @return target power
+         */
+        Optional<Long> getTargetPower(PortNumber port, Object component) {
+            NetconfSession session = cassini.getNetconfSession(cassini.did());
+            checkNotNull(session);
+            String filter = parsePort(cassini, port, null, null);
+            StringBuilder rpcReq = new StringBuilder();
+            rpcReq.append(RPC_TAG_NETCONF_BASE)
+                    .append("<get>")
+                    .append("<filter type='subtree'>")
+                    .append(filter)
+                    .append("</filter>")
+                    .append("</get>")
+                    .append(RPC_CLOSE_TAG);
+            XMLConfiguration xconf = cassini.executeRpc(session, rpcReq.toString());
+            try {
+                HierarchicalConfiguration config =
+                        xconf.configurationAt("data/components/component/optical-channel/config");
+                long power = Float.valueOf(config.getString("target-output-power")).longValue();
+                return Optional.of(power);
+            } catch (IllegalArgumentException e) {
+                return Optional.empty();
+            }
+        }
+
+        /**
+         * mirror method in the internal class.
+         * @param port port
+         * @param component component
+         * @param power target value
+         */
+        void setTargetPower(PortNumber port, Object component, long power) {
+            NetconfSession session = cassini.getNetconfSession(cassini.did());
+            checkNotNull(session);
+            String editConfig = parsePort(cassini, port, null, power);
+            StringBuilder rpcReq = new StringBuilder();
+            rpcReq.append(RPC_TAG_NETCONF_BASE)
+                    .append("<edit-config>")
+                    .append("<target><running/></target>")
+                    .append("<config>")
+                    .append(editConfig)
+                    .append("</config>")
+                    .append("</edit-config>")
+                    .append(RPC_CLOSE_TAG);
+            XMLConfiguration xconf = cassini.executeRpc(session, rpcReq.toString());
+            // The successful reply should be "<rpc-reply ...><ok /></rpc-reply>"
+            if (!xconf.getRoot().getChild(0).getName().equals("ok")) {
+                log.error("The <edit-config> operation to set target-output-power of Port({}:{}) is failed.",
+                        port.toString(), component.toString());
+            }
+        }
+
+        /**
+         * mirror method in the internal class.
+         * @param port port
+         * @param component the component.
+         * @return current output power.
+         */
+        Optional<Long> currentPower(PortNumber port, Object component) {
+            XMLConfiguration xconf = getOpticalChannelState(
+                                    cassini, port, "<output-power><instant/></output-power>");
+            try {
+                HierarchicalConfiguration config =
+                        xconf.configurationAt("data/components/component/optical-channel/state/output-power");
+                long currentPower = Float.valueOf(config.getString("instant")).longValue();
+                return Optional.of(currentPower);
+            } catch (IllegalArgumentException e) {
+                return Optional.empty();
+            }
+        }
+
+        /**
+         * mirror method in the internal class.
+         * @param port port
+         * @param component the component
+         * @return current input power
+         */
+        Optional<Long> currentInputPower(PortNumber port, Object component) {
+            XMLConfiguration xconf = getOpticalChannelState(
+                    cassini, port, "<input-power><instant/></input-power>");
+            try {
+                HierarchicalConfiguration config =
+                        xconf.configurationAt("data/components/component/optical-channel/state/input-power");
+                long currentPower = Float.valueOf(config.getString("instant")).longValue();
+                return Optional.of(currentPower);
+            } catch (IllegalArgumentException e) {
+                return Optional.empty();
+            }
+        }
+
+        Optional<Range<Long>> getTargetPowerRange(PortNumber port, Object component) {
+            XMLConfiguration xconf = getOpticalChannelState(
+                    cassini, port, "<target-power-range/>");
+            try {
+                HierarchicalConfiguration config =
+                        xconf.configurationAt("data/components/component/optical-channel/state/target-power-range");
+                long targetMin = Float.valueOf(config.getString("min")).longValue();
+                long targetMax = Float.valueOf(config.getString("max")).longValue();
+                return Optional.of(Range.open(targetMin, targetMax));
+            } catch (IllegalArgumentException e) {
+                return Optional.empty();
+            }
+
+        }
+
+        Optional<Range<Long>> getInputPowerRange(PortNumber port, Object component) {
+            XMLConfiguration xconf = getOpticalChannelState(
+                    cassini, port, "<input-power-range/>");
+            try {
+                HierarchicalConfiguration config =
+                        xconf.configurationAt("data/components/component/optical-channel/state/input-power-range");
+                long inputMin = Float.valueOf(config.getString("min")).longValue();
+                long inputMax = Float.valueOf(config.getString("max")).longValue();
+                return Optional.of(Range.open(inputMin, inputMax));
+            } catch (IllegalArgumentException e) {
+                return Optional.empty();
+            }
+        }
+
+        List<PortNumber> getPorts(Object component) {
+            // FIXME
+            log.warn("Not Implemented Yet!");
+            return new ArrayList<PortNumber>();
+        }
+
+        /**
+         * Get filtered content under <optical-channel><state>.
+         * @param pc power config instance
+         * @param port the port number
+         * @param underState the filter condition
+         * @return RPC reply
+         */
+        private static XMLConfiguration getOpticalChannelState(CassiniTerminalDevicePowerConfigExt pc,
+                                                               PortNumber port, String underState) {
+            NetconfSession session = pc.getNetconfSession(pc.did());
+            checkNotNull(session);
+            String name = ocName(pc, port);
+            StringBuilder rpcReq = new StringBuilder(RPC_TAG_NETCONF_BASE);
+            rpcReq.append("<get><filter><components xmlns=\"http://openconfig.net/yang/platform\"><component>")
+                    .append("<name>").append(name).append("</name>")
+                    .append("<optical-channel xmlns=\"http://openconfig.net/yang/terminal-device\">")
+                    .append("<state>")
+                    .append(underState)
+                    .append("</state></optical-channel></component></components></filter></get>")
+                    .append(RPC_CLOSE_TAG);
+            XMLConfiguration xconf = pc.executeRpc(session, rpcReq.toString());
+            return xconf;
+        }
+
+
+        /**
+         * Extract component name from portNumber's annotations.
+         * @param pc power config instance
+         * @param portNumber the port number
+         * @return the component name
+         */
+        private static String ocName(CassiniTerminalDevicePowerConfigExt pc, PortNumber portNumber) {
+            DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
+            DeviceId deviceId = pc.handler().data().deviceId();
+            return deviceService.getPort(deviceId, portNumber).annotations().value("oc-name");
+        }
+
+
+
+        /**
+         * Parse filtering string from port and component.
+         * @param portNumber Port Number
+         * @param component port component (optical-channel)
+         * @param power power value set.
+         * @return filtering string in xml format
+         */
+        private static String parsePort(CassiniTerminalDevicePowerConfigExt pc, PortNumber portNumber,
+                                        Object component, Long power) {
+            if (component == null) {
+                String name = ocName(pc, portNumber);
+                StringBuilder sb = new StringBuilder("<components xmlns=\"http://openconfig.net/yang/platform\">");
+                sb.append("<component>").append("<name>").append(name).append("</name>");
+                if (power != null) {
+                    // This is an edit-config operation.
+                    sb.append("<optical-channel xmlns=\"http://openconfig.net/yang/terminal-device\">")
+                            .append("<config>")
+                            .append("<target-output-power>")
+                            .append(power)
+                            .append("</target-output-power>")
+                            .append("</config>")
+                            .append("</optical-channel>");
+                }
+                sb.append("</component>").append("</components>");
+                return sb.toString();
+            } else {
+                log.error("Cannot process the component {}.", component.getClass());
+                return null;
+            }
+        }
+    }
+}