ONOS-7050 Refactored PI translation service and store

The translation store is now able to maintain mappings between
translated entities and specific instances of a PI entry in the network
(i.e. applied to a device).

The translation service has been refactored to allow users to
learn and forget translated entities.

The refactoring of the P4Runtime driver using this service will be
submitted separatelly.

Change-Id: Iaafd87d90232514853ca0dea0115dbae4f6e7886
diff --git a/core/api/src/main/java/org/onosproject/net/group/Group.java b/core/api/src/main/java/org/onosproject/net/group/Group.java
index 3e2494c..39c6a3d 100644
--- a/core/api/src/main/java/org/onosproject/net/group/Group.java
+++ b/core/api/src/main/java/org/onosproject/net/group/Group.java
@@ -16,11 +16,12 @@
 package org.onosproject.net.group;
 
 import org.onosproject.core.GroupId;
+import org.onosproject.net.pi.service.PiTranslatable;
 
 /**
  * ONOS representation of group that is stored in the system.
  */
-public interface Group extends GroupDescription {
+public interface Group extends GroupDescription, PiTranslatable {
     /**
      * State of the group object in ONOS.
      */
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionGroupHandle.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionGroupHandle.java
new file mode 100644
index 0000000..6c464de
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionGroupHandle.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2017-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.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import org.onosproject.net.DeviceId;
+
+/**
+ * Global identifier of a PI action group applied to a device, uniquely defined
+ * by a device ID, action profile ID and group ID.
+ */
+@Beta
+public final class PiActionGroupHandle extends PiHandle<PiActionGroup> {
+
+
+    private PiActionGroupHandle(DeviceId deviceId, PiActionGroup actionGroup) {
+        super(deviceId, actionGroup);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(deviceId(),
+                                piEntity().actionProfileId(),
+                                piEntity().id());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PiActionGroupHandle that = (PiActionGroupHandle) o;
+        return Objects.equal(deviceId(), that.deviceId()) &&
+                Objects.equal(piEntity().actionProfileId(),
+                              that.piEntity().actionProfileId()) &&
+                Objects.equal(piEntity().id(), piEntity().id());
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("deviceId", deviceId())
+                .add("actionProfileId", piEntity().actionProfileId())
+                .add("groupId", piEntity().id())
+                .toString();
+    }
+}
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
new file mode 100644
index 0000000..e8e70d1
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiHandle.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2017-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.annotations.Beta;
+import org.onosproject.net.DeviceId;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Global identifier of a PI entity applied to a device, unique in the scope of
+ * the whole network.
+ */
+@Beta
+public abstract class PiHandle<E extends PiEntity> {
+
+    private final DeviceId deviceId;
+    private final E piEntity;
+
+    protected PiHandle(DeviceId deviceId, E piEntity) {
+        this.deviceId = checkNotNull(deviceId);
+        this.piEntity = checkNotNull(piEntity);
+    }
+
+    /**
+     * Returns the device ID of this handle.
+     *
+     * @return device ID
+     */
+    public final DeviceId deviceId() {
+        return deviceId;
+    }
+
+    /**
+     * Returns the type of entity identified by this handle.
+     *
+     * @return PI entity type
+     */
+    public final PiEntityType entityType() {
+        return piEntity.piEntityType();
+    }
+
+    /**
+     * The entity to which this handle is associated.
+     *
+     * @return PI entity
+     */
+    public final E piEntity() {
+        return piEntity;
+    }
+
+    @Override
+    public abstract int hashCode();
+
+    @Override
+    public abstract boolean equals(Object obj);
+
+    @Override
+    public abstract String toString();
+}
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
new file mode 100644
index 0000000..7eeb7f6
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiTableEntryHandle.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2017-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.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import org.onosproject.net.DeviceId;
+
+/**
+ * Global identifier of a PI table entry applied on a device, uniquely defined
+ * by a device ID, table ID and match key.
+ */
+@Beta
+public final class PiTableEntryHandle extends PiHandle<PiTableEntry> {
+
+    private PiTableEntryHandle(DeviceId deviceId, PiTableEntry entry) {
+        super(deviceId, entry);
+    }
+
+    /**
+     * Creates a new handle for the given PI table entry and device ID.
+     *
+     * @param deviceId device ID
+     * @param entry    PI table entry
+     * @return PI table entry handle
+     */
+    public static PiTableEntryHandle of(DeviceId deviceId, PiTableEntry entry) {
+        return new PiTableEntryHandle(deviceId, entry);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(deviceId(),
+                                piEntity().table(),
+                                piEntity().matchKey());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        final PiTableEntryHandle other = (PiTableEntryHandle) obj;
+        return Objects.equal(this.deviceId(), other.deviceId())
+                && Objects.equal(this.piEntity().table(),
+                                 other.piEntity().table())
+                && Objects.equal(this.piEntity().matchKey(),
+                                 other.piEntity().matchKey());
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("deviceId", deviceId())
+                .add("tableId", piEntity().table())
+                .add("matchKey", piEntity().matchKey())
+                .toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiFlowRuleTranslationStore.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiFlowRuleTranslationStore.java
new file mode 100644
index 0000000..a80de10
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiFlowRuleTranslationStore.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017-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.service;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.pi.runtime.PiTableEntry;
+
+/**
+ * A PI translation store that keeps track of which flow rules have been
+ * translated to which PI table entries.
+ */
+@Beta
+public interface PiFlowRuleTranslationStore
+        extends PiTranslationStore<FlowRule, PiTableEntry> {
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiFlowRuleTranslator.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiFlowRuleTranslator.java
new file mode 100644
index 0000000..cc82f73
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiFlowRuleTranslator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017-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.service;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.pi.runtime.PiTableEntry;
+
+/**
+ * A translator of flow rules to PI table entries.
+ */
+@Beta
+public interface PiFlowRuleTranslator
+        extends PiTranslator<FlowRule, PiTableEntry> {
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiGroupTranslationStore.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiGroupTranslationStore.java
new file mode 100644
index 0000000..4fe526a
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiGroupTranslationStore.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017-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.service;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.group.Group;
+import org.onosproject.net.pi.runtime.PiActionGroup;
+
+/**
+ * A PI translation store that keeps track of which groups have been
+ * translated to which PI action groups.
+ */
+@Beta
+public interface PiGroupTranslationStore
+        extends PiTranslationStore<Group, PiActionGroup> {
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiGroupTranslator.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiGroupTranslator.java
new file mode 100644
index 0000000..d5eb5af
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiGroupTranslator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017-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.service;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.group.Group;
+import org.onosproject.net.pi.runtime.PiActionGroup;
+
+/**
+ * A translator of groups to PI action groups.
+ */
+@Beta
+public interface PiGroupTranslator
+        extends PiTranslator<Group, PiActionGroup> {
+}
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 8914eee..4ca094b 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
@@ -17,29 +17,34 @@
 package org.onosproject.net.pi.service;
 
 import com.google.common.annotations.Beta;
-import org.onosproject.net.pi.model.PiPipeconfId;
 import org.onosproject.net.pi.runtime.PiEntity;
 import org.onosproject.net.pi.runtime.PiEntityType;
+import org.onosproject.net.pi.runtime.PiHandle;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
- * Representation of the result of a PD-to-PI translation.
+ * Representation of the result of a PD-to-PI translation associated to a PI
+ * entity handle.
  */
 @Beta
-public final class PiTranslatedEntity {
+public final class PiTranslatedEntity<T extends PiTranslatable, E extends PiEntity> {
 
-    private final PiTranslatable original;
-    private final PiEntity translated;
-    private final PiPipeconfId pipeconfId;
-    private final PiEntityType type;
+    private final T original;
+    private final E translated;
+    private final PiHandle<E> handle;
 
-    public PiTranslatedEntity(PiTranslatable original, PiEntity translated,
-                              PiPipeconfId pipeconfId) {
+    /**
+     * Creates a new translated entity.
+     *
+     * @param original PD entity
+     * @param translated PI entity
+     * @param handle PI entity handle
+     */
+    public PiTranslatedEntity(T original, E translated, PiHandle<E> handle) {
         this.original = checkNotNull(original);
         this.translated = checkNotNull(translated);
-        this.pipeconfId = checkNotNull(pipeconfId);
-        this.type = checkNotNull(translated.piEntityType());
+        this.handle = checkNotNull(handle);
     }
 
     /**
@@ -48,7 +53,7 @@
      * @return type of the translated entity
      */
     public final PiEntityType entityType() {
-        return type;
+        return translated.piEntityType();
     }
 
     /**
@@ -56,7 +61,7 @@
      *
      * @return instance of PI translatable entity
      */
-    public final PiTranslatable original() {
+    public final T original() {
         return original;
     }
 
@@ -65,18 +70,16 @@
      *
      * @return PI entity
      */
-    public final PiEntity translated() {
+    public final E translated() {
         return translated;
     }
 
     /**
-     * The ID of the pipeconf for which this translation is valid. In other
-     * words, the PI entity is guaranteed to be functionally equivalent to the
-     * PD one when applied to a device configured with such pipeconf.
+     * Returns the PI entity handle.
      *
-     * @return PI pipeconf ID
+     * @return PI entity handle
      */
-    public final PiPipeconfId pipeconfId() {
-        return pipeconfId;
+    public final PiHandle<E> handle() {
+        return handle;
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationEvent.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationEvent.java
index 4f59079..9e2411d 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationEvent.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationEvent.java
@@ -18,14 +18,15 @@
 
 import com.google.common.annotations.Beta;
 import org.onosproject.event.AbstractEvent;
+import org.onosproject.net.pi.runtime.PiEntity;
 
 /**
  * Signals an event related to the translation of a protocol-dependent (PD)
  * entity to a protocol-independent (PI) one.
  */
 @Beta
-public final class PiTranslationEvent
-        extends AbstractEvent<PiTranslationEvent.Type, PiTranslatedEntity> {
+public final class PiTranslationEvent<T extends PiTranslatable, E extends PiEntity>
+        extends AbstractEvent<PiTranslationEvent.Type, PiTranslatedEntity<T, E>> {
 
     /**
      * Type of event.
@@ -50,7 +51,7 @@
      * @param type    type of event
      * @param subject subject of event
      */
-    public PiTranslationEvent(Type type, PiTranslatedEntity subject) {
+    public PiTranslationEvent(Type type, PiTranslatedEntity<T, E> subject) {
         super(type, subject);
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationException.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationException.java
new file mode 100644
index 0000000..d8a6c63
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017-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.service;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Signals that an error was encountered while translating an entity.
+ */
+@Beta
+public final class PiTranslationException extends Exception {
+
+    /**
+     * Creates a new exception with the given message.
+     *
+     * @param message a message
+     */
+    public PiTranslationException(String message) {
+        super(message);
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationService.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationService.java
index 6af3e83..c7a95c3 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationService.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationService.java
@@ -17,14 +17,6 @@
 package org.onosproject.net.pi.service;
 
 import com.google.common.annotations.Beta;
-import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.group.Group;
-import org.onosproject.net.pi.model.PiPipeconf;
-import org.onosproject.net.pi.model.PiPipeconfId;
-import org.onosproject.net.pi.runtime.PiActionGroup;
-import org.onosproject.net.pi.runtime.PiTableEntry;
-
-import java.util.Optional;
 
 /**
  * A service to translate protocol-dependent (PD) entities to
@@ -34,65 +26,16 @@
 public interface PiTranslationService {
 
     /**
-     * Returns a PI table entry equivalent to the given flow rule for the given
-     * protocol-independent pipeline configuration.
+     * Returns a flow rule translator.
      *
-     * @param rule     a flow rule
-     * @param pipeconf a pipeline configuration
-     * @return a table entry
-     * @throws PiTranslationException if the flow rule cannot be translated
+     * @return flow rule translator
      */
-    PiTableEntry translate(FlowRule rule, PiPipeconf pipeconf)
-            throws PiTranslationException;
+    PiFlowRuleTranslator flowRuleTranslator();
 
     /**
-     * Returns a PI action group equivalent to the given group for the given
-     * protocol-independent pipeline configuration.
+     * Returns a group translator.
      *
-     * @param group    a group
-     * @param pipeconf a pipeline configuration
-     * @return a PI action group
-     * @throws PiTranslationException if the group cannot be translated
+     * @return group translator
      */
-    PiActionGroup translate(Group group, PiPipeconf pipeconf)
-            throws PiTranslationException;
-
-    /**
-     * Returns a flow rule previously translated to the given PI table entry,
-     * for the given pipeconf ID, if present. If not present it means that such
-     * flow rule was never translated in the first place.
-     *
-     * @param piTableEntry PI table entry
-     * @param pipeconfId   pipeconf ID
-     * @return optional flow rule
-     */
-    Optional<FlowRule> lookup(PiTableEntry piTableEntry,
-                              PiPipeconfId pipeconfId);
-
-    /**
-     * Returns a group previously translated to the given PI action group, for
-     * the given pipeconf ID, if present. If not present it means that such
-     * group was never translated in the first place.
-     *
-     * @param piActionGroup PI action group
-     * @param pipeconfId    pipeconf ID
-     * @return optional group
-     */
-    Optional<Group> lookup(PiActionGroup piActionGroup,
-                           PiPipeconfId pipeconfId);
-
-    /**
-     * Signals that an error was encountered while translating an entity.
-     */
-    class PiTranslationException extends Exception {
-
-        /**
-         * Creates a new exception with the given message.
-         *
-         * @param message a message
-         */
-        public PiTranslationException(String message) {
-            super(message);
-        }
-    }
+    PiGroupTranslator groupTranslator();
 }
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 6e0dec7..6274deb 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
@@ -17,55 +17,44 @@
 package org.onosproject.net.pi.service;
 
 import com.google.common.annotations.Beta;
-import org.onosproject.net.pi.model.PiPipeconfId;
 import org.onosproject.net.pi.runtime.PiEntity;
+import org.onosproject.net.pi.runtime.PiHandle;
 import org.onosproject.store.Store;
 
 /**
- * PI translation service store abstraction that acts as a multi-language
- * dictionary. For each pipeconf ID (language) it maintains a mapping between a
- * protocol-dependent (PD) entity and an equivalent protocol-independent (PI)
- * one.
+ * PI translation store abstraction that maintains a mapping between a PI entity
+ * handle and a translated entity.
+ *
+ * @param <T> PD entity class (translatable to PI)
+ * @param <E> PI entity class
  */
 @Beta
-public interface PiTranslationStore
-        extends Store<PiTranslationEvent, PiTranslationStoreDelegate> {
+public interface PiTranslationStore<T extends PiTranslatable, E extends PiEntity>
+        extends Store<PiTranslationEvent<T, E>, PiTranslationStoreDelegate<T, E>> {
 
     /**
-     * Adds or update a mapping between the given PD entity (original) and the
-     * translated PI counterpart, for the given pipeconf ID.
+     * Adds or update a mapping between the given PI entity handle and
+     * translated entity.
      *
-     * @param original   PD entity
-     * @param translated PI entity
-     * @param pipeconfId pipeconf ID
+     * @param handle PI entity handle
+     * @param entity PI translated entity
      */
-    void addOrUpdate(PiTranslatable original, PiEntity translated,
-                     PiPipeconfId pipeconfId);
+    void addOrUpdate(PiHandle<E> handle, PiTranslatedEntity<T, E> entity);
 
     /**
-     * Removes a previously added mapping for the given PI entity and pipeconf
+     * Returns a PI translated entity for the given handle. Returns null if this
+     * store does not contain a mapping between the two for the given pipeconf
      * ID.
      *
-     * @param piEntity   PI entity
-     * @param pipeconfId pipeconf ID
+     * @param handle PI entity handle
+     * @return PI translated entity
      */
-    void remove(PiEntity piEntity, PiPipeconfId pipeconfId);
+    PiTranslatedEntity<T, E> get(PiHandle<E> handle);
 
     /**
-     * Removes all previously learned mappings for the given pipeconf ID.
+     * Removes a previously added mapping for the given PI entity handle.
      *
-     * @param pipeconfId pipeconf ID
+     * @param handle PI entity handle
      */
-    void removeAll(PiPipeconfId pipeconfId);
-
-    /**
-     * Returns a PD entity for the given PI one and pipeconf ID. Returns null if
-     * this store does not contain a mapping between the two for the given
-     * pipeconf ID.
-     *
-     * @param piEntity   PI entity
-     * @param pipeconfId pipeconf ID
-     * @return PD entity or null
-     */
-    PiTranslatable lookup(PiEntity piEntity, PiPipeconfId pipeconfId);
+    void remove(PiHandle<E> handle);
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationStoreDelegate.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationStoreDelegate.java
index 0fe5c75..2a8d16f 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationStoreDelegate.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationStoreDelegate.java
@@ -17,12 +17,17 @@
 package org.onosproject.net.pi.service;
 
 import com.google.common.annotations.Beta;
+import org.onosproject.net.pi.runtime.PiEntity;
 import org.onosproject.store.StoreDelegate;
 
 /**
- * PI translation service store delegate abstraction.
+ * PI translation store delegate abstraction.
+ *
+ * @param <T> PD entity class (translatable to PI)
+ * @param <E> PI entity class
  */
 @Beta
 public interface PiTranslationStoreDelegate
-        extends StoreDelegate<PiTranslationEvent> {
+        <T extends PiTranslatable, E extends PiEntity>
+        extends StoreDelegate<PiTranslationEvent<T, E>> {
 }
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
new file mode 100644
index 0000000..202636a
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslator.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017-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.service;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiEntity;
+import org.onosproject.net.pi.runtime.PiHandle;
+
+import java.util.Optional;
+
+/**
+ * A translator of PI entities to equivalent PD ones which offer means to learn
+ * translated entities for later use.
+ *
+ * @param <T> PD entity class (translatable to PI)
+ * @param <E> PI entity class
+ */
+@Beta
+public interface PiTranslator<T extends PiTranslatable, E extends PiEntity> {
+
+    /**
+     * Translate the given PD entity (original) and returns a PI entity that is
+     * equivalent to he PD one for the given pipeconf.
+     *
+     * @param original PD entity
+     * @param pipeconf pipeconf
+     * @return PI entity
+     * @throws PiTranslationException if a translation is not possible (see
+     *                                message for an explanation)
+     */
+    E translate(T original, PiPipeconf pipeconf)
+            throws PiTranslationException;
+
+    /**
+     * Stores a mapping between the given translated entity and handle.
+     *
+     * @param handle PI entity handle
+     * @param entity PI translated entity
+     */
+    void learn(PiHandle<E> handle, PiTranslatedEntity<T, E> entity);
+
+    /**
+     * Returns a PI translated entity that was previously associated with the
+     * given  handle, if present. If not present, it means a mapping between the
+     * two has not been learned by the system (via {@link #learn(PiHandle,
+     * PiTranslatedEntity)}) or that it has been removed (via {@link
+     * #forget(PiHandle)}). the
+     *
+     * @param handle PI entity handle
+     * @return optional PI translated entity
+     */
+    Optional<PiTranslatedEntity<T, E>> lookup(PiHandle<E> handle);
+
+    /**
+     * Removes any mapping for the given PI entity handle.
+     *
+     * @param handle PI entity handle.
+     */
+    void forget(PiHandle<E> handle);
+}