summaryrefslogtreecommitdiffstats
path: root/v3po/data-impl
diff options
context:
space:
mode:
authorMaros Marsalek <mmarsale@cisco.com>2016-05-17 09:10:39 +0200
committerMaros Marsalek <mmarsale@cisco.com>2016-05-23 09:24:12 +0000
commitd54ea758da8dcf71d52727c4f01f87090c50bf2e (patch)
treebf86e49ad4899b50c97654ae144d4b2e8902d1b8 /v3po/data-impl
parent9e59a344c5a5b81fb7b7292184e849ad0fc9507c (diff)
HONEYCOMB-61: Add BA broker for context data tree
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 <mmarsale@cisco.com>
Diffstat (limited to 'v3po/data-impl')
-rw-r--r--v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTree.java173
-rw-r--r--v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java134
-rw-r--r--v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java1
-rw-r--r--v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java174
-rw-r--r--v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java122
-rw-r--r--v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java4
-rw-r--r--v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java68
-rw-r--r--v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java (renamed from v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTree.java)73
-rw-r--r--v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java103
-rw-r--r--v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java37
-rw-r--r--v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java14
-rw-r--r--v3po/data-impl/src/main/yang/data-impl.yang17
-rw-r--r--v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java20
-rw-r--r--v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java (renamed from v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTreeTest.java)77
-rw-r--r--v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java10
-rw-r--r--v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegatorTest.java (renamed from v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTreeTest.java)14
-rw-r--r--v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java30
17 files changed, 716 insertions, 355 deletions
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
index 1e118ff2a..000000000
--- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTree.java
+++ /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();
- }
- }
-}
-
-
-
diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java
index a0b585143..c418ed332 100644
--- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java
+++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java
@@ -16,10 +16,13 @@
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());
+ }
+ }
}
diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java
index de83a198b..5833459ea 100644
--- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java
+++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java
@@ -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
index 000000000..2b9010747
--- /dev/null
+++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java
@@ -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
index 000000000..1082c479b
--- /dev/null
+++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java
@@ -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;
+ }
+ }
+}
+
+
+
diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java
index 25d1d8dda..a54b7f148 100644
--- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java
+++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java
@@ -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);
diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java
index 83c9e30bd..c38fa27ca 100644
--- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java
+++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java
@@ -16,14 +16,16 @@
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
diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTree.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java
index 175f22d34..e660ee429 100644
--- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTree.java
+++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java
@@ -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();
}
}
diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java
index fbeba7e07..3644a9fe7 100644
--- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java
+++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java
@@ -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));
+ }
}
diff --git a/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java b/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java
index 86a3f9db4..3e871e09a 100644
--- a/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java
+++ b/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java
@@ -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);
}
}
}
diff --git a/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java b/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java
index 2fbba75fa..286eaf664 100644
--- a/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java
+++ b/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java
@@ -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;
}
diff --git a/v3po/data-impl/src/main/yang/data-impl.yang b/v3po/data-impl/src/main/yang/data-impl.yang
index 454e99a66..3af9d8d3f 100644
--- a/v3po/data-impl/src/main/yang/data-impl.yang
+++ b/v3po/data-impl/src/main/yang/data-impl.yang
@@ -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
diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java
index a2908d591..55b92b50b 100644
--- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java
+++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java
@@ -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
diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTreeTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java
index b7f8b9d2c..fed32da8a 100644
--- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTreeTest.java
+++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java
@@ -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();
diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java
index 30fdd1392..a13621725 100644
--- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java
+++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java
@@ -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
diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTreeTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegatorTest.java
index 7e6abcdcd..4492c70a2 100644
--- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTreeTest.java
+++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegatorTest.java
@@ -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
diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java
index d0360dbd8..9cde27d2b 100644
--- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java
+++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java
@@ -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();