summaryrefslogtreecommitdiffstats
path: root/infra/translate-api
diff options
context:
space:
mode:
authorMaros Marsalek <mmarsale@cisco.com>2016-07-27 11:05:51 +0200
committerMaros Marsalek <mmarsale@cisco.com>2016-07-29 16:32:07 +0200
commit0578156b721fa01c8c645b8f9625ecebdb6449e4 (patch)
tree49d36f24e5d984a8c9f151b1440de88619f8b7de /infra/translate-api
parent007d4542388ca89be409ce1a4a4c7a36ddcb538f (diff)
HONEYCOMB-130: Separate v3po plugin from HC infra
Creating folders: - common/ - infra/ - v3po/ - vpp-common/ Change-Id: I2c39e1b17e39e7c0f0628f44aa5fe08563fa06e4 Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'infra/translate-api')
-rw-r--r--infra/translate-api/Readme.adoc9
-rw-r--r--infra/translate-api/pom.xml67
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java66
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java77
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java49
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java44
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java39
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java22
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java38
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java66
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java26
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java61
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java76
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java38
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ModifiableReaderRegistryBuilder.java41
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistry.java62
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistryBuilder.java27
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/DataObjectUpdate.java114
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/ListWriter.java33
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java50
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteFailedException.java166
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/Writer.java48
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java38
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/ModifiableWriterRegistryBuilder.java31
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistry.java213
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistryBuilder.java27
-rw-r--r--infra/translate-api/src/main/yang/translate-api.yang52
-rw-r--r--infra/translate-api/src/test/java/io/fd/honeycomb/v3po/translate/ReadFailedExceptionTest.java50
28 files changed, 1630 insertions, 0 deletions
diff --git a/infra/translate-api/Readme.adoc b/infra/translate-api/Readme.adoc
new file mode 100644
index 000000000..9e208744a
--- /dev/null
+++ b/infra/translate-api/Readme.adoc
@@ -0,0 +1,9 @@
+= Honeycomb translation layer API
+
+Extensible API for translation between Binding Aware data and actual device data.
+Consists of readers and writers responsible for communication with the device.
+
+Provides registry of readers and writers for the data layer.
+For every supported YANG model there should be at least one reader and writer registered.
+Readers and writers form two tree structures matching corresponding YANG models.
+Readers and writers can be attached to any non-leaf YANG node. \ No newline at end of file
diff --git a/infra/translate-api/pom.xml b/infra/translate-api/pom.xml
new file mode 100644
index 000000000..45f00fe19
--- /dev/null
+++ b/infra/translate-api/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 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.
+-->
+<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>impl-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../common/impl-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>translate-api</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-artifacts</artifactId>
+ <version>2.0.2-Beryllium-SR2</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-api</artifactId>
+ </dependency>
+
+ <!-- Testing Dependencies -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java
new file mode 100644
index 000000000..cff766e2a
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate;
+
+import com.google.common.base.Optional;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Mapping context is persisted storage where mapping matadata are stored.
+ * A snapshot is created for each transaction to provide consistent view over context data.
+ * After a transaction is successfully finished, objects added to this context are propagated to backing storage.
+ */
+public interface MappingContext extends AutoCloseable {
+
+ /**
+ * Read any mapping context data
+ *
+ * @param currentId Id of an object to read
+ *
+ * @return Relevant mapping context data
+ */
+ <T extends DataObject> Optional<T> read(@Nonnull final InstanceIdentifier<T> currentId);
+
+ /**
+ * Delete the node at specified path.
+ *
+ * @param path Node path
+ */
+ void delete(InstanceIdentifier<?> path);
+
+ /**
+ * Merge the specified data with the currently-present data
+ * at specified path.
+ *
+ * @param path Node path
+ * @param data Data to be merged
+ */
+ <T extends DataObject> void merge(InstanceIdentifier<T> path, T data);
+
+ /**
+ * Replace the data at specified path with supplied data.
+ *
+ * @param path Node path
+ * @param data New node data
+ */
+ <T extends DataObject> void put(InstanceIdentifier<T> path, T data);
+
+ @Override
+ void close();
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java
new file mode 100644
index 000000000..591a9e9bb
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate;
+
+import java.util.Collection;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Registry builder where {@link SubtreeManager}s can be added with or without relationships between them.
+ * The relationships express what the order of execution should be.
+ */
+public interface ModifiableSubtreeManagerRegistryBuilder<S extends SubtreeManager<? extends DataObject>> {
+
+ /**
+ * Add a handler responsible for writing only a single complex node.
+ */
+ ModifiableSubtreeManagerRegistryBuilder<S> add(@Nonnull S handler);
+
+ /**
+ * Add a handler responsible for writing multiple complex nodes within a subtree its responsible for. Identifiers for
+ * subtree nodes handled by a single handler have to be relative from {@link DataObject} that represents subtree
+ * root.
+ */
+ ModifiableSubtreeManagerRegistryBuilder<S> subtreeAdd(@Nonnull Set<InstanceIdentifier<?>> handledChildren,
+ @Nonnull S handler);
+
+ /**
+ * Add a handler and make sure it will be executed before handler identifier by relatedType is executed.
+ */
+ ModifiableSubtreeManagerRegistryBuilder<S> addBefore(@Nonnull S handler,
+ @Nonnull InstanceIdentifier<?> relatedType);
+
+ ModifiableSubtreeManagerRegistryBuilder<S> addBefore(@Nonnull S handler,
+ @Nonnull Collection<InstanceIdentifier<?>> relatedTypes);
+
+ ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddBefore(@Nonnull Set<InstanceIdentifier<?>> handledChildren,
+ @Nonnull S handler,
+ @Nonnull InstanceIdentifier<?> relatedType);
+
+ ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddBefore(@Nonnull Set<InstanceIdentifier<?>> handledChildren,
+ @Nonnull S handler,
+ @Nonnull Collection<InstanceIdentifier<?>> relatedTypes);
+
+ /**
+ * Add a handler and make sure it will be executed after handler identifier by relatedType is executed.
+ */
+ ModifiableSubtreeManagerRegistryBuilder<S> addAfter(@Nonnull S handler,
+ @Nonnull InstanceIdentifier<?> relatedType);
+
+ ModifiableSubtreeManagerRegistryBuilder<S> addAfter(@Nonnull S handler,
+ @Nonnull Collection<InstanceIdentifier<?>> relatedTypes);
+
+ ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddAfter(@Nonnull Set<InstanceIdentifier<?>> handledChildren,
+ @Nonnull S handler,
+ @Nonnull InstanceIdentifier<?> relatedType);
+
+ ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddAfter(@Nonnull Set<InstanceIdentifier<?>> handledChildren,
+ @Nonnull S handler,
+ @Nonnull Collection<InstanceIdentifier<?>> relatedTypes);
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java
new file mode 100644
index 000000000..cb2d4fde0
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate;
+
+import com.google.common.collect.Maps;
+import java.util.HashMap;
+
+/**
+ * Simple context class that provides transient storage during one or more read/write operations
+ */
+public class ModificationCache implements AutoCloseable {
+
+ protected final HashMap<Object, Object> map;
+
+ public ModificationCache() {
+ map = Maps.newHashMap();
+ }
+
+ public Object get(final Object o) {
+ return map.get(o);
+ }
+
+ public boolean containsKey(final Object o) {
+ return map.containsKey(o);
+ }
+
+ public Object put(final Object o, final Object o2) {
+ return map.put(o, o2);
+ }
+
+ @Override
+ public void close() {
+ map.clear();
+ }
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java
new file mode 100644
index 000000000..2c039aba0
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Common context for both writes and reads
+ */
+public interface ModificationContext extends AutoCloseable {
+
+ /**
+ * Get key value transient storage for customizers. Is cleared for each new transaction.
+ *
+ * @return Context for customizers
+ */
+ @Nonnull
+ ModificationCache getModificationCache();
+
+ /**
+ * Get persistent storage for mapping context. This context survives a modification.
+ *
+ * @return Mapping context accessor
+ */
+ @Nonnull
+ MappingContext getMappingContext();
+
+ @Override
+ void close();
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java
new file mode 100644
index 000000000..40842763d
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Base identifiable subtree manager(reader, writer etc.)
+ *
+ * @param <D> Specific DataObject derived type, that is managed by this manager
+ */
+@Beta
+public interface SubtreeManager<D extends DataObject> {
+
+ /**
+ * Gets the type of node managed by this reader.
+ *
+ * @return Absolute instance identifier for managed type
+ */
+ @Nonnull
+ InstanceIdentifier<D> getManagedDataObjectType();
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java
new file mode 100644
index 000000000..2434deddb
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate;
+
+public interface SubtreeManagerRegistryBuilder<R> {
+
+ R build();
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java
new file mode 100644
index 000000000..ee0049977
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Base exception for the translation layer
+ */
+@Beta
+public class TranslationException extends Exception {
+
+ public TranslationException(final String s) {
+ super(s);
+ }
+
+ public TranslationException(final String s, final Throwable cause) {
+ super(s, cause);
+ }
+
+ public TranslationException(final Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java
new file mode 100644
index 000000000..13a7a55da
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.read;
+
+import com.google.common.annotations.Beta;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * List reader, allowing read of all the elements.
+ *
+ * @param <D> Specific DataObject derived type, that is handled by this reader
+ */
+@Beta
+public interface ListReader
+ <D extends DataObject & Identifiable<K>, K extends Identifier<D>, B extends Builder<D>> extends Reader<D, B> {
+
+ /**
+ * Read all elements in this list.
+ *
+ * @param id Wildcarded identifier of list managed by this reader
+ * @param ctx Read context
+ *
+ * @return List of all entries in this list
+ * @throws ReadFailedException if read was unsuccessful
+ */
+ @Nonnull
+ List<D> readList(@Nonnull final InstanceIdentifier<D> id, @Nonnull final ReadContext ctx)
+ throws ReadFailedException;
+
+ /**
+ * Get IDs for all entries in the list.
+ */
+ List<K> getAllIds(@Nonnull InstanceIdentifier<D> id, @Nonnull ReadContext ctx)
+ throws ReadFailedException;
+
+ /**
+ * Merge read data into provided parent builder.
+ */
+ void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<D> readData);
+
+ @Override
+ default void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final D readValue) {
+ merge(parentBuilder, Collections.singletonList(readValue));
+ }
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java
new file mode 100644
index 000000000..e3ddd420c
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.read;
+
+import io.fd.honeycomb.v3po.translate.ModificationContext;
+
+/**
+ * Context providing information about current state of DataTree to readers
+ */
+public interface ReadContext extends ModificationContext {
+
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java
new file mode 100644
index 000000000..51d4fcb5a
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.read;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.v3po.translate.TranslationException;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Thrown when a reader or customizer is not able to read data for the given id.
+ */
+public class ReadFailedException extends TranslationException {
+
+ private final InstanceIdentifier<?> failedId;
+
+ /**
+ * Constructs an ReadFailedException given data id and exception cause.
+ *
+ * @param failedId instance identifier of the data object that could not be read
+ * @param cause the cause of read failure
+ */
+ public ReadFailedException(@Nonnull final InstanceIdentifier<?> failedId, final Throwable cause) {
+ super("Failed to read " + failedId, cause);
+ this.failedId = checkNotNull(failedId, "failedId should not be null");
+ }
+
+ /**
+ * Constructs an ReadFailedException given data id.
+ *
+ * @param failedId instance identifier of the data object that could not be read
+ */
+ public ReadFailedException(@Nonnull final InstanceIdentifier<?> failedId) {
+ this(failedId, null);
+ }
+
+ /**
+ * Returns id of the data object that could not be read.
+ *
+ * @return data object instance identifier
+ */
+ @Nonnull
+ public InstanceIdentifier<?> getFailedId() {
+ return failedId;
+ }
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java
new file mode 100644
index 000000000..d0bf0dea1
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.read;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.SubtreeManager;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Base reader, responsible for translation between DataObjects and any other side.
+ *
+ * @param <D> Specific DataObject derived type, that is handled by this reader
+ */
+@Beta
+public interface Reader<D extends DataObject, B extends Builder<D>> extends SubtreeManager<D> {
+
+ // TODO make async
+
+ /**
+ * Reads data identified by id
+ *
+ * @param id unique identifier of subtree to be read. The subtree must contain managed data object type. For
+ * identifiers pointing below node managed by this reader, it's reader's responsibility to filter out the
+ * right node or to delegate the read to a child reader.
+ * @param ctx Read context
+ *
+ * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list
+ * @throws ReadFailedException if read was unsuccessful
+ */
+ @Nonnull
+ Optional<? extends DataObject> read(@Nonnull InstanceIdentifier<? extends DataObject> id,
+ @Nonnull ReadContext ctx) throws ReadFailedException;
+
+ /**
+ * Fill in current node's attributes
+ *
+ * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present.
+ * @param builder Builder object for current node where the read attributes must be placed
+ * @param ctx Current read context
+ */
+ void readCurrentAttributes(@Nonnull InstanceIdentifier<D> id,
+ @Nonnull B builder,
+ @Nonnull ReadContext ctx) throws ReadFailedException;
+
+ /**
+ * Return new instance of a builder object for current node
+ *
+ * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present.
+ * @return Builder object for current node type
+ */
+ @Nonnull
+ B getBuilder(InstanceIdentifier<D> id);
+
+ /**
+ * Merge read data into provided parent builder.
+ */
+ void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final D readValue);
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java
new file mode 100644
index 000000000..61472f8d2
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.read;
+
+import com.google.common.annotations.Beta;
+import io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder;
+import javax.annotation.Nonnull;
+
+/**
+ * Factory producing readers for {@link ModifiableReaderRegistryBuilder}.
+ */
+@Beta
+public interface ReaderFactory extends AutoCloseable {
+
+ /**
+ * Initialize 1 or more readers and add them to provided registry.
+ */
+ void init(@Nonnull ModifiableReaderRegistryBuilder registry);
+
+ @Override
+ default void close() {
+ // NOOP TODO allow unregister
+ }
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ModifiableReaderRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ModifiableReaderRegistryBuilder.java
new file mode 100644
index 000000000..c2eba4f72
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ModifiableReaderRegistryBuilder.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.read.registry;
+
+import com.google.common.annotations.Beta;
+import io.fd.honeycomb.v3po.translate.ModifiableSubtreeManagerRegistryBuilder;
+import io.fd.honeycomb.v3po.translate.read.Reader;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Mutable registry that allows adding new readers.
+ */
+@Beta
+public interface ModifiableReaderRegistryBuilder
+ extends ModifiableSubtreeManagerRegistryBuilder<Reader<? extends DataObject, ? extends Builder<?>>> {
+
+ // TODO we should be able to add structural/reflexive readers automatically in the registry builder, we just need builder class
+ // We would need generated class loading strategy instance and then load builder classes relying on naming + package conventions of Binding spec
+ /**
+ * Add a structural reader that performs no read operation on its own, just fills in the hierarchy.
+ */
+ <D extends DataObject> void addStructuralReader(@Nonnull InstanceIdentifier<D> id,
+ @Nonnull Class<? extends Builder<D>> builderType);
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistry.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistry.java
new file mode 100644
index 000000000..308ec238d
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistry.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.read.registry;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import com.google.common.collect.Multimap;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Simple delegating reader suitable as a holder for all other root readers, providing readAll feature.
+ */
+@Beta
+public interface ReaderRegistry {
+
+ /**
+ * Performs read on all registered root readers and merges the results into a Multimap. Keys represent identifiers
+ * for root DataObjects from the data tree modeled by YANG.
+ *
+ * @param ctx Read context
+ *
+ * @return multimap that preserves deterministic iteration order across non-distinct key values
+ * @throws ReadFailedException if read was unsuccessful
+ */
+ @Nonnull
+ Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> readAll(@Nonnull final ReadContext ctx)
+ throws ReadFailedException;
+
+ /**
+ * Reads data identified by id.
+ *
+ * @param id unique identifier of subtree to be read. The subtree must contain managed data object type. For
+ * identifiers pointing below node managed by this reader, it's reader's responsibility to filter out the
+ * right node or to delegate the read to a child reader.
+ * @param ctx Read context
+ *
+ * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list
+ * @throws ReadFailedException if read was unsuccessful
+ */
+ @Nonnull
+ Optional<? extends DataObject> read(@Nonnull InstanceIdentifier<? extends DataObject> id,
+ @Nonnull ReadContext ctx)
+ throws ReadFailedException;
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistryBuilder.java
new file mode 100644
index 000000000..ff95d6248
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistryBuilder.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.read.registry;
+
+import com.google.common.annotations.Beta;
+import io.fd.honeycomb.v3po.translate.SubtreeManagerRegistryBuilder;
+
+/**
+ * Builder for reader registries.
+ */
+@Beta
+public interface ReaderRegistryBuilder extends SubtreeManagerRegistryBuilder<ReaderRegistry> {
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/DataObjectUpdate.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/DataObjectUpdate.java
new file mode 100644
index 000000000..0d891ecba
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/DataObjectUpdate.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.write;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Simple wrapper for BA id + data before and after state. Does not allow both before and after to be null.
+ */
+public class DataObjectUpdate {
+
+ @Nonnull
+ private final InstanceIdentifier<?> id;
+ @Nullable
+ private final DataObject dataBefore;
+ @Nullable
+ private final DataObject dataAfter;
+
+ private DataObjectUpdate(@Nonnull final InstanceIdentifier<?> id,
+ @Nullable final DataObject dataBefore,
+ @Nullable final DataObject dataAfter) {
+ this.id = checkNotNull(id);
+ this.dataAfter = dataAfter;
+ this.dataBefore = dataBefore;
+ }
+
+ public DataObject getDataBefore() {
+ return dataBefore;
+ }
+
+ public DataObject getDataAfter() {
+ return dataAfter;
+ }
+
+ public InstanceIdentifier<?> getId() {
+ return id;
+ }
+
+ public static DataObjectUpdate create(@Nonnull final InstanceIdentifier<?> id,
+ @Nullable final DataObject dataBefore,
+ @Nullable final DataObject dataAfter) {
+ checkArgument(!(dataBefore == null && dataAfter == null), "Both before and after data are null");
+ if (dataBefore != null) {
+ checkArgument(id.getTargetType().isAssignableFrom(dataBefore.getClass()));
+ }
+ if (dataAfter != null) {
+ checkArgument(id.getTargetType().isAssignableFrom(dataAfter.getClass()));
+ }
+
+ return dataAfter == null
+ ? new DataObjectDelete(id, dataBefore)
+ : new DataObjectUpdate(id, dataBefore, dataAfter);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final DataObjectUpdate that = (DataObjectUpdate) o;
+
+ return id.equals(that.id);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "DataObjectUpdate{" + "id=" + id
+ + ", dataBefore=" + dataBefore
+ + ", dataAfter=" + dataAfter
+ + '}';
+ }
+
+ public DataObjectUpdate reverse() {
+ return DataObjectUpdate.create(id, dataAfter, dataBefore);
+ }
+
+ public static class DataObjectDelete extends DataObjectUpdate {
+
+ private DataObjectDelete(@Nonnull final InstanceIdentifier<?> id,
+ @Nullable final DataObject dataBefore) {
+ super(id, dataBefore, null);
+ }
+ }
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/ListWriter.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/ListWriter.java
new file mode 100644
index 000000000..f29289d2d
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/ListWriter.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.write;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+
+/**
+ * List writer, responsible for translation between a list of DataObjects and any other side.
+ * Handling all update operations(create, update, delete)
+ *
+ * @param <D> Specific DataObject derived type, that is handled by this writer
+ * @param <K> Identifier/key for D
+ */
+@Beta
+public interface ListWriter<D extends DataObject & Identifiable<K>, K extends Identifier<D>> extends Writer<D> {
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java
new file mode 100644
index 000000000..3433b3f34
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.write;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.ModificationContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Context providing information about current state of DataTree to writers
+ */
+@Beta
+public interface WriteContext extends ModificationContext {
+
+ /**
+ * Read any config data object before current modification was applied
+ *
+ * @param currentId Id of an object to read
+ *
+ * @return Data before the modification was applied
+ */
+ <T extends DataObject> Optional<T> readBefore(@Nonnull final InstanceIdentifier<T> currentId);
+
+ /**
+ * Read any config data object from current modification
+ *
+ * @param currentId Id of an object to read
+ *
+ * @return Data from the modification
+ */
+ <T extends DataObject> Optional<T> readAfter(@Nonnull final InstanceIdentifier<T> currentId);
+
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteFailedException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteFailedException.java
new file mode 100644
index 000000000..10a664fcf
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteFailedException.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.write;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.v3po.translate.TranslationException;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Thrown when a writer or customizer is not able to write/update/delete data .
+ */
+public class WriteFailedException extends TranslationException {
+
+ private final InstanceIdentifier<?> failedId;
+
+ /**
+ * Constructs an WriteFailedException given data id, exception detail message and exception cause.
+ *
+ * @param failedId instance identifier of the data object that could not be read
+ * @param cause the cause of read failure
+ * @param message the exception detail message
+ */
+ public WriteFailedException(@Nonnull final InstanceIdentifier<?> failedId,
+ @Nonnull final String message,
+ @Nonnull final Throwable cause) {
+ super(message, cause);
+ this.failedId = checkNotNull(failedId, "failedId should not be null");
+ }
+
+ /**
+ * Constructs an WriteFailedException given data id.
+ *
+ * @param failedId instance identifier of the data object that could not be written
+ */
+ public WriteFailedException(@Nonnull final InstanceIdentifier<?> failedId,
+ @Nonnull final String message) {
+ super(message);
+ this.failedId = checkNotNull(failedId, "failedId should not be null");
+ }
+
+ /**
+ * Constructs an WriteFailedException given data id and exception cause.
+ *
+ * @param failedId instance identifier of the data object that could not be read
+ * @param cause the cause of read failure
+ */
+ public WriteFailedException(@Nonnull final InstanceIdentifier<?> failedId,
+ @Nonnull final Throwable cause) {
+ super(cause);
+ this.failedId = checkNotNull(failedId, "failedId should not be null");
+ }
+
+ /**
+ * Returns id of the data object that could not be written.
+ *
+ * @return data object instance identifier
+ */
+ @Nonnull
+ public InstanceIdentifier<?> getFailedId() {
+ return failedId;
+ }
+
+
+ /**
+ * Delete specific write failed exception
+ */
+ public static class DeleteFailedException extends WriteFailedException {
+
+ public DeleteFailedException(@Nonnull final InstanceIdentifier<?> failedId, @Nonnull final Throwable cause) {
+ super(failedId, getMsg(failedId), cause);
+ }
+
+ private static String getMsg(@Nonnull final InstanceIdentifier<?> failedId) {
+ return String.format("Failed to delete data at: %s", failedId);
+ }
+
+ public DeleteFailedException(@Nonnull final InstanceIdentifier<?> failedId) {
+ super(failedId, getMsg(failedId));
+ }
+ }
+
+ /**
+ * Create specific write failed exception
+ */
+ public static class CreateFailedException extends WriteFailedException {
+
+ private final DataObject data;
+
+ public CreateFailedException(@Nonnull final InstanceIdentifier<?> failedId,
+ @Nonnull final DataObject data,
+ @Nonnull final Throwable cause) {
+ super(failedId, getMsg(failedId, data), cause);
+ this.data = checkNotNull(data, "data");
+ }
+
+ private static String getMsg(final @Nonnull InstanceIdentifier<?> failedId, final DataObject data) {
+ return String.format("Failed to create data: %s at: %s", data, failedId);
+ }
+
+ public CreateFailedException(@Nonnull final InstanceIdentifier<?> failedId,
+ @Nonnull final DataObject data) {
+ super(failedId, getMsg(failedId, data));
+ this.data = checkNotNull(data, "data");
+ }
+
+ public DataObject getData() {
+ return data;
+ }
+ }
+
+ /**
+ * Update specific write failed exception
+ */
+ public static class UpdateFailedException extends WriteFailedException {
+
+ private final DataObject dataBefore;
+ private final DataObject dataAfter;
+
+ public UpdateFailedException(@Nonnull final InstanceIdentifier<?> failedId,
+ @Nonnull final DataObject dataBefore,
+ @Nonnull final DataObject dataAfter,
+ @Nonnull final Throwable cause) {
+ super(failedId, getMsg(failedId, dataBefore, dataAfter), cause);
+ this.dataBefore = checkNotNull(dataBefore, "dataBefore");
+ this.dataAfter = checkNotNull(dataAfter, "dataAfter");
+ }
+
+ private static String getMsg(final @Nonnull InstanceIdentifier<?> failedId, final DataObject dataBefore,
+ final DataObject dataAfter) {
+ return String.format("Failed to update data from: %s to: %s, at: %s", dataBefore, dataAfter, failedId);
+ }
+
+ public UpdateFailedException(@Nonnull final InstanceIdentifier<?> failedId,
+ @Nonnull final DataObject dataBefore,
+ @Nonnull final DataObject dataAfter) {
+ super(failedId, getMsg(failedId, dataBefore, dataAfter));
+ this.dataBefore = checkNotNull(dataBefore, "dataBefore");
+ this.dataAfter = checkNotNull(dataAfter, "dataAfter");
+ }
+
+ public DataObject getDataBefore() {
+ return dataBefore;
+ }
+
+ public DataObject getDataAfter() {
+ return dataAfter;
+ }
+ }
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/Writer.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/Writer.java
new file mode 100644
index 000000000..77abe341c
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/Writer.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.write;
+
+import com.google.common.annotations.Beta;
+import io.fd.honeycomb.v3po.translate.SubtreeManager;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Base writer, responsible for translation between DataObjects and any other side. Handling all update operations(create,
+ * update, delete)
+ *
+ * @param <D> Specific DataObject derived type, that is handled by this writer
+ */
+@Beta
+public interface Writer<D extends DataObject> extends SubtreeManager<D> {
+
+ /**
+ * Handle update operation. U from CRUD.
+ *
+ * @param id Identifier of data being written
+ * @param dataBefore Old data
+ * @param dataAfter New, updated data
+ * @param ctx Write context enabling writer to get information about candidate data as well as current data
+ * @throws WriteFailedException if update failed
+ */
+ void update(@Nonnull final InstanceIdentifier<? extends DataObject> id,
+ @Nullable final DataObject dataBefore,
+ @Nullable final DataObject dataAfter,
+ @Nonnull final WriteContext ctx) throws WriteFailedException;
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java
new file mode 100644
index 000000000..ffc76a0e4
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.write;
+
+import com.google.common.annotations.Beta;
+import io.fd.honeycomb.v3po.translate.write.registry.ModifiableWriterRegistryBuilder;
+import javax.annotation.Nonnull;
+
+/**
+ * Factory producing writers for {@link ModifiableWriterRegistryBuilder}.
+ */
+@Beta
+public interface WriterFactory extends AutoCloseable {
+
+ /**
+ * Initialize 1 or more writers and add them to provided registry.
+ */
+ void init(@Nonnull ModifiableWriterRegistryBuilder registry);
+
+ @Override
+ default void close() {
+ // NOOP TODO allow unregister
+ }
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/ModifiableWriterRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/ModifiableWriterRegistryBuilder.java
new file mode 100644
index 000000000..8670a5059
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/ModifiableWriterRegistryBuilder.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.write.registry;
+
+import com.google.common.annotations.Beta;
+import io.fd.honeycomb.v3po.translate.ModifiableSubtreeManagerRegistryBuilder;
+import io.fd.honeycomb.v3po.translate.write.Writer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+
+/**
+ * Mutable registry that allows adding new writers.
+ */
+@Beta
+public interface ModifiableWriterRegistryBuilder
+ extends ModifiableSubtreeManagerRegistryBuilder<Writer<? extends DataObject>> {
+
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistry.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistry.java
new file mode 100644
index 000000000..439a85410
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistry.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.write.registry;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import io.fd.honeycomb.v3po.translate.TranslationException;
+import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import io.fd.honeycomb.v3po.translate.write.Writer;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Special {@link Writer} capable of performing bulk updates.
+ */
+@Beta
+public interface WriterRegistry {
+
+ /**
+ * Performs bulk update.
+ *
+ * @throws BulkUpdateException in case bulk update fails
+ * @throws TranslationException in case some other error occurs while processing update request
+ */
+ void update(@Nonnull DataObjectUpdates updates,
+ @Nonnull WriteContext ctx) throws TranslationException;
+
+ /**
+ * Simple DTO containing updates for {@link WriterRegistry}. Currently only deletes and updates (create + update)
+ * are distinguished.
+ */
+ @Beta
+ final class DataObjectUpdates {
+
+ private final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates;
+ private final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> deletes;
+
+ /**
+ * Create new instance.
+ *
+ * @param updates All updates indexed by their unkeyed {@link InstanceIdentifier}
+ * @param deletes All deletes indexed by their unkeyed {@link InstanceIdentifier}
+ */
+ public DataObjectUpdates(@Nonnull final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates,
+ @Nonnull final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> deletes) {
+ this.deletes = deletes;
+ this.updates = updates;
+ }
+
+ public Multimap<InstanceIdentifier<?>, DataObjectUpdate> getUpdates() {
+ return updates;
+ }
+
+ public Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> getDeletes() {
+ return deletes;
+ }
+
+ public boolean isEmpty() {
+ return updates.isEmpty() && deletes.isEmpty();
+ }
+
+ @Override
+ public String toString() {
+ return "DataObjectUpdates{" + "updates=" + updates + ", deletes=" + deletes + '}';
+ }
+
+ /**
+ * Get a {@link Set} containing all update types from both updates as well as deletes.
+ */
+ public Set<InstanceIdentifier<?>> getTypeIntersection() {
+ return Sets.union(deletes.keySet(), updates.keySet());
+ }
+
+ /**
+ * Check whether there is only a single type of data object to be updated.
+ *
+ * @return true if there is only a single type of updates (update + delete)
+ */
+ public boolean containsOnlySingleType() {
+ return getTypeIntersection().size() == 1;
+ }
+
+ @Override
+ public boolean equals(final Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+
+ final DataObjectUpdates that = (DataObjectUpdates) other;
+
+ if (!updates.equals(that.updates)) {
+ return false;
+ }
+ return deletes.equals(that.deletes);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = updates.hashCode();
+ result = 31 * result + deletes.hashCode();
+ return result;
+ }
+
+ }
+
+ /**
+ * Thrown when bulk update failed.
+ */
+ @Beta
+ class BulkUpdateException extends TranslationException {
+
+ private final Reverter reverter;
+ private final Set<InstanceIdentifier<?>> failedIds;
+
+ /**
+ * Constructs an BulkUpdateException.
+ * @param failedIds instance identifiers of the data objects that were not processed during bulk update.
+ * @param cause the cause of bulk update failure
+ */
+ public BulkUpdateException(@Nonnull final Set<InstanceIdentifier<?>> failedIds,
+ @Nonnull final Reverter reverter,
+ @Nonnull final Throwable cause) {
+ super("Bulk update failed at: " + failedIds, cause);
+ this.failedIds = failedIds;
+ this.reverter = checkNotNull(reverter, "reverter should not be null");
+ }
+
+ /**
+ * Reverts changes that were successfully applied during bulk update before failure occurred.
+ *
+ * @throws Reverter.RevertFailedException if revert fails
+ */
+ public void revertChanges() throws Reverter.RevertFailedException {
+ reverter.revert();
+ }
+
+ public Set<InstanceIdentifier<?>> getFailedIds() {
+ return failedIds;
+ }
+ }
+
+ /**
+ * Abstraction over revert mechanism in case of a bulk update failure.
+ */
+ @Beta
+ interface Reverter {
+
+ /**
+ * Reverts changes that were successfully applied during bulk update before failure occurred. Changes are
+ * reverted in reverse order they were applied.
+ *
+ * @throws RevertFailedException if not all of applied changes were successfully reverted
+ */
+ void revert() throws RevertFailedException;
+
+ /**
+ * Thrown when some of the changes applied during bulk update were not reverted.
+ */
+ @Beta
+ class RevertFailedException extends TranslationException {
+
+ // TODO change to list of VppDataModifications to make debugging easier
+ private final Set<InstanceIdentifier<?>> notRevertedChanges;
+
+ /**
+ * Constructs a RevertFailedException with the list of changes that were not reverted.
+ *
+ * @param notRevertedChanges list of changes that were not reverted
+ * @param cause the cause of revert failure
+ */
+ public RevertFailedException(@Nonnull final Set<InstanceIdentifier<?>> notRevertedChanges,
+ final Throwable cause) {
+ super(cause);
+ checkNotNull(notRevertedChanges, "notRevertedChanges should not be null");
+ this.notRevertedChanges = ImmutableSet.copyOf(notRevertedChanges);
+ }
+
+ /**
+ * Returns the list of changes that were not reverted.
+ *
+ * @return list of changes that were not reverted
+ */
+ @Nonnull
+ public Set<InstanceIdentifier<?>> getNotRevertedChanges() {
+ return notRevertedChanges;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistryBuilder.java
new file mode 100644
index 000000000..3f0289ece
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistryBuilder.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate.write.registry;
+
+import com.google.common.annotations.Beta;
+import io.fd.honeycomb.v3po.translate.SubtreeManagerRegistryBuilder;
+
+/**
+ * Builder for writer registries.
+ */
+@Beta
+public interface WriterRegistryBuilder extends SubtreeManagerRegistryBuilder<WriterRegistry> {
+}
diff --git a/infra/translate-api/src/main/yang/translate-api.yang b/infra/translate-api/src/main/yang/translate-api.yang
new file mode 100644
index 000000000..796632dd2
--- /dev/null
+++ b/infra/translate-api/src/main/yang/translate-api.yang
@@ -0,0 +1,52 @@
+module translate-api {
+ yang-version 1;
+ namespace "urn:honeycomb:params:xml:ns:yang:translate:api";
+ prefix "tapi";
+
+ import config { prefix config; revision-date 2013-04-05; }
+
+ description
+ "This module contains the base YANG definitions for
+ readers/writers plugged into a honeycomb";
+
+ revision "2016-04-06" {
+ description
+ "Initial revision.";
+ }
+
+ identity honeycomb-reader-factory {
+ base "config:service-type";
+ config:java-class io.fd.honeycomb.v3po.translate.read.ReaderFactory;
+ }
+
+ identity honeycomb-reader-registry {
+ base "config:service-type";
+ config:java-class io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder;
+ }
+
+ identity honeycomb-reader-registry-builder {
+ base "config:service-type";
+ config:java-class io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistryBuilder;
+ }
+
+ identity honeycomb-writer-factory {
+ base "config:service-type";
+ config:java-class io.fd.honeycomb.v3po.translate.write.WriterFactory;
+ }
+
+ identity honeycomb-writer-registry {
+ base "config:service-type";
+ config:java-class io.fd.honeycomb.v3po.translate.write.registry.ModifiableWriterRegistryBuilder;
+ }
+
+ identity honeycomb-writer-registry-builder {
+ base "config:service-type";
+ config:java-class io.fd.honeycomb.v3po.translate.write.registry.WriterRegistryBuilder;
+ }
+
+ identity honeycomb-mapping-context {
+ base "config:service-type";
+ config:java-class io.fd.honeycomb.v3po.translate.MappingContext;
+ }
+
+} \ No newline at end of file
diff --git a/infra/translate-api/src/test/java/io/fd/honeycomb/v3po/translate/ReadFailedExceptionTest.java b/infra/translate-api/src/test/java/io/fd/honeycomb/v3po/translate/ReadFailedExceptionTest.java
new file mode 100644
index 000000000..71c0afbd3
--- /dev/null
+++ b/infra/translate-api/src/test/java/io/fd/honeycomb/v3po/translate/ReadFailedExceptionTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016 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.honeycomb.v3po.translate;
+
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class ReadFailedExceptionTest {
+
+ @Test
+ public void testInstantiation() {
+ final InstanceIdentifier<DataObject> id = InstanceIdentifier.create(DataObject.class);
+ ReadFailedException e = new ReadFailedException(id);
+ Assert.assertEquals(id, e.getFailedId());
+ Assert.assertNull(e.getCause());
+ Assert.assertTrue(e.getMessage().contains(id.toString()));
+ }
+
+ @Test
+ public void testInstantiationWithCause() {
+ final InstanceIdentifier<DataObject> id = InstanceIdentifier.create(DataObject.class);
+ final RuntimeException cause = new RuntimeException();
+ ReadFailedException e = new ReadFailedException(id, cause);
+ Assert.assertEquals(id, e.getFailedId());
+ Assert.assertEquals(cause, e.getCause());
+ Assert.assertTrue(e.getMessage().contains(id.toString()));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testInstantiationFailed() {
+ new ReadFailedException(null);
+ }
+} \ No newline at end of file