Change FlowBatchHandle to be interface class.

- Users can access to the shared flow batch operation map
  using the FlowBatchHandle.
- FlowBatchHandle is an interface and the instance of it
  can be obtained from APIs defined by FlowManagerService.
- The implementation of the map can be accessed only from
  the implementation of the FlowBatchHandle.
- This task is a part of ONOS-1692 and ONOS-1842.

Change-Id: I651a2886d166765ca5aae6abcc2b844153ffb2bc
diff --git a/src/main/java/net/onrc/onos/api/batchoperation/BatchOperation.java b/src/main/java/net/onrc/onos/api/batchoperation/BatchOperation.java
index 6232a86..65836c4 100644
--- a/src/main/java/net/onrc/onos/api/batchoperation/BatchOperation.java
+++ b/src/main/java/net/onrc/onos/api/batchoperation/BatchOperation.java
@@ -1,5 +1,7 @@
 package net.onrc.onos.api.batchoperation;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
@@ -15,13 +17,23 @@
     private List<T> ops;
 
     /**
-     * Constructor.
+     * Creates new {@link BatchOperation} object.
      */
     public BatchOperation() {
         ops = new LinkedList<>();
     }
 
     /**
+     * Creates {@link BatchOperation} object from a list of batch operation
+     * entries.
+     *
+     * @param batchOperations the list of batch operation entries.
+     */
+    public BatchOperation(List<T> batchOperations) {
+        ops = new LinkedList<>(checkNotNull(batchOperations));
+    }
+
+    /**
      * Removes all operations maintained in this object.
      */
     public void clear() {
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/FlowBatchHandle.java b/src/main/java/net/onrc/onos/api/flowmanager/FlowBatchHandle.java
index 351d9e9..1f1836a 100644
--- a/src/main/java/net/onrc/onos/api/flowmanager/FlowBatchHandle.java
+++ b/src/main/java/net/onrc/onos/api/flowmanager/FlowBatchHandle.java
@@ -1,40 +1,25 @@
 package net.onrc.onos.api.flowmanager;
 
-import net.onrc.onos.core.flowmanager.FlowOperationMap;
-
-
 /**
- * Handle class to handle flow batch operation.
+ * An interface for handling flow batch operation.
  */
-public class FlowBatchHandle {
-    private final FlowOperationMap flowOperationMap;
-    private final FlowBatchId batchId;
+public interface FlowBatchHandle {
+    /**
+     * Gets the flow batch operation.
+     *
+     * @return the flow batch operation
+     */
+    public FlowBatchOperation getFlowBatchOperation();
 
     /**
-     * Creates a handle using batch operation ID.
-     * <p>
-     * The ID is automatically generated and assigned by FlowManager, and used
-     * as an internal key for the flow batch operation map.
+     * Gets the state for the flow batch operation.
      *
-     * @param opMap the FlowOperationMap object which maintains the flow batch
-     *        operation
-     * @param id the batch operation ID
+     * @return the state for the flow batch operation
      */
-    public FlowBatchHandle(FlowOperationMap opMap, FlowBatchId id) {
-        flowOperationMap = opMap;
-        batchId = id;
-    }
+    public FlowBatchState getState();
 
     /**
-     * Gets the flow batch operation ID.
-     *
-     * @return the flow batch operation ID
+     * Purge the flow batch operation from the map.
      */
-    public FlowBatchId getBatchOperationId() {
-        return batchId;
-    }
-
-    public FlowBatchState getState() {
-        return flowOperationMap.getState(batchId);
-    }
+    public void purge();
 }
diff --git a/src/main/java/net/onrc/onos/api/flowmanager/FlowBatchOperation.java b/src/main/java/net/onrc/onos/api/flowmanager/FlowBatchOperation.java
index 71d5378..f59bee5 100644
--- a/src/main/java/net/onrc/onos/api/flowmanager/FlowBatchOperation.java
+++ b/src/main/java/net/onrc/onos/api/flowmanager/FlowBatchOperation.java
@@ -1,5 +1,7 @@
 package net.onrc.onos.api.flowmanager;
 
+import java.util.List;
+
 import net.onrc.onos.api.batchoperation.BatchOperation;
 import net.onrc.onos.api.batchoperation.BatchOperationEntry;
 
@@ -24,6 +26,24 @@
     }
 
     /**
+     * Creates new {@link FlowBatchOperation} object.
+     */
+    public FlowBatchOperation() {
+        super();
+    }
+
+    /**
+     * Creates new {@link FlowBatchOperation} object from a list of flow batch
+     * operation entries.
+     *
+     * @param batchOperations the list of flow batch operation entries
+     */
+    public FlowBatchOperation(
+            List<BatchOperationEntry<FlowBatchOperation.Operator, ?>> batchOperations) {
+        super(batchOperations);
+    }
+
+    /**
      * Adds an add-flow operation.
      *
      * @param flow the flow to be added
diff --git a/src/main/java/net/onrc/onos/core/flowmanager/FlowBatchHandleImpl.java b/src/main/java/net/onrc/onos/core/flowmanager/FlowBatchHandleImpl.java
new file mode 100644
index 0000000..61a450f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/flowmanager/FlowBatchHandleImpl.java
@@ -0,0 +1,51 @@
+package net.onrc.onos.core.flowmanager;
+
+
+import  static com.google.common.base.Preconditions.*;
+
+import net.onrc.onos.api.flowmanager.FlowBatchHandle;
+import net.onrc.onos.api.flowmanager.FlowBatchId;
+import net.onrc.onos.api.flowmanager.FlowBatchOperation;
+import net.onrc.onos.api.flowmanager.FlowBatchState;
+
+public class FlowBatchHandleImpl implements FlowBatchHandle {
+    private final FlowOperationMap flowOperationMap;
+    private final FlowBatchId batchId;
+
+    /**
+     * Creates a handle using batch operation ID.
+     * <p>
+     * The ID is automatically generated and assigned by FlowManager, and used
+     * as an internal key for the flow batch operation map.
+     *
+     * @param opMap the FlowOperationMap object which maintains the flow batch
+     *        operation
+     * @param id the batch operation ID
+     */
+    public FlowBatchHandleImpl(FlowOperationMap opMap, FlowBatchId id) {
+        flowOperationMap = opMap;
+        batchId = id;
+    }
+
+    @Override
+    public FlowBatchOperation getFlowBatchOperation() {
+        FlowBatchOperation op = checkNotNull(flowOperationMap.getBatchOperation(batchId),
+                "The requested flow batch operation does not exist in the map.");
+
+        // TODO: should be an instance of immutable batch operation class.
+        return new FlowBatchOperation(op.getOperations());
+    }
+
+    @Override
+    public FlowBatchState getState() {
+        return flowOperationMap.getState(batchId);
+    }
+
+    @Override
+    public void purge() {
+        FlowBatchState state = getState();
+        if (state == FlowBatchState.COMPLETED || state == FlowBatchState.FAILED) {
+            flowOperationMap.removeBatchOperation(batchId);
+        }
+    }
+}
diff --git a/src/main/java/net/onrc/onos/core/flowmanager/FlowBatchIdGeneratorWithIdBlockAllocator.java b/src/main/java/net/onrc/onos/core/flowmanager/FlowBatchIdGeneratorWithIdBlockAllocator.java
new file mode 100644
index 0000000..7646d64
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/flowmanager/FlowBatchIdGeneratorWithIdBlockAllocator.java
@@ -0,0 +1,35 @@
+package net.onrc.onos.core.flowmanager;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import net.onrc.onos.api.flowmanager.FlowBatchId;
+import net.onrc.onos.core.util.IdBlock;
+import net.onrc.onos.core.util.IdBlockAllocator;
+import net.onrc.onos.core.util.UnavailableIdException;
+
+/**
+ * Generates a global unique FlowBatchId using
+ * {@link IdBlockAllocator#allocateUniqueIdBlock()}.
+ */
+public class FlowBatchIdGeneratorWithIdBlockAllocator {
+    private final IdBlockAllocator allocator;
+    private IdBlock idBlock;
+
+    /**
+     * Creates a FlowBatchId generator instance using specified ID block allocator.
+     *
+     * @param allocator the ID block allocator to be used
+     */
+    public FlowBatchIdGeneratorWithIdBlockAllocator(IdBlockAllocator allocator) {
+        this.allocator = checkNotNull(allocator);
+        this.idBlock = allocator.allocateUniqueIdBlock();
+    }
+
+    public synchronized FlowBatchId getNewId() {
+        try {
+            return new FlowBatchId(idBlock.getNextId());
+        } catch (UnavailableIdException e) {
+            idBlock = allocator.allocateUniqueIdBlock();
+            return new FlowBatchId(idBlock.getNextId());
+        }
+    }
+}
diff --git a/src/main/java/net/onrc/onos/core/flowmanager/FlowManagerModule.java b/src/main/java/net/onrc/onos/core/flowmanager/FlowManagerModule.java
index 86a3320..7a0b243 100644
--- a/src/main/java/net/onrc/onos/core/flowmanager/FlowManagerModule.java
+++ b/src/main/java/net/onrc/onos/core/flowmanager/FlowManagerModule.java
@@ -43,7 +43,7 @@
         this.flowIdGenerator =
                 new FlowIdGeneratorWithIdBlockAllocator(idBlockAllocator);
         this.conflictDetectionPolicy = ConflictDetectionPolicy.FREE;
