HONEYCOMB-61: Add BA broker for context data tree
authorMaros Marsalek <[email protected]>
Tue, 17 May 2016 07:10:39 +0000 (09:10 +0200)
committerMaros Marsalek <[email protected]>
Mon, 23 May 2016 09:24:12 +0000 (09:24 +0000)
With broker, context data can be accessed in a transactional
manner, same as config data

+ Renamed data-api concepts to not include DataTree
+ Renamed context related concepts to better distinguish between them
+ Now passing full ReadContext to read customizers
+ Naming context is backed by context data broker

Change-Id: I0b2876dd74a31a9ced7d9b5145672868e12f8b82
Signed-off-by: Maros Marsalek <[email protected]>
87 files changed:
v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/DataModification.java [new file with mode: 0644]
v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/ModifiableDataManager.java [moved from v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/DataTreeSnapshot.java with 69% similarity]
v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/ModifiableDataTree.java [deleted file]
v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableDataManager.java [moved from v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableDataTree.java with 97% similarity]
v3po/data-api/src/main/yang/data-api.yang
v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTree.java [deleted file]
v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java
v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java
v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java [new file with mode: 0644]
v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java [new file with mode: 0644]
v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java
v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java
v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java [moved from v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTree.java with 77% similarity]
v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java
v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java
v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java
v3po/data-impl/src/main/yang/data-impl.yang
v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java
v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java [moved from v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTreeTest.java with 75% similarity]
v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java
v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegatorTest.java [moved from v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTreeTest.java with 92% similarity]
v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java
v3po/impl/src/main/config/context-datatree-config.xml
v3po/impl/src/main/config/default-config.xml
v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModule.java [new file with mode: 0644]
v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModuleFactory.java [new file with mode: 0644]
v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModule.java
v3po/impl/src/main/yang/v3po-impl.yang
v3po/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java [new file with mode: 0644]
v3po/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java [moved from v3po/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/Context.java with 93% similarity]
v3po/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java [new file with mode: 0644]
v3po/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java
v3po/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java
v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeChildReader.java
v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeListReader.java
v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/CompositeRootReader.java
v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/AbstractCompositeWriter.java
v3po/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/read/ListReaderCustomizer.java
v3po/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/read/RootReaderCustomizer.java
v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/NoopReaderCustomizer.java
v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/TransactionMappingContext.java [new file with mode: 0644]
v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/TransactionWriteContext.java
v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/util/TransactionWriteContextTest.java
v3po/v3po2vpp/src/main/config/default-config.xml
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/L2Customizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RoutingCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VhostUserCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VlanTagRewriteCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4Customizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/EthernetCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2Customizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/TapCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VhostUserCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VlanTagRewriteCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VersionCustomizer.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/ContextTestUtils.java [new file with mode: 0644]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceTypeTestUtils.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VhostUserCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VlanTagRewriteCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2CustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VlanTagRewriteCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/RootReaderCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/VppTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VppStateTest.java
v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/AbstractInterfaceTypeCustomizer.java
v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/DataTreeNamingContext.java [deleted file]
v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/NamingContext.java
v3po/vpp-translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/util/rev160406/NamingContextImplModule.java
v3po/vpp-translate-utils/src/main/yang/vpp-util.yang

diff --git a/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/DataModification.java b/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/DataModification.java
new file mode 100644 (file)
index 0000000..d05c557
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.data;
+
+import com.google.common.annotations.Beta;
+import io.fd.honeycomb.v3po.translate.TranslationException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+
+/**
+ * Modification of a {@link ModifiableDataManager}.
+ */
+@Beta
+public interface DataModification extends ReadableDataManager {
+
+    /**
+     * Delete the node at specified path.
+     *
+     * @param path Node path
+     */
+    void delete(YangInstanceIdentifier path);
+
+    /**
+     * Merge the specified data with the currently-present data
+     * at specified path.
+     *
+     * @param path Node path
+     * @param data Data to be merged
+     */
+    void merge(YangInstanceIdentifier path, NormalizedNode<?, ?> data);
+
+    /**
+     * Replace the data at specified path with supplied data.
+     *
+     * @param path Node path
+     * @param data New node data
+     */
+    void write(YangInstanceIdentifier path, NormalizedNode<?, ?> data);
+
+    /**
+     * Alters data tree using this modification.
+     *
+     * @throws DataValidationFailedException if modification data is not valid
+     * @throws TranslationException if failed while updating data tree state
+     */
+    void commit() throws DataValidationFailedException, TranslationException;
+
+    /**
+     * Validate and prepare modification before commit. Besides commit, no further operation is expected after validate
+     * and the behaviour is undefined.
+     *
+     * @throws DataValidationFailedException if modification data is not valid
+     */
+    void validate() throws DataValidationFailedException;
+}
 package io.fd.honeycomb.v3po.data;
 
 import com.google.common.annotations.Beta;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
 
 /**
- * Read-only snapshot of a {@link ReadableDataTree}.
+ * Facade over data tree that allows tree modification.
  */
 @Beta
-public interface DataTreeSnapshot extends ReadableDataTree {
+public interface ModifiableDataManager extends ReadableDataManager {
 
     /**
-     * Creates a new data tree modification.
+     * Creates read-only snapshot of a ModifiableDataTree.
      *
-     * @return A new data tree modification
+     * @return modification
      */
-    DataTreeModification newModification();
+    DataModification newModification();
 }
diff --git a/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/ModifiableDataTree.java b/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/ModifiableDataTree.java
deleted file mode 100644 (file)
index 8b21ddf..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.data;
-
-import com.google.common.annotations.Beta;
-import io.fd.honeycomb.v3po.translate.TranslationException;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
-
-/**
- * Facade over data tree that allows tree modification.
- */
-@Beta
-public interface ModifiableDataTree {
-    /**
-     * Alters data tree using supplied modification.
-     *
-     * @param modification data tree modification
-     * @throws DataValidationFailedException if modification data is not valid
-     * @throws TranslationException if failed while updating data tree state
-     */
-    void modify(final DataTreeModification modification) throws DataValidationFailedException, TranslationException;
-
-    /**
-     * Creates read-only snapshot of a ModifiableDataTree.
-     *
-     * @return Data tree snapshot.
-     */
-    DataTreeSnapshot takeSnapshot();
-}
@@ -28,7 +28,8 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
  * Facade over data tree that allows reading tree nodes.
  */
 @Beta
-public interface ReadableDataTree {
+public interface ReadableDataManager {
+
     /**
      * Reads a particular node from the data tree.
      *
index 92def4b..11d963e 100644 (file)
@@ -21,12 +21,12 @@ module data-api {
 
     identity honeycomb-readable-data-tree {
         base "config:service-type";
-        config:java-class io.fd.honeycomb.v3po.data.ReadableDataTree;
+        config:java-class io.fd.honeycomb.v3po.data.ReadableDataManager;
     }
 
     identity honeycomb-modifiable-data-tree {
         base "config:service-type";
-        config:java-class io.fd.honeycomb.v3po.data.ModifiableDataTree;
+        config:java-class io.fd.honeycomb.v3po.data.ModifiableDataManager;
     }
 
 }
\ No newline at end of file
diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTree.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTree.java
deleted file mode 100644 (file)
index 1e118ff..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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.data.impl;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static io.fd.honeycomb.v3po.data.impl.DataTreeUtils.childrenFromNormalized;
-
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.Futures;
-import io.fd.honeycomb.v3po.data.DataTreeSnapshot;
-import io.fd.honeycomb.v3po.data.ModifiableDataTree;
-import io.fd.honeycomb.v3po.data.ReadableDataTree;
-import io.fd.honeycomb.v3po.translate.TranslationException;
-import io.fd.honeycomb.v3po.translate.util.write.TransactionWriteContext;
-import io.fd.honeycomb.v3po.translate.write.WriteContext;
-import io.fd.honeycomb.v3po.translate.write.WriterRegistry;
-import java.util.Collections;
-import java.util.Map;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * DataTree implementation for configuration data.
- */
-public final class ConfigDataTree implements ModifiableDataTree {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ConfigDataTree.class);
-
-    private final BindingNormalizedNodeSerializer serializer;
-    private final DataTree dataTree;
-    private final WriterRegistry writerRegistry;
-    public static final ReadableDataTree EMPTY_OPERATIONAL = new ReadableDataTree() {
-        @Override
-        public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
-                @Nonnull final YangInstanceIdentifier path) {
-            return Futures.immediateCheckedFuture(Optional.<NormalizedNode<?, ?>>absent());
-        }
-    };
-
-    /**
-     * Creates configuration data tree instance.
-     *
-     * @param serializer     service for serialization between Java Binding Data representation and NormalizedNode
-     *                       representation.
-     * @param dataTree       data tree for configuration data representation
-     * @param writerRegistry service for translation between Java Binding Data and data provider, capable of performing
-     *                       bulk updates.
-     */
-    public ConfigDataTree(@Nonnull final BindingNormalizedNodeSerializer serializer,
-                          @Nonnull final DataTree dataTree, @Nonnull final WriterRegistry writerRegistry) {
-        this.serializer = checkNotNull(serializer, "serializer should not be null");
-        this.dataTree = checkNotNull(dataTree, "dataTree should not be null");
-        this.writerRegistry = checkNotNull(writerRegistry, "writerRegistry should not be null");
-    }
-
-    @Override
-    public DataTreeSnapshot takeSnapshot() {
-        return new ConfigSnapshot(dataTree.takeSnapshot());
-    }
-
-    @Override
-    public void modify(final DataTreeModification modification)
-            throws DataValidationFailedException, TranslationException {
-        LOG.debug("ConfigDataTree.modify");
-
-        dataTree.validate(modification);
-
-        final DataTreeCandidate candidate = dataTree.prepare(modification);
-
-        final DataTreeCandidateNode rootNode = candidate.getRootNode();
-        final YangInstanceIdentifier rootPath = candidate.getRootPath();
-        final Optional<NormalizedNode<?, ?>> normalizedDataBefore = rootNode.getDataBefore();
-        final Optional<NormalizedNode<?, ?>> normalizedDataAfter = rootNode.getDataAfter();
-        LOG.debug("ConfigDataTree.modify() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}",
-                rootPath, rootNode, normalizedDataBefore, normalizedDataAfter);
-
-        final Map<InstanceIdentifier<?>, DataObject> nodesBefore = extractNetconfData(normalizedDataBefore);
-        LOG.debug("ConfigDataTree.modify() extracted nodesBefore={}", nodesBefore.keySet());
-
-        final Map<InstanceIdentifier<?>, DataObject> nodesAfter = extractNetconfData(normalizedDataAfter);
-        LOG.debug("ConfigDataTree.modify() extracted nodesAfter={}", nodesAfter.keySet());
-
-        final DOMDataReadOnlyTransaction beforeTx = new ReadOnlyTransaction(EMPTY_OPERATIONAL, takeSnapshot());
-        final ConfigSnapshot modificationSnapshot = new ConfigSnapshot(modification);
-        final DOMDataReadOnlyTransaction afterTx = new ReadOnlyTransaction(EMPTY_OPERATIONAL, modificationSnapshot);
-        try (final WriteContext ctx = new TransactionWriteContext(serializer, beforeTx, afterTx)) {
-            writerRegistry.update(nodesBefore, nodesAfter, ctx);
-        } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException e) {
-            LOG.warn("Failed to apply all changes", e);
-            LOG.info("Trying to revert successful changes for current transaction");
-
-            try {
-                e.revertChanges();
-                LOG.info("Changes successfully reverted");
-            } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException revertFailedException) {
-                // fail with failed revert
-                LOG.error("Failed to revert successful changes", revertFailedException);
-                throw revertFailedException;
-            }
-
-            throw e; // fail with success revert
-        } catch (TranslationException e) {
-            LOG.error("Error while processing data change (before={}, after={})", nodesBefore, nodesAfter, e);
-            throw e;
-        }
-
-        dataTree.commit(candidate);
-    }
-
-    private Map<InstanceIdentifier<?>, DataObject> extractNetconfData(
-            final Optional<NormalizedNode<?, ?>> parentOptional) {
-        if (parentOptional.isPresent()) {
-            final DataContainerNode parent = (DataContainerNode) parentOptional.get();
-            return childrenFromNormalized(parent, serializer);
-        }
-        return Collections.emptyMap();
-    }
-
-    private final static class ConfigSnapshot implements DataTreeSnapshot {
-        private final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot snapshot;
-
-        ConfigSnapshot(@Nonnull final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot snapshot) {
-            this.snapshot = snapshot;
-        }
-
-        @Override
-        public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
-                @Nonnull final YangInstanceIdentifier path) {
-            final Optional<NormalizedNode<?, ?>> node = snapshot.readNode(path);
-            if (LOG.isTraceEnabled() && node.isPresent()) {
-                LOG.trace("ConfigSnapshot.read: {}", node.get());
-            }
-            return Futures.immediateCheckedFuture(node);
-        }
-
-        @Override
-        public DataTreeModification newModification() {
-            return snapshot.newModification();
-        }
-    }
-}
-
-
-
index a0b5851..c418ed3 100644 (file)
 
 package io.fd.honeycomb.v3po.data.impl;
 
-import com.google.common.base.Preconditions;
-import io.fd.honeycomb.v3po.data.DataTreeSnapshot;
-import io.fd.honeycomb.v3po.data.ModifiableDataTree;
-import io.fd.honeycomb.v3po.data.ReadableDataTree;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.v3po.data.DataModification;
+import io.fd.honeycomb.v3po.data.ModifiableDataManager;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import java.io.Closeable;
+import java.io.IOException;
 import java.util.Collections;
 import java.util.Map;
 import javax.annotation.Nonnull;
@@ -42,45 +45,36 @@ import org.slf4j.LoggerFactory;
  * Data Broker which provides data transaction functionality for YANG capable data provider using {@link NormalizedNode}
  * data format.
  */
-public class DataBroker implements DOMDataBroker {
+public class DataBroker implements DOMDataBroker, Closeable {
 
     private static final Logger LOG = LoggerFactory.getLogger(DataBroker.class);
-    private final ReadableDataTree operationalDataTree;
-    private final ModifiableDataTree configDataTree;
+    private final TransactionFactory transactionFactory;
 
     /**
      * Creates DataBroker instance.
      *
-     * @param operationalDataTree operational data
-     * @param configDataTree      configuration data
+     * @param transactionFactory transaction producing factory
      */
-    public DataBroker(@Nonnull final ReadableDataTree operationalDataTree,
-                      @Nonnull final ModifiableDataTree configDataTree) {
-        this.operationalDataTree =
-                Preconditions.checkNotNull(operationalDataTree, "operationalDataTree should not be null");
-        this.configDataTree = Preconditions.checkNotNull(configDataTree, "configDataTree should not be null");
-        LOG.trace("DataBroker({}).init() operationalDataTree={}, configDataTree={}", this, operationalDataTree, configDataTree);
+    public DataBroker(final TransactionFactory transactionFactory) {
+        this.transactionFactory = transactionFactory;
     }
 
     @Override
     public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
         LOG.trace("DataBroker({}).newReadOnlyTransaction()", this);
-        return new ReadOnlyTransaction(operationalDataTree, configDataTree.takeSnapshot());
+        return transactionFactory.newReadOnlyTransaction();
     }
 
     @Override
     public DOMDataReadWriteTransaction newReadWriteTransaction() {
         LOG.trace("DataBroker({}).newReadWriteTransaction()", this);
-        final DataTreeSnapshot configSnapshot = configDataTree.takeSnapshot();
-        final DOMDataReadOnlyTransaction readOnlyTx = new ReadOnlyTransaction(operationalDataTree, configSnapshot);
-        final DOMDataWriteTransaction writeOnlyTx = new WriteTransaction(configDataTree, configSnapshot);
-        return new ReadWriteTransaction(readOnlyTx, writeOnlyTx);
+        return transactionFactory.newReadWriteTransaction();
     }
 
     @Override
     public DOMDataWriteTransaction newWriteOnlyTransaction() {
         LOG.trace("DataBroker({}).newWriteOnlyTransaction()", this);
-        return new WriteTransaction(configDataTree);
+        return transactionFactory.newWriteOnlyTransaction();
     }
 
     @Override
@@ -101,6 +95,104 @@ public class DataBroker implements DOMDataBroker {
     public Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> getSupportedExtensions() {
         return Collections.emptyMap();
     }
+
+    /**
+     * Create DataBroker for a modifiable config DT, but only readable Operational
+     */
+    @Nonnull
+    public static DataBroker create(@Nonnull final ModifiableDataManager configDataTree,
+                             @Nonnull final ReadableDataManager operationalDataTree) {
+        checkNotNull(operationalDataTree, "operationalDataTree should not be null");
+        checkNotNull(configDataTree, "configDataTree should not be null");
+        return new DataBroker(new MainPipelineTxFactory(configDataTree, operationalDataTree));
+    }
+
+    /**
+     * Create DataBroker for modifiable operational DT, but no support for config
+     */
+    @Nonnull
+    public static DataBroker create(@Nonnull final ModifiableDataManager operationalDataTree) {
+        checkNotNull(operationalDataTree, "operationalDataTree should not be null");
+        return new DataBroker(new ContextPipelineTxFactory(operationalDataTree));
+    }
+
+    @Override
+    public void close() throws IOException {
+        // NOOP
+    }
+
+    /**
+     * Transaction provider factory to be used by {@link DataBroker}
+     */
+    public interface TransactionFactory {
+
+        DOMDataReadOnlyTransaction newReadOnlyTransaction();
+
+        DOMDataReadWriteTransaction newReadWriteTransaction();
+
+        DOMDataWriteTransaction newWriteOnlyTransaction();
+    }
+
+    /**
+     * Transaction factory specific for Honeycomb's main pipeline (config: read+write, operational: read-only)
+     */
+    private static class MainPipelineTxFactory implements TransactionFactory {
+        private final ReadableDataManager operationalDataTree;
+        private final ModifiableDataManager configDataTree;
+
+        MainPipelineTxFactory(@Nonnull final ModifiableDataManager configDataTree,
+                              @Nonnull final ReadableDataManager operationalDataTree) {
+            this.operationalDataTree = operationalDataTree;
+            this.configDataTree = configDataTree;
+        }
+
+        @Override
+        public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+            return ReadOnlyTransaction.create(configDataTree.newModification(), operationalDataTree);
+        }
+
+        @Override
+        public DOMDataReadWriteTransaction newReadWriteTransaction() {
+            final DataModification configModification = configDataTree.newModification();
+            return new ReadWriteTransaction(
+                ReadOnlyTransaction.create(configModification, operationalDataTree),
+                WriteTransaction.createConfigOnly(configModification));
+        }
+
+        @Override
+        public DOMDataWriteTransaction newWriteOnlyTransaction() {
+            return WriteTransaction.createConfigOnly(configDataTree.newModification());
+        }
+    }
+
+    /**
+     * Transaction factory specific for Honeycomb's context pipeline (config: none, operational: read+write)
+     */
+    private static class ContextPipelineTxFactory implements TransactionFactory {
+        private final ModifiableDataManager operationalDataTree;
+
+        ContextPipelineTxFactory(@Nonnull final ModifiableDataManager operationalDataTree) {
+            this.operationalDataTree = operationalDataTree;
+        }
+
+        @Override
+        public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+            return ReadOnlyTransaction.createOperationalOnly(operationalDataTree);
+        }
+
+        @Override
+        public DOMDataReadWriteTransaction newReadWriteTransaction() {
+            final DataModification dataModification = operationalDataTree.newModification();
+            return new ReadWriteTransaction(
+                ReadOnlyTransaction.createOperationalOnly(dataModification),
+                WriteTransaction.createOperationalOnly(dataModification));
+        }
+
+        @Override
+        public DOMDataWriteTransaction newWriteOnlyTransaction() {
+            return WriteTransaction.createOperationalOnly(operationalDataTree.newModification());
+        }
+    }
 }
 
 
