New P4RuntimeClient implementation that supports batching and error reporting

The new client API supports batching and provides detailed response for
write requests (e.g. if entity already exists when inserting), which was
not possible with the old one.

This patch includes:
- New more efficient implementation of P4RuntimeClient (no more locking,
use native gRPC executor, use stub deadlines)
- Ported all codecs to new AbstractCodec-based implementation (needed to
implement codec cache in the future)
- Uses batching in P4RuntimeFlowRuleProgrammable and
P4RuntimeGroupActionProgrammable
- Minor changes to PI framework runtime classes

Change-Id: I3fac42057bb4e1389d761006a32600c786598683
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiControlMetadataId.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPacketMetadataId.java
similarity index 68%
rename from core/api/src/main/java/org/onosproject/net/pi/model/PiControlMetadataId.java
rename to core/api/src/main/java/org/onosproject/net/pi/model/PiPacketMetadataId.java
index b17c766..53cf1b6 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/PiControlMetadataId.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPacketMetadataId.java
@@ -23,24 +23,24 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
- * Identifier of a control metadata in a protocol-independent pipeline, unique within the scope of a pipeline model.
+ * Identifier of a packet metadata in a protocol-independent pipeline, unique within the scope of a pipeline model.
  */
 @Beta
-public final class PiControlMetadataId extends Identifier<String> {
+public final class PiPacketMetadataId extends Identifier<String> {
 
-    private PiControlMetadataId(String name) {
+    private PiPacketMetadataId(String name) {
         super(name);
     }
 
     /**
-     * Returns an identifier for the given control metadata name.
+     * Returns an identifier for the given packet metadata name.
      *
-     * @param name control metadata name
-     * @return control metadata ID
+     * @param name packet metadata name
+     * @return packet metadata ID
      */
-    public static PiControlMetadataId of(String name) {
+    public static PiPacketMetadataId of(String name) {
         checkNotNull(name);
         checkArgument(!name.isEmpty(), "Name can't be empty");
-        return new PiControlMetadataId(name);
+        return new PiPacketMetadataId(name);
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiControlMetadataModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPacketMetadataModel.java
similarity index 82%
rename from core/api/src/main/java/org/onosproject/net/pi/model/PiControlMetadataModel.java
rename to core/api/src/main/java/org/onosproject/net/pi/model/PiPacketMetadataModel.java
index 3748eac..76fdbe4 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/PiControlMetadataModel.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPacketMetadataModel.java
@@ -19,17 +19,17 @@
 import com.google.common.annotations.Beta;
 
 /**
- * Model of a control metadata for a protocol-independent pipeline.
+ * Model of a packet metadata for a protocol-independent pipeline.
  */
 @Beta
-public interface PiControlMetadataModel {
+public interface PiPacketMetadataModel {
 
     /**
-     * Returns the ID of this control metadata.
+     * Returns the ID of this packet metadata.
      *
      * @return packet operation metadata ID
      */
-    PiControlMetadataId id();
+    PiPacketMetadataId id();
 
     /**
      * Returns the size in bits of this metadata.
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiPacketOperationModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPacketOperationModel.java
index 70659a6..c48ab6b 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/PiPacketOperationModel.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPacketOperationModel.java
@@ -34,11 +34,11 @@
     PiPacketOperationType type();
 
     /**
-     * Returns a list of control metadata models for this packet operation. The metadata models are returned in the same
+     * Returns a list of packet metadata models for this packet operation. The metadata models are returned in the same
      * order as they would appear on the control header that is prepended to the packet.
      *
      * @return list of packet operation metadata models
      */
-    List<PiControlMetadataModel> metadatas();
+    List<PiPacketMetadataModel> metadatas();
 
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineInterpreter.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineInterpreter.java
index cada0f9..1d1301e 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineInterpreter.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineInterpreter.java
@@ -17,6 +17,7 @@
 package org.onosproject.net.pi.model;
 
 import com.google.common.annotations.Beta;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.driver.HandlerBehaviour;
 import org.onosproject.net.flow.TrafficTreatment;
@@ -108,14 +109,16 @@
             throws PiInterpreterException;
 
     /**
-     * Returns an inbound packet equivalent to the given PI packet operation.
+     * Returns an inbound packet equivalent to the given PI packet-in operation
+     * for the given device.
      *
      * @param packetOperation packet operation
+     * @param deviceId        ID of the device that originated the packet-in
      * @return inbound packet
      * @throws PiInterpreterException if the packet operation cannot be mapped
      *                                to an inbound packet
      */
-    InboundPacket mapInboundPacket(PiPacketOperation packetOperation)
+    InboundPacket mapInboundPacket(PiPacketOperation packetOperation, DeviceId deviceId)
             throws PiInterpreterException;
 
     /**
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileGroup.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileGroup.java
index f86e70c..57e65a2 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileGroup.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileGroup.java
@@ -21,6 +21,7 @@
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.pi.model.PiActionProfileId;
 
 import java.util.Collection;
@@ -143,6 +144,11 @@
         return PiEntityType.ACTION_PROFILE_GROUP;
     }
 
+    @Override
+    public PiActionProfileGroupHandle handle(DeviceId deviceId) {
+        return PiActionProfileGroupHandle.of(deviceId, this);
+    }
+
     /**
      * Builder of action profile groups.
      */
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileGroupHandle.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileGroupHandle.java
index 519a1c4..3579054 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileGroupHandle.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileGroupHandle.java
@@ -27,7 +27,7 @@
  * defined by a device ID, action profile ID and group ID.
  */
 @Beta
-public final class PiActionProfileGroupHandle extends PiHandle<PiActionProfileGroup> {
+public final class PiActionProfileGroupHandle extends PiHandle {
 
     private final PiActionProfileId actionProfileId;
     private final PiActionProfileGroupId groupId;
@@ -39,10 +39,11 @@
     }
 
     /**
-     * Creates a new handle for the given device ID and PI action profile group.
+     * Creates a new handle for the given device ID and PI action profile
+     * group.
      *
      * @param deviceId device ID
-     * @param group PI action profile group
+     * @param group    PI action profile group
      * @return PI action profile group handle
      */
     public static PiActionProfileGroupHandle of(DeviceId deviceId,
@@ -50,6 +51,24 @@
         return new PiActionProfileGroupHandle(deviceId, group);
     }
 
+    /**
+     * Returns the action profile ID of this handle.
+     *
+     * @return action profile ID
+     */
+    public PiActionProfileId actionProfile() {
+        return actionProfileId;
+    }
+
+    /**
+     * Returns the group ID of this handle.
+     *
+     * @return group ID
+     */
+    public PiActionProfileGroupId groupId() {
+        return groupId;
+    }
+
     @Override
     public PiEntityType entityType() {
         return PiEntityType.ACTION_PROFILE_GROUP;
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileMember.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileMember.java
index b5df9d0..d850943 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileMember.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileMember.java
@@ -19,6 +19,7 @@
 import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.pi.model.PiActionProfileId;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -74,6 +75,11 @@
     }
 
     @Override
+    public PiActionProfileMemberHandle handle(DeviceId deviceId) {
+        return PiActionProfileMemberHandle.of(deviceId, this);
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) {
             return true;
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileMemberHandle.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileMemberHandle.java
index 40cb960..7dda091 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileMemberHandle.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileMemberHandle.java
@@ -27,7 +27,7 @@
  * Global identifier of a PI action profile member, uniquely defined by a
  * device ID, action profile ID, and member ID.
  */
-public final class PiActionProfileMemberHandle extends PiHandle<PiActionProfileMember> {
+public final class PiActionProfileMemberHandle extends PiHandle {
 
     private final PiActionProfileId actionProfileId;
     private final PiActionProfileMemberId memberId;
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCell.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCell.java
index 9508cbc..34ebd7b 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCell.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCell.java
@@ -19,21 +19,23 @@
 import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
+import org.onosproject.net.DeviceId;
 
 /**
  * Counter cell of a protocol-independent pipeline.
  */
 @Beta
-public final class PiCounterCell {
+public final class PiCounterCell implements PiEntity {
 
     private final PiCounterCellId cellId;
     private final PiCounterCellData counterData;
 
     /**
-     * Creates a new counter cell for the given cell identifier and counter cell data.
+     * Creates a new counter cell for the given cell identifier and counter cell
+     * data.
      *
-     * @param cellId  counter cell identifier
-     * @param piCounterCellData  counter cell data
+     * @param cellId            counter cell identifier
+     * @param piCounterCellData counter cell data
      */
     public PiCounterCell(PiCounterCellId cellId, PiCounterCellData piCounterCellData) {
         this.cellId = cellId;
@@ -41,11 +43,12 @@
     }
 
     /**
-     * Creates a new counter cell for the given cell identifier, number of packets and bytes.
+     * Creates a new counter cell for the given cell identifier, number of
+     * packets and bytes.
      *
      * @param cellId  counter cell identifier
-     * @param packets  number of packets
-     * @param bytes  number of bytes
+     * @param packets number of packets
+     * @param bytes   number of bytes
      */
     public PiCounterCell(PiCounterCellId cellId, long packets, long bytes) {
         this.cellId = cellId;
@@ -71,6 +74,16 @@
     }
 
     @Override
+    public PiEntityType piEntityType() {
+        return PiEntityType.COUNTER_CELL;
+    }
+
+    @Override
+    public PiCounterCellHandle handle(DeviceId deviceId) {
+        return PiCounterCellHandle.of(deviceId, this);
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) {
             return true;
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellHandle.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellHandle.java
new file mode 100644
index 0000000..c06fa52
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiCounterCellHandle.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.pi.runtime;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import org.onosproject.net.DeviceId;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Global identifier of a PI counter cell instantiated on a device, uniquely
+ * defined by a device ID and cell ID.
+ */
+public final class PiCounterCellHandle extends PiHandle {
+
+    private final PiCounterCellId cellId;
+
+    private PiCounterCellHandle(DeviceId deviceId, PiCounterCellId cellId) {
+        super(deviceId);
+        this.cellId = checkNotNull(cellId);
+    }
+
+    /**
+     * Creates a new handle for the given device ID and counter cell ID.
+     *
+     * @param deviceId device ID
+     * @param cellId counter cell ID
+     * @return new counter cell handle
+     */
+    public static PiCounterCellHandle of(DeviceId deviceId, PiCounterCellId cellId) {
+        return new PiCounterCellHandle(deviceId, cellId);
+    }
+
+    /**
+     * Creates a new handle for the given device ID and counter cell.
+     *
+     * @param deviceId device ID
+     * @param cell counter cell
+     * @return new counter cell handle
+     */
+    public static PiCounterCellHandle of(DeviceId deviceId, PiCounterCell cell) {
+        return new PiCounterCellHandle(deviceId, cell.cellId());
+    }
+
+    /**
+     * Returns the counter cell ID associated with this handle.
+     *
+     * @return counter cell ID
+     */
+    public PiCounterCellId cellId() {
+        return cellId;
+    }
+
+    @Override
+    public PiEntityType entityType() {
+        return PiEntityType.COUNTER_CELL;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(deviceId(), cellId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        final PiCounterCellHandle other = (PiCounterCellHandle) obj;
+        return Objects.equal(this.deviceId(), other.deviceId())
+                && Objects.equal(this.cellId, other.cellId);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("deviceId", deviceId())
+                .add("cellId", cellId)
+                .toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiEntity.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiEntity.java
index c3d5a01..531a6a2 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiEntity.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiEntity.java
@@ -17,6 +17,7 @@
 package org.onosproject.net.pi.runtime;
 
 import com.google.common.annotations.Beta;
+import org.onosproject.net.DeviceId;
 
 /**
  * Abstraction of an entity of a protocol-independent that can be read or write
@@ -31,4 +32,12 @@
      * @return entity type
      */
     PiEntityType piEntityType();
+
+    /**
+     * Returns a handle for this PI entity and the given device ID.
+     *
+     * @param deviceId device ID
+     * @return handle
+     */
+    PiHandle handle(DeviceId deviceId);
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiEntityType.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiEntityType.java
index 4c31830..0e99188 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiEntityType.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiEntityType.java
@@ -26,35 +26,56 @@
     /**
      * Table entry.
      */
-    TABLE_ENTRY,
+    TABLE_ENTRY("table entry"),
 
     /**
      * Action profile group.
      */
-    ACTION_PROFILE_GROUP,
+    ACTION_PROFILE_GROUP("action profile group"),
 
     /**
      * Action profile member.
      */
-    ACTION_PROFILE_MEMBER,
+    ACTION_PROFILE_MEMBER("action profile member"),
 
     /**
-     * Meter config.
+     * Meter cell config.
      */
-    METER_CELL_CONFIG,
+    METER_CELL_CONFIG("meter cell config"),
 
     /**
-     * Register entry.
+     * Register cell.
      */
-    REGISTER_CELL,
+    REGISTER_CELL("register cell"),
+
+    /**
+     * Counter cell.
+     */
+    COUNTER_CELL("counter cell"),
 
     /**
      * Packet Replication Engine (PRE) multicast group entry.
      */
-    PRE_MULTICAST_GROUP_ENTRY,
+    PRE_MULTICAST_GROUP_ENTRY("PRE multicast group entry"),
 
     /**
      * Packet Replication Engine (PRE) clone session entry.
      */
-    PRE_CLONE_SESSION_ENTRY
+    PRE_CLONE_SESSION_ENTRY("PRE clone session entry");
+
+    private final String humanReadableName;
+
+    PiEntityType(String humanReadableName) {
+        this.humanReadableName = humanReadableName;
+    }
+
+    /**
+     * Returns a human readable representation of this PI entity type (useful
+     * for logging).
+     *
+     * @return string
+     */
+    public String humanReadableName() {
+        return humanReadableName;
+    }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiHandle.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiHandle.java
index eb74288..c959096 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiHandle.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiHandle.java
@@ -26,7 +26,7 @@
  * the whole network.
  */
 @Beta
-public abstract class PiHandle<E extends PiEntity> {
+public abstract class PiHandle {
 
     private final DeviceId deviceId;
 
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMatchKey.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMatchKey.java
index a978bfa..4ce849f 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMatchKey.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMatchKey.java
@@ -31,7 +31,7 @@
 @Beta
 public final class PiMatchKey {
 
-    public static final PiMatchKey EMPTY = builder().build();
+    public static final PiMatchKey EMPTY = new PiMatchKey(ImmutableMap.of());
 
     private final ImmutableMap<PiMatchFieldId, PiFieldMatch> fieldMatches;
 
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterBand.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterBand.java
index efa53ff..b1dbcf5 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterBand.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterBand.java
@@ -26,7 +26,7 @@
  * Represents a band used within a meter.
  */
 @Beta
-public class PiMeterBand {
+public final class PiMeterBand {
     private final long rate;
     private final long burst;
 
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterCellConfig.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterCellConfig.java
index 96ba124..f13e276 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterCellConfig.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterCellConfig.java
@@ -20,6 +20,7 @@
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableList;
+import org.onosproject.net.DeviceId;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -71,6 +72,11 @@
     }
 
     @Override
+    public PiMeterCellHandle handle(DeviceId deviceId) {
+        return PiMeterCellHandle.of(deviceId, this);
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) {
             return true;
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterHandle.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterCellHandle.java
similarity index 72%
rename from core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterHandle.java
rename to core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterCellHandle.java
index 4baa6fa..382f60b 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterHandle.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMeterCellHandle.java
@@ -24,15 +24,15 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
- * Global identifier of a PI meter cell configuration applied to a device,
- * uniquely defined by a device ID and meter cell ID.
+ * Global identifier of a PI meter cell instantiated on a device, uniquely
+ * defined by a device ID and meter cell ID.
  */
 @Beta
-public final class PiMeterHandle extends PiHandle<PiMeterCellConfig> {
+public final class PiMeterCellHandle extends PiHandle {
 
     private final PiMeterCellId cellId;
 
-    private PiMeterHandle(DeviceId deviceId, PiMeterCellId meterCellId) {
+    private PiMeterCellHandle(DeviceId deviceId, PiMeterCellId meterCellId) {
         super(deviceId);
         this.cellId = meterCellId;
     }
@@ -44,9 +44,9 @@
      * @param meterCellId meter cell ID
      * @return PI meter handle
      */
-    public static PiMeterHandle of(DeviceId deviceId,
-                                   PiMeterCellId meterCellId) {
-        return new PiMeterHandle(deviceId, meterCellId);
+    public static PiMeterCellHandle of(DeviceId deviceId,
+                                       PiMeterCellId meterCellId) {
+        return new PiMeterCellHandle(deviceId, meterCellId);
     }
 
     /**
@@ -57,10 +57,19 @@
      * @param meterCellConfig meter config
      * @return PI meter handle
      */
-    public static PiMeterHandle of(DeviceId deviceId,
-                                   PiMeterCellConfig meterCellConfig) {
+    public static PiMeterCellHandle of(DeviceId deviceId,
+                                       PiMeterCellConfig meterCellConfig) {
         checkNotNull(meterCellConfig);
-        return new PiMeterHandle(deviceId, meterCellConfig.cellId());
+        return new PiMeterCellHandle(deviceId, meterCellConfig.cellId());
+    }
+
+    /**
+     * Returns the cell ID associated with this handle.
+     *
+     * @return cell ID
+     */
+    public PiMeterCellId cellId() {
+        return cellId;
     }
 
     @Override
@@ -81,7 +90,7 @@
         if (o == null || getClass() != o.getClass()) {
             return false;
         }
-        PiMeterHandle that = (PiMeterHandle) o;
+        PiMeterCellHandle that = (PiMeterCellHandle) o;
         return Objects.equal(deviceId(), that.deviceId()) &&
                 Objects.equal(cellId, that.cellId);
     }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntry.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntry.java
index 41b93f6..7a833aa 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntry.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntry.java
@@ -20,6 +20,7 @@
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableSet;
+import org.onosproject.net.DeviceId;
 
 import java.util.Collection;
 import java.util.Set;
@@ -71,6 +72,11 @@
     }
 
     @Override
+    public PiMulticastGroupEntryHandle handle(DeviceId deviceId) {
+        return PiMulticastGroupEntryHandle.of(deviceId, this);
+    }
+
+    @Override
     public int hashCode() {
         return Objects.hashCode(groupId, replicas);
     }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntryHandle.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntryHandle.java
index 65a3f28..b74ca8e 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntryHandle.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiMulticastGroupEntryHandle.java
@@ -29,11 +29,11 @@
  * ID.
  */
 @Beta
-public final class PiMulticastGroupEntryHandle extends PiHandle<PiMulticastGroupEntry> {
+public final class PiMulticastGroupEntryHandle extends PiHandle {
 
-    private final long groupId;
+    private final int groupId;
 
-    private PiMulticastGroupEntryHandle(DeviceId deviceId, long groupId) {
+    private PiMulticastGroupEntryHandle(DeviceId deviceId, int groupId) {
         super(deviceId);
         this.groupId = groupId;
     }
@@ -46,7 +46,7 @@
      * @return PI multicast group entry handle
      */
     public static PiMulticastGroupEntryHandle of(DeviceId deviceId,
-                                                 long groupId) {
+                                                 int groupId) {
         return new PiMulticastGroupEntryHandle(deviceId, groupId);
     }
 
@@ -64,6 +64,15 @@
         return new PiMulticastGroupEntryHandle(deviceId, entry.groupId());
     }
 
+    /**
+     * Returns the multicast group ID associated with this handle.
+     *
+     * @return group ID
+     */
+    public int groupId() {
+        return groupId;
+    }
+
     @Override
     public PiEntityType entityType() {
         return PiEntityType.PRE_MULTICAST_GROUP_ENTRY;
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiControlMetadata.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPacketMetadata.java
similarity index 67%
rename from core/api/src/main/java/org/onosproject/net/pi/runtime/PiControlMetadata.java
rename to core/api/src/main/java/org/onosproject/net/pi/runtime/PiPacketMetadata.java
index 3caa71c..385f099 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiControlMetadata.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPacketMetadata.java
@@ -19,36 +19,40 @@
 import com.google.common.annotations.Beta;
 import com.google.common.base.Objects;
 import org.onlab.util.ImmutableByteSequence;
-import org.onosproject.net.pi.model.PiControlMetadataId;
+import org.onosproject.net.pi.model.PiPacketMetadataId;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
- * Instance of a control metadata for a protocol-independent pipeline.
+ * Instance of a metadata field for a controller packet-in/out for a
+ * protocol-independent pipeline. Metadata are used to carry information other
+ * than the packet-in/out payload, such as the original ingress port of a
+ * packet-in, or the egress port of packet-out.
  */
 @Beta
-public final class PiControlMetadata {
+public final class PiPacketMetadata {
 
-    private final PiControlMetadataId id;
+    private final PiPacketMetadataId id;
     private final ImmutableByteSequence value;
 
     /**
-     * Creates a new control metadata instance for the given identifier and value.
+     * Creates a new packet metadata instance for the given identifier and
+     * value.
      *
-     * @param id    control metadata identifier
+     * @param id    packet metadata identifier
      * @param value value for this metadata
      */
-    private PiControlMetadata(PiControlMetadataId id, ImmutableByteSequence value) {
+    private PiPacketMetadata(PiPacketMetadataId id, ImmutableByteSequence value) {
         this.id = id;
         this.value = value;
     }
 
     /**
-     * Return the identifier of this control metadata.
+     * Return the identifier of this packet metadata.
      *
-     * @return control metadata identifier
+     * @return packet metadata identifier
      */
-    public PiControlMetadataId id() {
+    public PiPacketMetadataId id() {
         return id;
     }
 
@@ -69,7 +73,7 @@
         if (o == null || getClass() != o.getClass()) {
             return false;
         }
-        PiControlMetadata piPacket = (PiControlMetadata) o;
+        PiPacketMetadata piPacket = (PiPacketMetadata) o;
         return Objects.equal(id, piPacket.id()) &&
                 Objects.equal(value, piPacket.value());
     }
@@ -85,7 +89,7 @@
     }
 
     /**
-     * Returns a control metadata builder.
+     * Returns a packet metadata builder.
      *
      * @return a new builder
      */
@@ -94,11 +98,11 @@
     }
 
     /**
-     * Builder of protocol-independent control metadatas.
+     * Builder of protocol-independent packet metadatas.
      */
     public static final class Builder {
 
-        private PiControlMetadataId id;
+        private PiPacketMetadataId id;
         private ImmutableByteSequence value;
 
         private Builder() {
@@ -106,12 +110,12 @@
         }
 
         /**
-         * Sets the identifier of this control metadata.
+         * Sets the identifier of this packet metadata.
          *
-         * @param id control metadata identifier
+         * @param id packet metadata identifier
          * @return this
          */
-        public Builder withId(PiControlMetadataId id) {
+        public Builder withId(PiPacketMetadataId id) {
             this.id = id;
             return this;
         }
@@ -128,14 +132,14 @@
         }
 
         /**
-         * Returns a new control metadata instance.
+         * Returns a new packet metadata instance.
          *
-         * @return control metadata
+         * @return packet metadata
          */
-        public PiControlMetadata build() {
+        public PiPacketMetadata build() {
             checkNotNull(id);
             checkNotNull(value);
-            return new PiControlMetadata(id, value);
+            return new PiPacketMetadata(id, value);
         }
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPacketOperation.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPacketOperation.java
index 74c68d6..5811b97 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPacketOperation.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPacketOperation.java
@@ -21,8 +21,7 @@
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableSet;
 import org.onlab.util.ImmutableByteSequence;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.pi.model.PiControlMetadataId;
+import org.onosproject.net.pi.model.PiPacketMetadataId;
 import org.onosproject.net.pi.model.PiPacketOperationType;
 
 import java.util.Collection;
@@ -33,43 +32,33 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
- * Instance of a packet I/O operation, and its control metadatas, for a protocol-independent pipeline.
+ * Instance of a packet I/O operation that includes the packet body (frame) and
+ * its metadata, for a protocol-independent pipeline.
  */
 @Beta
 public final class PiPacketOperation {
 
-    private final DeviceId deviceId;
-    private final ImmutableByteSequence data;
-    private final Set<PiControlMetadata> packetMetadatas;
+    private final ImmutableByteSequence frame;
+    private final Set<PiPacketMetadata> packetMetadatas;
     private final PiPacketOperationType type;
 
     /**
-     * Creates a new packet I/O operation for the given device ID, data, control metadatas and operation type.
+     * Creates a new packet I/O operation for the given frame, packet metadata
+     * and operation type.
      *
-     * @param deviceId        device ID
-     * @param data            the packet raw data
-     * @param packetMetadatas collection of control metadata
-     * @param type            type of this packet operation
+     * @param frame     the packet raw data
+     * @param metadatas collection of packet metadata
+     * @param type      type of this packet operation
      */
-    private PiPacketOperation(DeviceId deviceId, ImmutableByteSequence data,
-                              Collection<PiControlMetadata> packetMetadatas,
+    private PiPacketOperation(ImmutableByteSequence frame,
+                              Collection<PiPacketMetadata> metadatas,
                               PiPacketOperationType type) {
-        this.deviceId = deviceId;
-        this.data = data;
-        this.packetMetadatas = ImmutableSet.copyOf(packetMetadatas);
+        this.frame = frame;
+        this.packetMetadatas = ImmutableSet.copyOf(metadatas);
         this.type = type;
     }
 
     /**
-     * Returns the device ID of this packet operation.
-     *
-     * @return device ID
-     */
-    public DeviceId deviceId() {
-        return deviceId;
-    }
-
-    /**
      * Return the type of this packet.
      *
      * @return packet type
@@ -84,15 +73,16 @@
      * @return packet data
      */
     public ImmutableByteSequence data() {
-        return data;
+        return frame;
     }
 
     /**
-     * Returns all metadatas of this packet. Returns an empty collection if the packet doesn't have any metadata.
+     * Returns all metadatas of this packet. Returns an empty collection if the
+     * packet doesn't have any metadata.
      *
      * @return collection of metadatas
      */
-    public Collection<PiControlMetadata> metadatas() {
+    public Collection<PiPacketMetadata> metadatas() {
         return packetMetadatas;
     }
 
@@ -106,22 +96,21 @@
         }
         PiPacketOperation that = (PiPacketOperation) o;
         return Objects.equal(packetMetadatas, that.packetMetadatas) &&
-                Objects.equal(deviceId, that.deviceId) &&
-                Objects.equal(data, that.data()) &&
+                Objects.equal(frame, that.data()) &&
                 Objects.equal(type, that.type());
     }
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(deviceId, data, packetMetadatas, type);
+        return Objects.hashCode(frame, packetMetadatas, type);
     }
 
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
-                .add("deviceId", deviceId)
-                .addValue(type.toString())
-                .addValue(packetMetadatas)
+                .add("type", type)
+                .add("metadata", packetMetadatas)
+                .add("frame", frame)
                 .toString();
     }
 
@@ -139,8 +128,7 @@
      */
     public static final class Builder {
 
-        private DeviceId deviceId;
-        private Map<PiControlMetadataId, PiControlMetadata> packetMetadatas = new HashMap<>();
+        private Map<PiPacketMetadataId, PiPacketMetadata> packetMetadatas = new HashMap<>();
         private PiPacketOperationType type;
         private ImmutableByteSequence data;
 
@@ -149,18 +137,6 @@
         }
 
         /**
-         * Sets the device ID.
-         *
-         * @param deviceId device ID
-         * @return this
-         */
-        public Builder forDevice(DeviceId deviceId) {
-            checkNotNull(deviceId);
-            this.deviceId = deviceId;
-            return this;
-        }
-
-        /**
          * Sets the raw packet data.
          *
          * @param data the packet raw data
@@ -173,13 +149,14 @@
         }
 
         /**
-         * Adds a control metadata. Only one metadata is allowed for a given metadata id. If a metadata with same id
-         * already exists it will be replaced by the given one.
+         * Adds a packet metadata. Only one metadata is allowed for a given
+         * metadata id. If a metadata with same id already exists it will be
+         * replaced by the given one.
          *
          * @param metadata packet metadata
          * @return this
          */
-        public Builder withMetadata(PiControlMetadata metadata) {
+        public Builder withMetadata(PiPacketMetadata metadata) {
             checkNotNull(metadata);
             packetMetadatas.put(metadata.id(), metadata);
 
@@ -192,7 +169,7 @@
          * @param metadatas collection of metadata
          * @return this
          */
-        public Builder withMetadatas(Collection<PiControlMetadata> metadatas) {
+        public Builder withMetadatas(Collection<PiPacketMetadata> metadatas) {
             checkNotNull(metadatas);
             metadatas.forEach(this::withMetadata);
             return this;
@@ -215,11 +192,10 @@
          * @return packet operation
          */
         public PiPacketOperation build() {
-            checkNotNull(deviceId);
             checkNotNull(data);
             checkNotNull(packetMetadatas);
             checkNotNull(type);
-            return new PiPacketOperation(deviceId, data, packetMetadatas.values(), type);
+            return new PiPacketOperation(data, packetMetadatas.values(), type);
         }
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPreReplica.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPreReplica.java
index 4f65e4d..3a03feb 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPreReplica.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiPreReplica.java
@@ -16,6 +16,7 @@
 
 package org.onosproject.net.pi.runtime;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Objects;
 import org.onosproject.net.PortNumber;
 
@@ -29,7 +30,8 @@
  * Each replica is uniquely identified inside a given multicast group or clone
  * session by the pair (egress port, instance ID).
  */
-public class PiPreReplica {
+@Beta
+public final class PiPreReplica {
 
     private final PortNumber egressPort;
     private final int instanceId;
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiRegisterCell.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiRegisterCell.java
index fd354ec..c50771b 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiRegisterCell.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiRegisterCell.java
@@ -19,6 +19,7 @@
 import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.pi.model.PiData;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -61,6 +62,12 @@
     }
 
     @Override
+    public PiHandle handle(DeviceId deviceId) {
+        // TODO: implement support for register cell handles
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    @Override
     public boolean equals(Object obj) {
         if (this == obj) {
             return true;
@@ -137,4 +144,4 @@
             return new PiRegisterCell(cellId, piData);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java
index b25ada5..ee3c3c3 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntry.java
@@ -19,9 +19,11 @@
 import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.pi.model.PiTableId;
 
 import java.util.Optional;
+import java.util.OptionalInt;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -112,8 +114,8 @@
      *
      * @return optional priority
      */
-    public Optional<Integer> priority() {
-        return priority == NO_PRIORITY ? Optional.empty() : Optional.of(priority);
+    public OptionalInt priority() {
+        return priority == NO_PRIORITY ? OptionalInt.empty() : OptionalInt.of(priority);
     }
 
     /**
@@ -203,6 +205,11 @@
         return PiEntityType.TABLE_ENTRY;
     }
 
+    @Override
+    public PiTableEntryHandle handle(DeviceId deviceId) {
+        return PiTableEntryHandle.of(deviceId, this);
+    }
+
     public static final class Builder {
 
         private PiTableId tableId;
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntryHandle.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntryHandle.java
index 2b210a1..b4edb3c 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntryHandle.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntryHandle.java
@@ -22,6 +22,8 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.pi.model.PiTableId;
 
+import java.util.OptionalInt;
+
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
@@ -29,30 +31,20 @@
  * by a device ID, table ID and match key.
  */
 @Beta
-public final class PiTableEntryHandle extends PiHandle<PiTableEntry> {
+public final class PiTableEntryHandle extends PiHandle {
+
+    private static final int NO_PRIORITY = -1;
 
     private final PiTableId tableId;
     private final PiMatchKey matchKey;
+    private final int priority;
 
-    private PiTableEntryHandle(DeviceId deviceId, PiTableId tableId, PiMatchKey matchKey) {
+    private PiTableEntryHandle(DeviceId deviceId, PiTableId tableId, PiMatchKey matchKey,
+                               Integer priority) {
         super(deviceId);
         this.tableId = tableId;
         this.matchKey = matchKey;
-    }
-
-    /**
-     * Creates a new handle for the given device ID, PI table ID, and match
-     * key.
-     *
-     * @param deviceId device ID
-     * @param tableId  table ID
-     * @param matchKey match key
-     * @return PI table entry handle
-     */
-    public static PiTableEntryHandle of(DeviceId deviceId, PiTableId tableId, PiMatchKey matchKey) {
-        checkNotNull(tableId);
-        checkNotNull(matchKey);
-        return new PiTableEntryHandle(deviceId, tableId, matchKey);
+        this.priority = priority;
     }
 
     /**
@@ -64,7 +56,37 @@
      */
     public static PiTableEntryHandle of(DeviceId deviceId, PiTableEntry entry) {
         checkNotNull(entry);
-        return PiTableEntryHandle.of(deviceId, entry.table(), entry.matchKey());
+        return new PiTableEntryHandle(
+                deviceId, entry.table(), entry.matchKey(),
+                entry.priority().orElse(NO_PRIORITY));
+    }
+
+    /**
+     * Returns the table ID associated with this handle.
+     *
+     * @return table ID
+     */
+    public PiTableId tableId() {
+        return tableId;
+    }
+
+    /**
+     * Returns the match key associated with this handle.
+     *
+     * @return match key
+     */
+    public PiMatchKey matchKey() {
+        return matchKey;
+    }
+
+    /**
+     * Returns the optional priority associated with this handle.
+     *
+     * @return optional priority
+     */
+    public OptionalInt priority() {
+        return priority == NO_PRIORITY
+                ? OptionalInt.empty() : OptionalInt.of(priority);
     }
 
     @Override
@@ -74,7 +96,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(deviceId(), tableId, matchKey);
+        return Objects.hashCode(deviceId(), tableId, matchKey, priority().orElse(NO_PRIORITY));
     }
 
     @Override
@@ -88,7 +110,8 @@
         final PiTableEntryHandle other = (PiTableEntryHandle) obj;
         return Objects.equal(this.deviceId(), other.deviceId())
                 && Objects.equal(this.tableId, other.tableId)
-                && Objects.equal(this.matchKey, other.matchKey);
+                && Objects.equal(this.matchKey, other.matchKey)
+                && Objects.equal(this.priority(), other.priority());
     }
 
     @Override
@@ -97,6 +120,7 @@
                 .add("deviceId", deviceId())
                 .add("tableId", tableId)
                 .add("matchKey", matchKey)
+                .add("priority", priority == NO_PRIORITY ? "N/A" : priority)
                 .toString();
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiPipeconfService.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiPipeconfService.java
index e9539a5..9943352 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/service/PiPipeconfService.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiPipeconfService.java
@@ -71,6 +71,16 @@
     Optional<PiPipeconf> getPipeconf(PiPipeconfId id);
 
     /**
+     * Returns the pipeconf instance associated with the given device, if
+     * present. If not present, it means no pipeconf has been associated with
+     * that device so far.
+     *
+     * @param deviceId a device identifier
+     * @return an optional pipeconf
+     */
+    Optional<PiPipeconf> getPipeconf(DeviceId deviceId);
+
+    /**
      * Signals that the given pipeconf is associated to the given infrastructure
      * device. As a result of this method, the pipeconf for the given device can
      * be later retrieved using {@link #ofDevice(DeviceId)}
@@ -107,7 +117,9 @@
      *
      * @param deviceId device identifier
      * @return an optional pipeconf identifier
+     * @deprecated in ONOS 2.1 use {@link #getPipeconf(DeviceId)} instead
      */
+    @Deprecated
     Optional<PiPipeconfId> ofDevice(DeviceId deviceId);
 
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslatedEntity.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslatedEntity.java
index 4ca094b..3c3d9f6 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslatedEntity.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslatedEntity.java
@@ -32,7 +32,7 @@
 
     private final T original;
     private final E translated;
-    private final PiHandle<E> handle;
+    private final PiHandle handle;
 
     /**
      * Creates a new translated entity.
@@ -41,7 +41,7 @@
      * @param translated PI entity
      * @param handle PI entity handle
      */
-    public PiTranslatedEntity(T original, E translated, PiHandle<E> handle) {
+    public PiTranslatedEntity(T original, E translated, PiHandle handle) {
         this.original = checkNotNull(original);
         this.translated = checkNotNull(translated);
         this.handle = checkNotNull(handle);
@@ -79,7 +79,7 @@
      *
      * @return PI entity handle
      */
-    public final PiHandle<E> handle() {
+    public final PiHandle handle() {
         return handle;
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationStore.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationStore.java
index 6274deb..a1f3a60 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationStore.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationStore.java
@@ -39,7 +39,7 @@
      * @param handle PI entity handle
      * @param entity PI translated entity
      */
-    void addOrUpdate(PiHandle<E> handle, PiTranslatedEntity<T, E> entity);
+    void addOrUpdate(PiHandle handle, PiTranslatedEntity<T, E> entity);
 
     /**
      * Returns a PI translated entity for the given handle. Returns null if this
@@ -49,12 +49,12 @@
      * @param handle PI entity handle
      * @return PI translated entity
      */
-    PiTranslatedEntity<T, E> get(PiHandle<E> handle);
+    PiTranslatedEntity<T, E> get(PiHandle handle);
 
     /**
      * Removes a previously added mapping for the given PI entity handle.
      *
      * @param handle PI entity handle
      */
-    void remove(PiHandle<E> handle);
+    void remove(PiHandle handle);
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslator.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslator.java
index 202636a..499fdc5 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslator.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslator.java
@@ -52,7 +52,7 @@
      * @param handle PI entity handle
      * @param entity PI translated entity
      */
-    void learn(PiHandle<E> handle, PiTranslatedEntity<T, E> entity);
+    void learn(PiHandle handle, PiTranslatedEntity<T, E> entity);
 
     /**
      * Returns a PI translated entity that was previously associated with the
@@ -64,12 +64,12 @@
      * @param handle PI entity handle
      * @return optional PI translated entity
      */
-    Optional<PiTranslatedEntity<T, E>> lookup(PiHandle<E> handle);
+    Optional<PiTranslatedEntity<T, E>> lookup(PiHandle handle);
 
     /**
      * Removes any mapping for the given PI entity handle.
      *
      * @param handle PI entity handle.
      */
-    void forget(PiHandle<E> handle);
+    void forget(PiHandle handle);
 }