Add timeout function to Intent.

Change-Id: Ice73b1560d3d66d1207e5f8114a103b9ca0e4f46
diff --git a/src/main/java/net/onrc/onos/apps/forwarding/Forwarding.java b/src/main/java/net/onrc/onos/apps/forwarding/Forwarding.java
index b8b2a2c..df70dd4 100644
--- a/src/main/java/net/onrc/onos/apps/forwarding/Forwarding.java
+++ b/src/main/java/net/onrc/onos/apps/forwarding/Forwarding.java
@@ -54,6 +54,9 @@
 
     private static final int SLEEP_TIME_FOR_DB_DEVICE_INSTALLED = 100; // milliseconds
     private static final int NUMBER_OF_THREAD_FOR_EXECUTOR = 1;
+    private static final int SRC_SWITCH_TIMEOUT_ADJUST_SECOND = 2;
+    private static final int DEFAULT_IDLE_TIMEOUT = 5;
+    private int idleTimeout = DEFAULT_IDLE_TIMEOUT;
 
     private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newScheduledThreadPool(NUMBER_OF_THREAD_FOR_EXECUTOR);
 
@@ -172,6 +175,19 @@
 
     @Override
     public void startUp(FloodlightModuleContext context) {
+        Map<String, String> configOptions = context.getConfigParams(this);
+
+        try {
+            if (Integer.parseInt(configOptions.get("idletimeout")) > 0) {
+                idleTimeout = Integer.parseInt(configOptions.get("idletimeout"));
+                log.info("idle_timeout for Forwarding is set to {}.", idleTimeout);
+            } else {
+                log.info("idle_timeout for Forwarding is less than 0. Use default {}.", idleTimeout);
+            }
+        } catch (NumberFormatException e) {
+            log.info("idle_timeout related config options were not set. Use default.");
+        }
+
         packetService.registerPacketListener(this);
 
         topology = topologyService.getTopology();
@@ -358,10 +374,11 @@
             ShortestPathIntent intent = new ShortestPathIntent(intentId,
                     sw.getDpid(), inPort.getNumber(), srcMacAddress.toLong(),
                     destinationDpid, destinationPort, dstMacAddress.toLong());
+            intent.setIdleTimeout(idleTimeout + SRC_SWITCH_TIMEOUT_ADJUST_SECOND);
+            intent.setFirstSwitchIdleTimeout(idleTimeout);
             IntentOperation.Operator operator = IntentOperation.Operator.ADD;
             operations.add(operator, intent);
             pathRuntime.executeIntentOperations(operations);
-
             // Add to waiting lists
             pendingFlows.put(pathspec, new PushedFlow(intentId));
             log.debug("Put a Path {} in the pending flow, intent ID {}", pathspec, intentId);
diff --git a/src/main/java/net/onrc/onos/core/intent/FlowEntry.java b/src/main/java/net/onrc/onos/core/intent/FlowEntry.java
index 526fe5f..bb051e2 100644
--- a/src/main/java/net/onrc/onos/core/intent/FlowEntry.java
+++ b/src/main/java/net/onrc/onos/core/intent/FlowEntry.java
@@ -19,6 +19,8 @@
     protected Match match;
     protected Set<Action> actions;
     protected Operator operator;
+    protected int hardTimeout = 0;
+    protected int idleTimeout = 0;
 
     public FlowEntry(long sw, long srcPort, long dstPort,
                      MACAddress srcMac, MACAddress dstMac,
@@ -28,8 +30,46 @@
         this.actions = new HashSet<Action>();
         this.actions.add(new ForwardAction(dstPort));
         this.operator = operator;
+
     }
 
+    /***
+     * Gets hard timeout value in seconds.
+     *
+     * @return hardTimeout
+     */
+    public int getHardTimeout() {
+        return hardTimeout;
+    }
+
+    /***
+     * Gets idle timeout value in seconds.
+     *
+     * @return idleTimeout
+     */
+    public int getIdleTimeout() {
+        return idleTimeout;
+    }
+
+    /***
+     * Sets hard timeout value in seconds.
+     *
+     * @param hardTimeout
+     */
+    public void setHardTimeout(int hardTimeout) {
+        this.hardTimeout = hardTimeout;
+    }
+
+    /***
+     * Sets idle timeout value in seconds.
+     *
+     * @param idleTimeout
+     */
+    public void setIdleTimeout(int idleTimeout) {
+        this.idleTimeout = idleTimeout;
+    }
+
+    @Override
     public String toString() {
         return match + "->" + actions;
     }
@@ -66,14 +106,18 @@
             default:
                 break;
         }
+        entry.setIdleTimeout(idleTimeout);
+        entry.setHardTimeout(hardTimeout);
         return entry;
     }
 
 
+    @Override
     public int hashCode() {
         return match.hashCode();
     }
 
