[ONOS-7732] Automating switch workflow - program counter refactoring

Change-Id: Ic5271121dad45222ded24ea41dbb2f5efba1ff2e
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ImmutableListWorkflow.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ImmutableListWorkflow.java
index ec2be65..3e54c94 100644
--- a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ImmutableListWorkflow.java
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ImmutableListWorkflow.java
@@ -74,32 +74,31 @@
         return getWorkletInstance(initWorkletType);
     }
 
-
     @Override
     public ProgramCounter next(WorkflowContext context) throws WorkflowException {
 
         int cnt = 0;
 
-        ProgramCounter pc = context.current();
-        check(pc != null, "Invalid program counter");
+        ProgramCounter current = context.current();
+        check(current != null, "Invalid program counter");
 
-        for (int i = pc.workletIndex(); i < workletTypeList.size(); i++) {
+        ProgramCounter pc = current.clone();
+
+        for (int i = current.workletIndex(); i < workletTypeList.size(); pc = increased(pc), i++) {
 
             if (cnt++ > Worklet.MAX_WORKS) {
                 throw new WorkflowException("Maximum worklet execution exceeded");
             }
 
-            String workletType = workletTypeList.get(i);
-
-            if (Worklet.Common.COMPLETED.tag().equals(workletType)) {
-                return ProgramCounter.valueOf(workletType, i);
+            if (pc.isCompleted()) {
+                return pc;
             }
 
-            if (Worklet.Common.INIT.tag().equals(workletType)) {
+            if (pc.isInit()) {
                 continue;
             }
 
-            Worklet worklet = getWorkletInstance(workletType);
+            Worklet worklet = getWorkletInstance(pc);
             Class workClass = worklet.getClass();
 
             if (BranchWorklet.class.isAssignableFrom(workClass)) {
@@ -121,11 +120,12 @@
                 // isNext is read only. It does not perform 'inhale'.
                 dataModelInjector.inject(worklet, context);
                 if (worklet.isNext(context)) {
-                    return ProgramCounter.valueOf(workletType, i);
+                    return pc;
                 }
             }
         }
-        throw new WorkflowException("workflow reached to end but not COMPLETED");
+        throw new WorkflowException("workflow reached to end but not COMPLETED (pc:"
+                + current + ", workflow:" + this.toString());
     }
 
     @Override
@@ -141,6 +141,12 @@
     }
 
     @Override
+    public Worklet getWorkletInstance(ProgramCounter pc) throws WorkflowException {
+
+        return getWorkletInstance(workletTypeList.get(pc.workletIndex()));
+    }
+
+    @Override
     public Worklet getWorkletInstance(String workletType) throws WorkflowException {
 
         if (Worklet.Common.INIT.tag().equals(workletType)) {
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ProgramCounter.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ProgramCounter.java
index 6af50e0..b6db8e7 100644
--- a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ProgramCounter.java
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/ProgramCounter.java
@@ -62,6 +62,30 @@
         this.workletIndex = workletIndex;
     }
 
+    /**
+     * Clones this workflow Program Counter.
+     * @return clone of this workflow Program Counter
+     */
+    public ProgramCounter clone() {
+        return ProgramCounter.valueOf(this.workletType(), this.workletIndex());
+    }
+
+    /**
+     * Returns whether this program counter is INIT worklet program counter.
+     * @return whether this program counter is INIT worklet program counter
+     */
+    public boolean isInit() {
+        return Worklet.Common.INIT.tag().equals(this.workletType);
+    }
+
+    /**
+     * Returns whether this program counter is COMPLETED worklet program counter.
+     * @return whether this program counter is COMPLETED worklet program counter
+     */
+    public boolean isCompleted() {
+        return Worklet.Common.COMPLETED.tag().equals(this.workletType);
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(this.toString());
diff --git a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Workflow.java b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Workflow.java
index 848a706..1404f9b 100644
--- a/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Workflow.java
+++ b/apps/workflow/api/src/main/java/org/onosproject/workflow/api/Workflow.java
@@ -56,6 +56,14 @@
 
     /**
      * Returns instance of worklet.
+     * @param pc program counter
+     * @return instance of worklet
+     * @throws WorkflowException workflow exception
+     */
+    Worklet getWorkletInstance(ProgramCounter pc) throws WorkflowException;
+
+    /**
+     * Returns instance of worklet.
      * @param workletType class name of worklet
      * @return instance of worklet
      * @throws WorkflowException workflow exception
diff --git a/apps/workflow/app/src/main/java/org/onosproject/workflow/impl/WorkFlowEngine.java b/apps/workflow/app/src/main/java/org/onosproject/workflow/impl/WorkFlowEngine.java
index b472c5f..5337c59 100644
--- a/apps/workflow/app/src/main/java/org/onosproject/workflow/impl/WorkFlowEngine.java
+++ b/apps/workflow/app/src/main/java/org/onosproject/workflow/impl/WorkFlowEngine.java
@@ -472,7 +472,7 @@
                 return task;
             }
 
-            Worklet worklet = workflow.getWorkletInstance(task.programCounter().workletType());
+            Worklet worklet = workflow.getWorkletInstance(task.programCounter());
             if (Worklet.Common.COMPLETED.equals(worklet) || Worklet.Common.INIT.equals(worklet)) {
                 log.error("Current worklet is {}, Ignored", worklet);
                 return task;
@@ -562,7 +562,7 @@
                 return task;
             }
 
-            Worklet worklet = workflow.getWorkletInstance(task.programCounter().workletType());
+            Worklet worklet = workflow.getWorkletInstance(task.programCounter());
             if (worklet == Worklet.Common.COMPLETED || worklet == Worklet.Common.INIT) {
                 log.error("execEventTimeoutTask: Current worklet is {}, Ignored", worklet);
                 return task;
@@ -632,7 +632,7 @@
                 return task;
             }
 
-            Worklet worklet = workflow.getWorkletInstance(task.programCounter().workletType());
+            Worklet worklet = workflow.getWorkletInstance(task.programCounter());
             if (worklet == Worklet.Common.COMPLETED || worklet == Worklet.Common.INIT) {
                 log.error("execTimeoutTask: Current worklet is {}, Ignored", worklet);
                 return task;
@@ -736,7 +736,7 @@
 
         try {
             final ProgramCounter pc = workflow.next(latestContext);
-            final Worklet worklet = workflow.getWorkletInstance(pc.workletType());
+            final Worklet worklet = workflow.getWorkletInstance(pc);
 
             if (worklet == Worklet.Common.INIT) {
                 log.error("workflow.next gave INIT. It cannot be executed (context: {})", context.name());