index de83a19..5833459 100644 (file)
@@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory;
  * Utility class for various operations on DataTree.
  */
 final class DataTreeUtils {
+
     private static final Logger LOG = LoggerFactory.getLogger(DataTreeUtils.class);
 
     private DataTreeUtils() {
diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java
new file mode 100644 (file)
index 0000000..2b90107
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * 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.data.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.util.concurrent.Futures.immediateCheckedFuture;
+import static io.fd.honeycomb.v3po.data.impl.DataTreeUtils.childrenFromNormalized;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.data.DataModification;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import io.fd.honeycomb.v3po.translate.TranslationException;
+import io.fd.honeycomb.v3po.translate.util.write.TransactionMappingContext;
+import io.fd.honeycomb.v3po.translate.util.write.TransactionWriteContext;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import io.fd.honeycomb.v3po.translate.write.WriterRegistry;
+import java.util.Collections;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Extension of {@link ModifiableDataTreeManager} that propagates data changes to underlying writer layer before they
+ * are fully committed in the backing data tree. Data changes are propagated in BA format.
+ */
+public final class ModifiableDataTreeDelegator extends ModifiableDataTreeManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ModifiableDataTreeDelegator.class);
+    private static final ReadableDataManager EMPTY_OPERATIONAL = p -> immediateCheckedFuture(Optional.absent());
+
+    // TODO what to use instead of deprecated BindingNormalizedNodeSerializer ?
+    private final BindingNormalizedNodeSerializer serializer;
+    private final WriterRegistry writerRegistry;
+    private final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker;
+
+    /**
+     * Creates configuration data tree instance.
+     *  @param serializer     service for serialization between Java Binding Data representation and NormalizedNode
+     *                       representation.
+     * @param dataTree       data tree for configuration data representation
+     * @param writerRegistry service for translation between Java Binding Data and data provider, capable of performing
+     * @param contextBroker BA broker providing full access to mapping context data
+     */
+    public ModifiableDataTreeDelegator(@Nonnull final BindingNormalizedNodeSerializer serializer,
+                                       @Nonnull final DataTree dataTree,
+                                       @Nonnull final WriterRegistry writerRegistry,
+                                       @Nonnull final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker) {
+        super(dataTree);
+        this.contextBroker = checkNotNull(contextBroker, "contextBroker should not be null");
+        this.serializer = checkNotNull(serializer, "serializer should not be null");
+        this.writerRegistry = checkNotNull(writerRegistry, "writerRegistry should not be null");
+    }
+
+    @Override
+    public DataModification newModification() {
+        return new ConfigSnapshot(super.newModification());
+    }
+
+    private final class ConfigSnapshot extends ModifiableDataTreeManager.ConfigSnapshot {
+
+        private final DataModification untouchedModification;
+
+        /**
+         * @param untouchedModification DataModification captured while this modification/snapshot was created.
+         *                              To be used later while invoking writers to provide them with before state
+         *                              (state without current modifications).
+         *                              It must be captured as close as possible to when current modification started.
+         */
+        ConfigSnapshot(final DataModification untouchedModification) {
+            this.untouchedModification = untouchedModification;
+        }
+
+        /**
+         * Pass the changes to underlying writer layer.
+         * Transform from BI to BA.
+         * Revert(Write data before to subtrees that have been successfully modified before failure) in case of failure.
+         */
+        @Override
+        protected void processCandidate(final DataTreeCandidate candidate)
+            throws TranslationException {
+            final DataTreeCandidateNode rootNode = candidate.getRootNode();
+            final YangInstanceIdentifier rootPath = candidate.getRootPath();
+            final Optional<NormalizedNode<?, ?>> normalizedDataBefore = rootNode.getDataBefore();
+            final Optional<NormalizedNode<?, ?>> normalizedDataAfter = rootNode.getDataAfter();
+            LOG.debug("ConfigDataTree.modify() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}",
+                rootPath, rootNode, normalizedDataBefore, normalizedDataAfter);
+
+            final Map<InstanceIdentifier<?>, DataObject> nodesBefore = toBindingAware(normalizedDataBefore);
+            LOG.debug("ConfigDataTree.modify() extracted nodesBefore={}", nodesBefore.keySet());
+            final Map<InstanceIdentifier<?>, DataObject> nodesAfter = toBindingAware(normalizedDataAfter);
+            LOG.debug("ConfigDataTree.modify() extracted nodesAfter={}", nodesAfter.keySet());
+
+            try (final WriteContext ctx = getTransactionWriteContext()) {
+                writerRegistry.update(nodesBefore, nodesAfter, ctx);
+
+                final CheckedFuture<Void, TransactionCommitFailedException> contextUpdateResult =
+                    ((TransactionMappingContext) ctx.getMappingContext()).submit();
+                // Blocking on context data update
+                contextUpdateResult.checkedGet();
+
+            } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException e) {
+                LOG.warn("Failed to apply all changes", e);
+                LOG.info("Trying to revert successful changes for current transaction");
+
+                try {
+                    e.revertChanges();
+                    LOG.info("Changes successfully reverted");
+                } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException revertFailedException) {
+                    // fail with failed revert
+                    LOG.error("Failed to revert successful changes", revertFailedException);
+                    throw revertFailedException;
+                }
+
+                throw e; // fail with success revert
+            } catch (TransactionCommitFailedException e) {
+                // FIXME revert should probably occur when context is not written successfully, but can that even happen ?
+                final String msg = "Error while updating mapping context data";
+                LOG.error(msg, e);
+                throw new TranslationException(msg, e);
+            } catch (TranslationException e) {
+                LOG.error("Error while processing data change (before={}, after={})", nodesBefore, nodesAfter, e);
+                throw e;
+            }
+        }
+
+        private TransactionWriteContext getTransactionWriteContext() {
+            // Before Tx must use modification
+            final DOMDataReadOnlyTransaction beforeTx = ReadOnlyTransaction.create(untouchedModification, EMPTY_OPERATIONAL);
+            // After Tx must use current modification
+            final DOMDataReadOnlyTransaction afterTx = ReadOnlyTransaction.create(this, EMPTY_OPERATIONAL);
+            final TransactionMappingContext mappingContext = new TransactionMappingContext(
+                contextBroker.newReadWriteTransaction());
+            return new TransactionWriteContext(serializer, beforeTx, afterTx, mappingContext);
+        }
+
+        private Map<InstanceIdentifier<?>, DataObject> toBindingAware(final Optional<NormalizedNode<?, ?>> parentOptional) {
+            if (parentOptional.isPresent()) {
+                final DataContainerNode parent = (DataContainerNode) parentOptional.get();
+                return childrenFromNormalized(parent, serializer);
+            }
+            return Collections.emptyMap();
+        }
+    }
+}
+
+
+
diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java
new file mode 100644 (file)
index 0000000..1082c47
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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.data.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.util.concurrent.Futures.immediateCheckedFuture;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.data.DataModification;
+import io.fd.honeycomb.v3po.data.ModifiableDataManager;
+import io.fd.honeycomb.v3po.translate.TranslationException;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * DataTree backed implementation for modifiable data manager.
+ */
+public class ModifiableDataTreeManager implements ModifiableDataManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ModifiableDataTreeManager.class);
+
+    private final DataTree dataTree;
+
+    public ModifiableDataTreeManager(@Nonnull final DataTree dataTree) {
+        this.dataTree = checkNotNull(dataTree, "dataTree should not be null");
+    }
+
+    @Override
+    public DataModification newModification() {
+        return new ConfigSnapshot();
+    }
+
+    @Override
+    public final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(@Nonnull final YangInstanceIdentifier path) {
+        return newModification().read(path);
+    }
+
+    protected class ConfigSnapshot implements DataModification {
+        private final DataTreeModification modification;
+        private boolean validated = false;
+
+        ConfigSnapshot() {
+            this(dataTree.takeSnapshot().newModification());
+        }
+
+        protected ConfigSnapshot(final DataTreeModification modification) {
+            this.modification = modification;
+        }
+
+        @Override
+        public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
+                @Nonnull final YangInstanceIdentifier path) {
+            final Optional<NormalizedNode<?, ?>> node = modification.readNode(path);
+            if (LOG.isTraceEnabled() && node.isPresent()) {
+                LOG.trace("ConfigSnapshot.read: {}", node.get());
+            }
+            return immediateCheckedFuture(node);
+        }
+
+        @Override
+        public final void delete(final YangInstanceIdentifier path) {
+            modification.delete(path);
+        }
+
+        @Override
+        public final void merge(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+            modification.merge(path, data);
+        }
+
+        @Override
+        public final void write(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+            modification.write(path, data);
+        }
+
+        @Override
+        public final void commit() throws DataValidationFailedException, TranslationException {
+            if(!validated) {
+                validate();
+            }
+            final DataTreeCandidate candidate = dataTree.prepare(modification);
+            processCandidate(candidate);
+            dataTree.commit(candidate);
+        }
+
+        protected void processCandidate(final DataTreeCandidate candidate) throws TranslationException {
+            // NOOP
+        }
+
+        @Override
+        public final void validate() throws DataValidationFailedException {
+            modification.ready();
+            dataTree.validate(modification);
+            validated = true;
+        }
+    }
+}
+
+
+
index 25d1d8d..a54b7f1 100644 (file)
@@ -127,6 +127,10 @@ public class PersistingDataTreeAdapter implements org.opendaylight.yangtools.yan
         if(currentRoot.isPresent()) {
             try {
                 LOG.trace("Persisting current data: {} into: {}", currentRoot.get(), path);
+                // Make sure the file gets overwritten
+                if(Files.exists(path)) {
+                    Files.delete(path);
+                }
                 // TODO once we are in static environment, do the writer, streamWriter and NNWriter initialization only once
                 final JsonWriter
                     jsonWriter = createJsonWriter(Files.newOutputStream(path, StandardOpenOption.CREATE), true);
index 83c9e30..c38fa27 100644 (file)
 
 package io.fd.honeycomb.v3po.data.impl;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-import io.fd.honeycomb.v3po.data.ReadableDataTree;
-import io.fd.honeycomb.v3po.data.DataTreeSnapshot;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -37,17 +39,27 @@ import org.slf4j.LoggerFactory;
 final class ReadOnlyTransaction implements DOMDataReadOnlyTransaction {
 
     private static final Logger LOG = LoggerFactory.getLogger(ReadOnlyTransaction.class);
-    private volatile ReadableDataTree operationalData;
-    private volatile DataTreeSnapshot configSnapshot;
 
-    ReadOnlyTransaction(@Nonnull final ReadableDataTree operationalData,
-                        @Nonnull final DataTreeSnapshot configSnapshot) {
-        this.operationalData = Preconditions.checkNotNull(operationalData, "operationalData should not be null");
-        this.configSnapshot = Preconditions.checkNotNull(configSnapshot, "config should not be null");
+    @Nullable
+    private volatile ReadableDataManager operationalData;
+    @Nullable
+    private volatile ReadableDataManager configSnapshot;
+
+    private volatile boolean closed = false;
+
+    /**
+     * @param configData config data tree manager. Null if config reads are not to be supported
+     * @param operationalData operational data tree manager. Null if operational reads are not to be supported
+     */
+    private ReadOnlyTransaction(@Nullable final ReadableDataManager configData,
+                                @Nullable final ReadableDataManager operationalData) {
+        this.configSnapshot = configData;
+        this.operationalData = operationalData;
     }
 
     @Override
     public void close() {
+        closed = true;
         configSnapshot = null;
         operationalData = null;
     }
@@ -57,12 +69,13 @@ final class ReadOnlyTransaction implements DOMDataReadOnlyTransaction {
             final LogicalDatastoreType store,
             final YangInstanceIdentifier path) {
         LOG.debug("ReadOnlyTransaction.read(), store={}, path={}", store, path);
-
-        Preconditions.checkState(configSnapshot != null, "Transaction was closed");
+        checkState(!closed, "Transaction has been closed");
 
         if (store == LogicalDatastoreType.OPERATIONAL) {
+            checkArgument(operationalData != null, "{} reads not supported", store);
             return operationalData.read(path);
         } else {
+            checkArgument(configSnapshot != null, "{} reads not supported", store);
             return configSnapshot.read(path);
         }
     }
@@ -73,7 +86,6 @@ final class ReadOnlyTransaction implements DOMDataReadOnlyTransaction {
         LOG.debug("ReadOnlyTransaction.exists() store={}, path={}", store, path);
 
         ListenableFuture<Boolean> listenableFuture = Futures.transform(read(store, path), IS_NODE_PRESENT);
-
         return Futures.makeChecked(listenableFuture, ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER);
     }
 
@@ -83,23 +95,25 @@ final class ReadOnlyTransaction implements DOMDataReadOnlyTransaction {
         return this;
     }
 
+    @Nonnull
+    static ReadOnlyTransaction createOperationalOnly(@Nonnull final ReadableDataManager operationalData) {
+        return new ReadOnlyTransaction(null, requireNonNull(operationalData));
+    }
+
+    @Nonnull
+    static ReadOnlyTransaction createConfigOnly(@Nonnull final ReadableDataManager configData) {
+        return new ReadOnlyTransaction(requireNonNull(configData), null);
+    }
+
+    @Nonnull
+    static ReadOnlyTransaction create(@Nonnull final ReadableDataManager configData,
+                                      @Nonnull final ReadableDataManager operationalData) {
+        return new ReadOnlyTransaction(requireNonNull(configData), requireNonNull(operationalData));
+    }
 
     private static final Function<? super Optional<NormalizedNode<?, ?>>, ? extends Boolean> IS_NODE_PRESENT =
-            new Function<Optional<NormalizedNode<?, ?>>, Boolean>() {
-                @Nullable
-                @Override
-                public Boolean apply(@Nullable final Optional<NormalizedNode<?, ?>> input) {
-                    return input == null
-                            ? Boolean.FALSE
-                            : input.isPresent();
-                }
-            };
+        (Function<Optional<NormalizedNode<?, ?>>, Boolean>) input -> input == null ? Boolean.FALSE : input.isPresent();
 
     private static final Function<? super Exception, ReadFailedException> ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER =
-            new Function<Exception, ReadFailedException>() {
-                @Override
-                public ReadFailedException apply(@Nullable final Exception e) {
-                    return new ReadFailedException("Exists failed", e);
-                }
-            };
+        (Function<Exception, ReadFailedException>) e -> new ReadFailedException("Exists failed", e);
 }
\ No newline at end of file
@@ -26,15 +26,18 @@ import com.google.common.collect.Collections2;
 import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
-import io.fd.honeycomb.v3po.data.ReadableDataTree;
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.read.ReaderRegistry;
+import io.fd.honeycomb.v3po.translate.util.write.TransactionMappingContext;
 import java.util.Collection;
 import java.util.Map;
 import javax.annotation.Nonnull;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
@@ -61,13 +64,14 @@ import org.slf4j.LoggerFactory;
 /**
  * ReadableDataTree implementation for operational data.
  */
-public final class OperationalDataTree implements ReadableDataTree {
-    private static final Logger LOG = LoggerFactory.getLogger(OperationalDataTree.class);
+public final class ReadableDataTreeDelegator implements ReadableDataManager {
+    private static final Logger LOG = LoggerFactory.getLogger(ReadableDataTreeDelegator.class);
 
     private final BindingNormalizedNodeSerializer serializer;
     private final ReaderRegistry readerRegistry;
     private final SchemaContext globalContext;
     private final DOMDataBroker netconfMonitoringDomDataBrokerDependency;
+    private final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker;
 
     /**
      * Creates operational data tree instance.
@@ -75,12 +79,16 @@ public final class OperationalDataTree implements ReadableDataTree {
      *                       representation.
      * @param globalContext  service for obtaining top level context data from all yang modules.
      * @param readerRegistry service responsible for translation between DataObjects and data provider.
-     * @param netconfMonitoringDomDataBrokerDependency
+     * @param netconfMonitoringDomDataBrokerDependency TODO remove
+     * @param contextBroker BA broker for context data
      */
-    public OperationalDataTree(@Nonnull BindingNormalizedNodeSerializer serializer,
-                               @Nonnull final SchemaContext globalContext, @Nonnull ReaderRegistry readerRegistry,
-                               final DOMDataBroker netconfMonitoringDomDataBrokerDependency) {
+    public ReadableDataTreeDelegator(@Nonnull BindingNormalizedNodeSerializer serializer,
+                                     @Nonnull final SchemaContext globalContext,
+                                     @Nonnull final ReaderRegistry readerRegistry,
+                                     @Nonnull final DOMDataBroker netconfMonitoringDomDataBrokerDependency,
+                                     @Nonnull final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker) {
         this.netconfMonitoringDomDataBrokerDependency = netconfMonitoringDomDataBrokerDependency;
+        this.contextBroker = checkNotNull(contextBroker, "contextBroker should not be null");
         this.globalContext = checkNotNull(globalContext, "globalContext should not be null");
         this.serializer = checkNotNull(serializer, "serializer should not be null");
         this.readerRegistry = checkNotNull(readerRegistry, "reader should not be null");
@@ -91,16 +99,35 @@ public final class OperationalDataTree implements ReadableDataTree {
             org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> read(
             @Nonnull final YangInstanceIdentifier yangInstanceIdentifier) {
 
-        try(ReadContext ctx = new ReadContextImpl()) {
+        try(TransactionMappingContext mappingContext = new TransactionMappingContext(contextBroker.newReadWriteTransaction());
+            ReadContext ctx = new ReadContextImpl(mappingContext)) {
+
+            final Optional<NormalizedNode<?, ?>> value;
             if (checkNotNull(yangInstanceIdentifier).equals(YangInstanceIdentifier.EMPTY)) {
-                return Futures.immediateCheckedFuture(readRoot(ctx));
+                value = readRoot(ctx);
             } else {
-                return Futures.immediateCheckedFuture(readNode(yangInstanceIdentifier, ctx));
+                value = readNode(yangInstanceIdentifier, ctx);
             }
+
+            // Submit context mapping updates
+            final CheckedFuture<Void, TransactionCommitFailedException> contextUpdateResult =
+                ((TransactionMappingContext) ctx.getMappingContext()).submit();
+            // Blocking on context data update
+            contextUpdateResult.checkedGet();
+
+            return Futures.immediateCheckedFuture(value);
+
         } catch (ReadFailedException e) {
             return Futures.immediateFailedCheckedFuture(
-                    new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException(
-                            "Failed to read VPP data", e));
+                new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException(
+                    "Failed to read VPP data", e));
+        } catch (TransactionCommitFailedException e) {
+            // FIXME revert should probably occur when context is not written successfully, but can that even happen ?
+            final String msg = "Error while updating mapping context data";
+            LOG.error(msg, e);
+            return Futures.immediateFailedCheckedFuture(
+                new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException(msg, e)
+            );
         }
     }
 
@@ -108,6 +135,8 @@ public final class OperationalDataTree implements ReadableDataTree {
                                                     final ReadContext ctx) throws ReadFailedException {
 
         // FIXME workaround for: https://git.opendaylight.org/gerrit/#/c/37499/
+        // Just delete, dedicated reader from NetconfMonitoringReaderModule takes care of netconf state data
+        // TODO test connecting with netconf and issuing a get (netconf-state) data should be provided
         if(yangInstanceIdentifier.getPathArguments().size() > 0 &&
             yangInstanceIdentifier.getPathArguments().get(0).getNodeType().equals(NetconfState.QNAME)) {
             return readFromNetconfDs(yangInstanceIdentifier);
@@ -222,17 +251,29 @@ public final class OperationalDataTree implements ReadableDataTree {
     }
 
     private static final class ReadContextImpl implements ReadContext {
-        public final Context ctx = new Context();
+
+        public final ModificationCache ctx = new ModificationCache();
+        private final MappingContext mappingContext;
+
+        private ReadContextImpl(final MappingContext mappingContext) {
+            this.mappingContext = mappingContext;
+        }
 
         @Nonnull
         @Override
-        public Context getContext() {
+        public ModificationCache getModificationCache() {
             return ctx;
         }
 
+        @Nonnull
+        @Override
+        public MappingContext getMappingContext() {
+            return mappingContext;
+        }
+
         @Override
         public void close() {
-            // Make sure to clear the storage in case some customizer stored it  to prevent memory leaks
+            // Make sure to clear the storage in case some customizer stored a reference to it to prevent memory leaks
             ctx.close();
         }
     }
index fbeba7e..3644a9f 100644 (file)
@@ -16,6 +16,8 @@
 
 package io.fd.honeycomb.v3po.data.impl;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
 import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.CANCELED;
 import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.COMMITED;
 import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.FAILED;
@@ -26,10 +28,10 @@ import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-import io.fd.honeycomb.v3po.data.ModifiableDataTree;
-import io.fd.honeycomb.v3po.data.DataTreeSnapshot;
+import io.fd.honeycomb.v3po.data.DataModification;
 import io.fd.honeycomb.v3po.translate.TranslationException;
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import javax.annotation.concurrent.NotThreadSafe;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -38,7 +40,6 @@ import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -47,30 +48,21 @@ import org.slf4j.LoggerFactory;
 final class WriteTransaction implements DOMDataWriteTransaction {
 
     private static final Logger LOG = LoggerFactory.getLogger(WriteTransaction.class);
-    private final ModifiableDataTree configDataTree;
-    private DataTreeModification modification;
-    private TransactionStatus status;
-
-    WriteTransaction(@Nonnull final ModifiableDataTree configDataTree,
-                     @Nonnull final DataTreeSnapshot configSnapshot) {
-        this.configDataTree = Preconditions.checkNotNull(configDataTree, "configDataTree should not be null");
-        Preconditions.checkNotNull(configSnapshot, "configSnapshot should not be null");
-        // initialize transaction state:
-        modification = configSnapshot.newModification();
-        status = NEW;
-    }
 
-    WriteTransaction(@Nonnull final ModifiableDataTree configDataTree) {
-        this(configDataTree, configDataTree.takeSnapshot());
-    }
+    @Nullable
+    private DataModification operationalModification;
+    @Nullable
+    private DataModification configModification;
+    private TransactionStatus status = NEW;
 
-    private static void checkConfigurationWrite(final LogicalDatastoreType store) {
-        Preconditions.checkArgument(LogicalDatastoreType.CONFIGURATION == store, "Write is not supported for operational data store");
+    private WriteTransaction(@Nullable final DataModification configModification,
+                             @Nullable final DataModification operationalModification) {
+        this.operationalModification = operationalModification;
+        this.configModification = configModification;
     }
 
     private void checkIsNew() {
         Preconditions.checkState(status == NEW, "Transaction was submitted or canceled");
-        Preconditions.checkState(modification != null, "DataTree modification should not be null");
     }
 
     @Override
@@ -78,8 +70,21 @@ final class WriteTransaction implements DOMDataWriteTransaction {
                     final NormalizedNode<?, ?> data) {
         LOG.debug("WriteTransaction.put() store={}, path={}, data={}", store, path, data);
         checkIsNew();
-        checkConfigurationWrite(store);
-        modification.write(path, data);
+        handleOperation(store, (modification) -> modification.write(path, data));
+    }
+
+    private void handleOperation(final LogicalDatastoreType store,
+                                 final java.util.function.Consumer<DataModification> r) {
+        switch (store) {
+            case CONFIGURATION:
+                checkArgument(configModification != null, "Modification of {} is not supported", store);
+                r.accept(configModification);
+                break;
+            case OPERATIONAL:
+                checkArgument(operationalModification != null, "Modification of {} is not supported", store);
+                r.accept(operationalModification);
+                break;
+        }
     }
 
     @Override
@@ -87,8 +92,7 @@ final class WriteTransaction implements DOMDataWriteTransaction {
                       final NormalizedNode<?, ?> data) {
         LOG.debug("WriteTransaction.merge() store={}, path={}, data={}", store, path, data);
         checkIsNew();
-        checkConfigurationWrite(store);
-        modification.merge(path, data);
+        handleOperation(store, (modification) -> modification.merge(path, data));
     }
 
     @Override
@@ -98,7 +102,6 @@ final class WriteTransaction implements DOMDataWriteTransaction {
             return false;
         } else {
             status = CANCELED;
-            modification = null;
             return true;
         }
     }
@@ -107,29 +110,38 @@ final class WriteTransaction implements DOMDataWriteTransaction {
     public void delete(LogicalDatastoreType store, final YangInstanceIdentifier path) {
         LOG.debug("WriteTransaction.delete() store={}, path={}", store, path);
         checkIsNew();
-        checkConfigurationWrite(store);
-        modification.delete(path);
+        handleOperation(store, (modification) -> modification.delete(path));
     }
 
     @Override
     public CheckedFuture<Void, TransactionCommitFailedException> submit() {
-        LOG.debug("WriteTransaction.submit()");
+        LOG.trace("WriteTransaction.submit()");
         checkIsNew();
 
-        // seal transaction:
-        modification.ready();
-        status = SUBMITED;
-
         try {
-            configDataTree.modify(modification);
+            status = SUBMITED;
+
+            // Validate first to catch any issues before attempting commit
+            if (configModification != null) {
+                configModification.validate();
+            }
+            if (operationalModification != null) {
+                operationalModification.validate();
+            }
+
+            if(configModification != null) {
+                configModification.commit();
+            }
+            if(operationalModification != null) {
+                operationalModification.commit();
+            }
+
             status = COMMITED;
         } catch (DataValidationFailedException | TranslationException e) {
             status = FAILED;
             LOG.error("Failed modify data tree", e);
             return Futures.immediateFailedCheckedFuture(
-                    new TransactionCommitFailedException("Failed to validate DataTreeModification", e));
-        } finally {
-            modification = null;
+                new TransactionCommitFailedException("Failed to validate DataTreeModification", e));
         }
         return Futures.immediateCheckedFuture(null);
     }
@@ -144,4 +156,21 @@ final class WriteTransaction implements DOMDataWriteTransaction {
     public Object getIdentifier() {
         return this;
     }
+
+
+    @Nonnull
+    static WriteTransaction createOperationalOnly(@Nonnull final DataModification operationalData) {
+        return new WriteTransaction(null, requireNonNull(operationalData));
+    }
+
+    @Nonnull
+    static WriteTransaction createConfigOnly(@Nonnull final DataModification configData) {
+        return new WriteTransaction(requireNonNull(configData), null);
+    }
+
+    @Nonnull
+    static WriteTransaction create(@Nonnull final DataModification configData,
+                            @Nonnull final DataModification operationalData) {
+        return new WriteTransaction(requireNonNull(configData), requireNonNull(operationalData));
+    }
 }
index 86a3f9d..3e871e0 100644 (file)
@@ -1,11 +1,14 @@
 package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411;
 
-import io.fd.honeycomb.v3po.data.DataTreeSnapshot;
-import io.fd.honeycomb.v3po.data.ModifiableDataTree;
-import io.fd.honeycomb.v3po.data.impl.ConfigDataTree;
-import io.fd.honeycomb.v3po.translate.TranslationException;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.data.DataModification;
+import io.fd.honeycomb.v3po.data.ModifiableDataManager;
+import io.fd.honeycomb.v3po.data.impl.ModifiableDataTreeDelegator;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,14 +38,15 @@ public class ConfigDataTreeModule extends
     public java.lang.AutoCloseable createInstance() {
         LOG.debug("ConfigDataTreeModule.createInstance()");
         return new CloseableConfigDataTree(
-                new ConfigDataTree(getSerializerDependency(), getDataTreeDependency(), getWriterRegistryDependency()));
+                new ModifiableDataTreeDelegator(getSerializerDependency(), getDataTreeDependency(), getWriterRegistryDependency(),
+                    getContextBindingBrokerDependency()));
     }
 
-    private static final class CloseableConfigDataTree implements ModifiableDataTree, AutoCloseable {
+    private static final class CloseableConfigDataTree implements ModifiableDataManager, AutoCloseable {
 
-        private final ConfigDataTree delegate;
+        private final ModifiableDataTreeDelegator delegate;
 
-        CloseableConfigDataTree(final ConfigDataTree delegate) {
+        CloseableConfigDataTree(final ModifiableDataTreeDelegator delegate) {
             this.delegate = delegate;
         }
 
@@ -53,16 +57,15 @@ public class ConfigDataTreeModule extends
         }
 
         @Override
-        public void modify(final DataTreeModification modification)
-                throws DataValidationFailedException, TranslationException {
-            LOG.trace("CloseableConfigDataTree.modify modification={}", modification);
-            delegate.modify(modification);
+        public DataModification newModification() {
+            LOG.trace("CloseableConfigDataTree.newModification");
+            return delegate.newModification();
         }
 
         @Override
-        public DataTreeSnapshot takeSnapshot() {
-            LOG.trace("CloseableConfigDataTree.takeSnapshot");
-            return delegate.takeSnapshot();
+        public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
+            @Nonnull final YangInstanceIdentifier path) {
+            return delegate.read(path);
         }
     }
 }
index 2fbba75..286eaf6 100644 (file)
@@ -2,8 +2,8 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.
 
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
-import io.fd.honeycomb.v3po.data.ReadableDataTree;
-import io.fd.honeycomb.v3po.data.impl.OperationalDataTree;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import io.fd.honeycomb.v3po.data.impl.ReadableDataTreeDelegator;
 import javax.annotation.Nonnull;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -37,15 +37,15 @@ public class OperationalDataTreeModule extends
     public java.lang.AutoCloseable createInstance() {
         LOG.debug("OperationalDataTreeModule.createInstance()");
         return new CloseableOperationalDataTree(
-                new OperationalDataTree(getSerializerDependency(), getSchemaServiceDependency().getGlobalContext(),
-                        getReaderRegistryDependency(), getNetconfMonitoringDomDataBrokerDependency()));
+                new ReadableDataTreeDelegator(getSerializerDependency(), getSchemaServiceDependency().getGlobalContext(),
+                        getReaderRegistryDependency(), getNetconfMonitoringDomDataBrokerDependency(), getContextBindingBrokerDependency()));
     }
 
-    private static final class CloseableOperationalDataTree implements ReadableDataTree, AutoCloseable {
+    private static final class CloseableOperationalDataTree implements ReadableDataManager, AutoCloseable {
 
-        private final OperationalDataTree delegate;
+        private final ReadableDataTreeDelegator delegate;
 
-        CloseableOperationalDataTree(final OperationalDataTree delegate) {
+        CloseableOperationalDataTree(final ReadableDataTreeDelegator delegate) {
             this.delegate = delegate;
         }
 
index 454e99a..3af9d8d 100644 (file)
@@ -121,6 +121,14 @@ module data-impl {
                 }
             }
 
+            container context-binding-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding:binding-async-data-broker;
+                    }
+                }
+            }
         }
     }
 
@@ -171,6 +179,15 @@ module data-impl {
                 }
             }
 
+            container context-binding-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding:binding-async-data-broker;
+                    }
+                }
+            }
+
         }
     }
 }
\ No newline at end of file
index a2908d5..55b92b5 100644 (file)
@@ -22,9 +22,9 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
-import io.fd.honeycomb.v3po.data.ReadableDataTree;
-import io.fd.honeycomb.v3po.data.ModifiableDataTree;
-import io.fd.honeycomb.v3po.data.DataTreeSnapshot;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import io.fd.honeycomb.v3po.data.ModifiableDataManager;
+import io.fd.honeycomb.v3po.data.DataModification;
 import java.util.Map;
 import org.junit.Before;
 import org.junit.Test;
@@ -42,18 +42,18 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 public class DataBrokerTest {
 
     @Mock
-    private ReadableDataTree operationalData;
+    private ReadableDataManager operationalData;
     @Mock
-    private ModifiableDataTree confiDataTree;
+    private ModifiableDataManager confiDataTree;
     @Mock
-    private DataTreeSnapshot configSnapshot;
+    private DataModification configSnapshot;
     private DataBroker broker;
 
     @Before
     public void setUp() {
         initMocks(this);
-        when(confiDataTree.takeSnapshot()).thenReturn(configSnapshot);
-        broker = new DataBroker(operationalData, confiDataTree);
+        when(confiDataTree.newModification()).thenReturn(configSnapshot);
+        broker = DataBroker.create(confiDataTree, operationalData);
     }
 
     @Test
@@ -64,7 +64,7 @@ public class DataBrokerTest {
 
         // verify that read and write transactions use the same config snapshot
         verify(configSnapshot).read(path);
-        verify(configSnapshot).newModification();
+        verify(confiDataTree).newModification();
     }
 
     @Test
@@ -72,7 +72,7 @@ public class DataBrokerTest {
         final DOMDataWriteTransaction writeTx = broker.newWriteOnlyTransaction();
 
         // verify that write transactions use config snapshot
-        verify(configSnapshot).newModification();
+        verify(confiDataTree).newModification();
     }
 
     @Test
@@ -25,13 +25,15 @@ import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
-import io.fd.honeycomb.v3po.data.DataTreeSnapshot;
+import com.google.common.util.concurrent.Futures;
+import io.fd.honeycomb.v3po.data.DataModification;
 import io.fd.honeycomb.v3po.translate.TranslationException;
 import io.fd.honeycomb.v3po.translate.write.WriteContext;
 import io.fd.honeycomb.v3po.translate.write.WriterRegistry;
@@ -42,6 +44,7 @@ import java.util.Map;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet;
@@ -55,9 +58,8 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
 
-public class ConfigDataTreeTest {
+public class ModifiableDataTreeDelegatorTest {
 
     @Mock
     private WriterRegistry writer;
@@ -66,14 +68,16 @@ public class ConfigDataTreeTest {
     @Mock
     private DataTree dataTree;
     @Mock
-    private DataTreeModification modification;
+    private org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification modification;
+    @Mock
+    private DataBroker contextBroker;
 
-    private ConfigDataTree configDataTree;
+    private ModifiableDataTreeManager configDataTree;
 
     @Before
     public void setUp() {
         initMocks(this);
-        configDataTree = new ConfigDataTree(serializer, dataTree, writer);
+        configDataTree = new ModifiableDataTreeDelegator(serializer, dataTree, writer, contextBroker);
     }
 
     @Test
@@ -81,17 +85,18 @@ public class ConfigDataTreeTest {
         final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot
                 snapshot = mock(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot.class);
         when(dataTree.takeSnapshot()).thenReturn(snapshot);
+        when(snapshot.newModification()).thenReturn(modification);
 
         final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class);
         final Optional node = mock(Optional.class);
-        doReturn(node).when(snapshot).readNode(path);
+        doReturn(node).when(modification).readNode(path);
 
-        final DataTreeSnapshot dataTreeSnapshot = configDataTree.takeSnapshot();
+        final DataModification dataTreeSnapshot = configDataTree.newModification();
         final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future =
                 dataTreeSnapshot.read(path);
 
-        verify(dataTree).takeSnapshot();
-        verify(snapshot).readNode(path);
+        verify(dataTree, times(2)).takeSnapshot();
+        verify(modification).readNode(path);
 
         assertTrue(future.isDone());
         assertEquals(node, future.get());
@@ -102,19 +107,29 @@ public class ConfigDataTreeTest {
         final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot
                 snapshot = mock(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot.class);
         when(dataTree.takeSnapshot()).thenReturn(snapshot);
-
         when(snapshot.newModification()).thenReturn(modification);
 
-        final DataTreeSnapshot dataTreeSnapshot = configDataTree.takeSnapshot();
-        final DataTreeModification newModification = dataTreeSnapshot.newModification();
-        verify(dataTree).takeSnapshot();
-        verify(snapshot).newModification();
-
-        assertEquals(modification, newModification);
+        final DataModification dataTreeSnapshot = configDataTree.newModification();
+        // Snapshot captured twice, so that original data could be provided to translation layer without any possible
+        // modification
+        verify(dataTree, times(2)).takeSnapshot();
+        verify(snapshot, times(2)).newModification();
     }
 
     @Test
     public void testCommitSuccessful() throws Exception {
+        final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot
+            snapshot = mock(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot.class);
+        when(dataTree.takeSnapshot()).thenReturn(snapshot);
+        when(snapshot.newModification()).thenReturn(modification);
+        final DataTreeCandidate prepare = mock(DataTreeCandidate.class);
+        doReturn(prepare).when(dataTree).prepare(modification);
+
+        final org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction ctxTransaction = mock(
+            org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction.class);
+        doReturn(ctxTransaction).when(contextBroker).newReadWriteTransaction();
+        doReturn(Futures.immediateCheckedFuture(null)).when(ctxTransaction).submit();
+
         final DataObject dataBefore = mockDataObject("before", Ethernet.class);
         final DataObject dataAfter = mockDataObject("after", Ethernet.class);
 
@@ -128,7 +143,9 @@ public class ConfigDataTreeTest {
         when(rootNode.getDataAfter()).thenReturn(Optional.<NormalizedNode<?, ?>>fromNullable(nodeAfter));
 
         // Run the test
-        configDataTree.modify(modification);
+        doReturn(rootNode).when(prepare).getRootNode();
+        final DataModification dataModification = configDataTree.newModification();
+        dataModification.commit();
 
         // Verify all changes were processed:
         verify(writer).update(
@@ -138,6 +155,8 @@ public class ConfigDataTreeTest {
 
         // Verify modification was validated
         verify(dataTree).validate(modification);
+        // Verify context transaction was finished
+        verify(ctxTransaction).submit();
     }
 
     private Map<InstanceIdentifier<?>, DataObject> mapOf(final DataObject dataBefore, final Class<Ethernet> type) {
@@ -154,6 +173,13 @@ public class ConfigDataTreeTest {
 
     @Test
     public void testCommitUndoSuccessful() throws Exception {
+        final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot
+            snapshot = mock(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot.class);
+        when(dataTree.takeSnapshot()).thenReturn(snapshot);
+        when(snapshot.newModification()).thenReturn(modification);
+        final DataTreeCandidate prepare = mock(DataTreeCandidate.class);
+        doReturn(prepare).when(dataTree).prepare(modification);
+
         // Prepare data changes:
         final DataObject dataBefore = mockDataObject("before", Ethernet.class);
         final DataObject dataAfter = mockDataObject("after", Ethernet.class);
@@ -177,7 +203,9 @@ public class ConfigDataTreeTest {
 
         // Run the test
         try {
-            configDataTree.modify(modification);
+            doReturn(rootNode).when(prepare).getRootNode();
+            final DataModification dataModification = configDataTree.newModification();
+            dataModification.commit();
         } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException e) {
             verify(writer).update(anyMap(), anyMap(), any(WriteContext.class));
             verify(reverter).revert();
@@ -190,6 +218,13 @@ public class ConfigDataTreeTest {
 
     @Test
     public void testCommitUndoFailed() throws Exception {
+        final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot
+            snapshot = mock(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot.class);
+        when(dataTree.takeSnapshot()).thenReturn(snapshot);
+        when(snapshot.newModification()).thenReturn(modification);
+        final DataTreeCandidate prepare = mock(DataTreeCandidate.class);
+        doReturn(prepare).when(dataTree).prepare(modification);
+
         // Prepare data changes:
         final DataObject dataBefore = mockDataObject("before", Ethernet.class);
         final DataObject dataAfter = mockDataObject("after", Ethernet.class);
@@ -219,7 +254,9 @@ public class ConfigDataTreeTest {
 
         // Run the test
         try {
-            configDataTree.modify(modification);
+            doReturn(rootNode).when(prepare).getRootNode();
+            final DataModification dataModification = configDataTree.newModification();
+            dataModification.commit();
         } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException e) {
             verify(writer).update(anyMap(), anyMap(), any(WriteContext.class));
             verify(reverter).revert();
index 30fdd13..a136217 100644 (file)
@@ -24,8 +24,8 @@ import static org.mockito.MockitoAnnotations.initMocks;
 
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
-import io.fd.honeycomb.v3po.data.ReadableDataTree;
-import io.fd.honeycomb.v3po.data.DataTreeSnapshot;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import io.fd.honeycomb.v3po.data.DataModification;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -37,16 +37,16 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 public class ReadOnlyTransactionTest {
 
     @Mock
-    private ReadableDataTree operationalData;
+    private ReadableDataManager operationalData;
     @Mock
-    private DataTreeSnapshot configSnapshot;
+    private DataModification configSnapshot;
 
     private ReadOnlyTransaction readOnlyTx;
 
     @Before
     public void setUp() {
         initMocks(this);
-        readOnlyTx = new ReadOnlyTransaction(operationalData, configSnapshot);
+        readOnlyTx = ReadOnlyTransaction.create(configSnapshot, operationalData);
     }
 
     @Test
@@ -42,6 +42,7 @@ import java.util.Map;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
@@ -58,14 +59,14 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
-public class OperationalDataTreeTest {
+public class ReadableDataTreeDelegatorTest {
 
     @Mock
     private BindingNormalizedNodeSerializer serializer;
     @Mock
     private ReaderRegistry reader;
 
-    private OperationalDataTree operationalData;
+    private ReadableDataTreeDelegator operationalData;
 
     @Mock
     private InstanceIdentifier<DataObject> id;
@@ -81,16 +82,23 @@ public class OperationalDataTreeTest {
     private DOMDataBroker netconfMonitoringBroker;
     @Mock
     private DOMDataReadOnlyTransaction domDataReadOnlyTransaction;
+    @Mock
+    private DataBroker contextBroker;
 
     @Before
     public void setUp() {
         initMocks(this);
-        operationalData = new OperationalDataTree(serializer, globalContext, reader, netconfMonitoringBroker);
+        operationalData = new ReadableDataTreeDelegator(serializer, globalContext, reader, netconfMonitoringBroker, contextBroker);
         doReturn(schemaNode).when(globalContext).getDataChildByName(any(QName.class));
 
         doReturn(domDataReadOnlyTransaction).when(netconfMonitoringBroker).newReadOnlyTransaction();
         doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(domDataReadOnlyTransaction)
             .read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class));
+
+        final org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction ctxTransaction = mock(
+            org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction.class);
+        doReturn(ctxTransaction).when(contextBroker).newReadWriteTransaction();
+        doReturn(Futures.immediateCheckedFuture(null)).when(ctxTransaction).submit();
     }
 
     @Test
index d0360db..9cde27d 100644 (file)
@@ -23,12 +23,10 @@ import static org.junit.Assert.fail;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
 import com.google.common.util.concurrent.CheckedFuture;
-import io.fd.honeycomb.v3po.data.ModifiableDataTree;
-import io.fd.honeycomb.v3po.data.DataTreeSnapshot;
+import io.fd.honeycomb.v3po.data.DataModification;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -36,54 +34,48 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
 
 public class WriteTransactionTest {
 
     @Mock
-    private ModifiableDataTree configDataTree;
-    @Mock
-    private DataTreeSnapshot configSnapshot;
+    private DataModification configSnapshot;
     @Mock
     private YangInstanceIdentifier path;
     @Mock
     private NormalizedNode<?,?> data;
-    @Mock
-    private DataTreeModification dataTreeModification;
 
     private WriteTransaction writeTx;
 
     @Before
     public void setUp() {
         initMocks(this);
-        when(configSnapshot.newModification()).thenReturn(dataTreeModification);
-        writeTx = new WriteTransaction(configDataTree, configSnapshot);
+        writeTx = WriteTransaction.createConfigOnly(configSnapshot);
     }
 
     @Test
     public void testPut() {
         writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data);
-        verify(dataTreeModification).write(path, data);
+        verify(configSnapshot).write(path, data);
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testPutOperational() {
         writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data);
-        verify(dataTreeModification).write(path, data);
+        verify(configSnapshot).write(path, data);
     }
 
     @Test(expected = IllegalStateException.class)
     public void testOnFinishedTx() {
         writeTx.submit();
         writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data);
-        verify(dataTreeModification).write(path, data);
+        verify(configSnapshot).write(path, data);
     }
 
     @Test
     public void testMerge() {
         writeTx.merge(LogicalDatastoreType.CONFIGURATION, path, data);
-        verify(dataTreeModification).merge(path, data);
+        verify(configSnapshot).merge(path, data);
     }
 
     @Test
@@ -100,19 +92,19 @@ public class WriteTransactionTest {
     @Test
     public void testDelete() {
         writeTx.delete(LogicalDatastoreType.CONFIGURATION, path);
-        verify(dataTreeModification).delete(path);
+        verify(configSnapshot).delete(path);
     }
 
     @Test
     public void testSubmit() throws Exception {
         writeTx.submit();
-        verify(dataTreeModification).ready();
-        verify(configDataTree).modify(dataTreeModification);
+        verify(configSnapshot).validate();
+        verify(configSnapshot).commit();
     }
 
     @Test
     public void testSubmitFailed() throws Exception {
-        doThrow(mock(DataValidationFailedException.class)).when(configDataTree).modify(dataTreeModification);
+        doThrow(mock(DataValidationFailedException.class)).when(configSnapshot).commit();
         final CheckedFuture<Void, TransactionCommitFailedException> future = writeTx.submit();
         try {
             future.get();
index c9f9902..13da9ec 100644 (file)
           </schema-service>
           <persist-file-path>etc/opendaylight/honeycomb/context.json</persist-file-path>
         </module>
+
+        <!-- DOM Data Broker for context data -->
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:v3po:impl">prefix:honeycomb-context-dom-data-broker</type>
+          <name>honeycomb-context-data-broker</name>
+          <!-- With persistence -->
+          <context-data-tree>
+            <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
+            <name>inmemory-persisted-context-data-tree</name>
+          </context-data-tree>
+        </module>
+
+        <!-- BA Data Broker for context data -->
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-forwarded-data-broker</type>
+          <name>honeycomb-context-binding-data-broker</name>
+          <binding-forwarded-data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+            <dom-async-broker>
+              <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+              <name>honeycomb-context-data-broker</name>
+            </dom-async-broker>
+            <schema-service>
+              <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+              <name>yang-schema-service</name>
+            </schema-service>
+            <binding-mapping-service>
+              <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+              <name>runtime-mapping-singleton</name>
+            </binding-mapping-service>
+          </binding-forwarded-data-broker>
+        </module>
       </modules>
+
+
       <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
         <service>
           <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
             </provider>
           </instance>
         </service>
+
+        <service>
+          <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+          <instance>
+            <name>honeycomb-context-data-broker</name>
+            <provider>/modules/module[type='honeycomb-context-dom-data-broker'][name='honeycomb-context-data-broker']</provider>
+          </instance>
+        </service>
+
+        <service>
+          <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+          <instance>
+            <name>honeycomb-context-binding-data-broker</name>
+            <provider>/modules/module[type='binding-forwarded-data-broker'][name='honeycomb-context-binding-data-broker']</provider>
+          </instance>
+        </service>
       </services>
     </data>
   </configuration>
index 89e1f7c..7106c78 100644 (file)
             <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry</type>
             <name>write-registry</name>
           </writer-registry>
+          <context-binding-broker>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+            <name>honeycomb-context-binding-data-broker</name>
+          </context-binding-broker>
         </module>
 
         <!-- FIXME workaround for: https://git.opendaylight.org/gerrit/#/c/37499/ Move to netconf-north-config-->
             <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
             <name>netconf-inmemory-data-broker</name>
           </netconf-monitoring-dom-data-broker>
+          <context-binding-broker>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+            <name>honeycomb-context-binding-data-broker</name>
+          </context-binding-broker>
         </module>
 
         <!-- DOM data broker which provides transaction functionality for HC using BI format-->
             <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry</type>
             <name>noop-writer-registry</name>
           </writer-registry>
+          <context-binding-broker>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+            <name>honeycomb-context-binding-data-broker</name>
+          </context-binding-broker>
         </module>
         <!-- DOM data broker for config initialization -->
         <module>
diff --git a/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModule.java b/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModule.java
new file mode 100644 (file)
index 0000000..1d1fa53
--- /dev/null
@@ -0,0 +1,26 @@
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+
+import io.fd.honeycomb.v3po.data.impl.DataBroker;
+import io.fd.honeycomb.v3po.data.impl.ModifiableDataTreeManager;
+
+public class ContextDataBrokerModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractContextDataBrokerModule {
+
+    public ContextDataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public ContextDataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.ContextDataBrokerModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        return DataBroker.create(new ModifiableDataTreeManager(getContextDataTreeDependency()));
+    }
+
+}
diff --git a/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModuleFactory.java b/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModuleFactory.java
new file mode 100644 (file)
index 0000000..360f5f4
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: v3po-impl yang module local name: honeycomb-context-dom-data-broker
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Mon May 16 15:27:12 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+public class ContextDataBrokerModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractContextDataBrokerModuleFactory {
+
+}
index 24e34c0..8aa3d64 100644 (file)
@@ -1,19 +1,6 @@
 package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
 
 import io.fd.honeycomb.v3po.data.impl.DataBroker;
-import java.util.Map;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
-import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,63 +29,6 @@ public class DataBrokerModule extends
     @Override
     public java.lang.AutoCloseable createInstance() {
         LOG.debug("DataBrokerModule.createInstance()");
-        return new CloseableDataBroker(
-                new DataBroker(getOperationalDataTreeDependency(), getConfigDataTreeDependency()));
-    }
-
-    private static final class CloseableDataBroker implements AutoCloseable, DOMDataBroker {
-
-        private final DataBroker delegate;
-
-        CloseableDataBroker(final DataBroker delegate) {
-            this.delegate = delegate;
-        }
-
-        @Override
-        public void close() throws Exception {
-            LOG.debug("CloseableDataBroker.close()");
-            // NOP
-        }
-
-        @Override
-        public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
-            LOG.trace("CloseableDataBroker.newReadOnlyTransaction()");
-            return delegate.newReadOnlyTransaction();
-        }
-
-        @Override
-        public DOMDataReadWriteTransaction newReadWriteTransaction() {
-            LOG.trace("CloseableDataBroker.newReadWriteTransaction()");
-            return delegate.newReadWriteTransaction();
-        }
-
-        @Override
-        public DOMDataWriteTransaction newWriteOnlyTransaction() {
-            LOG.trace("CloseableDataBroker.newWriteOnlyTransaction()");
-            return delegate.newWriteOnlyTransaction();
-        }
-
-        @Override
-        public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store,
-                                                                                      final YangInstanceIdentifier path,
-                                                                                      final DOMDataChangeListener listener,
-                                                                                      final DataChangeScope triggeringScope) {
-            LOG.trace("CloseableDataBroker.createTransactionChain store={}, path={}, listener={}, triggeringScope={}",
-                    store, path, listener, triggeringScope);
-            return delegate.registerDataChangeListener(store, path, listener, triggeringScope);
-        }
-
-        @Override
-        public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
-            LOG.trace("CloseableDataBroker.createTransactionChain listener={}", listener);
-            return delegate.createTransactionChain(listener);
-        }
-
-        @Nonnull
-        @Override
-        public Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> getSupportedExtensions() {
-            LOG.trace("CloseableDataBroker.getSupportedExtensions()");
-            return delegate.getSupportedExtensions();
-        }
+        return DataBroker.create(getConfigDataTreeDependency(), getOperationalDataTreeDependency());
     }
 }
index 30b70f3..3f7af61 100644 (file)
@@ -101,6 +101,28 @@ module v3po-impl {
         }
     }
 
+    identity honeycomb-context-dom-data-broker {
+        base config:module-type;
+        config:provided-service dom:dom-async-data-broker;
+        config:java-name-prefix ContextDataBroker;
+        description "DomBroker on top of context data-tree";
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case honeycomb-context-dom-data-broker {
+            when "/config:modules/config:module/config:type = 'honeycomb-context-dom-data-broker'";
+
+            container context-data-tree {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity dapi:data-tree;
+                    }
+                }
+            }
+        }
+    }
+
     identity netconf-monitoring-reader {
         base config:module-type;
         config:provided-service tapi:honeycomb-reader;
diff --git a/v3po/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java b/v3po/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java
new file mode 100644 (file)
index 0000000..cff766e
--- /dev/null
@@ -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();
+}
@@ -22,11 +22,11 @@ import java.util.HashMap;
 /**
  * Simple context class that provides transient storage during one or more read/write operations
  */
-public class Context implements AutoCloseable {
+public class ModificationCache implements AutoCloseable {
 
     protected final HashMap<Object, Object> map;
 
-    public Context() {
+    public ModificationCache() {
         map = Maps.newHashMap();
     }
 
diff --git a/v3po/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java b/v3po/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java
new file mode 100644 (file)
index 0000000..2c039ab
--- /dev/null
@@ -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();
+}
index 6b14735..e3ddd42 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.read;
 
-import io.fd.honeycomb.v3po.translate.Context;
-import javax.annotation.Nonnull;
+import io.fd.honeycomb.v3po.translate.ModificationContext;
 
 /**
- * Read Context
+ * Context providing information about current state of DataTree to readers
  */
-public interface ReadContext extends AutoCloseable {
+public interface ReadContext extends ModificationContext {
 
-    /**
-     * Get key value storage for customizers
-     *
-     * @return Context for customizers
-     */
-    @Nonnull
-    Context getContext();
-
-    @Override
-    void close();
 }
index bb0b331..3433b3f 100644 (file)
@@ -18,7 +18,7 @@ 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.Context;
+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;
@@ -27,34 +27,24 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  * Context providing information about current state of DataTree to writers
  */
 @Beta
-public interface WriteContext extends AutoCloseable {
+public interface WriteContext extends ModificationContext {
 
     /**
-     * Read any data object before current modification was applied
+     * 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
      */
-    Optional<DataObject> readBefore(@Nonnull final InstanceIdentifier<? extends DataObject> currentId);
+    <T extends DataObject> Optional<T> readBefore(@Nonnull final InstanceIdentifier<T> currentId);
 
     /**
-     * Read any data object from current modification
+     * Read any config data object from current modification
      *
      * @param currentId Id of an object to read
      *
      * @return Data from the modification
      */
-    Optional<DataObject> readAfter(@Nonnull final InstanceIdentifier<? extends DataObject> currentId);
+    <T extends DataObject> Optional<T> readAfter(@Nonnull final InstanceIdentifier<T> currentId);
 
-    /**
-     * Get key value storage for customizers
-     *
-     * @return Context for customizers
-     */
-    @Nonnull
-    Context getContext();
-
-    @Override
-    void close();
 }
index 1984cd8..89f9f56 100644 (file)
@@ -93,7 +93,7 @@ public final class CompositeChildReader<C extends DataObject, B extends Builder<
      */
     public CompositeChildReader(@Nonnull final Class<C> managedDataObjectType,
                                 @Nonnull final ChildReaderCustomizer<C, B> customizer) {
-        this(managedDataObjectType, RWUtils.<C>emptyChildReaderList(), RWUtils.<C>emptyAugReaderList(),
+        this(managedDataObjectType, RWUtils.emptyChildReaderList(), RWUtils.emptyAugReaderList(),
             customizer);
     }
 
@@ -112,7 +112,7 @@ public final class CompositeChildReader<C extends DataObject, B extends Builder<
     protected void readCurrentAttributes(@Nonnull final InstanceIdentifier<C> id, @Nonnull final B builder,
                                          @Nonnull final ReadContext ctx)
             throws ReadFailedException {
-        customizer.readCurrentAttributes(id, builder, ctx.getContext());
+        customizer.readCurrentAttributes(id, builder, ctx);
     }
 
     @Override
index 4c84c3a..7c438f6 100644 (file)
@@ -124,7 +124,7 @@ public final class CompositeListReader<C extends DataObject & Identifiable<K>, K
     public List<C> readList(@Nonnull final InstanceIdentifier<C> id,
                             @Nonnull final ReadContext ctx) throws ReadFailedException {
         LOG.trace("{}: Reading all list entries", this);
-        final List<K> allIds = customizer.getAllIds(id, ctx.getContext());
+        final List<K> allIds = customizer.getAllIds(id, ctx);
         LOG.debug("{}: Reading list entries for: {}", this, allIds);
 
         final ArrayList<C> allEntries = new ArrayList<>(allIds.size());
@@ -146,7 +146,7 @@ public final class CompositeListReader<C extends DataObject & Identifiable<K>, K
     protected void readCurrentAttributes(@Nonnull final InstanceIdentifier<C> id, @Nonnull final B builder,
                                          @Nonnull final ReadContext ctx)
             throws ReadFailedException {
-        customizer.readCurrentAttributes(id, builder, ctx.getContext());
+        customizer.readCurrentAttributes(id, builder, ctx);
     }
 
     @Override
index 0abae70..ea157aa 100644 (file)
@@ -99,7 +99,7 @@ public final class CompositeRootReader<C extends DataObject, B extends Builder<C
     @Override
     protected void readCurrentAttributes(@Nonnull final InstanceIdentifier<C> id, @Nonnull final B builder,
                                          @Nonnull final ReadContext ctx) throws ReadFailedException {
-        customizer.readCurrentAttributes(id, builder, ctx.getContext());
+        customizer.readCurrentAttributes(id, builder, ctx);
     }
 
     @Override
index 580910e..8b42a6c 100644 (file)
@@ -232,7 +232,7 @@ public abstract class AbstractCompositeWriter<D extends DataObject> implements W
             // If there's no dedicated writer, use write current
             // But we need current data after to do so
             final InstanceIdentifier<D> currentId = RWUtils.cutId(id, getManagedDataObjectType());
-            Optional<DataObject> currentDataAfter = ctx.readAfter(currentId);
+            Optional<D> currentDataAfter = ctx.readAfter(currentId);
             LOG.debug("{}: Dedicated subtree writer missing for: {}. Writing current.", this,
                 RWUtils.getNextId(id, getManagedDataObjectType()).getType(), currentDataAfter);
             writeCurrent(currentId, castToManaged(currentDataAfter.get()), ctx);
@@ -260,8 +260,8 @@ public abstract class AbstractCompositeWriter<D extends DataObject> implements W
     private void updateSubtreeFromCurrent(final InstanceIdentifier<? extends DataObject> id, final WriteContext ctx)
         throws WriteFailedException {
         final InstanceIdentifier<D> currentId = RWUtils.cutId(id, getManagedDataObjectType());
-        Optional<DataObject> currentDataBefore = ctx.readBefore(currentId);
-        Optional<DataObject> currentDataAfter = ctx.readAfter(currentId);
+        Optional<D> currentDataBefore = ctx.readBefore(currentId);
+        Optional<D> currentDataAfter = ctx.readAfter(currentId);
         LOG.debug("{}: Dedicated subtree writer missing for: {}. Updating current without subtree", this,
             RWUtils.getNextId(id, getManagedDataObjectType()).getType(), currentDataAfter);
         updateCurrent((InstanceIdentifier<D>) id, castToManaged(currentDataBefore.orNull()),
index 857743e..4a2e02c 100644 (file)
@@ -17,7 +17,7 @@
 package io.fd.honeycomb.v3po.translate.spi.read;
 
 import com.google.common.annotations.Beta;
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import java.util.List;
 import javax.annotation.Nonnull;
@@ -46,7 +46,7 @@ public interface ListReaderCustomizer<C extends DataObject & Identifiable<K>, K
      * @throws ReadFailedException if the list of IDs could not be read
      */
     @Nonnull
-    List<K> getAllIds(@Nonnull final InstanceIdentifier<C> id, @Nonnull final Context context) throws
+    List<K> getAllIds(@Nonnull final InstanceIdentifier<C> id, @Nonnull final ReadContext context) throws
             ReadFailedException;
     // TODO does it make sense with vpp APIs ? Should we replace it with a simple readAll ?
 
index da599eb..f0cb768 100644 (file)
@@ -17,8 +17,8 @@
 package io.fd.honeycomb.v3po.translate.spi.read;
 
 import com.google.common.annotations.Beta;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
-import io.fd.honeycomb.v3po.translate.Context;
 import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -45,8 +45,9 @@ public interface RootReaderCustomizer<C extends DataObject, B extends Builder<C>
      *
      * @param id      id of current data object
      * @param builder builder for creating read value
+     * @param ctx
      * @throws ReadFailedException if read was unsuccessful
      */
     void readCurrentAttributes(@Nonnull final InstanceIdentifier<C> id, @Nonnull final B builder,
-                               @Nonnull final Context ctx) throws ReadFailedException;
+                               @Nonnull final ReadContext ctx) throws ReadFailedException;
 }
index 3b703da..cf494ef 100644 (file)
@@ -16,7 +16,7 @@
 
 package io.fd.honeycomb.v3po.translate.util.read;
 
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer;
 import org.opendaylight.yangtools.concepts.Builder;
@@ -27,7 +27,7 @@ public abstract class NoopReaderCustomizer<C extends DataObject, B extends Build
     RootReaderCustomizer<C, B> {
 
     @Override
-    public void readCurrentAttributes(InstanceIdentifier<C> id, final B builder, final Context context) throws
+    public void readCurrentAttributes(InstanceIdentifier<C> id, final B builder, final ReadContext context) throws
         ReadFailedException {
         // Noop
     }
diff --git a/v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/TransactionMappingContext.java b/v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/TransactionMappingContext.java
new file mode 100644 (file)
index 0000000..60f4282
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.util.write;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Binding Transaction backed mapping context
+ */
+public class TransactionMappingContext implements MappingContext {
+
+    private final ReadWriteTransaction readWriteTransaction;
+
+    // TODO make async
+
+    public TransactionMappingContext(final ReadWriteTransaction readWriteTransaction) {
+        this.readWriteTransaction = readWriteTransaction;
+    }
+
+    @Override
+    public <T extends DataObject> Optional<T> read(@Nonnull final InstanceIdentifier<T> currentId) {
+        try {
+            return readWriteTransaction.read(LogicalDatastoreType.OPERATIONAL, currentId).checkedGet();
+        } catch (ReadFailedException e) {
+            throw new IllegalStateException("Unable to perform read", e);
+        }
+    }
+
+    @Override
+    public void delete(final InstanceIdentifier<?> path) {
+        readWriteTransaction.delete(LogicalDatastoreType.OPERATIONAL, path);
+    }
+
+    @Override
+    public <T extends DataObject> void merge(final InstanceIdentifier<T> path, T data) {
+        readWriteTransaction.merge(LogicalDatastoreType.OPERATIONAL, path, data, true);
+    }
+
+    @Override
+    public <T extends DataObject> void put(final InstanceIdentifier<T> path, T data) {
+        readWriteTransaction.put(LogicalDatastoreType.OPERATIONAL, path, data, true);
+    }
+
+    public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+        return readWriteTransaction.submit();
+    }
+
+    @Override
+    public void close() {
+        readWriteTransaction.cancel();
+    }
+}
index 37756d5..20bbf19 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.util.write;
 
+import static com.google.common.base.Preconditions.checkState;
+
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.write.WriteContext;
 import java.util.Map;
 import javax.annotation.Nonnull;
@@ -38,27 +41,37 @@ public final class TransactionWriteContext implements WriteContext {
 
     private final DOMDataReadOnlyTransaction beforeTx;
     private final DOMDataReadOnlyTransaction afterTx;
-    private final Context ctx;
+    private final ModificationCache ctx;
     private final BindingNormalizedNodeSerializer serializer;
+    private MappingContext mappingContext;
 
     public TransactionWriteContext(final BindingNormalizedNodeSerializer serializer,
                                    final DOMDataReadOnlyTransaction beforeTx,
-                                   final DOMDataReadOnlyTransaction afterTx) {
+                                   final DOMDataReadOnlyTransaction afterTx,
+                                   final MappingContext mappingContext) {
         this.serializer = serializer;
+        // TODO do we have a BA transaction adapter ? If so, use it here and don't pass serializer
         this.beforeTx = beforeTx;
         this.afterTx = afterTx;
-        this.ctx = new Context();
+        this.mappingContext = mappingContext;
+        this.ctx = new ModificationCache();
     }
 
     // TODO make this asynchronous
 
     @Override
-    public Optional<DataObject> readBefore(@Nonnull final InstanceIdentifier<? extends DataObject> currentId) {
+    public <T extends DataObject> Optional<T> readBefore(@Nonnull final InstanceIdentifier<T> currentId) {
         return read(currentId, beforeTx);
     }
 
-    private Optional<DataObject> read(final InstanceIdentifier<? extends DataObject> currentId,
-                                            final DOMDataReadOnlyTransaction tx) {
+    @Override
+    public <T extends DataObject> Optional<T> readAfter(@Nonnull final InstanceIdentifier<T> currentId) {
+        return read(currentId, afterTx);
+    }
+
+
+    private <T extends DataObject> Optional<T> read(final InstanceIdentifier<T> currentId,
+                                                    final DOMDataReadOnlyTransaction tx) {
         final YangInstanceIdentifier path = serializer.toYangInstanceIdentifier(currentId);
 
         final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read =
@@ -75,20 +88,25 @@ public final class TransactionWriteContext implements WriteContext {
             final NormalizedNode<?, ?> data = optional.get();
             final Map.Entry<InstanceIdentifier<?>, DataObject> entry = serializer.fromNormalizedNode(path, data);
 
-            return Optional.of(entry.getValue());
+            final Class<T> targetType = currentId.getTargetType();
+            checkState(targetType.isAssignableFrom(entry.getValue().getClass()),
+                "Unexpected data object type, should be: %s, but was: %s", targetType, entry.getValue().getClass());
+            return Optional.of(targetType.cast(entry.getValue()));
         } catch (ReadFailedException e) {
             throw new IllegalStateException("Unable to perform read", e);
         }
     }
 
+    @Nonnull
     @Override
-    public Optional<DataObject> readAfter(@Nonnull final InstanceIdentifier<? extends DataObject> currentId) {
-        return read(currentId, afterTx);
+    public ModificationCache getModificationCache() {
+        return ctx;
     }
 
+    @Nonnull
     @Override
-    public Context getContext() {
-        return ctx;
+    public MappingContext getMappingContext() {
+        return mappingContext;
     }
 
     /**
@@ -97,5 +115,7 @@ public final class TransactionWriteContext implements WriteContext {
     @Override
     public void close() {
         ctx.close();
+        beforeTx.close();
+        afterTx.close();
     }
 }
index 03dc0c2..8a3bfbd 100644 (file)
@@ -29,7 +29,8 @@ import static org.mockito.MockitoAnnotations.initMocks;
 
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.util.write.TransactionWriteContext;
 import java.util.Map;
 import org.junit.Before;
@@ -43,7 +44,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain;
 import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
-import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -62,13 +62,15 @@ public class TransactionWriteContextTest {
     private Optional<org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode<?, ?>> optional;
     @Mock
     private Map.Entry entry;
+    @Mock
+    private MappingContext contextBroker;
 
     private TransactionWriteContext transactionWriteContext;
 
     @Before
     public void setUp() {
         initMocks(this);
-        transactionWriteContext = new TransactionWriteContext(serializer, beforeTx, afterTx);
+        transactionWriteContext = new TransactionWriteContext(serializer, beforeTx, afterTx, contextBroker);
     }
 
     @Test
@@ -80,7 +82,7 @@ public class TransactionWriteContextTest {
         final InstanceIdentifier<BridgeDomain> instanceId =
                 InstanceIdentifier.create(Vpp.class).child(BridgeDomains.class).child(BridgeDomain.class);
 
-        final Optional<DataObject> dataObjects = transactionWriteContext.readBefore(instanceId);
+        final Optional<BridgeDomain> dataObjects = transactionWriteContext.readBefore(instanceId);
         assertNotNull(dataObjects);
         assertFalse(dataObjects.isPresent());
 
@@ -101,9 +103,9 @@ public class TransactionWriteContextTest {
                 BridgeDomains.QNAME).node(BridgeDomain.QNAME).build();
         when(serializer.toYangInstanceIdentifier(any(InstanceIdentifier.class))).thenReturn(yangId);
         when(serializer.fromNormalizedNode(eq(yangId), any(NormalizedNode.class))).thenReturn(entry);
-        when(entry.getValue()).thenReturn(mock(DataObject.class));
+        when(entry.getValue()).thenReturn(mock(BridgeDomain.class));
 
-        final Optional<DataObject> dataObjects = transactionWriteContext.readBefore(instanceId);
+        final Optional<BridgeDomain> dataObjects = transactionWriteContext.readBefore(instanceId);
         assertNotNull(dataObjects);
         assertTrue(dataObjects.isPresent());
 
@@ -127,12 +129,12 @@ public class TransactionWriteContextTest {
 
     @Test
     public void testGetContext() throws Exception {
-        assertNotNull(transactionWriteContext.getContext());
+        assertNotNull(transactionWriteContext.getModificationCache());
     }
 
     @Test
     public void testClose() throws Exception {
-        final Context context = transactionWriteContext.getContext();
+        final ModificationCache context = transactionWriteContext.getModificationCache();
         transactionWriteContext.close();
         // TODO verify context was closed
     }
index 02b0b7b..be45a29 100644 (file)
                     <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:util">prefix:naming-context-impl</type>
                     <name>interface-context</name>
                     <artificial-name-prefix>interface-</artificial-name-prefix>
-                    <context-data-tree>
-                        <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
-                        <name>inmemory-persisted-context-data-tree</name>
-                    </context-data-tree>
                 </module>
                 <module>
                     <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:util">prefix:naming-context-impl</type>
                     <name>bridge-domain-context</name>
                     <artificial-name-prefix>bridge-domain-</artificial-name-prefix>
-                    <context-data-tree>
-                        <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
-                        <name>inmemory-persisted-context-data-tree</name>
-                    </context-data-tree>
                 </module>
 
                 <module>
index e6ed62a..eb64262 100644 (file)
@@ -57,7 +57,7 @@ public class InterfaceCustomizer extends FutureJVppCustomizer implements ListWri
         throws WriteFailedException {
 
         try {
-            setInterface(id, dataAfter);
+            setInterface(id, dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             LOG.warn("Update of VppInterfaceAugment failed", e);
             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
@@ -72,7 +72,7 @@ public class InterfaceCustomizer extends FutureJVppCustomizer implements ListWri
         throws WriteFailedException.UpdateFailedException {
 
         try {
-            updateInterface(id, dataBefore, dataAfter);
+            updateInterface(id, dataBefore, dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             LOG.warn("Update of VppInterfaceAugment failed", e);
             throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
@@ -95,25 +95,25 @@ public class InterfaceCustomizer extends FutureJVppCustomizer implements ListWri
     }
 
 
-    private void setInterface(final InstanceIdentifier<Interface> id, final Interface swIf)
+    private void setInterface(final InstanceIdentifier<Interface> id, final Interface swIf,
+                              final WriteContext writeContext)
         throws VppApiInvocationException, WriteFailedException {
         LOG.debug("Setting interface: {} to: {}", id, swIf);
-        setInterfaceAttributes(swIf, swIf.getName());
+        setInterfaceAttributes(swIf, swIf.getName(), writeContext);
     }
 
-    private void setInterfaceAttributes(final Interface swIf, final String swIfName)
+    private void setInterfaceAttributes(final Interface swIf, final String swIfName, final WriteContext writeContext)
         throws VppApiInvocationException {
 
-        setInterfaceFlags(swIfName, interfaceContext.getIndex(swIfName),
+        setInterfaceFlags(swIfName, interfaceContext.getIndex(swIfName, writeContext.getMappingContext()),
             swIf.isEnabled() ? (byte) 1 : (byte) 0);
     }
 
     private void updateInterface(final InstanceIdentifier<Interface> id,
                                  final Interface dataBefore,
-                                 final Interface dataAfter) throws VppApiInvocationException {
+                                 final Interface dataAfter, final WriteContext writeContext) throws VppApiInvocationException {
         LOG.debug("Updating interface:{} to: {}", id, dataAfter);
-
-        setInterfaceAttributes(dataAfter, dataAfter.getName());
+        setInterfaceAttributes(dataAfter, dataAfter.getName(), writeContext);
     }
 
     private void setInterfaceFlags(final String swIfName, final int swIfIndex, final byte enabled)
index fc43cdb..5aea5de 100644 (file)
@@ -69,9 +69,9 @@ public class L2Customizer extends FutureJVppCustomizer implements ChildWriterCus
         throws WriteFailedException {
 
         final String ifcName = id.firstKeyOf(Interface.class).getName();
-        final int swIfc = interfaceContext.getIndex(ifcName);
+        final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
         try {
-            setL2(id, swIfc, ifcName, dataAfter);
+            setL2(id, swIfc, ifcName, dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             LOG.warn("Write of L2 failed", e);
             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
@@ -84,10 +84,10 @@ public class L2Customizer extends FutureJVppCustomizer implements ChildWriterCus
         throws WriteFailedException {
 
         final String ifcName = id.firstKeyOf(Interface.class).getName();
-        final int swIfc = interfaceContext.getIndex(ifcName);
+        final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
         // TODO handle update properly (if possible)
         try {
-            setL2(id, swIfc, ifcName, dataAfter);
+            setL2(id, swIfc, ifcName, dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             LOG.warn("Update of L2 failed", e);
             throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
@@ -100,21 +100,22 @@ public class L2Customizer extends FutureJVppCustomizer implements ChildWriterCus
         // TODO implement delete (if possible)
     }
 
-    private void setL2(final InstanceIdentifier<L2> id, final int swIfIndex, final String ifcName, final L2 vppL2)
+    private void setL2(final InstanceIdentifier<L2> id, final int swIfIndex, final String ifcName, final L2 vppL2,
+                       final WriteContext writeContext)
         throws VppApiInvocationException, WriteFailedException {
         LOG.debug("Setting L2 for interface: {}", ifcName);
         // Nothing besides interconnection here
-        setInterconnection(id, swIfIndex, ifcName, vppL2);
+        setInterconnection(id, swIfIndex, ifcName, vppL2, writeContext);
     }
 
     private void setInterconnection(final InstanceIdentifier<L2> id, final int swIfIndex, final String ifcName,
-                                    final L2 vppL2)
+                                    final L2 vppL2, final WriteContext writeContext)
         throws VppApiInvocationException, WriteFailedException {
         Interconnection ic = vppL2.getInterconnection();
         if (ic instanceof XconnectBased) {
-            setXconnectBasedL2(swIfIndex, ifcName, (XconnectBased) ic);
+            setXconnectBasedL2(swIfIndex, ifcName, (XconnectBased) ic, writeContext);
         } else if (ic instanceof BridgeBased) {
-            setBridgeBasedL2(swIfIndex, ifcName, (BridgeBased) ic);
+            setBridgeBasedL2(swIfIndex, ifcName, (BridgeBased) ic, writeContext);
         } else {
             // FIXME how does choice extensibility work
             // FIXME it is not even possible to create a dedicated customizer for Interconnection, since it's not a DataObject
@@ -125,7 +126,8 @@ public class L2Customizer extends FutureJVppCustomizer implements ChildWriterCus
         }
     }
 
-    private void setBridgeBasedL2(final int swIfIndex, final String ifcName, final BridgeBased bb)
+    private void setBridgeBasedL2(final int swIfIndex, final String ifcName, final BridgeBased bb,
+                                  final WriteContext writeContext)
         throws VppApiInvocationException {
 
         LOG.debug("Setting bridge based interconnection(bridge-domain={}) for interface: {}",
@@ -133,7 +135,7 @@ public class L2Customizer extends FutureJVppCustomizer implements ChildWriterCus
 
         String bdName = bb.getBridgeDomain();
 
-        int bdId = bridgeDomainContext.getIndex(bdName);
+        int bdId = bridgeDomainContext.getIndex(bdName, writeContext.getMappingContext());
         checkArgument(bdId > 0, "Unable to set Interconnection for Interface: %s, bridge domain: %s does not exist",
             ifcName, bdName);
 
@@ -168,14 +170,15 @@ public class L2Customizer extends FutureJVppCustomizer implements ChildWriterCus
         return swInterfaceSetL2Bridge;
     }
 
-    private void setXconnectBasedL2(final int swIfIndex, final String ifcName, final XconnectBased ic)
+    private void setXconnectBasedL2(final int swIfIndex, final String ifcName, final XconnectBased ic,
+                                    final WriteContext writeContext)
         throws VppApiInvocationException {
 
         String outSwIfName = ic.getXconnectOutgoingInterface();
         LOG.debug("Setting xconnect based interconnection(outgoing ifc={}) for interface: {}", outSwIfName,
             ifcName);
 
-        int outSwIfIndex = interfaceContext.getIndex(outSwIfName);
+        int outSwIfIndex = interfaceContext.getIndex(outSwIfName, writeContext.getMappingContext());
         checkArgument(outSwIfIndex > 0,
             "Unable to set Interconnection for Interface: %s, outgoing interface: %s does not exist",
             ifcName, outSwIfIndex);
index 4d17ba0..bf355e4 100644 (file)
@@ -60,7 +60,7 @@ public class RoutingCustomizer extends FutureJVppCustomizer implements ChildWrit
         throws WriteFailedException.CreateFailedException {
 
         try {
-            setRouting(id.firstKeyOf(Interface.class).getName(), dataAfter);
+            setRouting(id.firstKeyOf(Interface.class).getName(), dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             LOG.warn("Update of Routing failed", e);
             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
@@ -75,7 +75,7 @@ public class RoutingCustomizer extends FutureJVppCustomizer implements ChildWrit
 
         try {
             // TODO handle updates properly
-            setRouting(id.firstKeyOf(Interface.class).getName(), dataAfter);
+            setRouting(id.firstKeyOf(Interface.class).getName(), dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             LOG.warn("Update of Routing failed", e);
             throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
@@ -88,8 +88,8 @@ public class RoutingCustomizer extends FutureJVppCustomizer implements ChildWrit
         // TODO implement delete
     }
 
-    private void setRouting(final String name, final Routing rt) throws VppApiInvocationException {
-        final int swIfc = interfaceContext.getIndex(name);
+    private void setRouting(final String name, final Routing rt, final WriteContext writeContext) throws VppApiInvocationException {
+        final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext());
         LOG.debug("Setting routing for interface: {}, {}. Routing: {}", name, swIfc, rt);
 
         int vrfId = (rt != null)
index ecf2337..fb47b6a 100644 (file)
@@ -75,15 +75,16 @@ public class SubInterfaceCustomizer extends AbstractInterfaceTypeCustomizer<SubI
                                        @Nonnull final SubInterface dataAfter, @Nonnull final WriteContext writeContext)
             throws WriteFailedException.CreateFailedException {
         try {
-            createSubInterface(id.firstKeyOf(Interface.class).getName(), dataAfter);
+            createSubInterface(id.firstKeyOf(Interface.class).getName(), dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
         }
     }
 
-    private void createSubInterface(final String swIfName, final SubInterface subInterface) throws VppApiInvocationException {
+    private void createSubInterface(final String swIfName, final SubInterface subInterface,
+                                    final WriteContext writeContext) throws VppApiInvocationException {
         final String superIfName = subInterface.getSuperInterface();
-        final int swIfIndex = interfaceContext.getIndex(superIfName);
+        final int swIfIndex = interfaceContext.getIndex(superIfName, writeContext.getMappingContext());
         LOG.debug("Creating sub interface of {}(id={}): name={}, subInterface={}", superIfName, swIfIndex, swIfName, subInterface);
         final CompletionStage<CreateSubifReply> createSubifReplyCompletionStage =
                 getFutureJVpp().createSubif(getCreateSubifRequest(subInterface, swIfIndex));
@@ -96,7 +97,7 @@ public class SubInterfaceCustomizer extends AbstractInterfaceTypeCustomizer<SubI
         } else {
             LOG.debug("Sub interface created successfully for: {}, subInterface: {}", swIfName, subInterface);
             // Add new interface to our interface context
-            interfaceContext.addName(reply.swIfIndex, swIfName);
+            interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
         }
     }
 
index 72679fe..bafe788 100644 (file)
@@ -69,7 +69,7 @@ public class TapCustomizer extends AbstractInterfaceTypeCustomizer<Tap> {
                                        @Nonnull final WriteContext writeContext)
         throws WriteFailedException.CreateFailedException {
         try {
-            createTap(id.firstKeyOf(Interface.class).getName(), dataAfter);
+            createTap(id.firstKeyOf(Interface.class).getName(), dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             LOG.warn("Write of Tap failed", e);
             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
@@ -84,7 +84,7 @@ public class TapCustomizer extends AbstractInterfaceTypeCustomizer<Tap> {
 
         final int index;
         try {
-            index = interfaceContext.getIndex(ifcName);
+            index = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
         } catch (IllegalArgumentException e) {
             throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
         }
@@ -105,20 +105,20 @@ public class TapCustomizer extends AbstractInterfaceTypeCustomizer<Tap> {
 
         final int index;
         try {
-            index = interfaceContext.getIndex(ifcName);
+            index = interfaceContext.getIndex(ifcName, writeContext.getMappingContext());
         } catch (IllegalArgumentException e) {
             throw new WriteFailedException.DeleteFailedException(id, e);
         }
 
         try {
-            deleteTap(ifcName, index, dataBefore);
+            deleteTap(ifcName, index, dataBefore, writeContext);
         } catch (VppApiInvocationException e) {
             LOG.warn("Delete of Tap failed", e);
             throw new WriteFailedException.DeleteFailedException(id, e);
         }
     }
 
-    private void createTap(final String swIfName, final Tap tap) throws VppApiInvocationException {
+    private void createTap(final String swIfName, final Tap tap, final WriteContext writeContext) throws VppApiInvocationException {
         LOG.debug("Setting tap interface: {}. Tap: {}", swIfName, tap);
         final CompletionStage<TapConnectReply> tapConnectFuture =
             getFutureJVpp().tapConnect(getTapConnectRequest(tap.getTapName(), tap.getMac(), tap.getDeviceInstance()));
@@ -130,7 +130,7 @@ public class TapCustomizer extends AbstractInterfaceTypeCustomizer<Tap> {
         } else {
             LOG.debug("Tap set successfully for: {}, tap: {}", swIfName, tap);
             // Add new interface to our interface context
-            interfaceContext.addName(reply.swIfIndex, swIfName);
+            interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
         }
     }
 
@@ -148,7 +148,8 @@ public class TapCustomizer extends AbstractInterfaceTypeCustomizer<Tap> {
         }
     }
 
-    private void deleteTap(final String swIfName, final int index, final Tap dataBefore)
+    private void deleteTap(final String swIfName, final int index, final Tap dataBefore,
+                           final WriteContext writeContext)
         throws VppApiInvocationException {
         LOG.debug("Deleting tap interface: {}. Tap: {}", swIfName, dataBefore);
         final CompletionStage<TapDeleteReply> vxlanAddDelTunnelReplyCompletionStage =
@@ -161,7 +162,7 @@ public class TapCustomizer extends AbstractInterfaceTypeCustomizer<Tap> {
         } else {
             LOG.debug("Tap deleted successfully for: {}, tap: {}", swIfName, dataBefore);
             // Remove deleted interface from interface context
-            interfaceContext.removeName(swIfName);
+            interfaceContext.removeName(swIfName, writeContext.getMappingContext());
         }
     }
 
index ebefff3..5f7d626 100644 (file)
@@ -73,13 +73,13 @@ public class VhostUserCustomizer extends AbstractInterfaceTypeCustomizer<VhostUs
                                        @Nonnull final VhostUser dataAfter, @Nonnull final WriteContext writeContext)
             throws WriteFailedException.CreateFailedException {
         try {
-            createVhostUserIf(id.firstKeyOf(Interface.class).getName(), dataAfter);
+            createVhostUserIf(id.firstKeyOf(Interface.class).getName(), dataAfter, writeContext);
         } catch (VppApiInvocationException | IllegalInterfaceTypeException e) {
             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
         }
     }
 
-    private void createVhostUserIf(final String swIfName, final VhostUser vhostUser) throws VppApiInvocationException {
+    private void createVhostUserIf(final String swIfName, final VhostUser vhostUser, final WriteContext writeContext) throws VppApiInvocationException {
         LOG.debug("Creating vhost user interface: name={}, vhostUser={}", swIfName, vhostUser);
         final CompletionStage<CreateVhostUserIfReply> createVhostUserIfReplyCompletionStage =
                 getFutureJVpp().createVhostUserIf(getCreateVhostUserIfRequest(vhostUser));
@@ -92,7 +92,7 @@ public class VhostUserCustomizer extends AbstractInterfaceTypeCustomizer<VhostUs
         } else {
             LOG.debug("Vhost user interface created successfully for: {}, vhostUser: {}", swIfName, vhostUser);
             // Add new interface to our interface context
-            interfaceContext.addName(reply.swIfIndex, swIfName);
+            interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
         }
     }
 
@@ -118,17 +118,17 @@ public class VhostUserCustomizer extends AbstractInterfaceTypeCustomizer<VhostUs
         }
 
         try {
-            modifyVhostUserIf(id.firstKeyOf(Interface.class).getName(), dataAfter);
+            modifyVhostUserIf(id.firstKeyOf(Interface.class).getName(), dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
         }
     }
 
-    private void modifyVhostUserIf(final String swIfName, final VhostUser vhostUser) throws VppApiInvocationException {
+    private void modifyVhostUserIf(final String swIfName, final VhostUser vhostUser, final WriteContext writeContext) throws VppApiInvocationException {
         LOG.debug("Updating vhost user interface: name={}, vhostUser={}", swIfName, vhostUser);
         final CompletionStage<ModifyVhostUserIfReply> modifyVhostUserIfReplyCompletionStage =
                 getFutureJVpp()
-                        .modifyVhostUserIf(getModifyVhostUserIfRequest(vhostUser, interfaceContext.getIndex(swIfName)));
+                        .modifyVhostUserIf(getModifyVhostUserIfRequest(vhostUser, interfaceContext.getIndex(swIfName, writeContext.getMappingContext())));
 
         final ModifyVhostUserIfReply reply =
                 V3poUtils.getReply(modifyVhostUserIfReplyCompletionStage.toCompletableFuture());
@@ -155,16 +155,16 @@ public class VhostUserCustomizer extends AbstractInterfaceTypeCustomizer<VhostUs
                                         @Nonnull final VhostUser dataBefore, @Nonnull final WriteContext writeContext)
             throws WriteFailedException.DeleteFailedException {
         try {
-            deleteVhostUserIf(id.firstKeyOf(Interface.class).getName(), dataBefore);
+            deleteVhostUserIf(id.firstKeyOf(Interface.class).getName(), dataBefore, writeContext);
         } catch (VppApiInvocationException e) {
             throw new WriteFailedException.DeleteFailedException(id, e);
         }
     }
 
-    private void deleteVhostUserIf(final String swIfName, final VhostUser vhostUser) throws VppApiInvocationException {
+    private void deleteVhostUserIf(final String swIfName, final VhostUser vhostUser, final WriteContext writeContext) throws VppApiInvocationException {
         LOG.debug("Deleting vhost user interface: name={}, vhostUser={}", swIfName, vhostUser);
         final CompletionStage<DeleteVhostUserIfReply> deleteVhostUserIfReplyCompletionStage =
-                getFutureJVpp().deleteVhostUserIf(getDeleteVhostUserIfRequest(interfaceContext.getIndex(swIfName)));
+                getFutureJVpp().deleteVhostUserIf(getDeleteVhostUserIfRequest(interfaceContext.getIndex(swIfName, writeContext.getMappingContext())));
 
         final DeleteVhostUserIfReply reply =
                 V3poUtils.getReply(deleteVhostUserIfReplyCompletionStage.toCompletableFuture());
@@ -174,7 +174,7 @@ public class VhostUserCustomizer extends AbstractInterfaceTypeCustomizer<VhostUs
         } else {
             LOG.debug("Vhost user interface deleted successfully for: {}, vhostUser: {}", swIfName, vhostUser);
             // Remove interface from our interface context
-            interfaceContext.removeName(swIfName);
+            interfaceContext.removeName(swIfName, writeContext.getMappingContext());
         }
     }
 
index 7e7e319..d1e55a0 100644 (file)
@@ -70,14 +70,15 @@ public class VlanTagRewriteCustomizer extends FutureJVppCustomizer implements Ch
                                        @Nonnull final VlanTagRewrite dataAfter, @Nonnull final WriteContext writeContext)
             throws WriteFailedException.CreateFailedException {
         try {
-            setTagRewrite(id.firstKeyOf(Interface.class).getName(), dataAfter);
+            setTagRewrite(id.firstKeyOf(Interface.class).getName(), dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
         }
     }
 
-    private void setTagRewrite(final String ifname, final VlanTagRewrite cfg) throws VppApiInvocationException {
-        final int swIfIndex = interfaceContext.getIndex(ifname);
+    private void setTagRewrite(final String ifname, final VlanTagRewrite cfg, final WriteContext writeContext)
+        throws VppApiInvocationException {
+        final int swIfIndex = interfaceContext.getIndex(ifname, writeContext.getMappingContext());
         LOG.debug("Setting tag rewrite for interface {}(id=): {}", ifname, swIfIndex, cfg);
 
         final CompletionStage<L2InterfaceVlanTagRewriteReply> replyCompletionStage =
@@ -121,7 +122,7 @@ public class VlanTagRewriteCustomizer extends FutureJVppCustomizer implements Ch
             return;
         }
         try {
-            setTagRewrite(id.firstKeyOf(Interface.class).getName(), dataAfter);
+            setTagRewrite(id.firstKeyOf(Interface.class).getName(), dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
         }
@@ -135,7 +136,7 @@ public class VlanTagRewriteCustomizer extends FutureJVppCustomizer implements Ch
             // disable tag rewrite
             final VlanTagRewriteBuilder builder = new VlanTagRewriteBuilder();
             builder.setRewriteOperation(TagRewriteOperation.Disabled);
-            setTagRewrite(id.firstKeyOf(Interface.class).getName(), builder.build());
+            setTagRewrite(id.firstKeyOf(Interface.class).getName(), builder.build(), writeContext);
         } catch (VppApiInvocationException e) {
             throw new WriteFailedException.DeleteFailedException(id, e);
         }
index 9d11b59..3edd531 100644 (file)
@@ -71,7 +71,7 @@ public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer<Vxlan> {
                                        @Nonnull final WriteContext writeContext)
             throws WriteFailedException.CreateFailedException {
         try {
-            createVxlanTunnel(id.firstKeyOf(Interface.class).getName(), dataAfter);
+            createVxlanTunnel(id.firstKeyOf(Interface.class).getName(), dataAfter, writeContext);
         } catch (VppApiInvocationException | IllegalInterfaceTypeException e) {
             LOG.warn("Write of Vxlan failed", e);
             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
@@ -95,14 +95,14 @@ public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer<Vxlan> {
                                         @Nonnull final WriteContext writeContext)
             throws WriteFailedException.DeleteFailedException {
         try {
-            deleteVxlanTunnel(id.firstKeyOf(Interface.class).getName(), dataBefore);
+            deleteVxlanTunnel(id.firstKeyOf(Interface.class).getName(), dataBefore, writeContext);
         } catch (VppApiInvocationException e) {
             LOG.warn("Delete of Vxlan tunnel failed", e);
             throw new WriteFailedException.DeleteFailedException(id, e);
         }
     }
 
-    private void createVxlanTunnel(final String swIfName, final Vxlan vxlan) throws VppApiInvocationException {
+    private void createVxlanTunnel(final String swIfName, final Vxlan vxlan, final WriteContext writeContext) throws VppApiInvocationException {
         final byte isIpv6 = (byte) (isIpv6(vxlan) ? 1 : 0);
         final InetAddress srcAddress = InetAddresses.forString(getAddressString(vxlan.getSrc()));
         final InetAddress dstAddress = InetAddresses.forString(getAddressString(vxlan.getDst()));
@@ -123,7 +123,7 @@ public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer<Vxlan> {
         } else {
             LOG.debug("Vxlan tunnel set successfully for: {}, vxlan: {}", swIfName, vxlan);
             // Add new interface to our interface context
-            interfaceContext.addName(reply.swIfIndex, swIfName);
+            interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
         }
     }
 
@@ -143,7 +143,7 @@ public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer<Vxlan> {
         return addr.getIpv4Address() == null ? addr.getIpv6Address().getValue() : addr.getIpv4Address().getValue();
     }
 
-    private void deleteVxlanTunnel(final String swIfName, final Vxlan vxlan) throws VppApiInvocationException {
+    private void deleteVxlanTunnel(final String swIfName, final Vxlan vxlan, final WriteContext writeContext) throws VppApiInvocationException {
         final byte isIpv6 = (byte) (isIpv6(vxlan) ? 1 : 0);
         final InetAddress srcAddress = InetAddresses.forString(getAddressString(vxlan.getSrc()));
         final InetAddress dstAddress = InetAddresses.forString(getAddressString(vxlan.getDst()));
@@ -164,7 +164,7 @@ public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer<Vxlan> {
         } else {
             LOG.debug("Vxlan tunnel deleted successfully for: {}, vxlan: {}", swIfName, vxlan);
             // Remove interface from our interface context
-            interfaceContext.removeName(swIfName);
+            interfaceContext.removeName(swIfName, writeContext.getMappingContext());
         }
     }
 
index a54f6c5..4deb38f 100644 (file)
@@ -68,7 +68,7 @@ public class Ipv4Customizer extends FutureJVppCustomizer implements ChildWriterC
         throws WriteFailedException {
         try {
             final String ifcName = id.firstKeyOf(Interface.class).getName();
-            setIpv4(id, ifcName, dataAfter);
+            setIpv4(id, ifcName, dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             LOG.warn("Create of Ipv4 failed", e);
             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
@@ -84,7 +84,7 @@ public class Ipv4Customizer extends FutureJVppCustomizer implements ChildWriterC
 
         // TODO handle update in a better way
         try {
-            setIpv4(id, ifcName, dataAfter);
+            setIpv4(id, ifcName, dataAfter, writeContext);
         } catch (VppApiInvocationException e) {
             LOG.warn("Update of Ipv4 failed", e);
             throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
@@ -97,9 +97,10 @@ public class Ipv4Customizer extends FutureJVppCustomizer implements ChildWriterC
         // TODO implement delete
     }
 
-    private void setIpv4(final InstanceIdentifier<Ipv4> id, final String name, final Ipv4 ipv4)
+    private void setIpv4(final InstanceIdentifier<Ipv4> id, final String name, final Ipv4 ipv4,
+                         final WriteContext writeContext)
         throws WriteFailedException, VppApiInvocationException {
-        final int swIfc = interfaceContext.getIndex(name);
+        final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext());
 
         for (Address ipv4Addr : ipv4.getAddress()) {
             Subnet subnet = ipv4Addr.getSubnet();
index 74ea45c..8173b67 100644 (file)
@@ -16,7 +16,9 @@
 
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
-import io.fd.honeycomb.v3po.translate.Context;
+import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceCustomizer.getCachedInterfaceDump;
+
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
@@ -64,11 +66,11 @@ public class EthernetCustomizer extends FutureJVppCustomizer
     @Override
     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Ethernet> id,
                                       @Nonnull final EthernetBuilder builder,
-                                      @Nonnull final Context ctx) throws ReadFailedException {
+                                      @Nonnull final ReadContext ctx) throws ReadFailedException {
 
         final InterfaceKey key = id.firstKeyOf(Interface.class);
         final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), key,
-                interfaceContext.getIndex(key.getName()), ctx);
+                interfaceContext.getIndex(key.getName(), ctx.getMappingContext()), ctx.getModificationCache());
 
         builder.setMtu((int) iface.linkMtu);
         switch (iface.linkDuplex) {
index 51d4022..87c62f4 100644 (file)
@@ -16,7 +16,8 @@
 
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
@@ -69,13 +70,13 @@ public class InterfaceCustomizer extends FutureJVppCustomizer
 
     @Override
     public void readCurrentAttributes(@Nonnull InstanceIdentifier<Interface> id, @Nonnull InterfaceBuilder builder,
-                                      @Nonnull Context ctx) throws ReadFailedException {
+                                      @Nonnull ReadContext ctx) throws ReadFailedException {
         LOG.debug("Reading attributes for interface: {}", id);
         final InterfaceKey key = id.firstKeyOf(id.getTargetType());
 
         // Pass cached details from getAllIds to getDetails to avoid additional dumps
         final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), key,
-            interfaceContext.getIndex(key.getName()), ctx);
+            interfaceContext.getIndex(key.getName(), ctx.getMappingContext()), ctx.getModificationCache());
         LOG.debug("Interface details for interface: {}, details: {}", key.getName(), iface);
 
         builder.setName(key.getName());
@@ -94,7 +95,7 @@ public class InterfaceCustomizer extends FutureJVppCustomizer
 
     @Nonnull
     @SuppressWarnings("unchecked")
-    public static Map<Integer, SwInterfaceDetails> getCachedInterfaceDump(final @Nonnull Context ctx) {
+    public static Map<Integer, SwInterfaceDetails> getCachedInterfaceDump(final @Nonnull ModificationCache ctx) {
         return ctx.get(DUMPED_IFCS_CONTEXT_KEY) == null
             ? new HashMap<>() // allow customizers to update the cache
             : (Map<Integer, SwInterfaceDetails>) ctx.get(DUMPED_IFCS_CONTEXT_KEY);
@@ -103,7 +104,7 @@ public class InterfaceCustomizer extends FutureJVppCustomizer
     @Nonnull
     @Override
     public List<InterfaceKey> getAllIds(@Nonnull final InstanceIdentifier<Interface> id,
-                                        @Nonnull final Context context) throws ReadFailedException {
+                                        @Nonnull final ReadContext context) throws ReadFailedException {
         LOG.trace("Dumping all interfaces to get all IDs");
 
         final SwInterfaceDump request = new SwInterfaceDump();
@@ -120,20 +121,20 @@ public class InterfaceCustomizer extends FutureJVppCustomizer
         }
 
         // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes
-        context.put(DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream()
+        context.getModificationCache().put(DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream()
             .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails)));
 
         final List<InterfaceKey> interfacesKeys = ifaces.swInterfaceDetails.stream()
             .filter(elt -> elt != null)
             .map((elt) -> {
                 // Store interface name from VPP in context if not yet present
-                if (!interfaceContext.containsName(elt.swIfIndex)) {
-                    interfaceContext.addName(elt.swIfIndex, V3poUtils.toString(elt.interfaceName));
+                if (!interfaceContext.containsName(elt.swIfIndex, context.getMappingContext())) {
+                    interfaceContext.addName(elt.swIfIndex, V3poUtils.toString(elt.interfaceName), context.getMappingContext());
                 }
                 LOG.trace("Interface with name: {}, VPP name: {} and index: {} found in VPP",
-                    interfaceContext.getName(elt.swIfIndex), elt.interfaceName, elt.swIfIndex);
+                    interfaceContext.getName(elt.swIfIndex, context.getMappingContext()), elt.interfaceName, elt.swIfIndex);
 
-                return new InterfaceKey(interfaceContext.getName(elt.swIfIndex));
+                return new InterfaceKey(interfaceContext.getName(elt.swIfIndex, context.getMappingContext()));
             })
             .collect(Collectors.toList());
 
index a6c8873..ee66aef 100644 (file)
@@ -21,7 +21,7 @@ import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceCusto
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.v3po.utils.V3poUtils;
 import java.math.BigInteger;
 import java.util.Map;
@@ -158,7 +158,7 @@ public final class InterfaceUtils {
     @Nonnull
     public static SwInterfaceDetails getVppInterfaceDetails(@Nonnull final FutureJVpp futureJvpp,
                                                             @Nonnull InterfaceKey key, final int index,
-                                                            @Nonnull final Context ctx) {
+                                                            @Nonnull final ModificationCache ctx) {
         final SwInterfaceDump request = new SwInterfaceDump();
         request.nameFilter = key.getName().getBytes();
         request.nameFilterValid = 1;
@@ -225,7 +225,7 @@ public final class InterfaceUtils {
         return EthernetCsmacd.class;
     }
 
-    static boolean isInterfaceOfType(final Context ctx, final int index,
+    static boolean isInterfaceOfType(final ModificationCache ctx, final int index,
                                      final Class<? extends InterfaceType> ifcType) {
         final SwInterfaceDetails cachedDetails =
                 checkNotNull(getCachedInterfaceDump(ctx).get(index),
index 099d4c1..1bc9c2b 100644 (file)
@@ -17,7 +17,7 @@
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
 import com.google.common.base.Preconditions;
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
@@ -74,20 +74,20 @@ public class L2Customizer extends FutureJVppCustomizer
 
     @Override
     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2Builder builder,
-                                      @Nonnull final Context ctx) throws ReadFailedException {
+                                      @Nonnull final ReadContext ctx) throws ReadFailedException {
         LOG.debug("Reading attributes for L2: {}", id);
         final InterfaceKey key = id.firstKeyOf(Interface.class);
-        final int ifaceId = interfaceContext.getIndex(key.getName());
+        final int ifaceId = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
 
         final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), key,
-                ifaceId, ctx);
+                ifaceId, ctx.getModificationCache());
         LOG.debug("Interface details for interface: {}, details: {}", key.getName(), iface);
 
         final Optional<BridgeDomainSwIfDetails> bdForInterface = getBridgeDomainForInterface(ifaceId);
         if (bdForInterface.isPresent()) {
             final BridgeDomainSwIfDetails bdSwIfDetails = bdForInterface.get();
             final BridgeBasedBuilder bbBuilder = new BridgeBasedBuilder();
-            bbBuilder.setBridgeDomain(bridgeDomainContext.getName(bdSwIfDetails.bdId));
+            bbBuilder.setBridgeDomain(bridgeDomainContext.getName(bdSwIfDetails.bdId, ctx.getMappingContext()));
             // bbBuilder.setBridgedVirtualInterface // TODO where to find that value?
             if (bdSwIfDetails.shg != 0) {
                 bbBuilder.setSplitHorizonGroup((short)bdSwIfDetails.shg);
index b68acbf..ebd1cff 100644 (file)
@@ -19,7 +19,7 @@ package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType;
 
 import com.google.common.base.Preconditions;
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
@@ -70,18 +70,18 @@ public class SubInterfaceCustomizer extends FutureJVppCustomizer
 
     @Override
     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<SubInterface> id,
-                                      @Nonnull final SubInterfaceBuilder builder, @Nonnull final Context ctx)
+                                      @Nonnull final SubInterfaceBuilder builder, @Nonnull final ReadContext ctx)
             throws ReadFailedException {
         final InterfaceKey key = id.firstKeyOf(Interface.class);
         // Relying here that parent InterfaceCustomizer was invoked first (PREORDER)
         // to fill in the context with initial ifc mapping
-        final int index = interfaceContext.getIndex(key.getName());
-        if (!isInterfaceOfType(ctx, index, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.SubInterface.class)) {
+        final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+        if (!isInterfaceOfType(ctx.getModificationCache(), index, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.SubInterface.class)) {
             return;
         }
 
         LOG.debug("Reading attributes for sub interface: {}", id);
-        final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), key, index, ctx);
+        final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), key, index, ctx.getModificationCache());
         LOG.debug("VPP interface details: {}", ReflectionToStringBuilder.toString(iface));
 
         if (iface.subId == 0) {
@@ -90,7 +90,7 @@ public class SubInterfaceCustomizer extends FutureJVppCustomizer
         }
 
         builder.setIdentifier(Long.valueOf(iface.subId));
-        builder.setSuperInterface(interfaceContext.getName(iface.supSwIfIndex));
+        builder.setSuperInterface(interfaceContext.getName(iface.supSwIfIndex, ctx.getMappingContext()));
         builder.setNumberOfTags(Short.valueOf(iface.subNumberOfTags));
         builder.setVlanType(iface.subDot1Ad == 1 ? VlanType._802dot1q : VlanType._802dot1ad);
         if (iface.subExactMatch == 1) {
index e7cd560..358e914 100644 (file)
@@ -18,7 +18,7 @@ package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
 import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType;
 
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
@@ -72,12 +72,12 @@ public class TapCustomizer extends FutureJVppCustomizer
     @Override
     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Tap> id,
                                       @Nonnull final TapBuilder builder,
-                                      @Nonnull final Context ctx) throws ReadFailedException {
+                                      @Nonnull final ReadContext ctx) throws ReadFailedException {
         final InterfaceKey key = id.firstKeyOf(Interface.class);
         // Relying here that parent InterfaceCustomizer was invoked first (PREORDER)
         // to fill in the context with initial ifc mapping
-        final int index = interfaceContext.getIndex(key.getName());
-        if (!isInterfaceOfType(ctx, index, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap.class)) {
+        final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+        if (!isInterfaceOfType(ctx.getModificationCache(), index, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap.class)) {
             return;
         }
 
@@ -85,7 +85,7 @@ public class TapCustomizer extends FutureJVppCustomizer
 
         @SuppressWarnings("unchecked")
         Map<Integer, SwInterfaceTapDetails> mappedTaps =
-            (Map<Integer, SwInterfaceTapDetails>) ctx.get(DUMPED_TAPS_CONTEXT_KEY);
+            (Map<Integer, SwInterfaceTapDetails>) ctx.getModificationCache().get(DUMPED_TAPS_CONTEXT_KEY);
 
         if(mappedTaps == null) {
             // Full Tap dump has to be performed here, no filter or anything is here to help so at least we cache it
@@ -104,7 +104,7 @@ public class TapCustomizer extends FutureJVppCustomizer
                     .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails));
             }
 
-            ctx.put(DUMPED_TAPS_CONTEXT_KEY, mappedTaps);
+            ctx.getModificationCache().put(DUMPED_TAPS_CONTEXT_KEY, mappedTaps);
         }
 
         final SwInterfaceTapDetails swInterfaceTapDetails = mappedTaps.get(index);
index 70a6da1..d5ae8fa 100644 (file)
@@ -18,7 +18,7 @@ package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
 import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType;
 
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
@@ -74,12 +74,12 @@ public class VhostUserCustomizer extends FutureJVppCustomizer
     @Override
     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VhostUser> id,
                                       @Nonnull final VhostUserBuilder builder,
-                                      @Nonnull final Context ctx) throws ReadFailedException {
+                                      @Nonnull final ReadContext ctx) throws ReadFailedException {
         final InterfaceKey key = id.firstKeyOf(Interface.class);
         // Relying here that parent InterfaceCustomizer was invoked first (PREORDER)
         // to fill in the context with initial ifc mapping
-        final int index = interfaceContext.getIndex(key.getName());
-        if (!isInterfaceOfType(ctx, index, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class)) {
+        final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+        if (!isInterfaceOfType(ctx.getModificationCache(), index, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class)) {
             return;
         }
 
@@ -87,7 +87,7 @@ public class VhostUserCustomizer extends FutureJVppCustomizer
 
         @SuppressWarnings("unchecked")
         Map<Integer, SwInterfaceVhostUserDetails> mappedVhostUsers =
-            (Map<Integer, SwInterfaceVhostUserDetails>) ctx.get(DUMPED_VHOST_USERS_CONTEXT_KEY);
+            (Map<Integer, SwInterfaceVhostUserDetails>) ctx.getModificationCache().get(DUMPED_VHOST_USERS_CONTEXT_KEY);
 
         if(mappedVhostUsers == null) {
             // Full VhostUser dump has to be performed here, no filter or anything is here to help so at least we cache it
@@ -106,7 +106,7 @@ public class VhostUserCustomizer extends FutureJVppCustomizer
                     .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails));
             }
 
-            ctx.put(DUMPED_VHOST_USERS_CONTEXT_KEY, mappedVhostUsers);
+            ctx.getModificationCache().put(DUMPED_VHOST_USERS_CONTEXT_KEY, mappedVhostUsers);
         }
 
         // Relying here that parent InterfaceCustomizer was invoked first to fill in the context with initial ifc mapping
index d7404e6..d05e089 100644 (file)
@@ -17,7 +17,7 @@
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
 import com.google.common.base.Preconditions;
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
@@ -68,13 +68,13 @@ public class VlanTagRewriteCustomizer extends FutureJVppCustomizer
 
     @Override
     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<VlanTagRewrite> id,
-                                      @Nonnull final VlanTagRewriteBuilder builder, @Nonnull final Context ctx)
+                                      @Nonnull final VlanTagRewriteBuilder builder, @Nonnull final ReadContext ctx)
             throws ReadFailedException {
         LOG.debug("Reading attributes for sub interface: {}", id);
         final InterfaceKey key = id.firstKeyOf(Interface.class);
 
         final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), key,
-                interfaceContext.getIndex(key.getName()), ctx);
+                interfaceContext.getIndex(key.getName(), ctx.getMappingContext()), ctx.getModificationCache());
 
         builder.setFirstPushed(iface.subDot1Ad == 1 ? VlanType._802dot1q : VlanType._802dot1ad);
         builder.setRewriteOperation(TagRewriteOperation.forValue(iface.vtrOp));
index 8294160..81ba340 100644 (file)
@@ -18,7 +18,7 @@ package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
 import static com.google.common.base.Preconditions.checkState;
 
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
@@ -74,12 +74,12 @@ public class VxlanCustomizer extends FutureJVppCustomizer
     @Override
     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Vxlan> id,
                                       @Nonnull final VxlanBuilder builder,
-                                      @Nonnull final Context ctx) throws ReadFailedException {
+                                      @Nonnull final ReadContext ctx) throws ReadFailedException {
         final InterfaceKey key = id.firstKeyOf(Interface.class);
         // Relying here that parent InterfaceCustomizer was invoked first (PREORDER)
         // to fill in the context with initial ifc mapping
-        final int index = interfaceContext.getIndex(key.getName());
-        if (!InterfaceUtils.isInterfaceOfType(ctx, index, VxlanTunnel.class)) {
+        final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
+        if (!InterfaceUtils.isInterfaceOfType(ctx.getModificationCache(), index, VxlanTunnel.class)) {
             return;
         }
 
index 672a05f..6e94461 100644 (file)
@@ -96,11 +96,11 @@ public class BridgeDomainCustomizer
             // FIXME we need the bd index to be returned by VPP or we should have a counter field (maybe in context similar to artificial name)
             // Here we assign the next available ID from bdContext's perspective
             int index = 1;
-            while(bdContext.containsName(index)) {
+            while(bdContext.containsName(index, ctx.getMappingContext())) {
                 index++;
             }
             addOrUpdateBridgeDomain(index, dataBefore);
-            bdContext.addName(index, bdName);
+            bdContext.addName(index, bdName, ctx.getMappingContext());
         } catch (VppApiInvocationException e) {
             LOG.warn("Failed to create bridge domain", e);
             throw new WriteFailedException.CreateFailedException(id, dataBefore, e);
@@ -120,7 +120,7 @@ public class BridgeDomainCustomizer
         LOG.debug("deleteCurrentAttributes: id={}, dataBefore={}, ctx={}", id, dataBefore, ctx);
 
         final String bdName = id.firstKeyOf(BridgeDomain.class).getName();
-        int bdId = bdContext.getIndex(bdName);
+        int bdId = bdContext.getIndex(bdName, ctx.getMappingContext());
         final BridgeDomainAddDel request = new BridgeDomainAddDel();
         request.bdId = bdId;
 
@@ -154,7 +154,7 @@ public class BridgeDomainCustomizer
                 "BridgeDomain name changed. It should be deleted and then created.");
 
         try {
-            addOrUpdateBridgeDomain(bdContext.getIndex(bdName), dataAfter);
+            addOrUpdateBridgeDomain(bdContext.getIndex(bdName, ctx.getMappingContext()), dataAfter);
         } catch (VppApiInvocationException e) {
             LOG.warn("Failed to create bridge domain", e);
             throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
index 1a3855c..ac16c61 100644 (file)
@@ -20,7 +20,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.primitives.Longs;
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
@@ -70,7 +70,7 @@ public final class BridgeDomainCustomizer extends FutureJVppCustomizer
 
     @Override
     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<BridgeDomain> id,
-                                      @Nonnull final BridgeDomainBuilder builder, @Nonnull final Context context)
+                                      @Nonnull final BridgeDomainBuilder builder, @Nonnull final ReadContext context)
             throws ReadFailedException {
         LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: id={}, builderbuilder={}, context={}",
                 id, builder, context);
@@ -78,13 +78,13 @@ public final class BridgeDomainCustomizer extends FutureJVppCustomizer
         final BridgeDomainKey key = id.firstKeyOf(id.getTargetType());
         LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: key={}", key);
 
-        final int bdId = bdContext.getIndex(key.getName());
+        final int bdId = bdContext.getIndex(key.getName(), context.getMappingContext());
         LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: bdId={}", bdId);
 
         BridgeDomainDetailsReplyDump reply;
         BridgeDomainDetails bridgeDomainDetails;
         final BridgeDomainDump request = new BridgeDomainDump();
-        request.bdId = bdContext.getIndex(key.getName());
+        request.bdId = bdContext.getIndex(key.getName(), context.getMappingContext());
         try {
             reply = getFutureJVpp().bridgeDomainDump(request).toCompletableFuture().get();
             bridgeDomainDetails = Iterables.getOnlyElement(reply.bridgeDomainDetails);
@@ -102,7 +102,7 @@ public final class BridgeDomainCustomizer extends FutureJVppCustomizer
         builder.setLearn(byteToBoolean(bridgeDomainDetails.learn));
         builder.setUnknownUnicastFlood(byteToBoolean(bridgeDomainDetails.uuFlood));
 
-        builder.setInterface(getIfcs(bridgeDomainDetails, reply.bridgeDomainSwIfDetails));
+        builder.setInterface(getIfcs(bridgeDomainDetails, reply.bridgeDomainSwIfDetails, context));
 
         final L2FibTableDump l2FibRequest = new L2FibTableDump();
         l2FibRequest.bdId = bdId;
@@ -124,7 +124,7 @@ public final class BridgeDomainCustomizer extends FutureJVppCustomizer
                             ? L2Fib.Action.Filter
                             : L2Fib.Action.Forward))
                         .setBridgedVirtualInterface(byteToBoolean(entry.bviMac))
-                        .setOutgoingInterface(interfaceContext.getName(entry.swIfIndex))
+                        .setOutgoingInterface(interfaceContext.getName(entry.swIfIndex, context.getMappingContext()))
                         .setStaticConfig(byteToBoolean(entry.staticMac))
                         .setPhysAddress(address)
                         .setKey(new L2FibKey(address))
@@ -175,10 +175,11 @@ public final class BridgeDomainCustomizer extends FutureJVppCustomizer
     }
 
     private List<Interface> getIfcs(final BridgeDomainDetails bridgeDomainDetails,
-                                    final List<BridgeDomainSwIfDetails> bridgeDomainSwIfDetails) {
+                                    final List<BridgeDomainSwIfDetails> bridgeDomainSwIfDetails,
+                                    final ReadContext context) {
         final List<Interface> ifcs = new ArrayList<>(bridgeDomainSwIfDetails.size());
         for (BridgeDomainSwIfDetails anInterface : bridgeDomainSwIfDetails) {
-            final String interfaceName = interfaceContext.getName(anInterface.swIfIndex);
+            final String interfaceName = interfaceContext.getName(anInterface.swIfIndex, context.getMappingContext());
             if (anInterface.bdId == bridgeDomainDetails.bdId) {
                 ifcs.add(new InterfaceBuilder()
                         .setBridgedVirtualInterface(bridgeDomainDetails.bviSwIfIndex == anInterface.swIfIndex)
@@ -202,7 +203,7 @@ public final class BridgeDomainCustomizer extends FutureJVppCustomizer
     @Nonnull
     @Override
     public List<BridgeDomainKey> getAllIds(@Nonnull final InstanceIdentifier<BridgeDomain> id,
-                                           @Nonnull final Context context) {
+                                           @Nonnull final ReadContext context) {
         final BridgeDomainDump request = new BridgeDomainDump();
         request.bdId = -1; // dump call
 
@@ -228,7 +229,7 @@ public final class BridgeDomainCustomizer extends FutureJVppCustomizer
         for (BridgeDomainDetails detail : reply.bridgeDomainDetails) {
             logBridgeDomainDetails(detail);
 
-            final String bName = bdContext.getName(detail.bdId);
+            final String bName = bdContext.getName(detail.bdId, context.getMappingContext());
             LOG.debug("vppstate.BridgeDomainCustomizer.getAllIds: bName={}", bName);
             allIds.add(new BridgeDomainKey(bName));
         }
index 1db8217..4ad4a6e 100644 (file)
@@ -16,7 +16,7 @@
 
 package io.fd.honeycomb.v3po.translate.v3po.vppstate;
 
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
@@ -53,7 +53,7 @@ public final class VersionCustomizer
 
     @Override
     public void readCurrentAttributes(@Nonnull InstanceIdentifier<Version> id, @Nonnull final VersionBuilder builder,
-                                      @Nonnull final Context context) throws ReadFailedException {
+                                      @Nonnull final ReadContext context) throws ReadFailedException {
 
         ShowVersionReply reply;
         try {
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/ContextTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/ContextTestUtils.java
new file mode 100644 (file)
index 0000000..5c731bc
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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.v3po;
+
+import com.google.common.base.Optional;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContextKey;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+public class ContextTestUtils {
+
+    public static Optional<Mapping> getMapping(final String name, final int index) {
+        return Optional.of(new MappingBuilder().setName(name).setIndex(index).build());
+    }
+
+    public static KeyedInstanceIdentifier<Mapping, MappingKey> getMappingIid(final String name, final String namingContextName) {
+        return InstanceIdentifier.create(Contexts.class).child(
+                org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.class,
+                new NamingContextKey(namingContextName)).child(Mappings.class).child(Mapping.class, new MappingKey(name));
+    }
+}
index ff96131..fbb47b5 100644 (file)
@@ -19,21 +19,29 @@ package io.fd.honeycomb.v3po.translate.v3po.interfaces;
 import static org.mockito.Mockito.doReturn;
 
 import com.google.common.base.Optional;
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.write.WriteContext;
 import org.mockito.Matchers;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContextKey;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 
 final class InterfaceTypeTestUtils {
 
     private InterfaceTypeTestUtils() {}
 
     static void setupWriteContext(final WriteContext writeContext, final Class<? extends InterfaceType> ifcType) {
-        doReturn(new Context()).when(writeContext).getContext();
+        doReturn(new ModificationCache()).when(writeContext).getModificationCache();
         doReturn(Optional.of(new InterfaceBuilder()
             .setType(ifcType)
             .build())).when(writeContext).readAfter(Matchers.any(InstanceIdentifier.class));
     }
+
 }
index d706546..31ab3aa 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.interfaces;
 
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.MockitoAnnotations.initMocks;
 
+import io.fd.honeycomb.v3po.translate.MappingContext;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.v3po.translate.v3po.util.VppApiInvocationException;
 import io.fd.honeycomb.v3po.translate.write.WriteContext;
@@ -54,6 +57,8 @@ public class SubInterfaceCustomizerTest {
     private FutureJVpp api;
     @Mock
     private WriteContext writeContext;
+    @Mock
+    private MappingContext mappingContext;
 
     private NamingContext namingContext;
     private SubInterfaceCustomizer customizer;
@@ -65,10 +70,11 @@ public class SubInterfaceCustomizerTest {
         initMocks(this);
         InterfaceTypeTestUtils.setupWriteContext(writeContext,
                 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.SubInterface.class);
-        namingContext = new NamingContext("generatedSubInterfaceName");
+        namingContext = new NamingContext("generatedSubInterfaceName", "test-instance");
+        doReturn(mappingContext).when(writeContext).getMappingContext();
         // TODO create base class for tests using vppApi
         customizer = new SubInterfaceCustomizer(api, namingContext);
-        namingContext.addName(SUPER_IF_ID, SUPER_IF_NAME);
+        doReturn(getMapping(SUPER_IF_NAME, SUPER_IF_ID)).when(mappingContext).read(getMappingIid(SUPER_IF_NAME, "test-instance"));
     }
 
     private SubInterface generateSubInterface(final String superIfName) {
@@ -145,7 +151,7 @@ public class SubInterfaceCustomizerTest {
         customizer.writeCurrentAttributes(id, subInterface, writeContext);
 
         verifyCreateSubifWasInvoked(generateSubInterfaceRequest(SUPER_IF_ID));
-        assertTrue(namingContext.containsIndex(subIfaceName));
+        verify(mappingContext).put(eq(getMappingIid(subIfaceName, "test-instance")), eq(getMapping(subIfaceName, 0).get()));
     }
 
     @Test
@@ -161,7 +167,9 @@ public class SubInterfaceCustomizerTest {
         } catch (WriteFailedException.CreateFailedException e) {
             assertEquals(VppApiInvocationException.class, e.getCause().getClass());
             verifyCreateSubifWasInvoked(generateSubInterfaceRequest(SUPER_IF_ID));
-            assertFalse(namingContext.containsIndex(subIfaceName));
+            verify(mappingContext, times(0)).put(
+                eq(getMappingIid(subIfaceName, "test-instance")),
+                eq(getMapping(subIfaceName, 0).get()));
             return;
         }
         fail("WriteFailedException.CreateFailedException was expected");
index 8ae04f0..e717ec5 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.interfaces;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.v3po.translate.write.WriteContext;
 import java.util.concurrent.CompletableFuture;
@@ -55,8 +58,9 @@ public class TapCustomizerTest {
     private FutureJVpp vppApi;
     @Mock
     private WriteContext writeContext;
+    @Mock
+    private MappingContext mappingContext;
 
-    private NamingContext ctx;
     private TapCustomizer tapCustomizer;
 
     @Before
@@ -64,7 +68,11 @@ public class TapCustomizerTest {
         MockitoAnnotations.initMocks(this);
         InterfaceTypeTestUtils.setupWriteContext(writeContext,
             org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap.class);
-        ctx = new NamingContext("ifcintest");
+        final NamingContext ctx = new NamingContext("ifcintest", "test-instance");
+        final ModificationCache toBeReturned = new ModificationCache();
+        doReturn(toBeReturned).when(writeContext).getModificationCache();
+        doReturn(mappingContext).when(writeContext).getMappingContext();
+
         tapCustomizer = new TapCustomizer(vppApi, ctx);
     }
 
@@ -89,8 +97,8 @@ public class TapCustomizerTest {
         tapCustomizer.writeCurrentAttributes(getTapId("tap2"), getTapData("tap2", "ff:ff:ff:ff:ff:ff"), writeContext);
 
         verify(vppApi, times(2)).tapConnect(any(TapConnect.class));
-        assertTrue(ctx.containsIndex("tap"));
-        assertTrue(ctx.containsIndex("tap2"));
+        verify(mappingContext).put(eq(getMappingIid("tap", "test-instance")), eq(getMapping("tap", 0).get()));
+        verify(mappingContext).put(eq(getMappingIid("tap2", "test-instance")), eq(getMapping("tap2", 1).get()));
     }
 
     @Test
@@ -109,12 +117,13 @@ public class TapCustomizerTest {
         doReturn(replyModif).when(vppApi).tapModify(any(TapModify.class));
 
         tapCustomizer.writeCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), writeContext);
+        doReturn(getMapping("tap", 1)).when(mappingContext).read(getMappingIid("tap", "test-instance"));
         tapCustomizer.updateCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), getTapData("tap", "ff:ff:ff:ff:ff:f1"), writeContext);
 
         verify(vppApi).tapConnect(any(TapConnect.class));
         verify(vppApi).tapModify(any(TapModify.class));
-        assertTrue(ctx.containsIndex("tap"));
-        assertFalse(ctx.containsIndex("tap2"));
+
+        verify(mappingContext).put(eq(getMappingIid("tap", "test-instance")), eq(getMapping("tap", 0).get()));
     }
 
     @Test
@@ -132,11 +141,12 @@ public class TapCustomizerTest {
         doReturn(replyDelete).when(vppApi).tapDelete(any(TapDelete.class));
 
         tapCustomizer.writeCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), writeContext);
+        doReturn(getMapping("tap", 1)).when(mappingContext).read(getMappingIid("tap", "test-instance"));
         tapCustomizer.deleteCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), writeContext);
 
         verify(vppApi).tapConnect(any(TapConnect.class));
         verify(vppApi).tapDelete(any(TapDelete.class));
-        assertFalse(ctx.containsIndex("tap"));
+        verify(mappingContext).delete(eq(getMappingIid("tap", "test-instance")));
     }
 
     private InstanceIdentifier<Tap> getTapId(final String tap) {
index 15b2a75..1015f24 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.interfaces;
 
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.v3po.translate.v3po.util.VppApiInvocationException;
 import io.fd.honeycomb.v3po.translate.v3po.utils.V3poUtils;
@@ -63,8 +69,9 @@ public class VhostUserCustomizerTest {
     private FutureJVpp api;
     @Mock
     private WriteContext writeContext;
+    @Mock
+    private MappingContext mappingContext;
 
-    private NamingContext namingContext;
     private VhostUserCustomizer customizer;
     private static final int IFACE_ID = 1;
     private static final String IFACE_NAME = "eth0";
@@ -77,7 +84,11 @@ public class VhostUserCustomizerTest {
         initMocks(this);
         InterfaceTypeTestUtils.setupWriteContext(writeContext,
             org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class);
-        namingContext = new NamingContext("generatedInterfaceName");
+        final NamingContext namingContext = new NamingContext("generatedInterfaceName", "test-instance");
+        final ModificationCache toBeReturned = new ModificationCache();
+        doReturn(toBeReturned).when(writeContext).getModificationCache();
+        doReturn(mappingContext).when(writeContext).getMappingContext();
+
         // TODO create base class for tests using vppApi
         customizer = new VhostUserCustomizer(api, namingContext);
     }
@@ -186,7 +197,7 @@ public class VhostUserCustomizerTest {
 
         customizer.writeCurrentAttributes(ID, vhostUser, writeContext);
         verifyCreateVhostUserIfWasInvoked(vhostUser);
-        assertTrue(namingContext.containsIndex(IFACE_NAME));
+        verify(mappingContext).put(eq(getMappingIid(IFACE_NAME, "test-instance")), eq(getMapping(IFACE_NAME, 0).get()));
     }
 
     @Test
@@ -200,7 +211,7 @@ public class VhostUserCustomizerTest {
         } catch (WriteFailedException.CreateFailedException e) {
             assertEquals(VppApiInvocationException.class, e.getCause().getClass());
             verifyCreateVhostUserIfWasInvoked(vhostUser);
-            assertFalse(namingContext.containsIndex(IFACE_NAME));
+            verifyZeroInteractions(mappingContext);
             return;
         }
         fail("WriteFailedException.CreateFailedException was expected");
@@ -210,7 +221,7 @@ public class VhostUserCustomizerTest {
     public void testUpdateCurrentAttributes() throws Exception {
         final VhostUser vhostUserBefore = generateVhostUser(VhostUserRole.Client, "socketName0");
         final VhostUser vhostUserAfter = generateVhostUser(VhostUserRole.Server, "socketName1");
-        namingContext.addName(IFACE_ID, IFACE_NAME);
+        doReturn(getMapping(IFACE_NAME, IFACE_ID)).when(mappingContext).read(getMappingIid(IFACE_NAME, "test-instance"));
 
         whenModifyVhostUserIfThenSuccess();
 
@@ -230,7 +241,7 @@ public class VhostUserCustomizerTest {
     public void testUpdateCurrentAttributesFailed() throws Exception {
         final VhostUser vhostUserBefore = generateVhostUser(VhostUserRole.Client, "socketName0");
         final VhostUser vhostUserAfter = generateVhostUser(VhostUserRole.Server, "socketName1");
-        namingContext.addName(IFACE_ID, IFACE_NAME);
+        doReturn(getMapping(IFACE_NAME, IFACE_ID)).when(mappingContext).read(getMappingIid(IFACE_NAME, "test-instance"));
 
         whenModifyVhostUserIfThenFailure();
 
@@ -247,19 +258,19 @@ public class VhostUserCustomizerTest {
     @Test
     public void testDeleteCurrentAttributes() throws Exception {
         final VhostUser vhostUser = generateVhostUser(VhostUserRole.Client, "socketName");
-        namingContext.addName(IFACE_ID, IFACE_NAME);
+        doReturn(getMapping(IFACE_NAME, IFACE_ID)).when(mappingContext).read(getMappingIid(IFACE_NAME, "test-instance"));
 
         whenDeleteVhostUserIfThenSuccess();
 
         customizer.deleteCurrentAttributes(ID, vhostUser, writeContext);
         verifyDeleteVhostUserIfWasInvoked(IFACE_ID);
-        assertFalse(namingContext.containsIndex(IFACE_NAME));
+        verify(mappingContext).delete(eq(getMappingIid(IFACE_NAME, "test-instance")));
     }
 
     @Test
     public void testDeleteCurrentAttributesFailed() throws Exception {
         final VhostUser vhostUser = generateVhostUser(VhostUserRole.Client, "socketName");
-        namingContext.addName(IFACE_ID, IFACE_NAME);
+        doReturn(getMapping(IFACE_NAME, IFACE_ID)).when(mappingContext).read(getMappingIid(IFACE_NAME, "test-instance"));
 
         whenDeleteVhostUserIfThenFailure();
 
@@ -268,7 +279,9 @@ public class VhostUserCustomizerTest {
         } catch (WriteFailedException.DeleteFailedException e) {
             assertEquals(VppApiInvocationException.class, e.getCause().getClass());
             verifyDeleteVhostUserIfWasInvoked(IFACE_ID);
-            assertTrue(namingContext.containsIndex(IFACE_NAME));
+            // Delete from context not invoked if delete from VPP failed
+            verify(mappingContext, times(0)).delete(eq(getMappingIid(IFACE_NAME, "test-instance")));
+            verify(mappingContext).read(eq(getMappingIid(IFACE_NAME, "test-instance")));
             return;
         }
         fail("WriteFailedException.DeleteFailedException was expected");
index ae76814..39a9823 100644 (file)
@@ -16,6 +16,8 @@
 
 package io.fd.honeycomb.v3po.translate.v3po.interfaces;
 
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
@@ -24,6 +26,7 @@ import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.MockitoAnnotations.initMocks;
 
+import io.fd.honeycomb.v3po.translate.MappingContext;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.v3po.translate.v3po.util.VppApiInvocationException;
 import io.fd.honeycomb.v3po.translate.write.WriteContext;
@@ -55,6 +58,8 @@ public class VlanTagRewriteCustomizerTest {
     private FutureJVpp api;
     @Mock
     private WriteContext writeContext;
+    @Mock
+    private MappingContext mappingContext;
 
     private NamingContext namingContext;
     private VlanTagRewriteCustomizer customizer;
@@ -65,9 +70,10 @@ public class VlanTagRewriteCustomizerTest {
     @Before
     public void setUp() throws Exception {
         initMocks(this);
-        namingContext = new NamingContext("generatedSubInterfaceName");
+        namingContext = new NamingContext("generatedSubInterfaceName", "test-instance");
+        doReturn(mappingContext).when(writeContext).getMappingContext();
         customizer = new VlanTagRewriteCustomizer(api, namingContext);
-        namingContext.addName(VLAN_IF_ID, VLAN_IF_NAME);
+        doReturn(getMapping(VLAN_IF_NAME, VLAN_IF_ID)).when(mappingContext).read(getMappingIid(VLAN_IF_NAME, "test-instance"));
     }
 
     private InstanceIdentifier<VlanTagRewrite> getVlanTagRewriteId(final String name) {
index af7b4df..a5103b1 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.interfaces;
 
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
 import com.google.common.net.InetAddresses;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.v3po.translate.v3po.util.VppApiInvocationException;
 import io.fd.honeycomb.v3po.translate.write.WriteContext;
@@ -63,9 +68,10 @@ public class VxlanCustomizerTest {
     private FutureJVpp api;
     @Mock
     private WriteContext writeContext;
+    @Mock
+    private MappingContext mappingContext;
 
     private VxlanCustomizer customizer;
-    private NamingContext namingContext;
     private String ifaceName;
     private InstanceIdentifier<Vxlan> id;
 
@@ -75,7 +81,11 @@ public class VxlanCustomizerTest {
         InterfaceTypeTestUtils.setupWriteContext(writeContext,
             org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel.class);
         // TODO create base class for tests using vppApi
-        namingContext = new NamingContext("generateInterfaceNAme");
+        NamingContext namingContext = new NamingContext("generateInterfaceNAme", "test-instance");
+        final ModificationCache toBeReturned = new ModificationCache();
+        doReturn(toBeReturned).when(writeContext).getModificationCache();
+        doReturn(mappingContext).when(writeContext).getMappingContext();
+
         customizer = new VxlanCustomizer(api, namingContext);
 
         ifaceName = "eth0";
@@ -144,7 +154,7 @@ public class VxlanCustomizerTest {
 
         customizer.writeCurrentAttributes(id, vxlan, writeContext);
         verifyVxlanAddWasInvoked(vxlan);
-        assertTrue(namingContext.containsIndex(ifaceName));
+        verify(mappingContext).put(eq(getMappingIid(ifaceName, "test-instance")), eq(getMapping(ifaceName, 0).get()));
     }
 
     @Test
@@ -158,7 +168,8 @@ public class VxlanCustomizerTest {
         } catch (WriteFailedException.CreateFailedException e) {
             assertEquals(VppApiInvocationException.class, e.getCause().getClass());
             verifyVxlanAddWasInvoked(vxlan);
-            assertFalse(namingContext.containsIndex(ifaceName));
+            // Mapping not stored due to failure
+            verify(mappingContext, times(0)).put(eq(getMappingIid(ifaceName, "test-instance")), eq(getMapping(ifaceName, 0).get()));
             return;
         }
         fail("WriteFailedException.CreateFailedException was expected");
@@ -186,11 +197,11 @@ public class VxlanCustomizerTest {
         final Vxlan vxlan = generateVxlan();
 
         whenVxlanAddDelTunnelThenSuccess();
-        namingContext.addName(1, ifaceName);
+        doReturn(getMapping(ifaceName, 1)).when(mappingContext).read(getMappingIid(ifaceName, "test-instance"));
 
         customizer.deleteCurrentAttributes(id, vxlan, writeContext);
         verifyVxlanDeleteWasInvoked(vxlan);
-        assertFalse(namingContext.containsIndex(ifaceName));
+        verify(mappingContext).delete(eq(getMappingIid(ifaceName, "test-instance")));
     }
 
     @Test
@@ -198,14 +209,14 @@ public class VxlanCustomizerTest {
         final Vxlan vxlan = generateVxlan();
 
         whenVxlanAddDelTunnelThenFailure();
-        namingContext.addName(1, ifaceName);
+        doReturn(getMapping(ifaceName, 1)).when(mappingContext).read(getMappingIid(ifaceName, "test-instance"));
 
         try {
             customizer.deleteCurrentAttributes(id, vxlan, writeContext);
         } catch (WriteFailedException.DeleteFailedException e) {
             assertEquals(VppApiInvocationException.class, e.getCause().getClass());
             verifyVxlanDeleteWasInvoked(vxlan);
-            assertTrue(namingContext.containsIndex(ifaceName));
+            verify(mappingContext, times(0)).delete(eq(getMappingIid(ifaceName, "test-instance")));
             return;
         }
         fail("WriteFailedException.DeleteFailedException was expected");
index 3f33d14..822b16c 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.yangIfIndexToVpp;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
 import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
@@ -37,12 +42,17 @@ import java.util.concurrent.CompletionStage;
 import java.util.concurrent.ExecutionException;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.openvpp.jvpp.dto.SwInterfaceDetails;
 import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump;
 import org.openvpp.jvpp.dto.SwInterfaceDump;
@@ -58,13 +68,23 @@ public class InterfaceCustomizerTest extends
 
     @Override
     public void setUpBefore() {
-        interfacesContext = new NamingContext("generatedIfaceName");
+        interfacesContext = new NamingContext("generatedIfaceName", "test-instance");
     }
 
     @Override
     protected RootReaderCustomizer<Interface, InterfaceBuilder> initCustomizer() {
-        interfacesContext.addName(0, "eth0");
-        interfacesContext.addName(1, "eth1");
+        final KeyedInstanceIdentifier<Mapping, MappingKey> eth0Id = getMappingIid("eth0", "test-instance");
+        final KeyedInstanceIdentifier<Mapping, MappingKey> eth1Id = getMappingIid("eth1", "test-instance");
+        final Optional<Mapping> eth0 = getMapping("eth0", 0);
+        final Optional<Mapping> eth1 = getMapping("eth1", 1);
+
+        final List<Mapping> allMappings = Lists.newArrayList(getMapping("eth0", 0).get(), getMapping("eth1", 1).get());
+        final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build();
+        doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(eth0Id.firstIdentifierOf(Mappings.class));
+
+        doReturn(eth0).when(mappingContext).read(eth0Id);
+        doReturn(eth1).when(mappingContext).read(eth1Id);
+
         return new InterfaceCustomizer(api, interfacesContext);
     }
 
index b454446..b093815 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import io.fd.honeycomb.v3po.translate.Context;
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
 import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.test.ChildReaderCustomizerTest;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
@@ -33,6 +37,10 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
 import java.util.concurrent.ExecutionException;
 import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
@@ -43,6 +51,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.l2.Interconnection;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.l2.interconnection.BridgeBasedBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump;
 import org.openvpp.jvpp.dto.BridgeDomainDump;
 import org.openvpp.jvpp.dto.BridgeDomainSwIfDetails;
@@ -59,8 +68,8 @@ public class L2CustomizerTest extends ChildReaderCustomizerTest<L2, L2Builder> {
 
     @Override
     public void setUpBefore() {
-        interfaceContext = new NamingContext("generatedIfaceName");
-        bridgeDomainContext = new NamingContext("generatedBDName");
+        interfaceContext = new NamingContext("generatedIfaceName", "ifc-test-instance");
+        bridgeDomainContext = new NamingContext("generatedBDName", "bd-test-instance");
     }
 
     @Override
@@ -111,19 +120,28 @@ public class L2CustomizerTest extends ChildReaderCustomizerTest<L2, L2Builder> {
 
     @Test
     public void testRead() throws Exception {
-        final Context ctx = new Context();
         final Map<Integer, SwInterfaceDetails> cachedInterfaceDump = new HashMap<>();
         final int ifId = 1;
         final int bdId = 1;
         final String bdName = "bd001";
         final String ifName = "eth0.sub0";
-        interfaceContext.addName(ifId, ifName);
-        bridgeDomainContext.addName(bdId, bdName);
+        final KeyedInstanceIdentifier<Mapping, MappingKey> ifcIid = getMappingIid(ifName, "ifc-test-instance");
+        doReturn(getMapping(ifName, ifId)).when(mappingContext).read(ifcIid);
+        final KeyedInstanceIdentifier<Mapping, MappingKey> bdIid = getMappingIid(bdName, "bd-test-instance");
+        doReturn(getMapping(bdName, bdId)).when(mappingContext).read(bdIid);
+
+        List<Mapping> allMappings = Lists.newArrayList(getMapping(ifName, ifId).get());
+        Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build();
+        doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(ifcIid.firstIdentifierOf(Mappings.class));
+
+        allMappings = Lists.newArrayList(getMapping(bdName, bdId).get());
+        allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build();
+        doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(bdIid.firstIdentifierOf(Mappings.class));
 
         final SwInterfaceDetails ifaceDetails = new SwInterfaceDetails();
         ifaceDetails.subId = ifId;
         cachedInterfaceDump.put(ifId, ifaceDetails);
-        ctx.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump);
+        cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump);
 
         whenBridgeDomainSwIfDumpThenReturn(Collections.singletonList(generateBdSwIfDetails(ifId, bdId)));
 
index 8ed35e0..4f6857b 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
-import io.fd.honeycomb.v3po.translate.Context;
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.test.ChildReaderCustomizerTest;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
@@ -38,6 +48,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.SubInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.SubInterfaceBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.openvpp.jvpp.dto.SwInterfaceDetails;
 
 public class SubInterfaceCustomizerTest extends ChildReaderCustomizerTest<SubInterface, SubInterfaceBuilder> {
@@ -55,7 +66,7 @@ public class SubInterfaceCustomizerTest extends ChildReaderCustomizerTest<SubInt
 
     @Override
     public void setUpBefore() {
-        interfacesContext = new NamingContext("generatedIfaceName");
+        interfacesContext = new NamingContext("generatedIfaceName", "test-instance");
     }
 
     private InstanceIdentifier<SubInterface> getSubInterfaceId(final String name) {
@@ -74,21 +85,30 @@ public class SubInterfaceCustomizerTest extends ChildReaderCustomizerTest<SubInt
 
     @Test
     public void testRead() throws ReadFailedException {
-        final Context ctx = new Context();
         final Map<Integer, SwInterfaceDetails> cachedInterfaceDump = new HashMap<>();
         final int ifId = 1;
         final String ifName = "eth0.sub0";
-        interfacesContext.addName(ifId, ifName);
+
+        final KeyedInstanceIdentifier<Mapping, MappingKey> ifcIid = getMappingIid(ifName, "test-instance");
+        doReturn(getMapping(ifName, ifId)).when(mappingContext).read(ifcIid);
+        final KeyedInstanceIdentifier<Mapping, MappingKey> superIfcIid = getMappingIid("super", "test-instance");
+        doReturn(getMapping("super", 0)).when(mappingContext).read(superIfcIid);
+
+        final List<Mapping> allMappings = Lists.newArrayList(getMapping(ifName, ifId).get(), getMapping("super", 0).get());
+        final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build();
+        doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(ifcIid.firstIdentifierOf(Mappings.class));
+
         final SwInterfaceDetails ifaceDetails = new SwInterfaceDetails();
         ifaceDetails.subId = ifId;
         ifaceDetails.interfaceName = ifName.getBytes();
         cachedInterfaceDump.put(ifId, ifaceDetails);
-        ctx.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump);
+        cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump);
 
         final SubInterfaceBuilder builder = mock(SubInterfaceBuilder.class);
         getCustomizer().readCurrentAttributes(getSubInterfaceId(ifName), builder, ctx);
 
         verify(builder).setIdentifier((long)ifId);
+        verify(builder).setSuperInterface(anyString());
         verify(builder).setNumberOfTags((short)0);
         verify(builder).setVlanType(VlanType._802dot1ad);
         verify(builder, never()).setExactMatch(any());
index 2263160..d00745e 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
-import io.fd.honeycomb.v3po.translate.Context;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.test.ChildReaderCustomizerTest;
@@ -52,7 +54,7 @@ public class VlanTagRewriteCustomizerTest extends ChildReaderCustomizerTest<Vlan
 
     @Override
     public void setUpBefore() {
-        interfacesContext = new NamingContext("generatedIfaceName");
+        interfacesContext = new NamingContext("generatedIfaceName", "test-instance");
     }
 
 
@@ -76,15 +78,15 @@ public class VlanTagRewriteCustomizerTest extends ChildReaderCustomizerTest<Vlan
 
     @Test
     public void testRead() throws ReadFailedException {
-        final Context ctx = new Context();
         final Map<Integer, SwInterfaceDetails> cachedInterfaceDump = new HashMap<>();
         final int ifId = 1;
         final String ifName = "eth0.sub0";
-        interfacesContext.addName(ifId, ifName);
+        doReturn(getMapping(ifName, ifId)).when(mappingContext).read(getMappingIid(ifName, "test-instance"));
+
         final SwInterfaceDetails ifaceDetails = new SwInterfaceDetails();
         ifaceDetails.subId = ifId;
         cachedInterfaceDump.put(ifId, ifaceDetails);
-        ctx.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump);
+        cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump);
 
         final VlanTagRewriteBuilder builder = mock(VlanTagRewriteBuilder.class);
         getCustomizer().readCurrentAttributes(getVlanTagRewriteId(ifName), builder, ctx);
index 760e85b..db92ebf 100644 (file)
@@ -16,6 +16,8 @@
 
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -25,7 +27,6 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
 import com.google.common.collect.Lists;
-import io.fd.honeycomb.v3po.translate.Context;
 import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.test.ChildReaderCustomizerTest;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
@@ -50,7 +51,6 @@ import org.openvpp.jvpp.dto.VxlanTunnelDump;
 public class VxlanCustomizerTest extends ChildReaderCustomizerTest<Vxlan, VxlanBuilder> {
 
     private NamingContext interfacesContext;
-    private Context ctx;
     static final InstanceIdentifier<Vxlan> IID =
         InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey("ifc1"))
             .augmentation(VppInterfaceStateAugmentation.class).child(Vxlan.class);
@@ -61,15 +61,14 @@ public class VxlanCustomizerTest extends ChildReaderCustomizerTest<Vxlan, VxlanB
 
     @Override
     public void setUpBefore() {
-        interfacesContext = new NamingContext("vxlan-tunnel");
-        interfacesContext.addName(0, "ifc1");
+        interfacesContext = new NamingContext("vxlan-tunnel", "test-instance");
+        doReturn(getMapping("ifc1", 0)).when(mappingContext).read(getMappingIid("ifc1", "test-instance"));
 
-        ctx = new Context();
         final SwInterfaceDetails v = new SwInterfaceDetails();
         v.interfaceName = "vxlan-tunnel4".getBytes();
         final Map<Integer, SwInterfaceDetails> map = new HashMap<>();
         map.put(0, v);
-        ctx.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, map);
+        cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, map);
     }
 
     @Override
@@ -114,7 +113,7 @@ public class VxlanCustomizerTest extends ChildReaderCustomizerTest<Vxlan, VxlanB
 
     @Test(expected = NullPointerException.class)
     public void testReadCurrentAttributesVppNameNotCached() throws Exception {
-        InterfaceCustomizer.getCachedInterfaceDump(ctx).remove(0);
+        InterfaceCustomizer.getCachedInterfaceDump(cache).remove(0);
 
         final VxlanBuilder builder = getCustomizer().getBuilder(IID);
         getCustomizer().readCurrentAttributes(IID, builder, ctx);
@@ -124,7 +123,7 @@ public class VxlanCustomizerTest extends ChildReaderCustomizerTest<Vxlan, VxlanB
     public void testReadCurrentAttributesWrongType() throws Exception {
         final SwInterfaceDetails v = new SwInterfaceDetails();
         v.interfaceName = "tap-2".getBytes();
-        InterfaceCustomizer.getCachedInterfaceDump(ctx).put(0, v);
+        InterfaceCustomizer.getCachedInterfaceDump(cache).put(0, v);
 
         final VxlanBuilder builder = getCustomizer().getBuilder(IID);
         getCustomizer().readCurrentAttributes(IID, builder, ctx);
index 19d307e..8500ace 100644 (file)
 package io.fd.honeycomb.v3po.translate.v3po.test;
 
 import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.MockitoAnnotations.initMocks;
 
-import io.fd.honeycomb.v3po.translate.Context;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer;
 import org.junit.Before;
 import org.junit.Test;
@@ -39,8 +42,11 @@ public abstract class RootReaderCustomizerTest<D extends DataObject, B extends B
 
     @Mock
     protected FutureJVpp api;
+    protected ModificationCache cache;
     @Mock
-    protected Context ctx;
+    protected ReadContext ctx;
+    @Mock
+    protected MappingContext mappingContext;
 
     protected final Class<D> dataObjectClass;
     private RootReaderCustomizer<D, B> customizer;
@@ -52,6 +58,10 @@ public abstract class RootReaderCustomizerTest<D extends DataObject, B extends B
     @Before
     public void setUpParent() throws Exception {
         initMocks(this);
+        cache = new ModificationCache();
+        doReturn(cache).when(ctx).getModificationCache();
+        doReturn(mappingContext).when(ctx).getMappingContext();
+
         setUpBefore();
         customizer = initCustomizer();
         setUpAfter();
index f5b19a7..7436c9c 100644 (file)
  */
 package io.fd.honeycomb.v3po.translate.v3po.vpp;
 
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.v3po.translate.write.WriteContext;
 import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
@@ -34,6 +40,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder;
 import org.openvpp.jvpp.dto.BridgeDomainAddDel;
@@ -47,18 +54,22 @@ public class BridgeDomainCustomizerTest {
 
     @Mock
     private FutureJVpp api;
-
     @Mock
     private WriteContext ctx;
+    @Mock
+    private MappingContext mappingContext;
 
     private BridgeDomainCustomizer customizer;
-    private NamingContext namingContext;
 
     @Before
     public void setUp() throws Exception {
         initMocks(this);
         // TODO create base class for tests using vppApi
-        namingContext = new NamingContext("generatedBDName");
+        NamingContext namingContext = new NamingContext("generatedBDName", "test-instance");
+        final ModificationCache toBeReturned = new ModificationCache();
+        doReturn(toBeReturned).when(ctx).getModificationCache();
+        doReturn(mappingContext).when(ctx).getMappingContext();
+
         customizer = new BridgeDomainCustomizer(api, namingContext);
     }
 
@@ -139,12 +150,14 @@ public class BridgeDomainCustomizerTest {
         final int bdId = 1;
         final String bdName = "bd1";
         final BridgeDomain bd = generateBridgeDomain(bdName);
+        doReturn(Optional.absent()).when(mappingContext).read(getMappingIid(bdName, "test-instance").firstIdentifierOf(Mappings.class));
 
         whenBridgeDomainAddDelThenSuccess();
 
         customizer.writeCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx);
 
         verifyBridgeDomainAddOrUpdateWasInvoked(bd, bdId);
+        verify(mappingContext).put(getMappingIid(bdName, "test-instance"), getMapping(bdName, bdId).get());
     }
 
     @Test
@@ -153,6 +166,9 @@ public class BridgeDomainCustomizerTest {
         final String bdName = "bd1";
         final BridgeDomain bd = generateBridgeDomain(bdName);
 
+        // Returning no Mappings for "test-instance" makes bdContext.containsName() return false
+        doReturn(Optional.absent()).when(mappingContext).read(getMappingIid(bdName, "test-instance").firstIdentifierOf(Mappings.class));
+
         whenBridgeDomainAddDelThenFailure();
 
         try {
@@ -169,7 +185,7 @@ public class BridgeDomainCustomizerTest {
         final int bdId = 1;
         final String bdName = "bd1";
         final BridgeDomain bd = generateBridgeDomain(bdName);
-        namingContext.addName(bdId, bdName);
+        doReturn(getMapping(bdName, bdId)).when(mappingContext).read(getMappingIid(bdName, "test-instance"));
 
         whenBridgeDomainAddDelThenSuccess();
 
@@ -182,6 +198,7 @@ public class BridgeDomainCustomizerTest {
     public void testDeleteUnknownBridgeDomain() throws Exception {
         final String bdName = "bd1";
         final BridgeDomain bd = generateBridgeDomain("bd1");
+        doReturn(Optional.absent()).when(mappingContext).read(getMappingIid(bdName, "test-instance"));
 
         try {
             customizer.deleteCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx);
@@ -197,7 +214,7 @@ public class BridgeDomainCustomizerTest {
         final int bdId = 1;
         final String bdName = "bd1";
         final BridgeDomain bd = generateBridgeDomain(bdName);
-        namingContext.addName(bdId, bdName);
+        doReturn(getMapping(bdName, bdId)).when(mappingContext).read(getMappingIid(bdName, "test-instance"));
 
         whenBridgeDomainAddDelThenFailure();
 
@@ -215,7 +232,7 @@ public class BridgeDomainCustomizerTest {
     public void testUpdateBridgeDomain() throws Exception {
         final int bdId = 1;
         final String bdName = "bd1";
-        namingContext.addName(bdId, bdName);
+        doReturn(getMapping(bdName, bdId)).when(mappingContext).read(getMappingIid(bdName, "test-instance"));
 
         final byte arpTermBefore = 1;
         final byte floodBefore = 1;
@@ -241,6 +258,7 @@ public class BridgeDomainCustomizerTest {
         final String bdName = "bd1";
         final BridgeDomain bdBefore = generateBridgeDomain(bdName, 0, 1, 0 ,1, 0);
         final BridgeDomain bdAfter = generateBridgeDomain(bdName, 1, 1, 0 ,1, 0);
+        doReturn(Optional.absent()).when(mappingContext).read(getMappingIid(bdName, "test-instance"));
 
         try {
             customizer.updateCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bdBefore, bdAfter, ctx);
@@ -257,7 +275,7 @@ public class BridgeDomainCustomizerTest {
         final String bdName = "bd1";
         final BridgeDomain bdBefore = generateBridgeDomain(bdName, 0, 1, 0 ,1, 0);
         final BridgeDomain bdAfter = generateBridgeDomain(bdName, 1, 1, 0 ,1, 0);
-        namingContext.addName(bdId, bdName);
+        doReturn(getMapping(bdName, bdId)).when(mappingContext).read(getMappingIid(bdName, "test-instance"));
 
         whenBridgeDomainAddDelThenFailure();
 
index 820cf05..1b30fdd 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.vpp;
 
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
+import com.google.common.base.Optional;
 import com.google.common.collect.Iterators;
 import com.google.common.collect.Lists;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.impl.write.CompositeRootWriter;
 import io.fd.honeycomb.v3po.translate.util.write.DelegatingWriterRegistry;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
@@ -38,6 +44,9 @@ import java.util.concurrent.ExecutionException;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains;
@@ -54,17 +63,24 @@ public class VppTest {
 
     private static final byte ADD_OR_UPDATE_BD = 1;
     private static final byte ZERO = 0;
+    @Mock
     private FutureJVpp api;
+    @Mock
+    private WriteContext ctx;
+    @Mock
+    private MappingContext mappingContext;
+
     private DelegatingWriterRegistry rootRegistry;
     private CompositeRootWriter<Vpp> vppWriter;
-    private WriteContext ctx;
-    private NamingContext bdContext;
 
     @Before
     public void setUp() throws Exception {
-        api = mock(FutureJVpp.class);
-        ctx = mock(WriteContext.class);
-        bdContext = new NamingContext("generatedBdName");
+        MockitoAnnotations.initMocks(this);
+        NamingContext bdContext = new NamingContext("generatedBdName", "test-instance");
+        final ModificationCache toBeReturned = new ModificationCache();
+        doReturn(toBeReturned).when(ctx).getModificationCache();
+        doReturn(mappingContext).when(ctx).getMappingContext();
+
         vppWriter = VppUtils.getVppWriter(api, bdContext);
         rootRegistry = new DelegatingWriterRegistry(
             Collections.<Writer<? extends DataObject>>singletonList(vppWriter));
@@ -134,6 +150,8 @@ public class VppTest {
         final int bdId = 1;
         final BridgeDomains bdn1 = getBridgeDomains("bdn1");
         whenBridgeDomainAddDelThen(0);
+        doReturn(Optional
+            .absent()).when(mappingContext).read(getMappingIid("bdn1", "test-instance").firstIdentifierOf(Mappings.class));
 
         rootRegistry.update(
                 InstanceIdentifier.create(Vpp.class),
@@ -149,6 +167,8 @@ public class VppTest {
         final int bdId = 1;
         final BridgeDomains bdn1 = getBridgeDomains("bdn1");
         whenBridgeDomainAddDelThen(0);
+        doReturn(Optional
+            .absent()).when(mappingContext).read(getMappingIid("bdn1", "test-instance").firstIdentifierOf(Mappings.class));
 
         vppWriter.update(InstanceIdentifier.create(Vpp.class),
                 null,
@@ -156,6 +176,7 @@ public class VppTest {
                 ctx);
 
         verifyBridgeDomainAddDel(Iterators.getOnlyElement(bdn1.getBridgeDomain().iterator()), bdId);
+        verify(mappingContext).put(getMappingIid("bdn1", "test-instance"), getMapping("bdn1", 1).get());
     }
 
     @Test
@@ -163,9 +184,11 @@ public class VppTest {
         final BridgeDomains bdn1 = getBridgeDomains("bdn1");
         final int bdId = 1;
         final Vpp vpp = new VppBuilder().setBridgeDomains(bdn1).build();
+        doReturn(Optional
+            .absent()).when(mappingContext).read(getMappingIid("bdn1", "test-instance").firstIdentifierOf(Mappings.class));
         whenBridgeDomainAddDelThen(0);
 
-        rootRegistry.update(Collections.<InstanceIdentifier<?>, DataObject>emptyMap(),
+        rootRegistry.update(Collections.emptyMap(),
             Collections.<InstanceIdentifier<?>, DataObject>singletonMap(InstanceIdentifier.create(Vpp.class),
                 vpp), ctx);
 
@@ -178,7 +201,7 @@ public class VppTest {
         final BridgeDomains bdn1 = getBridgeDomains(bdName);
         final int bdId = 1;
         whenBridgeDomainAddDelThen(0);
-        bdContext.addName(bdId, bdName);
+        doReturn(getMapping(bdName, bdId)).when(mappingContext).read(getMappingIid(bdName, "test-instance"));
 
         rootRegistry.update(
             InstanceIdentifier.create(Vpp.class),
@@ -204,7 +227,8 @@ public class VppTest {
     public void writeUpdate() throws Exception {
         final String bdName = "bdn1";
         final int bdn1Id = 1;
-        bdContext.addName(bdn1Id, bdName);
+        doReturn(getMapping(bdName, bdn1Id)).when(mappingContext).read(getMappingIid(bdName, "test-instance"));
+
         final BridgeDomains domainsBefore = getBridgeDomains(bdName);
         final BridgeDomain bdn1Before = domainsBefore.getBridgeDomain().get(0);
 
index c482c44..3690386 100644 (file)
@@ -40,8 +40,8 @@ public class BridgeDomainCustomizerTest extends ListReaderCustomizerTest<BridgeD
 
     @Override
     public void setUpBefore() {
-        bdContext = new NamingContext("generatedBdName");
-        interfacesContext = new NamingContext("generatedIfaceName");
+        bdContext = new NamingContext("generatedBdName", "bd-test-instance");
+        interfacesContext = new NamingContext("generatedIfaceName", "ifc-test-instance");
     }
 
     @Test
index bf1d121..3d75d09 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.vppstate;
 
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.ContextTestUtils.getMappingIid;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Multimap;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.impl.read.CompositeListReader;
 import io.fd.honeycomb.v3po.translate.impl.read.CompositeRootReader;
 import io.fd.honeycomb.v3po.translate.read.ReadContext;
@@ -43,6 +49,9 @@ import java.util.concurrent.ExecutionException;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder;
@@ -72,6 +81,8 @@ public class VppStateTest {
     private FutureJVpp api;
     @Mock
     private ReadContext ctx;
+    @Mock
+    private MappingContext mappingContext;
 
     private NamingContext bdContext;
     private NamingContext interfaceContext;
@@ -82,9 +93,12 @@ public class VppStateTest {
     @Before
     public void setUp() throws Exception {
         initMocks(this);
+        final ModificationCache cache = new ModificationCache();
+        doReturn(cache).when(ctx).getModificationCache();
+        doReturn(mappingContext).when(ctx).getMappingContext();
 
-        bdContext = new NamingContext("generatedBdName");
-        interfaceContext = new NamingContext("generatedInterfaceName");
+        bdContext = new NamingContext("generatedBdName", "bd-test-instance");
+        interfaceContext = new NamingContext("generatedIfaceName", "ifc-test-instance");
         vppStateReader = VppStateTestUtils.getVppStateReader(api, bdContext, interfaceContext);
         readerRegistry = new DelegatingReaderRegistry(Collections.<Reader<? extends DataObject>>singletonList(vppStateReader));
     }
@@ -146,7 +160,14 @@ public class VppStateTest {
         final Version version = getVersion();
         whenShowVersionThenReturn(0, version);
 
-        final List<BridgeDomainDetails> bdList = Arrays.asList(new BridgeDomainDetails(), new BridgeDomainDetails());
+        final BridgeDomainDetails bridgeDomainDetails = new BridgeDomainDetails();
+        final BridgeDomainDetails bridgeDomainDetails2 = new BridgeDomainDetails();
+        bridgeDomainDetails2.bdId = 1;
+
+        final List<BridgeDomainDetails> bdList = Arrays.asList(bridgeDomainDetails, bridgeDomainDetails2);
+        mockBdMapping(bridgeDomainDetails, "bd1");
+        mockBdMapping(bridgeDomainDetails2, "bd2");
+
         whenBridgeDomainDumpThenReturn(bdList);
 
         final Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> dataObjects = readerRegistry.readAll(ctx);
@@ -171,8 +192,10 @@ public class VppStateTest {
     public void testReadBridgeDomains() throws Exception {
         final Version version = getVersion();
         whenShowVersionThenReturn(0, version);
-        whenBridgeDomainDumpThenReturn(Collections.singletonList(new BridgeDomainDetails()));
+        final BridgeDomainDetails details = new BridgeDomainDetails();
+        whenBridgeDomainDumpThenReturn(Collections.singletonList(details));
 
+        mockBdMapping(details, "bdn1");
         VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get();
 
         Optional<? extends DataObject> read =
@@ -189,7 +212,9 @@ public class VppStateTest {
         final BridgeDomainDetails bd = new BridgeDomainDetails();
         bd.bdId = 0;
         final String bdName = "bdn1";
-        bdContext.addName(bd.bdId, bdName);
+        mockBdMapping(bd, bdName);
+        mockMapping("eth1", 0, "ifc-test-instance");
+
         whenBridgeDomainDumpThenReturn(Collections.singletonList(bd));
         final L2FibTableEntry l2FibEntry = new L2FibTableEntry();
         l2FibEntry.bdId = 0;
@@ -204,18 +229,44 @@ public class VppStateTest {
         assertTrue(read.isPresent());
 
         // non existing l2fib
-        read =
-            readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child(
+        read = readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child(
                 BridgeDomain.class, new BridgeDomainKey("bdn1"))
                 .child(L2Fib.class, new L2FibKey(new PhysAddress("FF:FF:FF:04:05:06"))), ctx);
         assertFalse(read.isPresent());
     }
 
+    private void mockBdMapping(final BridgeDomainDetails bd, final String bdName) {
+        mockMapping(bdName, bd.bdId, "bd-test-instance");
+    }
+
+    private void mockMapping(final String name, final int id, final String namingContextName) {
+        final InstanceIdentifier<Mappings> mappingsIid = getMappingIid(name, namingContextName).firstIdentifierOf(Mappings.class);
+
+        final Optional<Mapping> singleMapping = getMapping(name, id);
+        final Optional<Mappings> previousMappings = mappingContext.read(mappingsIid);
+
+        final MappingsBuilder mappingsBuilder;
+        if(previousMappings != null && previousMappings.isPresent()) {
+            mappingsBuilder = new MappingsBuilder(previousMappings.get());
+        } else {
+            mappingsBuilder = new MappingsBuilder();
+            mappingsBuilder.setMapping(Lists.newArrayList());
+        }
+
+        final List<Mapping> mappingList = mappingsBuilder.getMapping();
+        mappingList.add(singleMapping.get());
+        doReturn(Optional.of(mappingsBuilder.setMapping(mappingList).build()))
+            .when(mappingContext).read(mappingsIid);
+        doReturn(singleMapping).when(mappingContext).read(getMappingIid(name, namingContextName));
+    }
+
     @Test
     public void testReadBridgeDomainAll() throws Exception {
         final Version version = getVersion();
         whenShowVersionThenReturn(0, version);
-        whenBridgeDomainDumpThenReturn(Collections.singletonList(new BridgeDomainDetails()));
+        final BridgeDomainDetails details = new BridgeDomainDetails();
+        whenBridgeDomainDumpThenReturn(Collections.singletonList(details));
+        mockBdMapping(details, "bd2");
 
         VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get();
 
@@ -234,7 +285,8 @@ public class VppStateTest {
         final BridgeDomainDetails bd = new BridgeDomainDetails();
         bd.bdId = 0;
         final String bdName = "bdn1";
-        bdContext.addName(bd.bdId, bdName);
+        mockBdMapping(bd, bdName);
+
         whenBridgeDomainDumpThenReturn(Collections.singletonList(bd));
         whenShowVersionThenReturn(0, getVersion());
 
@@ -245,12 +297,15 @@ public class VppStateTest {
                 BridgeDomain.class, new BridgeDomainKey(bdName)), ctx);
 
         assertTrue(read.isPresent());
-        assertEquals(Iterables.find(readRoot.getBridgeDomains().getBridgeDomain(),
-                input -> input.getKey().getName().equals(bdName)), read.get());
+        assertEquals(readRoot.getBridgeDomains().getBridgeDomain().stream().filter(
+                input -> input.getKey().getName().equals(bdName)).findFirst().get(),
+            read.get());
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testReadBridgeDomainNotExisting() throws Exception {
+        doReturn(Optional.absent()).when(mappingContext).read(getMappingIid("NOT EXISTING", "bd-test-instance"));
+        
         final Optional<? extends DataObject> read =
             readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child(
                 BridgeDomain.class, new BridgeDomainKey("NOT EXISTING")), ctx);
index 45ac193..e1a5bf2 100644 (file)
@@ -45,17 +45,17 @@ public abstract class AbstractInterfaceTypeCustomizer<D extends DataObject>
     }
 
     private void checkProperInterfaceType(@Nonnull final WriteContext writeContext,
-                                  @Nonnull final InstanceIdentifier<D> id) {
+                                          @Nonnull final InstanceIdentifier<D> id) {
         final InstanceIdentifier<Interface> ifcTypeFromIid = id.firstIdentifierOf(Interface.class);
         checkArgument(ifcTypeFromIid != null, "Instance identifier does not contain {} type", Interface.class);
         checkArgument(id.firstKeyOf(Interface.class) != null, "Instance identifier does not contain keyed {} type",
             Interface.class);
-        final Optional<DataObject> interfaceConfigOperational = writeContext.readAfter(ifcTypeFromIid);
-        checkState(interfaceConfigOperational.isPresent(),
-            "Unable to get Interface configuration for an interface being updated under ID");
+        final Optional<Interface> interfaceConfig = writeContext.readAfter(ifcTypeFromIid);
+        checkState(interfaceConfig.isPresent(),
+            "Unable to get Interface configuration for an interface: %s currently being updated", ifcTypeFromIid);
 
         IllegalInterfaceTypeException
-            .checkInterfaceType((Interface) interfaceConfigOperational.get(), getExpectedInterfaceType());
+            .checkInterfaceType(interfaceConfig.get(), getExpectedInterfaceType());
     }
 
     protected abstract Class<? extends InterfaceType> getExpectedInterfaceType();
diff --git a/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/DataTreeNamingContext.java b/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/DataTreeNamingContext.java
deleted file mode 100644 (file)
index 3b20b28..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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.v3po.util;
-
-import com.google.common.collect.Lists;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import javax.annotation.Nonnull;
-import javax.annotation.concurrent.ThreadSafe;
-import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts;
-import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
-import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
-import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Naming context keeping a mapping between int index and string name.
- * Provides artificial names to unknown indices.
- */
-@ThreadSafe
-public class DataTreeNamingContext extends NamingContext {
-
-    // FIXME this has to be accessed by readers/writers in a transactional manner and the transaction will only be committed once
-    // the Read or Write operation finishes successfully
-    // Context datatree has to become a first class citizen of Honeycomb, and Honeycomb needs to create and provide
-    // context read write transaction as part of context to read/write customizers
-    // This will then become just a utility writer relying on transaction provided by the infrastructure
-    // Btw. the context transaction needs to disable commit/submit when being passed to customizers
-
-    private static final Logger LOG = LoggerFactory.getLogger(DataTreeNamingContext.class);
-
-    private static final QName NAME_KEY_QNAME = QName.create(Contexts.QNAME, "name");
-    private static final QName INDEX_QNAME = QName.create(Contexts.QNAME, "index");
-
-    private final String instanceName;
-    private final DataTree contextDataTree;
-
-    private final YangInstanceIdentifier.NodeIdentifierWithPredicates namingContextNodeId;
-    private final YangInstanceIdentifier namingContextIid;
-
-    public DataTreeNamingContext(final String artificialNamePrefix, final String instanceName,
-                                 final DataTree contextDataTree) {
-        super(artificialNamePrefix);
-        this.instanceName = instanceName;
-        this.contextDataTree = contextDataTree;
-
-        namingContextNodeId = getNodeId(
-            org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.QNAME,
-            Collections.singletonMap(NAME_KEY_QNAME, instanceName));
-        namingContextIid = YangInstanceIdentifier.create(
-            getNodeId(Contexts.QNAME),
-            getNodeId(org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.QNAME),
-            namingContextNodeId);
-
-        // FIXME read current mappings and initialize map
-        mergeNewContextInDataTree(instanceName);
-    }
-
-    // TODO move the data tree aspect into a dedicated class
-    private void mergeNewContextInDataTree(final String instanceName) {
-        final DataTreeModification dataTreeModification = getModification();
-
-        final YangInstanceIdentifier.NodeIdentifier namingContextsNodeIdForMapNode = getNodeId(
-            org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.QNAME);
-
-        final ContainerNode newMapping = Builders.containerBuilder()
-            .withNodeIdentifier(getNodeId(Contexts.QNAME))
-            .withChild(Builders.mapBuilder()
-                .withNodeIdentifier(namingContextsNodeIdForMapNode)
-                .withChild(Builders.mapEntryBuilder()
-                    .withNodeIdentifier(namingContextNodeId)
-                    .withChild(ImmutableNodes.leafNode(NAME_KEY_QNAME, instanceName))
-                    .withChild(Builders.containerBuilder()
-                        .withNodeIdentifier(getNodeId(Mappings.QNAME))
-                        .withChild(Builders.mapBuilder()
-                            .withNodeIdentifier(getNodeId(Mapping.QNAME))
-                            .build())
-                        .build())
-                    .build())
-                .build())
-            .build();
-
-        // FIXME add logs or debug to resolve:
-//        2016-05-13 15:48:52,401 | WARN  | config-pusher    | DataTreeNamingContext            | 240 - io.fd.honeycomb.v3po.vpp-translate-utils - 1.0.0.SNAPSHOT | Unable to update context: interface-context in context data tree
-//        org.opendaylight.yangtools.yang.data.api.schema.tree.ModifiedNodeDoesNotExistException: Node /(urn:honeycomb:params:xml:ns:yang:naming:context?revision=2016-05-13)contexts/naming-context/naming-context[{(urn:honeycomb:params:xml:ns:yang:naming:context?revision=2016-05-13)name=interface-context}] does not exist. Cannot apply modification to its children.
-//        at org.opendaylight.yangtools.yang.data.impl.schema.tree.AbstractNodeContainerModificationStrategy.checkTouchApplicable(AbstractNodeContainerModificationStrategy.java:276)[55:org.opendaylight.yangtools.yang-data-impl:0.8.0.Beryllium]
-        // FIXME looks like a timing issue, did not occur when debugging
-
-        dataTreeModification.merge(YangInstanceIdentifier.create(getNodeId(Contexts.QNAME)), newMapping);
-
-        commitModification(dataTreeModification);
-    }
-
-    private void commitModification(final DataTreeModification dataTreeModification) {
-        try {
-            dataTreeModification.ready();
-            contextDataTree.validate(dataTreeModification);
-            contextDataTree.commit(contextDataTree.prepare(dataTreeModification));
-        } catch (DataValidationFailedException e) {
-            LOG.warn("Unable to update context: {} in context data tree", instanceName, e);
-            throw new IllegalStateException("Unable to update context in context data tree", e);
-        }
-    }
-
-    private DataTreeModification getModification() {
-        final DataTreeSnapshot dataTreeSnapshot = contextDataTree.takeSnapshot();
-        return dataTreeSnapshot.newModification();
-    }
-
-    private static YangInstanceIdentifier.NodeIdentifierWithPredicates getNodeId(@Nonnull final QName qName,
-                                                                                 @Nonnull final Map<QName, Object> keys) {
-        return new YangInstanceIdentifier.NodeIdentifierWithPredicates(qName, keys);
-    }
-
-    private static YangInstanceIdentifier.NodeIdentifier getNodeId(@Nonnull final QName qName) {
-        return new YangInstanceIdentifier.NodeIdentifier(qName);
-    }
-
-    public synchronized void addName(final int index, final String name) {
-        addMappingToDataTree(name, index);
-        super.addName(index, name);
-    }
-
-    private void addMappingToDataTree(final String name, final int index) {
-        final DataTreeModification dataTreeModification = getModification();
-
-        final YangInstanceIdentifier.NodeIdentifierWithPredicates mappingNodeId = getNodeId(Mapping.QNAME,
-            Collections.singletonMap(NAME_KEY_QNAME, name));
-
-        final List<YangInstanceIdentifier.PathArgument> pathArguments = namingContextIid.getPathArguments();
-        final ArrayList<YangInstanceIdentifier.PathArgument> newPathArgs = Lists.newArrayList(pathArguments);
-        newPathArgs.add(getNodeId(Mappings.QNAME));
-        newPathArgs.add(getNodeId(Mapping.QNAME));
-        newPathArgs.add(mappingNodeId);
-
-        final YangInstanceIdentifier identifier = YangInstanceIdentifier.create(newPathArgs);
-
-        final NormalizedNode<?, ?> newMapping = Builders.mapEntryBuilder()
-            .withNodeIdentifier(mappingNodeId)
-            .withChild(ImmutableNodes.leafNode(NAME_KEY_QNAME, name))
-            .withChild(ImmutableNodes.leafNode(INDEX_QNAME, index))
-            .build();
-
-        dataTreeModification.write(identifier, newMapping);
-
-        commitModification(dataTreeModification);
-    }
-
-    public synchronized int removeName(@Nonnull final String name) {
-        removeMappingFromDataTree(name);
-        return super.removeName(name);
-    }
-
-    private void removeMappingFromDataTree(final String name) {
-        final DataTreeModification dataTreeModification = getModification();
-
-        final YangInstanceIdentifier.NodeIdentifierWithPredicates mappingNodeId = getNodeId(Mapping.QNAME,
-            Collections.singletonMap(NAME_KEY_QNAME, name));
-
-        final YangInstanceIdentifier identifier = YangInstanceIdentifier.create(
-            namingContextIid.getLastPathArgument(), getNodeId(Mappings.QNAME), getNodeId(Mapping.QNAME), mappingNodeId);
-
-        dataTreeModification.delete(identifier);
-
-        commitModification(dataTreeModification);
-    }
-}
index 9affd06..d32f272 100644 (file)
 package io.fd.honeycomb.v3po.translate.v3po.util;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
 
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContextKey;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Naming context keeping a mapping between int index and string name.
- * Provides artificial names to unknown indices.
+ * Utility adapter on top of {@link MappingContext}
  */
-public class NamingContext implements AutoCloseable {
+public final class NamingContext implements AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(NamingContext.class);
 
-    private final BiMap<String, Integer> nameMapping = HashBiMap.create();
     private final String artificialNamePrefix;
+    private KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext, NamingContextKey>
+        namingContextIid;
 
-    public NamingContext(final String artificialNamePrefix) {
+    /**
+     * Collector expecting only a single resulting item from a stream
+     */
+    private static final Collector<Mapping, ?, Mapping> SINGLE_ITEM_COLLECTOR = Collectors.collectingAndThen(
+        Collectors.toList(),
+        list -> {
+            if (list.size() != 1) {
+                throw new IllegalStateException("Unexpected size of list: " + list + ". Single item expected");
+            }
+            return list.get(0);
+        });
+
+    public NamingContext(final String artificialNamePrefix, final String instanceName) {
         this.artificialNamePrefix = artificialNamePrefix;
+        namingContextIid = InstanceIdentifier.create(Contexts.class).child(
+            org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.class,
+            new NamingContextKey(instanceName));
     }
 
     @Nonnull
-    public synchronized String getName(final int index) {
-        if(!nameMapping.inverse().containsKey(index)) {
+    public synchronized String getName(final int index, final MappingContext mappingContext) {
+        if (!containsName(index, mappingContext)) {
             final String artificialName = getArtificialName(index);
             LOG.info("Assigning artificial name: {} for index: {}", artificialName, index);
-            addName(index, artificialName);
+            addName(index, artificialName, mappingContext);
         }
-        return nameMapping.inverse().get(index);
+
+        final Optional<Mappings> read = mappingContext.read(namingContextIid.child(Mappings.class));
+        checkState(read.isPresent(), "Mapping for index: %s is not present. But should be", index);
+
+        return read.get().getMapping().stream()
+            .filter(mapping -> mapping.getIndex().equals(index))
+            .collect(SINGLE_ITEM_COLLECTOR).getName();
+    }
+
+    public synchronized boolean containsName(final int index, final MappingContext mappingContext) {
+        final Optional<Mappings> read = mappingContext.read(namingContextIid.child(Mappings.class));
+        return read.isPresent()
+            ? read.get().getMapping().stream().anyMatch(mapping -> mapping.getIndex().equals(index))
+            : false;
     }
 
-    public synchronized boolean containsName(final int index) {
-        return nameMapping.inverse().containsKey(index);
+    public synchronized void addName(final int index, final String name, final MappingContext mappingContext) {
+        final KeyedInstanceIdentifier<Mapping, MappingKey> mappingIid = getMappingIid(name);
+        mappingContext.put(mappingIid, new MappingBuilder().setIndex(index).setName(name).build());
     }
 
-    public synchronized void addName(final int index, final String name) {
-        nameMapping.put(name, index);
+    private KeyedInstanceIdentifier<Mapping, MappingKey> getMappingIid(final String name) {
+        return namingContextIid.child(Mappings.class).child(Mapping.class, new MappingKey(name));
     }
 
-    public synchronized int removeName(final String name) {
-        return nameMapping.remove(name);
+    public synchronized void removeName(final String name, final MappingContext mappingContext) {
+        mappingContext.delete(getMappingIid(name));
     }
 
     /**
@@ -68,14 +108,15 @@ public class NamingContext implements AutoCloseable {
      * @return integer index value matching supplied name
      * @throws IllegalArgumentException if name was not found
      */
-    public synchronized int getIndex(String name) {
-        checkArgument(nameMapping.containsKey(name), "Name %s not found. Known names: %s",
-                name, nameMapping);
-        return nameMapping.get(name);
+    public synchronized int getIndex(final String name, final MappingContext mappingContext) {
+        final Optional<Mapping> read = mappingContext.read(getMappingIid(name));
+        checkArgument(read.isPresent(), "No mapping stored for name: %s", name);
+        return read.get().getIndex();
+
     }
 
-    public synchronized boolean containsIndex(String interfaceName) {
-        return nameMapping.containsKey(interfaceName);
+    public synchronized boolean containsIndex(final String name, final MappingContext mappingContext) {
+        return mappingContext.read(getMappingIid(name)).isPresent();
     }
 
     private String getArtificialName(final int index) {
@@ -84,6 +125,6 @@ public class NamingContext implements AutoCloseable {
 
     @Override
     public void close() throws Exception {
-        nameMapping.clear();
+        /// Not removing the mapping from backing storage
     }
 }
index 50b577a..60a816d 100644 (file)
@@ -1,6 +1,6 @@
 package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.util.rev160406;
 
-import io.fd.honeycomb.v3po.translate.v3po.util.DataTreeNamingContext;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
 
 public class NamingContextImplModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.util.rev160406.AbstractNamingContextImplModule {
     public NamingContextImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
@@ -18,10 +18,9 @@ public class NamingContextImplModule extends org.opendaylight.yang.gen.v1.urn.ho
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        return new DataTreeNamingContext(
+        return new NamingContext(
             getArtificialNamePrefix(),
-            getIdentifier().getInstanceName(),
-            getContextDataTreeDependency());
+            getIdentifier().getInstanceName());
     }
 
 }
index bd90384..23615d0 100644 (file)
@@ -31,15 +31,6 @@ module vpp-util {
             leaf artificial-name-prefix {
                 type string;
             }
-
-            container context-data-tree {
-                uses config:service-ref {
-                    refine type {
-                        mandatory true;
-                        config:required-identity dapi:data-tree;
-                    }
-                }
-            }
         }
     }