[GEANT] Property netconfReplyTimeout added in Settings.

Change-Id: I60399c5cc9a00857f275fa8016520b2d909e9912
diff --git a/protocols/netconf/ctl/pom.xml b/protocols/netconf/ctl/pom.xml
index d82dcb6..4f9795b 100644
--- a/protocols/netconf/ctl/pom.xml
+++ b/protocols/netconf/ctl/pom.xml
@@ -45,6 +45,19 @@
             <artifactId>ganymed-ssh2</artifactId>
             <version>262</version>
         </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-osgi</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfControllerImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfControllerImpl.java
index bd4f4b0..0e34a39 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfControllerImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfControllerImpl.java
@@ -19,10 +19,13 @@
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.IpAddress;
+import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceService;
@@ -42,17 +45,30 @@
 import org.slf4j.LoggerFactory;
 
 import java.util.Arrays;
+import java.util.Dictionary;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArraySet;
 
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
+
 /**
  * The implementation of NetconfController.
  */
 @Component(immediate = true)
 @Service
 public class NetconfControllerImpl implements NetconfController {
+    private static final String PROP_NETCONF_REPLY_TIMEOUT = "netconfReplyTimeout";
+    private static final int DEFAULT_REPLY_TIMEOUT_SECONDS = 5;
+    @Property(name = PROP_NETCONF_REPLY_TIMEOUT, intValue = DEFAULT_REPLY_TIMEOUT_SECONDS,
+            label = "Time (in seconds) waiting for a NetConf reply")
+    protected static int netconfReplyTimeout = DEFAULT_REPLY_TIMEOUT_SECONDS;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ComponentConfigService cfgService;
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceService deviceService;
 
@@ -71,15 +87,42 @@
 
     @Activate
     public void activate(ComponentContext context) {
+        cfgService.registerProperties(getClass());
+        modified(context);
         log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
+        cfgService.unregisterProperties(getClass(), false);
         netconfDeviceMap.clear();
         log.info("Stopped");
     }
 
+    @Modified
+    public void modified(ComponentContext context) {
+        if (context == null) {
+            netconfReplyTimeout = DEFAULT_REPLY_TIMEOUT_SECONDS;
+            log.info("No component configuration");
+            return;
+        }
+
+        Dictionary<?, ?> properties = context.getProperties();
+
+        int newNetconfReplyTimeout;
+        try {
+            String s = get(properties, PROP_NETCONF_REPLY_TIMEOUT);
+            newNetconfReplyTimeout = isNullOrEmpty(s) ?
+                    netconfReplyTimeout : Integer.parseInt(s.trim());
+        } catch (NumberFormatException e) {
+            log.warn("Component configuration had invalid value", e);
+            return;
+        }
+
+        netconfReplyTimeout = newNetconfReplyTimeout;
+        log.info("Settings: {} = {}", PROP_NETCONF_REPLY_TIMEOUT, netconfReplyTimeout);
+    }
+
     @Override
     public void addDeviceListener(NetconfDeviceListener listener) {
         if (!netconfDeviceListeners.contains(listener)) {
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java
index 9f4b47a..bf46b07 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java
@@ -55,7 +55,6 @@
     private static final String MESSAGE_ID_STRING = "message-id";
     private static final String HELLO = "<hello";
     private static final String NEW_LINE = "\n";
-    private static final int FUTURE_REPLY_TIMEOUT = 5000;
     private static final String ERROR = "ERROR ";
     private static final String END_OF_RPC_OPEN_TAG = "\">";
     private static final String EQUAL = "=";
@@ -196,9 +195,10 @@
         request = formatXmlHeader(request);
         CompletableFuture<String> futureReply = request(request);
         messageIdInteger.incrementAndGet();
+        int replyTimeout = NetconfControllerImpl.netconfReplyTimeout;
         String rp;
         try {
-            rp = futureReply.get(FUTURE_REPLY_TIMEOUT, TimeUnit.MILLISECONDS);
+            rp = futureReply.get(replyTimeout, TimeUnit.SECONDS);
         } catch (InterruptedException | ExecutionException | TimeoutException e) {
             throw new NetconfException("No matching reply for request " + request, e);
         }
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfControllerImplTest.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfControllerImplTest.java
index 19d54f4..45304ea 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfControllerImplTest.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfControllerImplTest.java
@@ -20,7 +20,10 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.osgi.ComponentContextAdapter;
 import org.onlab.packet.IpAddress;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.key.DeviceKeyService;
@@ -32,8 +35,11 @@
 import org.onosproject.netconf.NetconfDeviceOutputEventListener;
 import org.onosproject.netconf.NetconfException;
 import org.onosproject.netconf.NetconfSession;
+import org.osgi.service.component.ComponentContext;
 
 import java.lang.reflect.Field;
+import java.util.Dictionary;
+import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Optional;
@@ -79,14 +85,17 @@
     private static final int BAD_DEVICE_PORT = 13;
     private static final int IPV6_DEVICE_PORT = 14;
 
+    private static ComponentConfigService cfgService = new ComponentConfigAdapter();
     private static DeviceService deviceService = new NetconfDeviceServiceMock();
     private static DeviceKeyService deviceKeyService = new NetconfDeviceKeyServiceMock();
 
+    private final ComponentContext context = new MockComponentContext();
 
     @Before
     public void setUp() throws Exception {
         ctrl = new NetconfControllerImpl();
         ctrl.deviceFactory = new TestNetconfDeviceFactory();
+        ctrl.cfgService = cfgService;
         ctrl.deviceService = deviceService;
         ctrl.deviceKeyService = deviceKeyService;
 
@@ -125,6 +134,30 @@
     }
 
     /**
+     * Test initialization of component configuration.
+     */
+    @Test
+    public void testActivate() {
+        assertEquals("Incorrect NetConf session timeout, should be default",
+                     5, ctrl.netconfReplyTimeout);
+        ctrl.activate(null);
+        assertEquals("Incorrect NetConf session timeout, should be default",
+                     5, ctrl.netconfReplyTimeout);
+    }
+
+    /**
+     * Test modification of component configuration.
+     */
+    @Test
+    public void testModified() {
+        assertEquals("Incorrect NetConf session timeout, should be default",
+                     5, ctrl.netconfReplyTimeout);
+        ctrl.modified(context);
+        assertEquals("Incorrect NetConf session timeout",
+                     1, ctrl.netconfReplyTimeout);
+    }
+
+    /**
      * Test to add DeviceListeners,
      * and also to check whether the netconfDeviceListeners set is
      * updating or not which was present in NetconfControllerImpl class.
@@ -323,4 +356,52 @@
         }
 
     }
+
+    private class MockComponentContext extends ComponentContextAdapter {
+        @Override
+        public Dictionary getProperties() {
+            return new MockDictionary();
+        }
+    }
+
+    private class MockDictionary extends Dictionary {
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return false;
+        }
+
+        @Override
+        public Enumeration keys() {
+            return null;
+        }
+
+        @Override
+        public Enumeration elements() {
+            return null;
+        }
+
+        @Override
+        public Object get(Object key) {
+            if (key.equals("netconfReplyTimeout")) {
+                return "1";
+            }
+            return null;
+        }
+
+        @Override
+        public Object put(Object key, Object value) {
+            return null;
+        }
+
+        @Override
+        public Object remove(Object key) {
+            return null;
+        }
+    }
 }