ONOS-6555 Default pipeconf implementation and builder

Change-Id: I80ac4f6e939d30a943653a1d63d5cff07b368620
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java b/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java
new file mode 100644
index 0000000..e457052
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.model;
+
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.net.driver.Behaviour;
+
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Default pipeconf implementation.
+ */
+public final class DefaultPiPipeconf implements PiPipeconf {
+
+    private final PiPipeconfId id;
+    private final PiPipelineModel pipelineModel;
+    private final Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours;
+    private final Map<ExtensionType, InputStream> extensions;
+
+    private DefaultPiPipeconf(PiPipeconfId id, PiPipelineModel pipelineModel,
+                              Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours,
+                              Map<ExtensionType, InputStream> extensions) {
+        this.id = id;
+        this.pipelineModel = pipelineModel;
+        this.behaviours = behaviours;
+        this.extensions = extensions;
+    }
+
+    @Override
+    public PiPipeconfId id() {
+        return id;
+    }
+
+    @Override
+    public PiPipelineModel pipelineModel() {
+        return pipelineModel;
+    }
+
+    @Override
+    public Collection<Class<? extends Behaviour>> behaviours() {
+        return behaviours.keySet();
+    }
+
+    @Override
+    public Optional<Class<? extends Behaviour>> implementation(Class<? extends Behaviour> behaviour) {
+        return Optional.ofNullable(behaviours.get(behaviour));
+    }
+
+    @Override
+    public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
+        return behaviours.containsKey(behaviourClass);
+    }
+
+    @Override
+    public Optional<InputStream> extension(ExtensionType type) {
+        return Optional.ofNullable(extensions.get(type));
+    }
+
+    /**
+     * Returns a new pipeconf builder.
+     *
+     * @return pipeconf builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder of pipeconf implementations.
+     */
+    public static class Builder {
+
+        private PiPipeconfId id;
+        private PiPipelineModel pipelineModel;
+        private ImmutableMap.Builder<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviourMapBuilder
+                = ImmutableMap.builder();
+        private ImmutableMap.Builder<ExtensionType, InputStream> extensionMapBuilder = ImmutableMap.builder();
+
+        /**
+         * Sets the identifier of this pipeconf.
+         *
+         * @param id pipeconf identifier
+         * @return this
+         */
+        public Builder withId(PiPipeconfId id) {
+            this.id = id;
+            return this;
+        }
+
+        /**
+         * Sets the pipeline model of this pipeconf.
+         *
+         * @param model pipeline model
+         * @return this
+         */
+        public Builder withPipelineModel(PiPipelineModel model) {
+            this.pipelineModel = model;
+            return this;
+        }
+
+        /**
+         * Adds a behaviour to this pipeconf.
+         *
+         * @param clazz          behavior interface class
+         * @param implementation behavior implementation class
+         * @return this
+         */
+        public Builder addBehaviour(Class<? extends Behaviour> clazz, Class<? extends Behaviour> implementation) {
+            checkNotNull(clazz);
+            checkNotNull(implementation);
+            behaviourMapBuilder.put(clazz, implementation);
+            return this;
+        }
+
+        /**
+         * Adds an extension to this pipeconf.
+         *
+         * @param type        extension type
+         * @param inputStream input stream pointing at the extension
+         * @return this
+         */
+        public Builder addExtension(ExtensionType type, InputStream inputStream) {
+            checkNotNull(type);
+            checkNotNull(inputStream);
+            extensionMapBuilder.put(type, inputStream);
+            return this;
+        }
+
+        /**
+         * Creates a new pipeconf.
+         *
+         * @return pipeconf instance
+         */
+        public PiPipeconf build() {
+            checkNotNull(id);
+            checkNotNull(pipelineModel);
+            return new DefaultPiPipeconf(id, pipelineModel, behaviourMapBuilder.build(), extensionMapBuilder.build());
+        }
+
+    }
+}
diff --git a/core/net/src/test/java/org/onosproject/net/pi/impl/MockPipeconf.java b/core/net/src/test/java/org/onosproject/net/pi/impl/MockPipeconf.java
deleted file mode 100644
index 4e98567..0000000
--- a/core/net/src/test/java/org/onosproject/net/pi/impl/MockPipeconf.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2017-present Open Networking Laboratory
- *
- * 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 com.eclipsesource.json.Json;
-import com.google.common.collect.Maps;
-import org.onosproject.bmv2.model.Bmv2PipelineModelParser;
-import org.onosproject.net.driver.Behaviour;
-import org.onosproject.net.pi.model.PiPipeconf;
-import org.onosproject.net.pi.model.PiPipeconfId;
-import org.onosproject.net.pi.model.PiPipelineInterpreter;
-import org.onosproject.net.pi.model.PiPipelineModel;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Optional;
-
-/**
- * Mock pipeconf implementation.
- */
-public class MockPipeconf implements PiPipeconf {
-
-    private static final String PIPECONF_ID = "org.project.pipeconf.default";
-    private static final String JSON_PATH = "/org/onosproject/net/pi/impl/default.json";
-
-    private final PiPipeconfId id;
-    private final PiPipelineModel pipelineModel;
-    protected final Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours;
-
-    public MockPipeconf() throws IOException {
-        this.id = new PiPipeconfId(PIPECONF_ID);
-        this.pipelineModel = loadDefaultModel();
-        this.behaviours = Maps.newHashMap();
-
-        behaviours.put(PiPipelineInterpreter.class, MockInterpreter.class);
-    }
-
-    static PiPipelineModel loadDefaultModel() throws IOException {
-        return Bmv2PipelineModelParser.parse(Json.parse(new BufferedReader(new InputStreamReader(
-                MockPipeconf.class.getResourceAsStream(JSON_PATH)))).asObject());
-    }
-
-    @Override
-    public PiPipeconfId id() {
-        return this.id;
-    }
-
-    @Override
-    public PiPipelineModel pipelineModel() {
-        return pipelineModel;
-    }
-
-    @Override
-    public Collection<Class<? extends Behaviour>> behaviours() {
-        return behaviours.keySet();
-    }
-
-    @Override
-    public Optional<Class<? extends Behaviour>> implementation(Class<? extends Behaviour> behaviour) {
-        return Optional.ofNullable(behaviours.get(behaviour));
-    }
-
-    @Override
-    public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
-        return behaviours.containsKey(behaviourClass);
-    }
-
-    @Override
-    public Optional<InputStream> extension(ExtensionType type) {
-        return Optional.empty();
-    }
-}
diff --git a/core/net/src/test/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorTest.java b/core/net/src/test/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorTest.java
index 547e957..f060125 100644
--- a/core/net/src/test/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorTest.java
+++ b/core/net/src/test/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorTest.java
@@ -20,6 +20,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.packet.MacAddress;
+import org.onosproject.bmv2.model.Bmv2PipelineModelParser;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.DefaultApplicationId;
 import org.onosproject.net.DeviceId;
