Better handling of extensions in PiPipeconf
Now built using a URL, while input streams are generated on-demand.
Before it could happen that the input stream was completelly read by
someone, leaving it unusable by others.
Change-Id: I61a76bf8b8c1d2f6e2d987661025e0323d59e1c7
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
index e457052..e6f9406 100644
--- 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
@@ -19,12 +19,16 @@
import com.google.common.collect.ImmutableMap;
import org.onosproject.net.driver.Behaviour;
+import java.io.IOException;
import java.io.InputStream;
+import java.net.URL;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import static java.lang.String.format;
/**
* Default pipeconf implementation.
@@ -34,11 +38,11 @@
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 final Map<ExtensionType, URL> extensions;
private DefaultPiPipeconf(PiPipeconfId id, PiPipelineModel pipelineModel,
Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours,
- Map<ExtensionType, InputStream> extensions) {
+ Map<ExtensionType, URL> extensions) {
this.id = id;
this.pipelineModel = pipelineModel;
this.behaviours = behaviours;
@@ -72,7 +76,15 @@
@Override
public Optional<InputStream> extension(ExtensionType type) {
- return Optional.ofNullable(extensions.get(type));
+ if (extensions.containsKey(type)) {
+ try {
+ return Optional.of(extensions.get(type).openStream());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ return Optional.empty();
+ }
}
/**
@@ -93,7 +105,7 @@
private PiPipelineModel pipelineModel;
private ImmutableMap.Builder<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviourMapBuilder
= ImmutableMap.builder();
- private ImmutableMap.Builder<ExtensionType, InputStream> extensionMapBuilder = ImmutableMap.builder();
+ private ImmutableMap.Builder<ExtensionType, URL> extensionMapBuilder = ImmutableMap.builder();
/**
* Sets the identifier of this pipeconf.
@@ -134,17 +146,27 @@
/**
* Adds an extension to this pipeconf.
*
- * @param type extension type
- * @param inputStream input stream pointing at the extension
+ * @param type extension type
+ * @param url url pointing at the extension file
* @return this
*/
- public Builder addExtension(ExtensionType type, InputStream inputStream) {
+ public Builder addExtension(ExtensionType type, URL url) {
checkNotNull(type);
- checkNotNull(inputStream);
- extensionMapBuilder.put(type, inputStream);
+ checkNotNull(url);
+ checkArgument(checkUrl(url), format("Extension url %s seems to be empty/non existent", url.toString()));
+ extensionMapBuilder.put(type, url);
return this;
}
+ private boolean checkUrl(URL url) {
+ try {
+ int byteCount = url.openStream().available();
+ return byteCount > 0;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
/**
* Creates a new pipeconf.
*
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconf.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconf.java
index f94ae6e..389da5c 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconf.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconf.java
@@ -68,9 +68,9 @@
boolean hasBehaviour(Class<? extends Behaviour> behaviourClass);
/**
- * Returns, if present, an input stream of ad device-specific or control
- * protocol-specific extension of this configuration. For example, if requesting a
- * target-specific P4 binary, this will return the same bytes produced by the P4 compiler.
+ * Returns, if present, an input stream pointing at the beginning of a file representing a device-specific or
+ * control protocol-specific extension of this configuration. For example, if requesting a target-specific P4
+ * binary, this will return the same bytes produced by the P4 compiler.
*
* @param type extension type
* @return extension input stream
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 f060125..894865e 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
@@ -61,7 +61,7 @@
public void setUp() throws Exception {
pipeconf = DefaultPiPipeconf.builder()
.withId(new PiPipeconfId("mock-pipeconf"))
- .withPipelineModel(Bmv2PipelineModelParser.parse(this.getClass().getResourceAsStream(BMV2_JSON_PATH)))
+ .withPipelineModel(Bmv2PipelineModelParser.parse(this.getClass().getResource(BMV2_JSON_PATH)))
.addBehaviour(PiPipelineInterpreter.class, MockInterpreter.class)
.build();
}
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 a0a6c04..9850004 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
@@ -54,6 +54,7 @@
import java.io.IOException;
import java.io.InputStream;
+import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -71,7 +72,7 @@
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 final URL bmv2JsonConfigUrl = this.getClass().getResource(BMV2_JSON_PATH);
private static final DeviceId DEVICE_ID = DeviceId.deviceId("test:test");
private static final String BASE_DRIVER = "baseDriver";
@@ -106,7 +107,7 @@
piPipeconfService = new PiPipeconfManager();
piPipeconf = DefaultPiPipeconf.builder()
.withId(new PiPipeconfId(PIPECONF_ID))
- .withPipelineModel(Bmv2PipelineModelParser.parse(bmv2JsonConfigStream))
+ .withPipelineModel(Bmv2PipelineModelParser.parse(bmv2JsonConfigUrl))
.addBehaviour(Pipeliner.class, PipelinerAdapter.class)
.build();
completeDriverName = BASE_DRIVER + ":" + piPipeconf.id();
diff --git a/drivers/bmv2/BUCK b/drivers/bmv2/BUCK
index b406b08..3726829 100644
--- a/drivers/bmv2/BUCK
+++ b/drivers/bmv2/BUCK
@@ -27,6 +27,7 @@
'//incubator/bmv2/model:onos-incubator-bmv2-model',
'//incubator/grpc-dependencies:grpc-core-repkg-1.3.0',
'//lib:grpc-netty-1.3.0',
+ '//drivers/default:onos-drivers-default',
]
TEST_DEPS = [
@@ -43,6 +44,7 @@
'//protocols/grpc/ctl:onos-protocols-grpc-ctl',
'//protocols/grpc/proto:onos-protocols-grpc-proto',
'//incubator/bmv2/model:onos-incubator-bmv2-model',
+ '//drivers/default:onos-drivers-default',
] + GRPC_DEPS
osgi_jar_with_tests(
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java
index 4903c3e..3004627 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java
@@ -17,12 +17,14 @@
package org.onosproject.drivers.bmv2;
import org.onosproject.bmv2.model.Bmv2PipelineModelParser;
+import org.onosproject.driver.pipeline.DefaultSingleTablePipeline;
+import org.onosproject.net.behaviour.Pipeliner;
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 java.io.InputStream;
+import java.net.URL;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
@@ -42,16 +44,16 @@
static PiPipeconf get() {
- final InputStream jsonConfigStream = Bmv2DefaultPipeconfFactory.class.getResourceAsStream(JSON_PATH);
- final InputStream p4InfoStream = Bmv2DefaultPipeconfFactory.class.getResourceAsStream(P4INFO_PATH);
+ final URL jsonUrl = Bmv2DefaultPipeconfFactory.class.getResource(JSON_PATH);
+ final URL p4InfoUrl = Bmv2DefaultPipeconfFactory.class.getResource(P4INFO_PATH);
return DefaultPiPipeconf.builder()
.withId(new PiPipeconfId(PIPECONF_ID))
- .withPipelineModel(Bmv2PipelineModelParser.parse(jsonConfigStream))
- // TODO: reuse default single table pipeliner.
+ .withPipelineModel(Bmv2PipelineModelParser.parse(jsonUrl))
.addBehaviour(PiPipelineInterpreter.class, Bmv2DefaultInterpreter.class)
- .addExtension(P4_INFO_TEXT, p4InfoStream)
- .addExtension(BMV2_JSON, jsonConfigStream)
+ .addBehaviour(Pipeliner.class, DefaultSingleTablePipeline.class)
+ .addExtension(P4_INFO_TEXT, p4InfoUrl)
+ .addExtension(BMV2_JSON, jsonUrl)
.build();
}
}
diff --git a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2PipelineModelParser.java b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2PipelineModelParser.java
index b7a1f15c..470ea78 100644
--- a/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2PipelineModelParser.java
+++ b/incubator/bmv2/model/src/main/java/org/onosproject/bmv2/model/Bmv2PipelineModelParser.java
@@ -30,10 +30,13 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -75,13 +78,16 @@
/**
* Parse the input stream pointing to a BMv2 JSON configuration, to a Bmv2PipelineModel object.
*
- * @param jsonInputStream input stream pointing to a BMv2 JSON configuration
+ * @param url URL pointing to a BMv2 JSON configuration
* @return Bmv2PipelineModel BMv2 pipeline model object
*/
- public static Bmv2PipelineModel parse(InputStream jsonInputStream) {
+ public static Bmv2PipelineModel parse(URL url) {
+ checkNotNull(url, "Url cannot be null");
try {
+ InputStream inputStream = url.openStream();
+ checkArgument(inputStream.available() > 0, "Empty or non-existent JSON at " + url.toString());
return parse(Json.parse(new BufferedReader(
- new InputStreamReader(jsonInputStream))).asObject());
+ new InputStreamReader(inputStream))).asObject());
} catch (IOException e) {
throw new RuntimeException(e);
}