Bug 4940 - correctly implement default-request-timeout-millis
[netconf.git] / opendaylight / netconf / sal-netconf-connector / src / main / java / org / opendaylight / netconf / sal / connect / netconf / sal / KeepaliveSalFacade.java
index 569f642130208795016994cd67f233b7b56f0c60..c450ac68fecd83c40d8eff6c306e30d02e6b35c1 100644 (file)
@@ -51,28 +51,33 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler<NetconfSess
     // 2 minutes keepalive delay by default
     private static final long DEFAULT_DELAY = TimeUnit.MINUTES.toSeconds(2);
 
+    // 1 minute transaction timeout by default
+    private static final long DEFAULT_TRANSACTION_TIMEOUT_MILLI = TimeUnit.MILLISECONDS.toMillis(60000);
+
     private final RemoteDeviceId id;
     private final RemoteDeviceHandler<NetconfSessionPreferences> salFacade;
     private final ScheduledExecutorService executor;
     private final long keepaliveDelaySeconds;
     private final ResetKeepalive resetKeepaliveTask;
+    private final long defaultRequestTimeoutMillis;
 
     private volatile NetconfDeviceCommunicator listener;
     private volatile ScheduledFuture<?> currentKeepalive;
     private volatile DOMRpcService currentDeviceRpc;
 
     public KeepaliveSalFacade(final RemoteDeviceId id, final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
-                              final ScheduledExecutorService executor, final long keepaliveDelaySeconds) {
+                              final ScheduledExecutorService executor, final long keepaliveDelaySeconds, final long defaultRequestTimeoutMillis) {
         this.id = id;
         this.salFacade = salFacade;
         this.executor = executor;
         this.keepaliveDelaySeconds = keepaliveDelaySeconds;
+        this.defaultRequestTimeoutMillis = defaultRequestTimeoutMillis;
         this.resetKeepaliveTask = new ResetKeepalive();
     }
 
     public KeepaliveSalFacade(final RemoteDeviceId id, final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
                               final ScheduledExecutorService executor) {
-        this(id, salFacade, executor, DEFAULT_DELAY);
+        this(id, salFacade, executor, DEFAULT_DELAY, DEFAULT_TRANSACTION_TIMEOUT_MILLI);
     }
 
     /**
@@ -118,7 +123,7 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler<NetconfSess
     @Override
     public void onDeviceConnected(final SchemaContext remoteSchemaContext, final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc) {
         this.currentDeviceRpc = deviceRpc;
-        final DOMRpcService deviceRpc1 = new KeepaliveDOMRpcService(deviceRpc, resetKeepaliveTask);
+        final DOMRpcService deviceRpc1 = new KeepaliveDOMRpcService(deviceRpc, resetKeepaliveTask, defaultRequestTimeoutMillis, executor);
         salFacade.onDeviceConnected(remoteSchemaContext, netconfSessionPreferences, deviceRpc1);
 
         LOG.debug("{}: Netconf session initiated, starting keepalives", id);
@@ -214,7 +219,7 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler<NetconfSess
     /**
      * Reset keepalive after each RPC response received
      */
-    private class ResetKeepalive implements com.google.common.util.concurrent.FutureCallback<DOMRpcResult> {
+    private class ResetKeepalive implements FutureCallback<DOMRpcResult> {
         @Override
         public void onSuccess(@Nullable final DOMRpcResult result) {
             // No matter what response we got, rpc-reply or rpc-error, we got it from device so the netconf session is OK
@@ -230,17 +235,44 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler<NetconfSess
         }
     }
 
+    /*
+     * Request timeout task is called once the defaultRequestTimeoutMillis is
+     * reached. At this moment, if the request is not yet finished, we cancel
+     * it.
+     */
+    private static final class RequestTimeoutTask implements Runnable {
+
+        private final CheckedFuture<DOMRpcResult, DOMRpcException> rpcResultFuture;
+
+        public RequestTimeoutTask(final CheckedFuture<DOMRpcResult, DOMRpcException> rpcResultFuture) {
+            this.rpcResultFuture = rpcResultFuture;
+        }
+
+        @Override
+        public void run() {
+            if (!rpcResultFuture.isDone()) {
+                rpcResultFuture.cancel(true);
+            }
+        }
+    }
+
     /**
-     * DOMRpcService proxy that attaches reset-keepalive-task to each RPC invocation.
+     * DOMRpcService proxy that attaches reset-keepalive-task and schedule
+     * request-timeout-task to each RPC invocation.
      */
     private static final class KeepaliveDOMRpcService implements DOMRpcService {
 
         private final DOMRpcService deviceRpc;
         private ResetKeepalive resetKeepaliveTask;
+        private final long defaultRequestTimeoutMillis;
+        private final ScheduledExecutorService executor;
 
-        public KeepaliveDOMRpcService(final DOMRpcService deviceRpc, final ResetKeepalive resetKeepaliveTask) {
+        public KeepaliveDOMRpcService(final DOMRpcService deviceRpc, final ResetKeepalive resetKeepaliveTask,
+                final long defaultRequestTimeoutMillis, final ScheduledExecutorService executor) {
             this.deviceRpc = deviceRpc;
             this.resetKeepaliveTask = resetKeepaliveTask;
+            this.defaultRequestTimeoutMillis = defaultRequestTimeoutMillis;
+            this.executor = executor;
         }
 
         @Nonnull
@@ -248,6 +280,10 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler<NetconfSess
         public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(@Nonnull final SchemaPath type, final NormalizedNode<?, ?> input) {
             final CheckedFuture<DOMRpcResult, DOMRpcException> domRpcResultDOMRpcExceptionCheckedFuture = deviceRpc.invokeRpc(type, input);
             Futures.addCallback(domRpcResultDOMRpcExceptionCheckedFuture, resetKeepaliveTask);
+
+            final RequestTimeoutTask timeoutTask = new RequestTimeoutTask(domRpcResultDOMRpcExceptionCheckedFuture);
+            executor.schedule(timeoutTask, defaultRequestTimeoutMillis, TimeUnit.MILLISECONDS);
+
             return domRpcResultDOMRpcExceptionCheckedFuture;
         }