summaryrefslogtreecommitdiffstats
path: root/samples
diff options
context:
space:
mode:
Diffstat (limited to 'samples')
-rw-r--r--samples/asciidoc/Readme.adoc3
-rw-r--r--samples/pom.xml39
-rw-r--r--samples/samples-api/asciidoc/Readme.adoc3
-rw-r--r--samples/samples-api/pom.xml23
-rw-r--r--samples/samples-api/src/main/yang/sample-plugin.yang42
-rw-r--r--samples/samples-impl/asciidoc/Readme.adoc3
-rw-r--r--samples/samples-impl/pom.xml75
-rw-r--r--samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/Module.java60
-rw-r--r--samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/ModuleConfiguration.java29
-rw-r--r--samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/ModuleStateReaderFactory.java70
-rw-r--r--samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/VxlanReadCustomizer.java173
-rw-r--r--samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/ModuleWriterFactory.java60
-rw-r--r--samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/VxlanWriteCustomizer.java111
-rw-r--r--samples/samples-impl/src/main/resources/module.json3
14 files changed, 694 insertions, 0 deletions
diff --git a/samples/asciidoc/Readme.adoc b/samples/asciidoc/Readme.adoc
new file mode 100644
index 000000000..82961d0fe
--- /dev/null
+++ b/samples/asciidoc/Readme.adoc
@@ -0,0 +1,3 @@
+= samples
+
+Overview of samples \ No newline at end of file
diff --git a/samples/pom.xml b/samples/pom.xml
new file mode 100644
index 000000000..a2e058e49
--- /dev/null
+++ b/samples/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>hc2vpp-aggregator</artifactId>
+ <groupId>io.fd.hc2vpp</groupId>
+ <version>1.17.04-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>io.fd.hc2vpp.samples</groupId>
+ <artifactId>samples</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>samples-api</module>
+ <module>samples-impl</module>
+ </modules>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project> \ No newline at end of file
diff --git a/samples/samples-api/asciidoc/Readme.adoc b/samples/samples-api/asciidoc/Readme.adoc
new file mode 100644
index 000000000..7bc14dc6f
--- /dev/null
+++ b/samples/samples-api/asciidoc/Readme.adoc
@@ -0,0 +1,3 @@
+= samples-api
+
+Overview of samples-api \ No newline at end of file
diff --git a/samples/samples-api/pom.xml b/samples/samples-api/pom.xml
new file mode 100644
index 000000000..a6fa1f63b
--- /dev/null
+++ b/samples/samples-api/pom.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>api-parent</artifactId>
+ <version>1.17.04-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>io.fd.hc2vpp.common</groupId>
+ <artifactId>samples-api</artifactId>
+ <version>1.17.01-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>ietf-inet-types-2013-07-15</artifactId>
+ </dependency>
+ </dependencies>
+</project> \ No newline at end of file
diff --git a/samples/samples-api/src/main/yang/sample-plugin.yang b/samples/samples-api/src/main/yang/sample-plugin.yang
new file mode 100644
index 000000000..099ab65b8
--- /dev/null
+++ b/samples/samples-api/src/main/yang/sample-plugin.yang
@@ -0,0 +1,42 @@
+module sample-plugin {
+
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:sample:plugin";
+ prefix "samples";
+
+ revision 2016-12-14 {
+ description "Sample model for demonstration of transation code";
+ }
+
+ import ietf-inet-types {
+ prefix "inet";
+ }
+
+ grouping sample-plugin-params {
+ container vxlans {
+ list vxlan-tunnel {
+
+ key id;
+ leaf id {
+ type string;
+ }
+
+ leaf src {
+ type inet:ip-address;
+ }
+ leaf dst {
+ type inet:ip-address;
+ }
+ }
+ }
+ }
+
+ container sample-plugin-state {
+ config false;
+ uses sample-plugin-params;
+ }
+
+ container sample-plugin {
+ uses sample-plugin-params;
+ }
+} \ No newline at end of file
diff --git a/samples/samples-impl/asciidoc/Readme.adoc b/samples/samples-impl/asciidoc/Readme.adoc
new file mode 100644
index 000000000..893c0ebfb
--- /dev/null
+++ b/samples/samples-impl/asciidoc/Readme.adoc
@@ -0,0 +1,3 @@
+= samples-impl
+
+Overview of samples-impl \ No newline at end of file
diff --git a/samples/samples-impl/pom.xml b/samples/samples-impl/pom.xml
new file mode 100644
index 000000000..72938cbca
--- /dev/null
+++ b/samples/samples-impl/pom.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>io.fd.hc2vpp.common</groupId>
+ <artifactId>vpp-impl-parent</artifactId>
+ <version>1.17.04-SNAPSHOT</version>
+ <relativePath>../../vpp-common/vpp-impl-parent</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>samples-impl</artifactId>
+ <version>1.17.01-SNAPSHOT</version>
+
+ <dependencies>
+ <!-- Api classes generated from yang model -->
+ <dependency>
+ <groupId>io.fd.hc2vpp.common</groupId>
+ <artifactId>samples-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- Infrastructure communication interfaces -->
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>translate-spi</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- Vpp api java wrapped -->
+ <dependency>
+ <groupId>io.fd.vpp</groupId>
+ <artifactId>jvpp-core</artifactId>
+ </dependency>
+ <!-- Infrastructure utils for translation code -->
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>translate-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- Jvpp specific utils for translation code -->
+ <dependency>
+ <groupId>io.fd.hc2vpp.common</groupId>
+ <artifactId>vpp-translate-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- Generic implementations for communication interfaces-->
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>translate-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- Initialization interfaces for infrastructure-->
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>cfg-init</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- Google juice injection -->
+ <dependency>
+ <groupId>com.google.inject</groupId>
+ <artifactId>guice</artifactId>
+ </dependency>
+ <!-- Google juice multibindings -->
+ <dependency>
+ <groupId>com.google.inject.extensions</groupId>
+ <artifactId>guice-multibindings</artifactId>
+ </dependency>
+ <!-- Configuration injection -->
+ <dependency>
+ <groupId>net.jmob</groupId>
+ <artifactId>guice.conf</artifactId>
+ </dependency>
+ </dependencies>
+
+</project> \ No newline at end of file
diff --git a/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/Module.java b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/Module.java
new file mode 100644
index 000000000..d6f38caaf
--- /dev/null
+++ b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/Module.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.samples;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.samples.read.ModuleStateReaderFactory;
+import io.fd.hc2vpp.samples.write.ModuleWriterFactory;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import net.jmob.guice.conf.core.ConfigurationModule;
+
+
+/**
+ * Module class instantiating sample-plugin plugin components.
+ */
+public final class Module extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ // requests injection of properties
+ install(ConfigurationModule.create());
+ requestInjection(ModuleConfiguration.class);
+
+ // bind naming context instance for reader and writer factories
+ // the first parameter is artificial name prefix in cases a name needs to be reconstructed for a vxlan tunnel
+ // that is present in VPP but not in Honeycomb (could be extracted into configuration)
+ // the second parameter is just the naming context ID (could be extracted into configuration)
+ binder().bind(NamingContext.class).toInstance(new NamingContext("vxlan-tunnel", "vxlan-tunnel-context"));
+
+ // creates reader factory binding
+ // can hold multiple binding for separate yang modules
+ final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
+ readerFactoryBinder.addBinding().to(ModuleStateReaderFactory.class);
+
+ // create writer factory binding
+ // can hold multiple binding for separate yang modules
+ final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+ writerFactoryBinder.addBinding().to(ModuleWriterFactory.class);
+
+
+ // Disable notification producer for now
+// Multibinder.newSetBinder(binder(), ManagedNotificationProducer.class).addBinding()
+// .to(SampleNotificationProducer.class);
+ }
+} \ No newline at end of file
diff --git a/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/ModuleConfiguration.java b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/ModuleConfiguration.java
new file mode 100644
index 000000000..6766213ab
--- /dev/null
+++ b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/ModuleConfiguration.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.samples;
+
+
+import net.jmob.guice.conf.core.BindConfig;
+import net.jmob.guice.conf.core.InjectConfig;
+import net.jmob.guice.conf.core.Syntax;
+
+@BindConfig(value = "module", syntax = Syntax.JSON)
+public class ModuleConfiguration {
+
+ // inject property from resource file
+ @InjectConfig(value = "some.prop.name")
+ String somePropValue;
+}
diff --git a/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/ModuleStateReaderFactory.java b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/ModuleStateReaderFactory.java
new file mode 100644
index 000000000..83e91a2ad
--- /dev/null
+++ b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/ModuleStateReaderFactory.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.samples.read;
+
+import com.google.inject.Inject;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.SamplePluginState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.SamplePluginStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.Vxlans;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.VxlansBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnel;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Factory producing readers for sample-plugin plugin's data.
+ */
+public final class ModuleStateReaderFactory implements ReaderFactory {
+
+ public static final InstanceIdentifier<SamplePluginState> ROOT_STATE_CONTAINER_ID =
+ InstanceIdentifier.create(SamplePluginState.class);
+
+ /**
+ * Injected vxlan naming context shared with writer, provided by this plugin
+ */
+ @Inject
+ private NamingContext vxlanNamingContext;
+ /**
+ * Injected jvpp core APIs, provided by Honeycomb's infrastructure
+ */
+ @Inject
+ private FutureJVppCore jvppCore;
+
+ @Override
+ public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) {
+ // register reader that only delegate read's to its children
+ registry.addStructuralReader(ROOT_STATE_CONTAINER_ID, SamplePluginStateBuilder.class);
+ // register reader that only delegate read's to its children
+ registry.addStructuralReader(ROOT_STATE_CONTAINER_ID.child(Vxlans.class), VxlansBuilder.class);
+
+ // just adds reader to the structure
+ // use addAfter/addBefore if you want to add specific order to readers on the same level of tree
+ // use subtreeAdd if you want to handle multiple nodes in single customizer/subtreeAddAfter/subtreeAddBefore if you also want to add order
+ // be aware that instance identifier passes to subtreeAdd/subtreeAddAfter/subtreeAddBefore should define subtree,
+ // therefore it should be relative from handled node down - InstanceIdentifier.create(HandledNode), not parent.child(HandledNode.class)
+ registry.add(new GenericListReader<>(
+ // What part of subtree this reader handles is identified by an InstanceIdentifier
+ ROOT_STATE_CONTAINER_ID.child(Vxlans.class).child(VxlanTunnel.class),
+ // Customizer (the actual translation code to do the heavy lifting)
+ new VxlanReadCustomizer(jvppCore, vxlanNamingContext)));
+ }
+} \ No newline at end of file
diff --git a/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/VxlanReadCustomizer.java b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/VxlanReadCustomizer.java
new file mode 100644
index 000000000..133155b6f
--- /dev/null
+++ b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/read/VxlanReadCustomizer.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.samples.read;
+
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import io.fd.hc2vpp.common.translate.util.AddressTranslator;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.vpp.jvpp.core.dto.VxlanTunnelDetails;
+import io.fd.vpp.jvpp.core.dto.VxlanTunnelDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.VxlanTunnelDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.VxlansBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnelKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import javax.annotation.Nonnull;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+/**
+ * Reader for {@link VxlanTunnel} list node from our YANG model.
+ */
+public final class VxlanReadCustomizer implements
+ ListReaderCustomizer<VxlanTunnel, VxlanTunnelKey, VxlanTunnelBuilder>,
+ // provides utility methods to translate binary data
+ ByteDataTranslator,
+ // provides utility methods to translate Ipv4,Ipv6,Mac addresses.
+ // in case that just one address family processing is needed,use *address-family-name*Translator,
+ // for ex Ipv4Translator
+ AddressTranslator,
+ // provides utility methods to consume results of jvpp api calls
+ JvppReplyConsumer {
+
+ // JVpp core. This is the Java API for VPP's core API.
+ private final FutureJVppCore jVppCore;
+ // Naming context for interfaces
+ // Honeycomb provides a "context" storage for plugins. This storage is used for storing metadata required during
+ // data translation (just like in this plugin). An example of such metadata would be interface identifier. In Honeycomb
+ // we use string names for interfaces, however VPP uses only indices (that are created automatically).
+ // This means that translation layer has to store the mapping between HC interface name <-> VPP' interface index.
+ // And since vxlan tunnel is a type of interface in VPP, the same applies here
+ //
+ // Honeycomb provides a couple utilities on top of context storage such as NamingContext. It is just a map
+ // backed by context storage that makes the lookup and storing easier.
+ private final NamingContext vxlanNamingContext;
+
+ // Dump manager that provides intelligent caching based on provided contextual key
+ private DumpCacheManager<VxlanTunnelDetailsReplyDump, Integer> dumpManager;
+
+ public VxlanReadCustomizer(final FutureJVppCore jVppCore, final NamingContext vxlanNamingContext) {
+ this.jVppCore = jVppCore;
+ this.vxlanNamingContext = vxlanNamingContext;
+
+ this.dumpManager = new DumpCacheManager.DumpCacheManagerBuilder<VxlanTunnelDetailsReplyDump, Integer>()
+ // executor handles dumping of data itself, based on provided lambda
+ // instanceIdentifier - identifier of entity that we are caching, should be the one passed as parameter
+ // to getAllIds or readCurrentAttributes. Caching is by default performed based on this key
+ // param - can be anything that needs to be bind to request
+ .withExecutor((instanceIdentifier, param) -> {
+ // creates dump request
+ final VxlanTunnelDump vxlanTunnelDump = new VxlanTunnelDump();
+ // binds parameters, in this case index of interface
+ vxlanTunnelDump.swIfIndex = param;
+ // perform dump action with default timeout and either return result or throw ReadFailedException
+ // identified by provided instanceIdentifier
+ return getReplyForRead(jVppCore.vxlanTunnelDump(vxlanTunnelDump).toCompletableFuture(), instanceIdentifier);
+ })
+ // this provides type-awareness for caching, so multiple DumpManagers can be used withing the same
+ // customizer, using same instance identifiers, as long as they handle different data types
+ .acceptOnly(VxlanTunnelDetailsReplyDump.class)
+
+ // either acceptOnly is required or custom cache key factory must be provided to tell manager,
+ // how to produce keys. can be used to change caching scope of data
+ //.withCacheKeyFactory()
+
+ // serves as post-dump processing of any kind, triggered only once after calling executor
+ //.withPostProcessingFunction()
+ .build();
+ }
+
+ /**
+ * Provide a list of IDs for all VXLANs in VPP
+ */
+ @Nonnull
+ @Override
+ public List<VxlanTunnelKey> getAllIds(@Nonnull final InstanceIdentifier<VxlanTunnel> id,
+ @Nonnull final ReadContext context)
+ throws ReadFailedException {
+
+ final Optional<VxlanTunnelDetailsReplyDump> dump = dumpManager.getDump(id, context.getModificationCache(), 0);
+
+ if (!dump.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ return dump.get().vxlanTunnelDetails.stream()
+ // Need a name of an interface here. Use context to look it up from index
+ // In case the naming context does not contain such mapping, it creates an artificial one
+ .map(a -> new VxlanTunnelKey(vxlanNamingContext.getName(a.swIfIndex, context.getMappingContext())))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<VxlanTunnel> readData) {
+ // Just set the readValue into parent builder
+ // The cast has to be performed here
+ ((VxlansBuilder) builder).setVxlanTunnel(readData);
+ }
+
+ @Nonnull
+ @Override
+ public VxlanTunnelBuilder getBuilder(@Nonnull final InstanceIdentifier<VxlanTunnel> id) {
+ // Setting key from id is not necessary, builder will take care of that
+ return new VxlanTunnelBuilder();
+ }
+
+ /**
+ * Read all the attributes of a single VXLAN tunnel
+ */
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id,
+ @Nonnull final VxlanTunnelBuilder builder,
+ @Nonnull final ReadContext ctx) throws ReadFailedException {
+ // The ID received here contains the name of a particular interface that should be read
+ // It was either requested directly by HC users or is one of the IDs from getAllIds that could have been invoked
+ // just before this method invocation
+ final String vxlanName = id.firstKeyOf(VxlanTunnel.class).getId();
+
+ // Naming context must contain the mapping because:
+ // 1. The vxlan tunnel was created in VPP using HC + this plugin meaning we stored the mapping in write customizer
+ // 2. The vxlan tunnel was already present in VPP, but HC reconciliation mechanism took care of that (as long as proper Initializer is provided by this plugin)
+
+ final Optional<VxlanTunnelDetailsReplyDump> dump = dumpManager.getDump(id, ctx.getModificationCache(),
+ vxlanNamingContext.getIndex(vxlanName, ctx.getMappingContext()));
+
+
+ Preconditions.checkState(dump.isPresent() && dump.get().vxlanTunnelDetails != null);
+ final VxlanTunnelDetails singleVxlanDetail = dump.get().vxlanTunnelDetails.stream().findFirst().get();
+
+ // Now translate all attributes into provided builder
+ final Boolean isIpv6 = byteToBoolean(singleVxlanDetail.isIpv6);
+ builder.setSrc(arrayToIpAddress(isIpv6, singleVxlanDetail.srcAddress));
+ builder.setDst(arrayToIpAddress(isIpv6, singleVxlanDetail.dstAddress));
+ // There are additional attributes of a vxlan tunnel that wont be used here
+ }
+} \ No newline at end of file
diff --git a/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/ModuleWriterFactory.java b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/ModuleWriterFactory.java
new file mode 100644
index 000000000..346141429
--- /dev/null
+++ b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/ModuleWriterFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.samples.write;
+
+import com.google.inject.Inject;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.impl.write.GenericWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.SamplePlugin;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.Vxlans;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnel;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Factory producing writers for sample-plugin plugin's data.
+ */
+public final class ModuleWriterFactory implements WriterFactory {
+
+ private static final InstanceIdentifier<SamplePlugin> ROOT_CONTAINER_ID = InstanceIdentifier.create(SamplePlugin.class);
+
+ /**
+ * Injected vxlan naming context shared with writer, provided by this plugin
+ */
+ @Inject
+ private NamingContext vxlanNamingContext;
+ /**
+ * Injected jvpp core APIs, provided by Honeycomb's infrastructure
+ */
+ @Inject
+ private FutureJVppCore jvppCore;
+
+ @Override
+ public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+ // Unlike ReaderFactory, there's no need to add structural writers, just the writers that actually do something
+
+ // register writer for vxlan tunnel
+ registry.add(new GenericWriter<>(
+ // What part of subtree this writer handles is identified by an InstanceIdentifier
+ ROOT_CONTAINER_ID.child(Vxlans.class).child(VxlanTunnel.class),
+ // Customizer (the actual translation code to do the heavy lifting)
+ new VxlanWriteCustomizer(jvppCore, vxlanNamingContext)));
+ }
+} \ No newline at end of file
diff --git a/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/VxlanWriteCustomizer.java b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/VxlanWriteCustomizer.java
new file mode 100644
index 000000000..77c67b290
--- /dev/null
+++ b/samples/samples-impl/src/main/java/io/fd/hc2vpp/samples/write/VxlanWriteCustomizer.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.samples.write;
+
+
+import io.fd.hc2vpp.common.translate.util.AddressTranslator;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.VxlanAddDelTunnel;
+import io.fd.vpp.jvpp.core.dto.VxlanAddDelTunnelReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev161214.sample.plugin.params.vxlans.VxlanTunnelKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Writer for {@link VxlanTunnel} list node from our YANG model.
+ */
+public final class VxlanWriteCustomizer implements ListWriterCustomizer<VxlanTunnel, VxlanTunnelKey>,
+ ByteDataTranslator,
+ AddressTranslator,
+ JvppReplyConsumer {
+
+ /**
+ * JVpp APIs
+ */
+ private final FutureJVppCore jvppCore;
+ /**
+ * Shared vxlan tunnel naming context
+ */
+ private final NamingContext vxlanTunnelNamingContext;
+
+ public VxlanWriteCustomizer(final FutureJVppCore jvppCore, final NamingContext vxlanTunnelNamingContext) {
+ this.jvppCore = jvppCore;
+ this.vxlanTunnelNamingContext = vxlanTunnelNamingContext;
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id,
+ @Nonnull final VxlanTunnel dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ // Create and set vxlan tunnel add request
+ final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel();
+ // 1 for add, 0 for delete
+ vxlanAddDelTunnel.isAdd = 1;
+ // dataAfter is the new vxlanTunnel configuration
+ final boolean isIpv6 = dataAfter.getSrc().getIpv6Address() != null;
+ vxlanAddDelTunnel.isIpv6 = booleanToByte(isIpv6);
+ vxlanAddDelTunnel.srcAddress = ipAddressToArray(isIpv6, dataAfter.getSrc());
+ vxlanAddDelTunnel.dstAddress = ipAddressToArray(isIpv6, dataAfter.getDst());
+ // There are other input parameters that are not exposed by our YANG model, default values will be used
+
+
+ final VxlanAddDelTunnelReply replyForWrite = getReplyForWrite(jvppCore.vxlanAddDelTunnel(vxlanAddDelTunnel).toCompletableFuture(), id);
+
+ // VPP returns the index of new vxlan tunnel
+ final int newVxlanTunnelIndex = replyForWrite.swIfIndex;
+ // It's important to store it in context so that reader knows to which name a vxlan tunnel is mapped
+ vxlanTunnelNamingContext.addName(newVxlanTunnelIndex, dataAfter.getId(), writeContext.getMappingContext());
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id,
+ @Nonnull final VxlanTunnel dataBefore,
+ @Nonnull final VxlanTunnel dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ // Not supported at VPP API level, throw exception
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("Vxlan tunnel update is not supported by VPP"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanTunnel> id,
+ @Nonnull final VxlanTunnel dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ // Create and set vxlan tunnel add request
+ final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel();
+ // 1 for add, 0 for delete
+ vxlanAddDelTunnel.isAdd = 0;
+ // Vxlan tunnel is identified by its attributes when deleting, not index, so set all attributes
+ // dataBefore is the vxlan tunnel that's being deleted
+ final boolean isIpv6 = dataBefore.getSrc().getIpv6Address() != null;
+ vxlanAddDelTunnel.isIpv6 = booleanToByte(isIpv6);
+ vxlanAddDelTunnel.srcAddress = ipAddressToArray(isIpv6, dataBefore.getSrc());
+ vxlanAddDelTunnel.dstAddress = ipAddressToArray(isIpv6, dataBefore.getDst());
+ // There are other input parameters that are not exposed by our YANG model, default values will be used
+
+ final VxlanAddDelTunnelReply replyForWrite = getReplyForWrite(jvppCore.vxlanAddDelTunnel(vxlanAddDelTunnel).toCompletableFuture(), id);
+ // It's important to remove the mapping from context
+ vxlanTunnelNamingContext.removeName(dataBefore.getId(), writeContext.getMappingContext());
+ }
+} \ No newline at end of file
diff --git a/samples/samples-impl/src/main/resources/module.json b/samples/samples-impl/src/main/resources/module.json
new file mode 100644
index 000000000..da70698d2
--- /dev/null
+++ b/samples/samples-impl/src/main/resources/module.json
@@ -0,0 +1,3 @@
+{
+ "some.prop.name":"someValue"
+} \ No newline at end of file