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/net/src/main/java/org/onosproject/net/pi/impl/AbstractPiTranslatorImpl.java b/core/net/src/main/java/org/onosproject/net/pi/impl/AbstractPiTranslatorImpl.java
new file mode 100644
index 0000000..5d7178c
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/AbstractPiTranslatorImpl.java
@@ -0,0 +1,58 @@
+/*
+ * 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.impl;
+
+import org.onosproject.net.pi.runtime.PiEntity;
+import org.onosproject.net.pi.runtime.PiHandle;
+import org.onosproject.net.pi.service.PiTranslatable;
+import org.onosproject.net.pi.service.PiTranslatedEntity;
+import org.onosproject.net.pi.service.PiTranslationStore;
+import org.onosproject.net.pi.service.PiTranslator;
+
+import java.util.Optional;
+
+/**
+ * Abstract implementation of a PI translator backed by a PI translation store.
+ *
+ * @param <T> PD entity class
+ * @param <E> PI entity class
+ */
+public abstract class AbstractPiTranslatorImpl
+        <T extends PiTranslatable, E extends PiEntity>
+        implements PiTranslator<T, E> {
+
+    private final PiTranslationStore<T, E> store;
+
+    AbstractPiTranslatorImpl(PiTranslationStore<T, E> store) {
+        this.store = store;
+    }
+
+    @Override
+    public void learn(PiHandle<E> handle, PiTranslatedEntity<T, E> entity) {
+        store.addOrUpdate(handle, entity);
+    }
+
+    @Override
+    public Optional<PiTranslatedEntity<T, E>> lookup(PiHandle<E> handle) {
+        return Optional.ofNullable(store.get(handle));
+    }
+
+    @Override
+    public void forget(PiHandle<E> handle) {
+        store.remove(handle);
+    }
+}
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/CriterionTranslatorHelper.java b/core/net/src/main/java/org/onosproject/net/pi/impl/CriterionTranslatorHelper.java
index 22d53fd..7f43e22 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/CriterionTranslatorHelper.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/CriterionTranslatorHelper.java
@@ -86,13 +86,13 @@
 import org.onosproject.net.pi.runtime.PiFieldMatch;
 import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
 import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
+import org.onosproject.net.pi.service.PiTranslationException;
 
 import java.util.Map;
 
 import static java.lang.String.format;
 import static org.onlab.util.ImmutableByteSequence.ByteSequenceTrimException;
 import static org.onosproject.net.pi.impl.CriterionTranslator.CriterionTranslatorException;
-import static org.onosproject.net.pi.service.PiTranslationService.PiTranslationException;
 
 /**
  * Helper class to translate criterion instances to PI field matches.
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslator.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorImpl.java
similarity index 98%
rename from core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslator.java
rename to core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorImpl.java
index d856fd3..f04e7b0 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslator.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorImpl.java
@@ -46,6 +46,7 @@
 import org.onosproject.net.pi.runtime.PiTableAction;
 import org.onosproject.net.pi.runtime.PiTableEntry;
 import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
+import org.onosproject.net.pi.service.PiTranslationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -62,17 +63,16 @@
 import static org.onosproject.net.pi.impl.CriterionTranslatorHelper.translateCriterion;
 import static org.onosproject.net.pi.impl.PiUtils.getInterpreterOrNull;
 import static org.onosproject.net.pi.impl.PiUtils.translateTableId;
-import static org.onosproject.net.pi.service.PiTranslationService.PiTranslationException;
 
 /**
  * Implementation of flow rule translation logic.
  */
