ONOS-7050 First stab at PI translation store

Change-Id: I7f48802b1f5d70fbe3e6cead2800855de18b9207
diff --git a/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java b/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java
index 27a604c..b62007f 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java
@@ -18,12 +18,13 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.GroupId;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.pi.service.PiTranslatable;
 
 /**
  * Represents a generalized match & action pair to be applied to an
  * infrastructure device.
  */
-public interface FlowRule {
+public interface FlowRule extends PiTranslatable {
 
     IndexTableId DEFAULT_TABLE = IndexTableId.of(0);
     int MAX_TIMEOUT = 60;
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionGroup.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionGroup.java
index 1d9a94b..9084bea 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionGroup.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionGroup.java
@@ -34,7 +34,7 @@
  * Instance of an action group of a protocol-independent pipeline.
  */
 @Beta
-public final class PiActionGroup {
+public final class PiActionGroup implements PiEntity {
 
     private final PiActionGroupId id;
     private final PiActionGroupType type;
@@ -125,6 +125,11 @@
         return new Builder();
     }
 
+    @Override
+    public PiEntityType piEntityType() {
+        return PiEntityType.GROUP;
+    }
+
     /**
      * Builder of action groups.
      */
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
new file mode 100644
index 0000000..c3d5a01
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiEntity.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+/**
+ * Abstraction of an entity of a protocol-independent that can be read or write
+ * at runtime.
+ */
+@Beta
+public interface PiEntity {
+
+    /**
+     * Returns the type of this entity.
+     *
+     * @return entity type
+     */
+    PiEntityType piEntityType();
+}
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
new file mode 100644
index 0000000..e01e520
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiEntityType.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.runtime;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Type of runtime entity of a protocol-independent pipeline.
+ */
+@Beta
+public enum PiEntityType {
+    /**
+     * Table entry.
+     */
+    TABLE_ENTRY,
+
+    /**
+     * Action profile group.
+     */
+    GROUP
+}
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 cd7e493..5770c6b 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
@@ -30,7 +30,7 @@
  * Instance of a table entry in a protocol-independent pipeline.
  */
 @Beta
-public final class PiTableEntry {
+public final class PiTableEntry implements PiEntity {
 
     public static final PiTableEntry EMTPY = new PiTableEntry();
 
@@ -160,6 +160,11 @@
         return new Builder();
     }
 
+    @Override
+    public PiEntityType piEntityType() {
+        return PiEntityType.TABLE_ENTRY;
+    }
+
     public static final class Builder {
 
         private PiTableId tableId;
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslatable.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslatable.java
new file mode 100644
index 0000000..316c3ed
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslatable.java
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+/**
+ * Abstraction of protocol-dependent (PD) entity that can be translated to an
+ * equivalent protocol-independent (PI) one.
+ */
+@Beta
+public interface PiTranslatable {
+}
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
new file mode 100644
index 0000000..8914eee
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslatedEntity.java
@@ -0,0 +1,82 @@
+/*
+ * 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.PiPipeconfId;
+import org.onosproject.net.pi.runtime.PiEntity;
+import org.onosproject.net.pi.runtime.PiEntityType;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Representation of the result of a PD-to-PI translation.
+ */
+@Beta
+public final class PiTranslatedEntity {
+
+    private final PiTranslatable original;
+    private final PiEntity translated;
+    private final PiPipeconfId pipeconfId;
+    private final PiEntityType type;
+
+    public PiTranslatedEntity(PiTranslatable original, PiEntity translated,
+                              PiPipeconfId pipeconfId) {
+        this.original = checkNotNull(original);
+        this.translated = checkNotNull(translated);
+        this.pipeconfId = checkNotNull(pipeconfId);
+        this.type = checkNotNull(translated.piEntityType());
+    }
+
+    /**
+     * Returns the type of the translated entity.
+     *
+     * @return type of the translated entity
+     */
+    public final PiEntityType entityType() {
+        return type;
+    }
+
+    /**
+     * Returns the original PD entity.
+     *
+     * @return instance of PI translatable entity
+     */
+    public final PiTranslatable original() {
+        return original;
+    }
+
+    /**
+     * Returns the translated PI entity.
+     *
+     * @return PI entity
+     */
+    public final PiEntity 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.
+     *
+     * @return PI pipeconf ID
+     */
+    public final PiPipeconfId pipeconfId() {
+        return pipeconfId;
+    }
+}
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
new file mode 100644
index 0000000..4f59079
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.event.AbstractEvent;
+
+/**
+ * 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> {
+
+    /**
+     * Type of event.
+     */
+    public enum Type {
+        /**
+         * Signals that A PD entity has been translated to a PI one, and the
+         * mapping between the two entities has been learned by the system.
+         */
+        LEARNED,
+
+        /**
+         * Signals that a previously learned mapping between a PD entity and its
+         * PI counterpart has been removed.
+         */
+        FORGOT,
+    }
+
+    /**
+     * Creates a new translation event.
+     *
+     * @param type    type of event
+     * @param subject subject of event
+     */
+    public PiTranslationEvent(Type type, PiTranslatedEntity subject) {
+        super(type, subject);
+    }
+}
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 210b7e0..6af3e83 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
@@ -20,40 +20,68 @@
 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 entities to protocol-independent ones.
+ * A service to translate protocol-dependent (PD) entities to
+ * protocol-independent (PI) ones.
  */
 @Beta
 public interface PiTranslationService {
 
     /**
-     * Returns a PI table entry equivalent to the given flow rule for the given protocol-independent pipeline
-     * configuration.
+     * Returns a PI table entry equivalent to the given flow rule for the given
+     * protocol-independent pipeline configuration.
      *
      * @param rule     a flow rule
      * @param pipeconf a pipeline configuration
      * @return a table entry
      * @throws PiTranslationException if the flow rule cannot be translated
      */
-    PiTableEntry translateFlowRule(FlowRule rule, PiPipeconf pipeconf)
+    PiTableEntry translate(FlowRule rule, PiPipeconf pipeconf)
             throws PiTranslationException;
 
     /**
-     * Returns a PI action group equivalent to the given group for the given protocol-independent pipeline
-     * configuration.
+     * Returns a PI action group equivalent to the given group for the given
+     * protocol-independent pipeline configuration.
      *
      * @param group    a group
      * @param pipeconf a pipeline configuration
      * @return a PI action group
      * @throws PiTranslationException if the group cannot be translated
      */
-    PiActionGroup translateGroup(Group group, PiPipeconf pipeconf)
+    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 {
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
new file mode 100644
index 0000000..6e0dec7
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationStore.java
@@ -0,0 +1,71 @@
+/*
+ * 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.PiPipeconfId;
+import org.onosproject.net.pi.runtime.PiEntity;
+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.
+ */
+@Beta
+public interface PiTranslationStore
+        extends Store<PiTranslationEvent, PiTranslationStoreDelegate> {
+
+    /**
+     * Adds or update a mapping between the given PD entity (original) and the
+     * translated PI counterpart, for the given pipeconf ID.
+     *
+     * @param original   PD entity
+     * @param translated PI entity
+     * @param pipeconfId pipeconf ID
+     */
+    void addOrUpdate(PiTranslatable original, PiEntity translated,
+                     PiPipeconfId pipeconfId);
+
+    /**
+     * Removes a previously added mapping for the given PI entity and pipeconf
+     * ID.
+     *
+     * @param piEntity   PI entity
+     * @param pipeconfId pipeconf ID
+     */
+    void remove(PiEntity piEntity, PiPipeconfId pipeconfId);
+
+    /**
+     * Removes all previously learned mappings for the given pipeconf ID.
+     *
+     * @param pipeconfId pipeconf ID
+     */
+    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);
+}
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
new file mode 100644
index 0000000..0fe5c75
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiTranslationStoreDelegate.java
@@ -0,0 +1,28 @@
+/*
+ * 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.store.StoreDelegate;
+
+/**
+ * PI translation service store delegate abstraction.
+ */
+@Beta
+public interface PiTranslationStoreDelegate
+        extends StoreDelegate<PiTranslationEvent> {
+}