+    @Override
     public boolean equals(Object o) {
         if (!(o instanceof FlowEntry)) {
             return false;
diff --git a/src/main/java/net/onrc/onos/core/intent/ShortestPathIntent.java b/src/main/java/net/onrc/onos/core/intent/ShortestPathIntent.java
index 94f3f36..660cb7c 100644
--- a/src/main/java/net/onrc/onos/core/intent/ShortestPathIntent.java
+++ b/src/main/java/net/onrc/onos/core/intent/ShortestPathIntent.java
@@ -14,6 +14,10 @@
     protected long dstPortNumber;
     protected long dstMacAddress;
     protected String pathIntentId = null;
+    protected int idleTimeout;
+    protected int hardTimeout;
+    protected int firstSwitchIdleTimeout;
+    protected int firstSwitchHardTimetout;
 
     /**
      * Default constructor for Kryo deserialization.
@@ -106,6 +110,46 @@
         return pathIntentId;
     }
 
+    @Deprecated
+    public int getIdleTimeout() {
+        return idleTimeout;
+    }
+
+    @Deprecated
+    public int getHardTimeout() {
+        return hardTimeout;
+    }
+
+    @Deprecated
+    public void setIdleTimeout(int idleTimeout) {
+        this.idleTimeout = idleTimeout;
+    }
+
+    @Deprecated
+    public void setHardTimeout(int hardTimeout) {
+        this.hardTimeout = hardTimeout;
+    }
+
+    @Deprecated
+    public int getFirstSwitchIdleTimeout() {
+        return firstSwitchIdleTimeout;
+    }
+
+    @Deprecated
+    public int getFirstSwitchHardTimetout() {
+        return firstSwitchHardTimetout;
+    }
+
+    @Deprecated
+    public void setFirstSwitchIdleTimeout(int firstSwitchIdleTimeout) {
+        this.firstSwitchIdleTimeout = firstSwitchIdleTimeout;
+    }
+
+    @Deprecated
+    public void setFirstSwitchHardTimetout(int firstSwitchHardTimetout) {
+        this.firstSwitchHardTimetout = firstSwitchHardTimetout;
+    }
+
     @Override
     public int hashCode() {
         // TODO: Is this the intended behavior?
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/PlanCalcRuntime.java b/src/main/java/net/onrc/onos/core/intent/runtime/PlanCalcRuntime.java
index 087bff8..73a31b8 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/PlanCalcRuntime.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/PlanCalcRuntime.java
@@ -58,8 +58,9 @@
             PathIntent intent = (PathIntent) i.intent;
             Intent parent = intent.getParentIntent();
             long srcPort, dstPort;
-            long lastDstSw = -1, lastDstPort = -1;
+            long lastDstSw = -1, lastDstPort = -1, firstSrcSw = -1;
             MACAddress srcMac, dstMac;
+            int idleTimeout = 0, hardTimeout = 0, firstSwitchIdleTimeout = 0, firstSwitchHardTimeout = 0;
             if (parent instanceof ShortestPathIntent) {
                 ShortestPathIntent pathIntent = (ShortestPathIntent) parent;
 //              Switch srcSwitch = graph.getSwitch(pathIntent.getSrcSwitchDpid());
@@ -69,8 +70,13 @@
                 dstMac = MACAddress.valueOf(pathIntent.getDstMac());
 //              Switch dstSwitch = graph.getSwitch(pathIntent.getDstSwitchDpid());
                 lastDstSw = pathIntent.getDstSwitchDpid();
+                firstSrcSw = pathIntent.getSrcSwitchDpid();
 //              lastDstPort = dstSwitch.getPort(pathIntent.getDstPortNumber());
                 lastDstPort = pathIntent.getDstPortNumber();
+                idleTimeout = pathIntent.getIdleTimeout();
+                hardTimeout = pathIntent.getHardTimeout();
+                firstSwitchIdleTimeout = pathIntent.getFirstSwitchIdleTimeout();
+                firstSwitchHardTimeout = pathIntent.getFirstSwitchHardTimetout();
             } else {
                 log.warn("Unsupported Intent: {}", parent);
                 continue;
@@ -86,6 +92,13 @@
 //              dstPort = link.getSrcPort();
                 dstPort = linkEvent.getSrc().getNumber();
                 FlowEntry fe = new FlowEntry(sw, srcPort, dstPort, srcMac, dstMac, i.operator);
+                if (sw != firstSrcSw) {
+                    fe.setIdleTimeout(idleTimeout);
+                    fe.setHardTimeout(hardTimeout);
+                } else {
+                    fe.setIdleTimeout(firstSwitchIdleTimeout);
+                    fe.setHardTimeout(firstSwitchHardTimeout);
+                }
                 entries.add(fe);
 //              srcPort = link.getDstPort();
                 srcPort = linkEvent.getDst().getNumber();
@@ -95,6 +108,8 @@
                 long sw = lastDstSw;
                 dstPort = lastDstPort;
                 FlowEntry fe = new FlowEntry(sw, srcPort, dstPort, srcMac, dstMac, i.operator);
+                fe.setIdleTimeout(idleTimeout);
+                fe.setHardTimeout(hardTimeout);
                 entries.add(fe);
             }
             // install flow entries in reverse order
@@ -104,6 +119,18 @@
         return flowEntries;
     }
 
+    // This method is for a testing purpose. Please leave it right now.
+    private List<Set<FlowEntry>> simpleBuildPhases(List<Collection<FlowEntry>> flowEntries) {
+        List<Set<FlowEntry>> plan = new ArrayList<>();
+        Set<FlowEntry> phase = new HashSet<>();
+        for (Collection<FlowEntry> c : flowEntries) {
+            phase.addAll(c);
+        }
+        plan.add(phase);
+
+        return plan;
+    }
+
     private List<Set<FlowEntry>> buildPhases(List<Collection<FlowEntry>> flowEntries) {
         Map<FlowEntry, Integer> map = new HashMap<>();
         List<Set<FlowEntry>> plan = new ArrayList<>();