@@ -30,7 +31,10 @@
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.pi.model.DefaultPiPipeconf;
 import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiPipeconfId;
+import org.onosproject.net.pi.model.PiPipelineInterpreter;
 import org.onosproject.net.pi.runtime.PiTableEntry;
 import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
 
@@ -48,12 +52,18 @@
 @SuppressWarnings("ConstantConditions")
 public class PiFlowRuleTranslatorTest {
 
+    private static final String BMV2_JSON_PATH = "/org/onosproject/net/pi/impl/default.json";
+
     private Random random = new Random();
     private PiPipeconf pipeconf;
 
     @Before
     public void setUp() throws Exception {
-        pipeconf = new MockPipeconf();
+        pipeconf = DefaultPiPipeconf.builder()
+                .withId(new PiPipeconfId("mock-pipeconf"))
+                .withPipelineModel(Bmv2PipelineModelParser.parse(this.getClass().getResourceAsStream(BMV2_JSON_PATH)))
+                .addBehaviour(PiPipelineInterpreter.class, MockInterpreter.class)
+                .build();
     }
 
     @Test
diff --git a/core/net/src/test/java/org/onosproject/net/pi/impl/PiPipeconfManagerTest.java b/core/net/src/test/java/org/onosproject/net/pi/impl/PiPipeconfManagerTest.java
index a3f5cfb..a0a6c04 100644
--- a/core/net/src/test/java/org/onosproject/net/pi/impl/PiPipeconfManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/pi/impl/PiPipeconfManagerTest.java
@@ -23,6 +23,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.util.ItemNotFoundException;
+import org.onosproject.bmv2.model.Bmv2PipelineModelParser;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.behaviour.Pipeliner;
 import org.onosproject.net.behaviour.PipelinerAdapter;
@@ -45,6 +46,8 @@
 import org.onosproject.net.driver.DriverProvider;
 import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.driver.DriverServiceAdapter;
+import org.onosproject.net.pi.model.DefaultPiPipeconf;
+import org.onosproject.net.pi.model.PiPipeconf;
 import org.onosproject.net.pi.model.PiPipeconfId;
 import org.onosproject.net.pi.model.PiPipelineInterpreter;
 import org.onosproject.net.pi.runtime.PiPipeconfConfig;
@@ -57,9 +60,7 @@
 import java.util.Map;
 import java.util.Set;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 
 /**
@@ -67,6 +68,11 @@
  */
 public class PiPipeconfManagerTest {
 
+    private static final String PIPECONF_ID = "org.project.pipeconf.default";
+    private static final String BMV2_JSON_PATH = "/org/onosproject/net/pi/impl/default.json";
+
+    private final InputStream bmv2JsonConfigStream = this.getClass().getResourceAsStream(BMV2_JSON_PATH);
+
     private static final DeviceId DEVICE_ID = DeviceId.deviceId("test:test");
     private static final String BASE_DRIVER = "baseDriver";
     private static final Set<Class<? extends Behaviour>> EXPECTED_BEHAVIOURS =
@@ -93,14 +99,17 @@
 
     //Services
     private PiPipeconfManager piPipeconfService;
-    private MockPipeconf piPipeconf;
+    private PiPipeconf piPipeconf;
 
     @Before
     public void setUp() throws IOException {
         piPipeconfService = new PiPipeconfManager();
-        piPipeconf = new MockPipeconf();
+        piPipeconf = DefaultPiPipeconf.builder()
+                .withId(new PiPipeconfId(PIPECONF_ID))
+                .withPipelineModel(Bmv2PipelineModelParser.parse(bmv2JsonConfigStream))
+                .addBehaviour(Pipeliner.class, PipelinerAdapter.class)
+                .build();
         completeDriverName = BASE_DRIVER + ":" + piPipeconf.id();
-        piPipeconf.behaviours.put(Pipeliner.class, PipelinerAdapter.class);
         piPipeconfService.cfgService = cfgService;
         piPipeconfService.driverService = driverService;
         piPipeconfService.driverAdminService = driverAdminService;
@@ -132,7 +141,7 @@
         assertEquals("Incorrect configuration service", null, piPipeconfService.cfgService);
         assertFalse("Config factory should be unregistered", cfgFactories.contains(piPipeconfService.factory));
         assertFalse("Network configuration listener should be unregistered",
-                netCfgListeners.contains(piPipeconfService.cfgListener));
+                    netCfgListeners.contains(piPipeconfService.cfgListener));
     }
 
     @Test
@@ -145,7 +154,7 @@
     public void getPipeconf() {
         piPipeconfService.register(piPipeconf);
         assertEquals("Returned PiPipeconf is not correct", piPipeconf,
-                piPipeconfService.getPipeconf(piPipeconf.id()).get());
+                     piPipeconfService.getPipeconf(piPipeconf.id()).get());
     }
 
 
@@ -159,7 +168,7 @@
 
         piPipeconfService.register(piPipeconf);
         assertEquals("Returned PiPipeconf is not correct", piPipeconf,
-                piPipeconfService.getPipeconf(piPipeconf.id()).get());
+                     piPipeconfService.getPipeconf(piPipeconf.id()).get());
 
         piPipeconfService.bindToDevice(piPipeconfId, DEVICE_ID).whenComplete((booleanResult, ex) -> {