-        this.flowOperationMap = new FlowOperationMap();
+        this.flowOperationMap = new FlowOperationMap(idBlockAllocator);
 
         // TODO: MatchActionOperationsIdGenerator should be retrieved from MatchAction Module.
         this.maIdGenerator =
@@ -94,7 +94,7 @@
      */
     @Override
     public FlowBatchHandle executeBatch(FlowBatchOperation ops) {
-        return flowOperationMap.putOperation(ops);
+        return flowOperationMap.putBatchOperation(ops);
     }
 
     @Override
diff --git a/src/main/java/net/onrc/onos/core/flowmanager/FlowOperationMap.java b/src/main/java/net/onrc/onos/core/flowmanager/FlowOperationMap.java
index e9d66c3..6535269 100644
--- a/src/main/java/net/onrc/onos/core/flowmanager/FlowOperationMap.java
+++ b/src/main/java/net/onrc/onos/core/flowmanager/FlowOperationMap.java
@@ -4,46 +4,79 @@
 import net.onrc.onos.api.flowmanager.FlowBatchId;
 import net.onrc.onos.api.flowmanager.FlowBatchOperation;
 import net.onrc.onos.api.flowmanager.FlowBatchState;
+import net.onrc.onos.core.util.IdBlockAllocator;
 
 /**
  * Manages the set of flow operations throughout the ONOS instances.
+ * <p>
+ * Application can access to this map using {@link FlowBatchHandle}.
  */
 public class FlowOperationMap {
-    public FlowBatchHandle putOperation(FlowBatchOperation ops) {
-        FlowBatchId id = getUniqueBatchOperationId();
-        if (id == null) {
-            return null;
-        }
-        if (putBatchOperation(id, ops)) {
-            return null;
-        }
+    private final FlowBatchIdGeneratorWithIdBlockAllocator flowBatchIdGenerator;
 
-        return new FlowBatchHandle(this, id);
+    /**
+     * Creates a driver for the shared flow batch operation map.
+     *
+     * @param allocator {@link IdBlockAllocator} to be used for batch IDs
+     */
+    FlowOperationMap(IdBlockAllocator allocator) {
+        flowBatchIdGenerator = new FlowBatchIdGeneratorWithIdBlockAllocator(allocator);
     }
 
-    public void setState(long id, FlowBatchState state) {
-        // TODO implement it
+    /**
+     * Adds a flow batch operation to the map.
+     *
+     * @param ops the flow batch operation to be added
+     * @return {@link FlowBatchHandle} handle if succeeded, null otherwise
+     */
+    FlowBatchHandle putBatchOperation(FlowBatchOperation ops) {
+        FlowBatchId id = flowBatchIdGenerator.getNewId();
+
+        // TODO: put batch operation to map
+
+        boolean succeeded = false;
+
+        return succeeded ? new FlowBatchHandleImpl(this, id) : null;
     }
 
-    public FlowBatchOperation getOperation(long id) {
+    /**
+     * Gets the flow batch operation from the map specified with an ID.
+     *
+     * @param id the ID for the operation
+     * @return the flow batch operation if exists, null otherwise
+     */
+    FlowBatchOperation getBatchOperation(FlowBatchId id) {
+        // TODO: implement it
+        return null;
+    }
+
+    /**
+     * Removes the flow batch operation from the map specified with an ID.
+     */
+    void removeBatchOperation(FlowBatchId id) {
+        // TODO: implement it
+    }
+
+    /**
+     * Gets the state for the flow batch operation specified with an ID.
+     *
+     * @param id the ID for the batch operation
+     * @return the state of the batch operation
+     */
+    FlowBatchState getState(FlowBatchId id) {
         // TODO implement it
         return null;
     }
 
-    public FlowBatchState getState(FlowBatchId id) {
-        // TODO implement it
-        return null;
-    }
-
-    // ====== private methods
-
-    private FlowBatchId getUniqueBatchOperationId() {
-        // TODO implement it
-        return null;
-    }
-
-    private boolean putBatchOperation(FlowBatchId id, FlowBatchOperation ops) {
-        // TODO implement it
+    /**
+     * Updates the state for the flow batch operation specified with an ID.
+     *
+     * @param id the ID for the batch operation
+     * @param state new state for the batch operation
+     * @return true if succeeded, false otherwise
+     */
+    boolean setState(FlowBatchId id, FlowBatchState state) {
+        // TODO: implement it
         return false;
     }
 }