-final class PiFlowRuleTranslator {
+final class PiFlowRuleTranslatorImpl {
 
     public static final int MAX_PI_PRIORITY = (int) Math.pow(2, 24);
-    private static final Logger log = LoggerFactory.getLogger(PiFlowRuleTranslator.class);
+    private static final Logger log = LoggerFactory.getLogger(PiFlowRuleTranslatorImpl.class);
 
-    private PiFlowRuleTranslator() {
+    private PiFlowRuleTranslatorImpl() {
         // Hide constructor.
     }
 
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiGroupTranslator.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiGroupTranslatorImpl.java
similarity index 95%
rename from core/net/src/main/java/org/onosproject/net/pi/impl/PiGroupTranslator.java
rename to core/net/src/main/java/org/onosproject/net/pi/impl/PiGroupTranslatorImpl.java
index 255ccb9..eeabebc 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiGroupTranslator.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiGroupTranslatorImpl.java
@@ -29,21 +29,21 @@
 import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
 import org.onosproject.net.pi.runtime.PiGroupKey;
 import org.onosproject.net.pi.runtime.PiTableAction;
-import org.onosproject.net.pi.service.PiTranslationService.PiTranslationException;
+import org.onosproject.net.pi.service.PiTranslationException;
 
 import java.nio.ByteBuffer;
 
 import static java.lang.String.format;
-import static org.onosproject.net.pi.impl.PiFlowRuleTranslator.translateTreatment;
+import static org.onosproject.net.pi.impl.PiFlowRuleTranslatorImpl.translateTreatment;
 import static org.onosproject.net.pi.impl.PiUtils.getInterpreterOrNull;
 import static org.onosproject.net.pi.runtime.PiTableAction.Type.ACTION;
 
 /**
  * Implementation of group translation logic.
  */
-final class PiGroupTranslator {
+final class PiGroupTranslatorImpl {
 
-    private PiGroupTranslator() {
+    private PiGroupTranslatorImpl() {
         // Hides constructor.
     }
 
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiTranslationServiceImpl.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiTranslationServiceImpl.java
index b6d90f0..9780fac 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiTranslationServiceImpl.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiTranslationServiceImpl.java
@@ -28,19 +28,19 @@
 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 org.onosproject.net.pi.service.PiTranslatable;
+import org.onosproject.net.pi.service.PiFlowRuleTranslationStore;
+import org.onosproject.net.pi.service.PiFlowRuleTranslator;
+import org.onosproject.net.pi.service.PiGroupTranslationStore;
+import org.onosproject.net.pi.service.PiGroupTranslator;
+import org.onosproject.net.pi.service.PiTranslationException;
 import org.onosproject.net.pi.service.PiTranslationService;
-import org.onosproject.net.pi.service.PiTranslationStore;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Optional;
-
 /**
- * Implementation of the protocol-independent translation service.
+ * Implementation of the PI translation service.
  */
 @Component(immediate = true)
 @Service
@@ -54,58 +54,76 @@
     protected DeviceService deviceService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    private PiTranslationStore translationStore;
+    private PiFlowRuleTranslationStore flowRuleTranslationStore;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private PiGroupTranslationStore groupTranslationStore;
+
+    private PiFlowRuleTranslator flowRuleTranslator;
+    private PiGroupTranslator groupTranslator;
 
     @Activate
     public void activate() {
+        flowRuleTranslator = new InternalFlowRuleTranslator(flowRuleTranslationStore);
+        groupTranslator = new InternalGroupTranslator(groupTranslationStore);
         log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
+        flowRuleTranslator = null;
+        groupTranslator = null;
         log.info("Stopped");
     }
 
     @Override
-    public PiTableEntry translate(FlowRule rule, PiPipeconf pipeconf)
-            throws PiTranslationException {
-        final PiTableEntry piTableEntry = PiFlowRuleTranslator
-                .translate(rule, pipeconf, getDevice(rule.deviceId()));
-        translationStore.addOrUpdate(rule, piTableEntry, pipeconf.id());
-        return piTableEntry;
+    public PiFlowRuleTranslator flowRuleTranslator() {
+        return flowRuleTranslator;
     }
 
     @Override
-    public Optional<FlowRule> lookup(PiTableEntry piTableEntry,
-                                     PiPipeconfId pipeconfId) {
-        final PiTranslatable original = translationStore
-                .lookup(piTableEntry, pipeconfId);
-        return original == null
-                ? Optional.empty()
-                : Optional.of((FlowRule) original);
-    }
-
-    @Override
-    public PiActionGroup translate(Group group, PiPipeconf pipeconf)
-            throws PiTranslationException {
-        return PiGroupTranslator.translate(group, pipeconf,
-                                           getDevice(group.deviceId()));
-    }
-
-    @Override
-    public Optional<Group> lookup(PiActionGroup piActionGroup,
-                                  PiPipeconfId pipeconfId) {
-        // TODO: implement learning and lookup of groups
-        return Optional.empty();
+    public PiGroupTranslator groupTranslator() {
+        return groupTranslator;
     }
 
     private Device getDevice(DeviceId deviceId) throws PiTranslationException {
         final Device device = deviceService.getDevice(deviceId);
         if (device == null) {
-            throw new PiTranslationException(
-                    "Unable to get device " + deviceId);
+            throw new PiTranslationException("Unable to get device " + deviceId);
         }
         return device;
     }
+
+    private final class InternalFlowRuleTranslator
+            extends AbstractPiTranslatorImpl<FlowRule, PiTableEntry>
+            implements PiFlowRuleTranslator {
+
+        private InternalFlowRuleTranslator(PiFlowRuleTranslationStore store) {
+            super(store);
+        }
+
+        @Override
+        public PiTableEntry translate(FlowRule original, PiPipeconf pipeconf)
+                throws PiTranslationException {
+            return PiFlowRuleTranslatorImpl
+                    .translate(original, pipeconf, getDevice(original.deviceId()));
+        }
+    }
+
+    private final class InternalGroupTranslator
+            extends AbstractPiTranslatorImpl<Group, PiActionGroup>
+            implements PiGroupTranslator {
+
+        private InternalGroupTranslator(PiGroupTranslationStore store) {
+            super(store);
+        }
+
+        @Override
+        public PiActionGroup translate(Group original, PiPipeconf pipeconf)
+                throws PiTranslationException {
+            return PiGroupTranslatorImpl
+                    .translate(original, pipeconf, getDevice(original.deviceId()));
+        }
+    }
 }
 
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiUtils.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiUtils.java
index 6e93d67..78bca5f 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiUtils.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiUtils.java
@@ -22,7 +22,7 @@
 import org.onosproject.net.pi.model.PiPipeconf;
 import org.onosproject.net.pi.model.PiPipelineInterpreter;
 import org.onosproject.net.pi.model.PiTableId;
-import org.onosproject.net.pi.service.PiTranslationService;
+import org.onosproject.net.pi.service.PiTranslationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -60,23 +60,23 @@
     }
 
     static PiTableId translateTableId(TableId tableId, PiPipelineInterpreter interpreter)
-            throws PiTranslationService.PiTranslationException {
+            throws PiTranslationException {
         switch (tableId.type()) {
             case PIPELINE_INDEPENDENT:
                 return (PiTableId) tableId;
             case INDEX:
                 IndexTableId indexId = (IndexTableId) tableId;
                 if (interpreter == null) {
-                    throw new PiTranslationService.PiTranslationException(format(
+                    throw new PiTranslationException(format(
                             "Unable to map table ID '%d' from index to PI: missing interpreter", indexId.id()));
                 } else if (!interpreter.mapFlowRuleTableId(indexId.id()).isPresent()) {
-                    throw new PiTranslationService.PiTranslationException(format(
+                    throw new PiTranslationException(format(
                             "Unable to map table ID '%d' from index to PI: missing ID in interpreter", indexId.id()));
                 } else {
                     return interpreter.mapFlowRuleTableId(indexId.id()).get();
                 }
             default:
-                throw new PiTranslationService.PiTranslationException(format(
+                throw new PiTranslationException(format(
                         "Unrecognized table ID type %s", tableId.type().name()));
         }
     }