Add configurable method to SimpleFlowRuleStore
- Add @Modified annotation
- Delete TODO annotation

Change-Id: Ida2855c23105f68cfa2f2b7bb4ec3f384a2de838
diff --git a/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java b/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java
index 274c84f..8924b61 100644
--- a/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java
+++ b/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java
@@ -27,8 +27,11 @@
 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.Service;
 import org.onlab.util.NewConcurrentHashMap;
+import org.onlab.util.Tools;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.flow.CompletedBatchOperation;
 import org.onosproject.net.flow.DefaultFlowEntry;
@@ -48,10 +51,12 @@
 import org.onosproject.net.flow.StoredFlowEntry;
 import org.onosproject.net.flow.TableStatisticsEntry;
 import org.onosproject.store.AbstractStore;
+import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Dictionary;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -87,8 +92,10 @@
 
     private final AtomicInteger localBatchIdGen = new AtomicInteger();
 
-    // TODO: make this configurable
-    private int pendingFutureTimeoutMinutes = 5;
+    private static final int DEFAULT_PENDING_FUTURE_TIMEOUT_MINUTES = 5;
+    @Property(name = "pendingFutureTimeoutMinutes", intValue = DEFAULT_PENDING_FUTURE_TIMEOUT_MINUTES,
+            label = "Expiration time after an entry is created that it should be automatically removed")
+    private int pendingFutureTimeoutMinutes = DEFAULT_PENDING_FUTURE_TIMEOUT_MINUTES;
 
     private Cache<Integer, SettableFuture<CompletedBatchOperation>> pendingFutures =
             CacheBuilder.newBuilder()
@@ -108,6 +115,21 @@
         log.info("Stopped");
     }
 
+    @Modified
+    public void modified(ComponentContext context) {
+
+        readComponentConfiguration(context);
+
+        // Reset Cache and copy all.
+        Cache<Integer, SettableFuture<CompletedBatchOperation>> prevFutures = pendingFutures;
+        pendingFutures = CacheBuilder.newBuilder()
+                .expireAfterWrite(pendingFutureTimeoutMinutes, TimeUnit.MINUTES)
+                .removalListener(new TimeoutFuture())
+                .build();
+
+        pendingFutures.putAll(prevFutures.asMap());
+    }
+
 
     @Override
     public int getFlowRuleCount() {
@@ -120,6 +142,27 @@
         return sum;
     }
 
+    /**
+     * Extracts properties from the component configuration context.
+     *
+     * @param context the component context
+     */
+    private void readComponentConfiguration(ComponentContext context) {
+        Dictionary<?, ?> properties = context.getProperties();
+
+        Integer newPendingFutureTimeoutMinutes =
+                Tools.getIntegerProperty(properties, "pendingFutureTimeoutMinutes");
+        if (newPendingFutureTimeoutMinutes == null) {
+            pendingFutureTimeoutMinutes = DEFAULT_PENDING_FUTURE_TIMEOUT_MINUTES;
+            log.info("Pending future timeout is not configured, " +
+                             "using current value of {}", pendingFutureTimeoutMinutes);
+        } else {
+            pendingFutureTimeoutMinutes = newPendingFutureTimeoutMinutes;
+            log.info("Configured. Pending future timeout is configured to {}",
+                     pendingFutureTimeoutMinutes);
+        }
+    }
+
     private static NewConcurrentHashMap<FlowId, List<StoredFlowEntry>> lazyEmptyFlowTable() {
         return NewConcurrentHashMap.<FlowId, List<StoredFlowEntry>>ifNeeded();
     }
@@ -332,19 +375,6 @@
         notifyDelegate(event);
     }
 
-    private static final class TimeoutFuture
-        implements RemovalListener<Integer, SettableFuture<CompletedBatchOperation>> {
-        @Override
-        public void onRemoval(RemovalNotification<Integer, SettableFuture<CompletedBatchOperation>> notification) {
-            // wrapping in ExecutionException to support Future.get
-            if (notification.wasEvicted()) {
-                notification.getValue()
-                    .setException(new ExecutionException("Timed out",
-                                                     new TimeoutException()));
-            }
-        }
-    }
-
     @Override
     public FlowRuleEvent updateTableStatistics(DeviceId deviceId,
                                                List<TableStatisticsEntry> tableStats) {
@@ -360,4 +390,17 @@
         }
         return ImmutableList.copyOf(tableStats);
     }
+
+    private static final class TimeoutFuture
+            implements RemovalListener<Integer, SettableFuture<CompletedBatchOperation>> {
+        @Override
+        public void onRemoval(RemovalNotification<Integer, SettableFuture<CompletedBatchOperation>> notification) {
+            // wrapping in ExecutionException to support Future.get
+            if (notification.wasEvicted()) {
+                notification.getValue()
+                        .setException(new ExecutionException("Timed out",
+                                                             new TimeoutException()));
+            }
+        }
+    }
 }
diff --git a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
index bb2df35..a31f38d 100644
--- a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -148,7 +148,6 @@
 
     private final InternalDeviceProvider listener = new InternalDeviceProvider();
 
-    // TODO: We need to make the poll interval configurable.
     static final int POLL_INTERVAL = 5;
     @Property(name = "PortStatsPollFrequency", intValue = POLL_INTERVAL,
     label = "Frequency (in seconds) for polling switch Port statistics")