import org.opendaylight.restconf.nb.rfc8040.rests.services.api.RestconfStreamsSubscriptionService;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfTransaction;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.DeleteDataTransactionUtil;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.PatchDataTransactionUtil;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.PlainPatchDataTransactionUtil;
private void createAllYangNotificationStreams(final RestconfStrategy strategy,
final EffectiveModelContext schemaContext, final UriInfo uriInfo) {
- strategy.prepareReadWriteExecution();
+ final RestconfTransaction transaction = strategy.prepareWriteExecution();
final boolean exist = checkExist(schemaContext, strategy);
for (final NotificationDefinition notificationDefinition : schemaContext.getNotifications()) {
final NotificationListenerAdapter notifiStreamJSON =
CreateStreamUtil.createYangNotifiStream(notificationDefinition, schemaContext,
NotificationOutputType.JSON);
- writeNotificationStreamToDatastore(schemaContext, uriInfo, strategy, exist, notifiStreamXML);
- writeNotificationStreamToDatastore(schemaContext, uriInfo, strategy, exist, notifiStreamJSON);
+ writeNotificationStreamToDatastore(schemaContext, uriInfo, transaction, exist, notifiStreamXML);
+ writeNotificationStreamToDatastore(schemaContext, uriInfo, transaction, exist, notifiStreamJSON);
}
try {
- strategy.commit().get();
+ transaction.commit().get();
} catch (final InterruptedException | ExecutionException e) {
throw new RestconfDocumentedException("Problem while putting data to DS.", e);
}
}
private void writeNotificationStreamToDatastore(final EffectiveModelContext schemaContext,
- final UriInfo uriInfo, final RestconfStrategy strategy, final boolean exist,
+ final UriInfo uriInfo, final RestconfTransaction transaction, final boolean exist,
final NotificationListenerAdapter listener) {
final URI uri = streamUtils.prepareUriByStreamName(uriInfo, listener.getStreamName());
final NormalizedNode<?, ?> mapToStreams =
listener.getSchemaPath().lastNodeIdentifier(), schemaContext.getNotifications(), null,
listener.getOutputType(), uri, SubscribeToStreamUtil.getMonitoringModule(schemaContext), exist);
writeDataToDS(schemaContext,
- listener.getSchemaPath().lastNodeIdentifier().getLocalName(), strategy, exist, mapToStreams);
+ listener.getSchemaPath().lastNodeIdentifier().getLocalName(), transaction, exist, mapToStreams);
}
private static boolean checkExist(final EffectiveModelContext schemaContext, final RestconfStrategy strategy) {
}
private static void writeDataToDS(final EffectiveModelContext schemaContext, final String name,
- final RestconfStrategy strategy, final boolean exist,
+ final RestconfTransaction transaction, final boolean exist,
final NormalizedNode<?, ?> mapToStreams) {
final String pathId;
if (exist) {
} else {
pathId = Rfc8040.MonitoringModule.PATH_TO_STREAMS;
}
- strategy.merge(LogicalDatastoreType.OPERATIONAL, IdentifierCodec.deserialize(pathId, schemaContext),
+ transaction.merge(LogicalDatastoreType.OPERATIONAL, IdentifierCodec.deserialize(pathId, schemaContext),
mapToStreams);
}
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.common.api.ReadFailedException;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
this.outstanding = total;
}
- static BatchedExistenceCheck start(final RestconfStrategy read,
+ static BatchedExistenceCheck start(final DOMTransactionChain transactionChain,
final LogicalDatastoreType datastore, final YangInstanceIdentifier parentPath,
final Collection<? extends NormalizedNode<?, ?>> children) {
final BatchedExistenceCheck ret = new BatchedExistenceCheck(children.size());
- for (NormalizedNode<?, ?> child : children) {
- final YangInstanceIdentifier path = parentPath.node(child.getIdentifier());
- read.exists(datastore, path).addCallback(new FutureCallback<Boolean>() {
- @Override
- public void onSuccess(final Boolean result) {
- ret.complete(path, result);
- }
-
- @Override
- @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
- public void onFailure(final Throwable throwable) {
- final Exception e;
- if (throwable instanceof Exception) {
- e = (Exception) throwable;
- } else {
- e = new ExecutionException(throwable);
+ try (DOMDataTreeReadTransaction tx = transactionChain.newReadOnlyTransaction()) {
+ for (NormalizedNode<?, ?> child : children) {
+ final YangInstanceIdentifier path = parentPath.node(child.getIdentifier());
+ tx.exists(datastore, path).addCallback(new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(final Boolean result) {
+ ret.complete(path, result);
}
- ret.complete(path, ReadFailedException.MAPPER.apply(e));
- }
- }, MoreExecutors.directExecutor());
- }
+ @Override
+ @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
+ public void onFailure(final Throwable throwable) {
+ final Exception e;
+ if (throwable instanceof Exception) {
+ e = (Exception) throwable;
+ } else {
+ e = new ExecutionException(throwable);
+ }
- return ret;
+ ret.complete(path, ReadFailedException.MAPPER.apply(e));
+ }
+ }, MoreExecutors.directExecutor());
+ }
+ return ret;
+ }
}
Entry<YangInstanceIdentifier, ReadFailedException> getFailure() throws InterruptedException {
*/
package org.opendaylight.restconf.nb.rfc8040.rests.transactions;
-import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;
-import static org.opendaylight.restconf.nb.rfc8040.rests.utils.DeleteDataTransactionUtil.DELETE_TX_TYPE;
-import static org.opendaylight.restconf.nb.rfc8040.rests.utils.PostDataTransactionUtil.checkItemDoesNotExists;
import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.ListenableFuture;
-import java.util.Collection;
-import java.util.Map;
import java.util.Optional;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.common.api.ReadFailedException;
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
-import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
-import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
-import org.opendaylight.restconf.nb.rfc8040.rests.utils.DeleteDataTransactionUtil;
-import org.opendaylight.restconf.nb.rfc8040.rests.utils.TransactionUtil;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
-import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
/**
* Implementation of RESTCONF operations using {@link DOMTransactionChain} and related concepts.
*/
public final class MdsalRestconfStrategy extends RestconfStrategy {
private final DOMTransactionChain transactionChain;
- private final TransactionChainHandler transactionChainHandler;
-
- private DOMDataTreeReadWriteTransaction rwTx;
public MdsalRestconfStrategy(final DOMDataBroker dataBroker) {
this(new TransactionChainHandler(dataBroker));
}
public MdsalRestconfStrategy(final TransactionChainHandler transactionChainHandler) {
- this.transactionChainHandler = requireNonNull(transactionChainHandler);
- transactionChain = transactionChainHandler.get();
+ transactionChain = requireNonNull(transactionChainHandler).get();
}
@Override
- public void prepareReadWriteExecution() {
- rwTx = transactionChain.newReadWriteTransaction();
- }
-
- @Override
- public void cancel() {
- if (rwTx != null) {
- rwTx.cancel();
- rwTx = null;
- }
- transactionChain.close();
+ public RestconfTransaction prepareWriteExecution() {
+ return new MdsalRestconfTransaction(transactionChain);
}
@Override
public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store,
final YangInstanceIdentifier path) {
- if (rwTx != null) {
- return rwTx.read(store, path);
- } else {
- try (DOMDataTreeReadTransaction tx = transactionChain.newReadOnlyTransaction()) {
- return tx.read(store, path);
- }
+ try (DOMDataTreeReadTransaction tx = transactionChain.newReadOnlyTransaction()) {
+ return tx.read(store, path);
}
}
@Override
public FluentFuture<Boolean> exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- return rwTx.exists(store, path);
- }
-
- @Override
- public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- DeleteDataTransactionUtil.checkItemExists(this, LogicalDatastoreType.CONFIGURATION, path,
- DELETE_TX_TYPE);
- rwTx.delete(store, path);
- }
-
- @Override
- public void remove(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- rwTx.delete(store, path);
- }
-
- @Override
- public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> data) {
- rwTx.merge(store, path, data);
- }
-
- @Override
- public void create(final LogicalDatastoreType store, final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> data, final SchemaContext schemaContext) {
- if (data instanceof MapNode || data instanceof LeafSetNode) {
- final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
- merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(emptySubTree.getIdentifier()),
- emptySubTree);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, this);
-
- final Collection<? extends NormalizedNode<?, ?>> children =
- ((NormalizedNodeContainer<?, ?, ?>) data).getValue();
- final BatchedExistenceCheck check =
- BatchedExistenceCheck.start(this, LogicalDatastoreType.CONFIGURATION, path, children);
-
- for (final NormalizedNode<?, ?> child : children) {
- final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
- rwTx.put(store, childPath, child);
- }
-
- // ... finally collect existence checks and abort the transaction if any of them failed.
- checkExistence(path, check);
- } else {
- checkItemDoesNotExists(this, LogicalDatastoreType.CONFIGURATION, path);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, this);
- rwTx.put(store, path, data);
- }
- }
-
- @Override
- public void replace(final LogicalDatastoreType store, final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> data, final SchemaContext schemaContext) {
- if (data instanceof MapNode || data instanceof LeafSetNode) {
- final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
- merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(emptySubtree.getIdentifier()),
- emptySubtree);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, this);
-
- for (final NormalizedNode<?, ?> child : ((NormalizedNodeContainer<?, ?, ?>) data).getValue()) {
- final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
- rwTx.put(store, childPath, child);
- }
- } else {
- TransactionUtil.ensureParentsByMerge(path, schemaContext, this);
- rwTx.put(store, path, data);
+ try (DOMDataTreeReadTransaction tx = transactionChain.newReadOnlyTransaction()) {
+ return tx.exists(store, path);
}
}
@Override
- public FluentFuture<? extends @NonNull CommitInfo> commit() {
- final FluentFuture<? extends @NonNull CommitInfo> ret = verifyNotNull(rwTx).commit();
- rwTx = null;
- return ret;
- }
-
- @Override
- public DOMTransactionChain getTransactionChain() {
- return transactionChain;
- }
-
- @Override
- public TransactionChainHandler getTransactionChainHandler() {
- return transactionChainHandler;
- }
-
- private static void checkExistence(final YangInstanceIdentifier path, final BatchedExistenceCheck check) {
- final Map.Entry<YangInstanceIdentifier, ReadFailedException> failure;
- try {
- failure = check.getFailure();
- } catch (InterruptedException e) {
- throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
- }
-
- if (failure != null) {
- final ReadFailedException e = failure.getValue();
- if (e == null) {
- throw new RestconfDocumentedException("Data already exists",
- RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.DATA_EXISTS, failure.getKey());
- }
-
- throw new RestconfDocumentedException(
- "Could not determine the existence of path " + failure.getKey(), e, e.getErrorList());
- }
+ public void close() {
+ transactionChain.close();
}
}
--- /dev/null
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.nb.rfc8040.rests.transactions;
+
+import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
+import static org.opendaylight.restconf.nb.rfc8040.rests.utils.DeleteDataTransactionUtil.DELETE_TX_TYPE;
+import static org.opendaylight.restconf.nb.rfc8040.rests.utils.PostDataTransactionUtil.checkItemDoesNotExists;
+
+import com.google.common.util.concurrent.FluentFuture;
+import java.util.Collection;
+import java.util.Map;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.ReadFailedException;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.restconf.nb.rfc8040.rests.utils.DeleteDataTransactionUtil;
+import org.opendaylight.restconf.nb.rfc8040.rests.utils.TransactionUtil;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+final class MdsalRestconfTransaction extends RestconfTransaction {
+ private final DOMTransactionChain transactionChain;
+ private DOMDataTreeReadWriteTransaction rwTx;
+
+ MdsalRestconfTransaction(DOMTransactionChain transactionChain) {
+ this.transactionChain = requireNonNull(transactionChain);
+ this.rwTx = transactionChain.newReadWriteTransaction();
+ }
+
+ @Override
+ public void cancel() {
+ if (rwTx != null) {
+ rwTx.cancel();
+ rwTx = null;
+ }
+ transactionChain.close();
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ final FluentFuture<Boolean> isExists = verifyNotNull(rwTx).exists(store, path);
+ DeleteDataTransactionUtil.checkItemExists(isExists, path, DELETE_TX_TYPE);
+ rwTx.delete(store, path);
+ }
+
+ @Override
+ public void remove(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ verifyNotNull(rwTx).delete(store, path);
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data) {
+ verifyNotNull(rwTx).merge(store, path, data);
+ }
+
+ @Override
+ public void create(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data, final SchemaContext schemaContext) {
+ if (data instanceof MapNode || data instanceof LeafSetNode) {
+ final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
+ merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(emptySubTree.getIdentifier()),
+ emptySubTree);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, this);
+
+ final Collection<? extends NormalizedNode<?, ?>> children =
+ ((NormalizedNodeContainer<?, ?, ?>) data).getValue();
+ final BatchedExistenceCheck check =
+ BatchedExistenceCheck.start(transactionChain, LogicalDatastoreType.CONFIGURATION, path, children);
+
+ for (final NormalizedNode<?, ?> child : children) {
+ final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
+ verifyNotNull(rwTx).put(store, childPath, child);
+ }
+ // ... finally collect existence checks and abort the transaction if any of them failed.
+ checkExistence(path, check);
+ } else {
+ final FluentFuture<Boolean> isExists = verifyNotNull(rwTx).exists(store, path);
+ checkItemDoesNotExists(isExists, path);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, this);
+ verifyNotNull(rwTx).put(store, path, data);
+ }
+ }
+
+ @Override
+ public void replace(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data, final SchemaContext schemaContext) {
+ if (data instanceof MapNode || data instanceof LeafSetNode) {
+ final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
+ merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(emptySubtree.getIdentifier()),
+ emptySubtree);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, this);
+
+ for (final NormalizedNode<?, ?> child : ((NormalizedNodeContainer<?, ?, ?>) data).getValue()) {
+ final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
+ verifyNotNull(rwTx).put(store, childPath, child);
+ }
+ } else {
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, this);
+ verifyNotNull(rwTx).put(store, path, data);
+ }
+ }
+
+ @Override
+ public FluentFuture<? extends @NonNull CommitInfo> commit() {
+ final FluentFuture<? extends @NonNull CommitInfo> ret = verifyNotNull(rwTx).commit();
+ rwTx = null;
+ return ret;
+ }
+
+ private static void checkExistence(final YangInstanceIdentifier path, final BatchedExistenceCheck check) {
+ final Map.Entry<YangInstanceIdentifier, ReadFailedException> failure;
+ try {
+ failure = check.getFailure();
+ } catch (InterruptedException e) {
+ throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
+ }
+
+ if (failure != null) {
+ final ReadFailedException e = failure.getValue();
+ if (e == null) {
+ throw new RestconfDocumentedException("Data already exists",
+ RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.DATA_EXISTS, failure.getKey());
+ }
+
+ throw new RestconfDocumentedException(
+ "Could not determine the existence of path " + failure.getKey(), e, e.getErrorList());
+ }
+ }
+}
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
-import java.util.List;
import java.util.Optional;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.common.api.ReadFailedException;
-import org.opendaylight.mdsal.dom.api.DOMRpcResult;
-import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
-import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
-import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final NetconfDataTreeService netconfService;
- private List<ListenableFuture<? extends DOMRpcResult>> resultsFutures;
-
public NetconfRestconfStrategy(final NetconfDataTreeService netconfService) {
this.netconfService = requireNonNull(netconfService);
}
@Override
- public void prepareReadWriteExecution() {
- resultsFutures = netconfService.lock();
- }
-
- @Override
- public void cancel() {
- netconfService.discardChanges();
- netconfService.unlock();
+ public RestconfTransaction prepareWriteExecution() {
+ return new NetconfRestconfTransaction(netconfService);
}
@Override
}
@Override
- public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- resultsFutures.add(netconfService.delete(store, path));
- }
-
- @Override
- public void remove(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- resultsFutures.add(netconfService.remove(store, path));
- }
-
- @Override
- public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> data) {
- resultsFutures.add(netconfService.merge(store, path, data, Optional.empty()));
- }
-
- @Override
- public void create(final LogicalDatastoreType store, final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> data, final SchemaContext schemaContext) {
- if (data instanceof MapNode || data instanceof LeafSetNode) {
- final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
- merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(emptySubTree.getIdentifier()),
- emptySubTree);
-
- for (final NormalizedNode<?, ?> child : ((NormalizedNodeContainer<?, ?, ?>) data).getValue()) {
- final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
- resultsFutures.add(netconfService.create(store, childPath, child, Optional.empty()));
- }
- } else {
- resultsFutures.add(netconfService.create(store, path, data, Optional.empty()));
- }
- }
-
- @Override
- public void replace(final LogicalDatastoreType store, final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> data, final SchemaContext schemaContext) {
- if (data instanceof MapNode || data instanceof LeafSetNode) {
- final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
- merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(emptySubTree.getIdentifier()),
- emptySubTree);
-
- for (final NormalizedNode<?, ?> child : ((NormalizedNodeContainer<?, ?, ?>) data).getValue()) {
- final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
- resultsFutures.add(netconfService.replace(store, childPath, child, Optional.empty()));
- }
- } else {
- resultsFutures.add(netconfService.replace(store, path, data, Optional.empty()));
- }
- }
-
- @Override
- public FluentFuture<? extends @NonNull CommitInfo> commit() {
- return FluentFuture.from(netconfService.commit(resultsFutures));
- }
-
- /**
- * As we are not using any transactions here, always return null.
- */
- @Override
- public DOMTransactionChain getTransactionChain() {
- return null;
- }
-
- /**
- * As we are not using any transactions here, always return null.
- */
- @Override
- public TransactionChainHandler getTransactionChainHandler() {
- return null;
+ public void close() {
}
private static <T> FluentFuture<T> remapException(final ListenableFuture<T> input) {
--- /dev/null
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.nb.rfc8040.rests.transactions;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+final class NetconfRestconfTransaction extends RestconfTransaction {
+ private final NetconfDataTreeService netconfService;
+
+ private List<ListenableFuture<? extends DOMRpcResult>> resultsFutures;
+
+ NetconfRestconfTransaction(final NetconfDataTreeService netconfService) {
+ this.netconfService = requireNonNull(netconfService);
+ this.resultsFutures = netconfService.lock();
+ }
+
+ @Override
+ public void cancel() {
+ resultsFutures = null;
+ netconfService.discardChanges();
+ netconfService.unlock();
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ resultsFutures.add(netconfService.delete(store, path));
+ }
+
+ @Override
+ public void remove(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ resultsFutures.add(netconfService.remove(store, path));
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data) {
+ resultsFutures.add(netconfService.merge(store, path, data, Optional.empty()));
+ }
+
+ @Override
+ public void create(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data, final SchemaContext schemaContext) {
+ if (data instanceof MapNode || data instanceof LeafSetNode) {
+ final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
+ merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(emptySubTree.getIdentifier()),
+ emptySubTree);
+
+ for (final NormalizedNode<?, ?> child : ((NormalizedNodeContainer<?, ?, ?>) data).getValue()) {
+ final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
+ resultsFutures.add(netconfService.create(store, childPath, child, Optional.empty()));
+ }
+ } else {
+ resultsFutures.add(netconfService.create(store, path, data, Optional.empty()));
+ }
+ }
+
+ @Override
+ public void replace(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data, final SchemaContext schemaContext) {
+ if (data instanceof MapNode || data instanceof LeafSetNode) {
+ final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
+ merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(emptySubTree.getIdentifier()),
+ emptySubTree);
+
+ for (final NormalizedNode<?, ?> child : ((NormalizedNodeContainer<?, ?, ?>) data).getValue()) {
+ final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
+ resultsFutures.add(netconfService.replace(store, childPath, child, Optional.empty()));
+ }
+ } else {
+ resultsFutures.add(netconfService.replace(store, path, data, Optional.empty()));
+ }
+ }
+
+ @Override
+ public FluentFuture<? extends @NonNull CommitInfo> commit() {
+ return FluentFuture.from(netconfService.commit(resultsFutures));
+ }
+}
import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.Optional;
-import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
import org.opendaylight.mdsal.dom.api.DOMMountPoint;
-import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
-import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
/**
* Baseline execution strategy for various RESTCONF operations.
*/
// FIXME: it seems the first three operations deal with lifecycle of a transaction, while others invoke various
// operations. This should be handled through proper allocation indirection.
-public abstract class RestconfStrategy {
+public abstract class RestconfStrategy implements AutoCloseable {
RestconfStrategy() {
// Hidden on purpose
}
/**
* Lock the entire datastore.
- */
- public abstract void prepareReadWriteExecution();
-
- /**
- * Confirm previous operations.
*
- * @return a FluentFuture containing the result of the commit information
- */
- public abstract FluentFuture<? extends @NonNull CommitInfo> commit();
-
- /**
- * Rollback changes and unlock the datastore.
+ * @return A {@link RestconfTransaction}. This transaction needs to be either committed or canceled before doing
+ * anything else.
*/
- public abstract void cancel();
+ public abstract RestconfTransaction prepareWriteExecution();
/**
* Read data from the datastore.
*/
public abstract FluentFuture<Boolean> exists(LogicalDatastoreType store, YangInstanceIdentifier path);
- /**
- * Delete data from the datastore.
- *
- * @param store the logical data store which should be modified
- * @param path the data object path
- */
- public abstract void delete(LogicalDatastoreType store, YangInstanceIdentifier path);
-
- /**
- * Remove data from the datastore.
- *
- * @param store the logical data store which should be modified
- * @param path the data object path
- */
- public abstract void remove(LogicalDatastoreType store, YangInstanceIdentifier path);
-
- /**
- * Merges a piece of data with the existing data at a specified path.
- *
- * @param store the logical data store which should be modified
- * @param path the data object path
- * @param data the data object to be merged to the specified path
- */
- public abstract void merge(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data);
-
- /**
- * Stores a piece of data at the specified path.
- *
- * @param store the logical data store which should be modified
- * @param path the data object path
- * @param data the data object to be merged to the specified path
- * @param schemaContext static view of compiled yang files
- */
- public abstract void create(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data,
- SchemaContext schemaContext);
-
- /**
- * Replace a piece of data at the specified path.
- *
- * @param store the logical data store which should be modified
- * @param path the data object path
- * @param data the data object to be merged to the specified path
- * @param schemaContext static view of compiled yang files
- */
- public abstract void replace(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data,
- SchemaContext schemaContext);
-
-
- /**
- * Get transaction chain for creating specific transaction for specific operation.
- *
- * @return transaction chain or null
- */
- // FIXME: these look like an implementation detail
- public abstract @Nullable DOMTransactionChain getTransactionChain();
-
- /**
- * Get transaction chain handler for creating new transaction chain.
- *
- * @return {@link TransactionChainHandler} or null
- */
- // FIXME: these look like an implementation detail
- public abstract @Nullable TransactionChainHandler getTransactionChainHandler();
+ @Override
+ public abstract void close();
}
--- /dev/null
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.nb.rfc8040.rests.transactions;
+
+import com.google.common.annotations.Beta;
+import com.google.common.util.concurrent.FluentFuture;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * A handle to a set of operations being executed atomically on top of some backing store.
+ */
+// FIXME: it seems the first two operations deal with lifecycle of a transaction, while others invoke various
+// operations. This should be handled through proper allocation indirection.
+@Beta
+public abstract class RestconfTransaction {
+ RestconfTransaction() {
+ // Hidden on purpose
+ }
+
+ /**
+ * Rollback changes and unlock the datastore.
+ */
+ // FIXME: this looks synchronous, but it should not be
+ public abstract void cancel();
+
+ /**
+ * Confirm previous operations.
+ *
+ * @return a FluentFuture containing the result of the commit information
+ */
+ public abstract FluentFuture<? extends @NonNull CommitInfo> commit();
+
+ /**
+ * Delete data from the datastore.
+ *
+ * @param store the logical data store which should be modified
+ * @param path the data object path
+ */
+ public abstract void delete(LogicalDatastoreType store, YangInstanceIdentifier path);
+
+ /**
+ * Remove data from the datastore.
+ *
+ * @param store the logical data store which should be modified
+ * @param path the data object path
+ */
+ public abstract void remove(LogicalDatastoreType store, YangInstanceIdentifier path);
+
+ /**
+ * Merges a piece of data with the existing data at a specified path.
+ *
+ * @param store the logical data store which should be modified
+ * @param path the data object path
+ * @param data the data object to be merged to the specified path
+ */
+ public abstract void merge(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data);
+
+ /**
+ * Stores a piece of data at the specified path.
+ *
+ * @param store the logical data store which should be modified
+ * @param path the data object path
+ * @param data the data object to be merged to the specified path
+ * @param schemaContext static view of compiled yang files
+ */
+ public abstract void create(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data,
+ SchemaContext schemaContext);
+
+ /**
+ * Replace a piece of data at the specified path.
+ *
+ * @param store the logical data store which should be modified
+ * @param path the data object path
+ * @param data the data object to be merged to the specified path
+ * @param schemaContext static view of compiled yang files
+ */
+ public abstract void replace(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data,
+ SchemaContext schemaContext);
+}
import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfTransaction;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* @return {@link Response}
*/
public static Response deleteData(final RestconfStrategy strategy, final YangInstanceIdentifier path) {
- strategy.prepareReadWriteExecution();
+ final RestconfTransaction transaction = strategy.prepareWriteExecution();
try {
- strategy.delete(LogicalDatastoreType.CONFIGURATION, path);
+ transaction.delete(LogicalDatastoreType.CONFIGURATION, path);
} catch (RestconfDocumentedException e) {
// close transaction if any and pass exception further
- strategy.cancel();
+ transaction.cancel();
throw e;
}
- final FluentFuture<? extends CommitInfo> future = strategy.commit();
+ final FluentFuture<? extends CommitInfo> future = transaction.commit();
final ResponseFactory response = new ResponseFactory(Status.NO_CONTENT);
//This method will close transactionChain if any
- FutureCallbackTx.addCallback(future, DELETE_TX_TYPE, response, strategy.getTransactionChain(), path);
+ FutureCallbackTx.addCallback(future, DELETE_TX_TYPE, response, strategy, path);
return response.build();
}
* Check if items already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
* data does NOT already exists.
*
- * @param strategy Object that perform the actual DS operations
- * @param store Datastore
- * @param path Path to be checked
- * @param operationType Type of operation (READ, POST, PUT, DELETE...)
+ * @param isExistsFuture if checked data exists
+ * @param path Path to be checked
+ * @param operationType Type of operation (READ, POST, PUT, DELETE...)
*/
- public static void checkItemExists(final RestconfStrategy strategy,
- final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ public static void checkItemExists(final FluentFuture<Boolean> isExistsFuture,
+ final YangInstanceIdentifier path,
final String operationType) {
- final FluentFuture<Boolean> future = strategy.exists(store, path);
final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
- FutureCallbackTx.addCallback(future, operationType, response);
+ FutureCallbackTx.addCallback(isExistsFuture, operationType, response);
if (!response.result) {
LOG.trace("Operation via Restconf was not executed because data at {} does not exist", path);
import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
import org.opendaylight.mdsal.dom.api.DOMActionException;
import org.opendaylight.mdsal.dom.api.DOMRpcException;
-import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
import org.opendaylight.mdsal.dom.spi.SimpleDOMActionResult;
import org.opendaylight.netconf.api.DocumentedException;
import org.opendaylight.netconf.api.NetconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
* type of operation (READ, POST, PUT, DELETE)
* @param dataFactory
* factory setting result
- * @param transactionChain
- * transaction chain
+ * @param strategy Strategy for various RESTCONF operations
+ * @param path unique identifier of a particular node instance in the data tree
* @throws RestconfDocumentedException
* if the Future throws an exception
*/
// FIXME: this is a *synchronous operation* and has to die
static <T> void addCallback(final ListenableFuture<T> listenableFuture, final String txType,
final FutureDataFactory<? super T> dataFactory,
- @Nullable final DOMTransactionChain transactionChain)
+ @Nullable final RestconfStrategy strategy,
+ final YangInstanceIdentifier path)
throws RestconfDocumentedException {
- addCallback(listenableFuture, txType, dataFactory, transactionChain, null);
- }
- /**
- * Add callback to the future object and close transaction chain.
- *
- * @param listenableFuture
- * future object
- * @param txType
- * type of operation (READ, POST, PUT, DELETE)
- * @param dataFactory
- * factory setting result
- * @param transactionChain
- * transaction chain
- * @param path
- * unique identifier of a particular node instance in the data tree.
- * @throws RestconfDocumentedException
- * if the Future throws an exception
- */
- static <T> void addCallback(final ListenableFuture<T> listenableFuture, final String txType,
- final FutureDataFactory<? super T> dataFactory, @Nullable final DOMTransactionChain transactionChain,
- YangInstanceIdentifier path) throws RestconfDocumentedException {
try {
final T result = listenableFuture.get();
dataFactory.setResult(result);
throw new RestconfDocumentedException("Transaction failed", e);
}
} finally {
- if (transactionChain != null) {
- transactionChain.close();
+ if (strategy != null) {
+ strategy.close();
}
}
}
import org.opendaylight.restconf.common.patch.PatchStatusContext;
import org.opendaylight.restconf.common.patch.PatchStatusEntity;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfTransaction;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
final EffectiveModelContext schemaContext) {
final List<PatchStatusEntity> editCollection = new ArrayList<>();
boolean noError = true;
- strategy.prepareReadWriteExecution();
+ final RestconfTransaction transaction = strategy.prepareWriteExecution();
for (final PatchEntity patchEntity : context.getData()) {
if (noError) {
case CREATE:
try {
createDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(),
- schemaContext, strategy);
+ schemaContext, transaction);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
break;
case DELETE:
try {
- deleteDataWithinTransaction(patchEntity.getTargetNode(), strategy);
+ deleteDataWithinTransaction(patchEntity.getTargetNode(), transaction);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
case MERGE:
try {
mergeDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(),
- schemaContext, strategy);
+ schemaContext, transaction);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
case REPLACE:
try {
replaceDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(),
- schemaContext, strategy);
+ schemaContext, transaction);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
break;
case REMOVE:
try {
- removeDataWithinTransaction(patchEntity.getTargetNode(), strategy);
+ removeDataWithinTransaction(patchEntity.getTargetNode(), transaction);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
// if no errors then submit transaction, otherwise cancel
if (noError) {
final ResponseFactory response = new ResponseFactory(Status.OK);
- final FluentFuture<? extends CommitInfo> future = strategy.commit();
+ final FluentFuture<? extends CommitInfo> future = transaction.commit();
try {
//This method will close transactionChain if any
- FutureCallbackTx.addCallback(future, PATCH_TX_TYPE, response, strategy.getTransactionChain());
+ FutureCallbackTx.addCallback(future, PATCH_TX_TYPE, response, strategy, null);
} catch (final RestconfDocumentedException e) {
// if errors occurred during transaction commit then patch failed and global errors are reported
return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), false,
return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), true, null);
} else {
- strategy.cancel();
+ transaction.cancel();
return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
}
}
*
* @param path Path for data to be created
* @param payload Data to be created
- * @param strategy Object that perform the actual DS operations
+ * @param transaction A handle to a set of DS operations
*/
private static void createDataWithinTransaction(final YangInstanceIdentifier path,
final NormalizedNode<?, ?> payload,
final EffectiveModelContext schemaContext,
- final RestconfStrategy strategy) {
+ final RestconfTransaction transaction) {
LOG.trace("POST {} within Restconf Patch: {} with payload {}", LogicalDatastoreType.CONFIGURATION.name(),
path, payload);
- createData(payload, path, strategy, schemaContext, true);
+ transaction.create(LogicalDatastoreType.CONFIGURATION, path, payload, schemaContext);
}
/**
* Remove data within one transaction.
*
* @param path Path for data to be deleted
- * @param strategy Object that perform the actual DS operations
+ * @param transaction A handle to a set of DS operations
*/
private static void deleteDataWithinTransaction(final YangInstanceIdentifier path,
- final RestconfStrategy strategy) {
+ final RestconfTransaction transaction) {
LOG.trace("Delete {} within Restconf Patch: {}", LogicalDatastoreType.CONFIGURATION.name(), path);
- strategy.delete(LogicalDatastoreType.CONFIGURATION, path);
+ transaction.delete(LogicalDatastoreType.CONFIGURATION, path);
}
/**
*
* @param path Path for data to be merged
* @param payload Data to be merged
- * @param strategy Object that perform the actual DS operations
+ * @param transaction A handle to a set of DS operations
*/
private static void mergeDataWithinTransaction(final YangInstanceIdentifier path,
final NormalizedNode<?, ?> payload,
final EffectiveModelContext schemaContext,
- final RestconfStrategy strategy) {
+ final RestconfTransaction transaction) {
LOG.trace("Merge {} within Restconf Patch: {} with payload {}", LogicalDatastoreType.CONFIGURATION.name(),
path, payload);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
- strategy.merge(LogicalDatastoreType.CONFIGURATION, path, payload);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
+ transaction.merge(LogicalDatastoreType.CONFIGURATION, path, payload);
}
/**
* Do NOT check if data exists and remove it within one transaction.
*
* @param path Path for data to be deleted
- * @param strategy Object that perform the actual DS operations
+ * @param transaction A handle to a set of DS operations
*/
private static void removeDataWithinTransaction(final YangInstanceIdentifier path,
- final RestconfStrategy strategy) {
+ final RestconfTransaction transaction) {
LOG.trace("Remove {} within Restconf Patch: {}", LogicalDatastoreType.CONFIGURATION.name(), path);
- strategy.remove(LogicalDatastoreType.CONFIGURATION, path);
+ transaction.remove(LogicalDatastoreType.CONFIGURATION, path);
}
/**
*
* @param path Path for data to be created
* @param payload Data to be created
- * @param strategy Object that perform the actual DS operations
+ * @param transaction A handle to a set of DS operations
*/
private static void replaceDataWithinTransaction(final YangInstanceIdentifier path,
final NormalizedNode<?, ?> payload,
final EffectiveModelContext schemaContext,
- final RestconfStrategy strategy) {
+ final RestconfTransaction transaction) {
LOG.trace("PUT {} within Restconf Patch: {} with payload {}",
LogicalDatastoreType.CONFIGURATION.name(), path, payload);
- createData(payload, path, strategy, schemaContext, false);
- }
-
- /**
- * Create data within one transaction. If {@code errorIfExists} is set to {@code true} then data will be checked
- * for existence before created, otherwise they will be overwritten.
- *
- * @param data Data to be created
- * @param path Path for data to be created
- * @param strategy Object that perform the actual DS operations
- * @param errorIfExists Enable checking for existence of data (throws error if already exists)
- */
- private static void createData(final NormalizedNode<?, ?> data,
- final YangInstanceIdentifier path,
- final RestconfStrategy strategy,
- final EffectiveModelContext schemaContext,
- final boolean errorIfExists) {
- if (errorIfExists) {
- strategy.create(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
- } else {
- strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
- }
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, path, payload, schemaContext);
}
}
import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfTransaction;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
final RestconfStrategy strategy,
final EffectiveModelContext schemaContext) {
- strategy.prepareReadWriteExecution();
+ final RestconfTransaction transaction = strategy.prepareWriteExecution();
YangInstanceIdentifier path = payload.getInstanceIdentifierContext().getInstanceIdentifier();
NormalizedNode<?, ?> data = payload.getData();
try {
LOG.trace("Merge CONFIGURATION within Restconf Patch: {} with payload {}", path, data);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
- strategy.merge(LogicalDatastoreType.CONFIGURATION, path, data);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
+ transaction.merge(LogicalDatastoreType.CONFIGURATION, path, data);
} catch (final RestconfDocumentedException e) {
- strategy.cancel();
+ transaction.cancel();
throw new IllegalArgumentException(e);
}
- final FluentFuture<? extends CommitInfo> future = strategy.commit();
+ final FluentFuture<? extends CommitInfo> future = transaction.commit();
final ResponseFactory response = new ResponseFactory(Status.OK);
- FutureCallbackTx.addCallback(future, PatchDataTransactionUtil.PATCH_TX_TYPE, response,
- strategy.getTransactionChain()); // closes transactionChain if any, may throw
-
+ // closes transactionChain if any, may throw
+ FutureCallbackTx.addCallback(future, PatchDataTransactionUtil.PATCH_TX_TYPE, response, strategy, path);
return response.build();
}
}
import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfTransaction;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfDataServiceConstant.PostPutQueryParameters.Insert;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
final URI location = resolveLocation(uriInfo, path, schemaContext, payload.getData());
final ResponseFactory dataFactory = new ResponseFactory(Status.CREATED).location(location);
//This method will close transactionChain if any
- FutureCallbackTx.addCallback(future, POST_TX_TYPE, dataFactory, strategy.getTransactionChain(), path);
+ FutureCallbackTx.addCallback(future, POST_TX_TYPE, dataFactory, strategy, path);
return dataFactory.build();
}
final RestconfStrategy strategy,
final EffectiveModelContext schemaContext,
final Insert insert, final String point) {
- strategy.prepareReadWriteExecution();
+ final RestconfTransaction transaction = strategy.prepareWriteExecution();
if (insert == null) {
- makePost(path, data, schemaContext, strategy);
- return strategy.commit();
+ makePost(path, data, schemaContext, transaction);
+ return transaction.commit();
}
PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
case FIRST:
readData = PutDataTransactionUtil.readList(strategy, path.getParent().getParent());
if (readData == null || ((NormalizedNodeContainer<?, ?, ?>) readData).getValue().isEmpty()) {
- strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
- return strategy.commit();
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+ return transaction.commit();
}
- checkItemDoesNotExists(strategy, LogicalDatastoreType.CONFIGURATION, path);
- strategy.remove(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
- strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
- strategy.replace(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent(), readData,
+ checkItemDoesNotExists(strategy.exists(LogicalDatastoreType.CONFIGURATION, path), path);
+ transaction.remove(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent(), readData,
schemaContext);
- return strategy.commit();
+ return transaction.commit();
case LAST:
- makePost(path, data, schemaContext, strategy);
- return strategy.commit();
+ makePost(path, data, schemaContext, transaction);
+ return transaction.commit();
case BEFORE:
readData = PutDataTransactionUtil.readList(strategy, path.getParent().getParent());
if (readData == null || ((NormalizedNodeContainer<?, ?, ?>) readData).getValue().isEmpty()) {
- strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
- return strategy.commit();
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+ return transaction.commit();
}
- checkItemDoesNotExists(strategy, LogicalDatastoreType.CONFIGURATION, path);
+ checkItemDoesNotExists(strategy.exists(LogicalDatastoreType.CONFIGURATION, path), path);
insertWithPointPost(path, data, schemaContext, point,
- (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) readData, true, strategy);
- return strategy.commit();
+ (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) readData, true, transaction);
+ return transaction.commit();
case AFTER:
readData = PutDataTransactionUtil.readList(strategy, path.getParent().getParent());
if (readData == null || ((NormalizedNodeContainer<?, ?, ?>) readData).getValue().isEmpty()) {
- strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
- return strategy.commit();
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+ return transaction.commit();
}
- checkItemDoesNotExists(strategy, LogicalDatastoreType.CONFIGURATION, path);
+ checkItemDoesNotExists(strategy.exists(LogicalDatastoreType.CONFIGURATION, path), path);
insertWithPointPost(path, data, schemaContext, point,
- (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) readData, false, strategy);
- return strategy.commit();
+ (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) readData, false, transaction);
+ return transaction.commit();
default:
throw new RestconfDocumentedException(
"Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
final NormalizedNode<?, ?> data,
final EffectiveModelContext schemaContext, final String point,
final NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> readList,
- final boolean before, final RestconfStrategy strategy) {
+ final boolean before, final RestconfTransaction transaction) {
final YangInstanceIdentifier parent = path.getParent().getParent();
- strategy.remove(LogicalDatastoreType.CONFIGURATION, parent);
+ transaction.remove(LogicalDatastoreType.CONFIGURATION, parent);
final InstanceIdentifierContext<?> instanceIdentifier =
ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
int lastItemPosition = 0;
}
int lastInsertedPosition = 0;
final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, parent);
- strategy.merge(LogicalDatastoreType.CONFIGURATION,
+ transaction.merge(LogicalDatastoreType.CONFIGURATION,
YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
for (final NormalizedNode<?, ?> nodeChild : readList.getValue()) {
if (lastInsertedPosition == lastItemPosition) {
- strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
}
final YangInstanceIdentifier childPath = parent.node(nodeChild.getIdentifier());
- strategy.replace(LogicalDatastoreType.CONFIGURATION, childPath, nodeChild, schemaContext);
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, childPath, nodeChild, schemaContext);
lastInsertedPosition++;
}
}
private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
- final SchemaContext schemaContext, final RestconfStrategy strategy) {
+ final SchemaContext schemaContext, final RestconfTransaction transaction) {
try {
- strategy.create(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+ transaction.create(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
} catch (RestconfDocumentedException e) {
// close transaction if any and pass exception further
- strategy.cancel();
+ transaction.cancel();
throw e;
}
}
* Check if items do NOT already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
* data already exists.
*
- * @param strategy Object that perform the actual DS operations
- * @param store Datastore
- * @param path Path to be checked
+ * @param isExistsFuture if checked data exists
+ * @param path Path to be checked
*/
- public static void checkItemDoesNotExists(final RestconfStrategy strategy,
- final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- final FluentFuture<Boolean> future = strategy.exists(store, path);
+ public static void checkItemDoesNotExists(final FluentFuture<Boolean> isExistsFuture,
+ final YangInstanceIdentifier path) {
final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
-
- FutureCallbackTx.addCallback(future, POST_TX_TYPE, response);
+ FutureCallbackTx.addCallback(isExistsFuture, POST_TX_TYPE, response);
if (response.result) {
LOG.trace("Operation via Restconf was not executed because data at {} already exists", path);
import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfTransaction;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfDataServiceConstant.PostPutQueryParameters.Insert;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
import org.opendaylight.yangtools.yang.common.QName;
final RestconfStrategy strategy, final Insert insert, final String point) {
final YangInstanceIdentifier path = payload.getInstanceIdentifierContext().getInstanceIdentifier();
- strategy.prepareReadWriteExecution();
final FluentFuture<Boolean> existsFuture = strategy.exists(LogicalDatastoreType.CONFIGURATION, path);
+ final FutureDataFactory<Boolean> existsResponse = new FutureDataFactory<>();
+ FutureCallbackTx.addCallback(existsFuture, PUT_TX_TYPE, existsResponse);
+
+ final ResponseFactory responseFactory =
+ new ResponseFactory(existsResponse.result ? Status.NO_CONTENT : Status.CREATED);
final FluentFuture<? extends CommitInfo> submitData = submitData(path, schemaContext, strategy,
- payload.getData(), insert, point);
- final ResponseFactory response = new ResponseFactory();
+ payload.getData(), insert, point);
//This method will close transactionChain if any
- FutureCallbackTx.addCallback(submitData, PUT_TX_TYPE, response, strategy.getTransactionChain());
-
- final FutureDataFactory<Boolean> isExists = new FutureDataFactory<>();
- FutureCallbackTx.addCallback(existsFuture, PUT_TX_TYPE, isExists);
- return response.status(isExists.result ? Status.NO_CONTENT : Status.CREATED).build();
+ FutureCallbackTx.addCallback(submitData, PUT_TX_TYPE, responseFactory, strategy, path);
+ return responseFactory.build();
}
/**
final RestconfStrategy strategy,
final NormalizedNode<?, ?> data,
final Insert insert, final String point) {
+ final RestconfTransaction transaction = strategy.prepareWriteExecution();
if (insert == null) {
- return makePut(path, schemaContext, strategy, data);
+ return makePut(path, schemaContext, transaction, data);
}
checkListAndOrderedType(schemaContext, path);
case FIRST:
readData = readList(strategy, path.getParent());
if (readData == null || ((NormalizedNodeContainer<?, ?, ?>) readData).getValue().isEmpty()) {
- return makePut(path, schemaContext, strategy, data);
+ return makePut(path, schemaContext, transaction, data);
}
- strategy.remove(LogicalDatastoreType.CONFIGURATION, path.getParent());
- strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
- strategy.replace(LogicalDatastoreType.CONFIGURATION, path.getParent(), readData, schemaContext);
- return strategy.commit();
+ transaction.remove(LogicalDatastoreType.CONFIGURATION, path.getParent());
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, path.getParent(), readData, schemaContext);
+ return transaction.commit();
case LAST:
- return makePut(path, schemaContext, strategy, data);
+ return makePut(path, schemaContext, transaction, data);
case BEFORE:
readData = readList(strategy, path.getParent());
if (readData == null || ((NormalizedNodeContainer<?, ?, ?>) readData).getValue().isEmpty()) {
- return makePut(path, schemaContext, strategy, data);
+ return makePut(path, schemaContext, transaction, data);
}
- insertWithPointPut(strategy, path, data, schemaContext, point,
+ insertWithPointPut(transaction, path, data, schemaContext, point,
(NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) readData, true);
- return strategy.commit();
+ return transaction.commit();
case AFTER:
readData = readList(strategy, path.getParent());
if (readData == null || ((NormalizedNodeContainer<?, ?, ?>) readData).getValue().isEmpty()) {
- return makePut(path, schemaContext, strategy, data);
+ return makePut(path, schemaContext, transaction, data);
}
- insertWithPointPut(strategy, path, data, schemaContext, point,
+ insertWithPointPut(transaction, path, data, schemaContext, point,
(NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) readData, false);
- return strategy.commit();
+ return transaction.commit();
default:
throw new RestconfDocumentedException(
"Used bad value of insert parameter. Possible values are first, last, before or after, "
path,false);
}
- private static void insertWithPointPut(final RestconfStrategy strategy,
+ private static void insertWithPointPut(final RestconfTransaction transaction,
final YangInstanceIdentifier path,
final NormalizedNode<?, ?> data,
final EffectiveModelContext schemaContext, final String point,
final NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> readList,
final boolean before) {
- strategy.remove(LogicalDatastoreType.CONFIGURATION, path.getParent());
+ transaction.remove(LogicalDatastoreType.CONFIGURATION, path.getParent());
final InstanceIdentifierContext<?> instanceIdentifier =
ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
int lastItemPosition = 0;
}
int lastInsertedPosition = 0;
final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
- strategy.merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(emptySubtree.getIdentifier()),
+ transaction.merge(LogicalDatastoreType.CONFIGURATION,
+ YangInstanceIdentifier.create(emptySubtree.getIdentifier()),
emptySubtree);
for (final NormalizedNode<?, ?> nodeChild : readList.getValue()) {
if (lastInsertedPosition == lastItemPosition) {
- strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
}
final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
- strategy.replace(LogicalDatastoreType.CONFIGURATION, childPath, nodeChild, schemaContext);
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, childPath, nodeChild, schemaContext);
lastInsertedPosition++;
}
}
private static FluentFuture<? extends CommitInfo> makePut(final YangInstanceIdentifier path,
final SchemaContext schemaContext,
- final RestconfStrategy strategy,
+ final RestconfTransaction transaction,
final NormalizedNode<?, ?> data) {
- strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
- return strategy.commit();
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext);
+ return transaction.commit();
}
public static DataSchemaNode checkListAndOrderedType(final EffectiveModelContext ctx,
case RestconfDataServiceConstant.ReadData.ALL:
return readAllData(strategy, path, withDefa, ctx);
default:
- strategy.cancel();
+ strategy.close();
throw new RestconfDocumentedException(
new RestconfError(RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.INVALID_VALUE,
"Invalid content parameter: " + valueOfContent, null,
final ListenableFuture<Optional<NormalizedNode<?, ?>>> listenableFuture = strategy.read(store, path);
if (closeTransactionChain) {
//Method close transactionChain if any
- FutureCallbackTx.addCallback(listenableFuture, READ_TYPE_TX, dataFactory, strategy.getTransactionChain());
+ FutureCallbackTx.addCallback(listenableFuture, READ_TYPE_TX, dataFactory, strategy, path);
} else {
FutureCallbackTx.addCallback(listenableFuture, READ_TYPE_TX, dataFactory);
}
import java.util.Iterator;
import java.util.List;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfTransaction;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
*
* @param path path of data
* @param schemaContext {@link SchemaContext}
- * @param strategy object that perform the actual DS operations
+ * @param transaction A handle to a set of DS operations
*/
// FIXME: this method should only be invoked in MdsalRestconfStrategy, and even then only if we are crossing
// an implicit list.
public static void ensureParentsByMerge(final YangInstanceIdentifier path, final SchemaContext schemaContext,
- final RestconfStrategy strategy) {
+ final RestconfTransaction transaction) {
final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
YangInstanceIdentifier rootNormalizedPath = null;
final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
- strategy.merge(LogicalDatastoreType.CONFIGURATION, rootNormalizedPath, parentStructure);
+ transaction.merge(LogicalDatastoreType.CONFIGURATION, rootNormalizedPath, parentStructure);
}
}
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMMountPoint;
import org.opendaylight.mdsal.dom.api.DOMMountPointService;
import org.opendaylight.mdsal.dom.api.DOMNotificationService;
@Mock
private DOMDataTreeReadTransaction mockReadOnlyTx;
+ @Mock
+ private DOMDataTreeWriteTransaction mockWriteTx;
+
@Mock
private DOMMountPointService mockMountPointService;
doReturn(immediateFluentFuture(Optional.empty())).when(mockReadOnlyTx).read(
eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class));
-
doNothing().when(mockReadWriteTx).put(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class),
any(NormalizedNode.class));
doReturn(CommitInfo.emptyFluentFuture()).when(mockReadWriteTx).commit();
- doReturn(immediateFalseFluentFuture()).when(mockReadWriteTx).exists(
+ doReturn(immediateFalseFluentFuture()).when(mockReadOnlyTx).exists(
eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class));
-
+ doReturn(immediateFalseFluentFuture()).when(mockReadWriteTx).exists(
+ eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class));
doReturn(mockReadOnlyTx).when(mockTxChain).newReadOnlyTransaction();
doReturn(mockReadWriteTx).when(mockTxChain).newReadWriteTransaction();
-
doReturn(mockTxChain).when(mockDOMDataBroker).createTransactionChain(any());
final TransactionChainHandler txChainHandler = new TransactionChainHandler(mockDOMDataBroker);
verifyLeafNode(actualNode, TEST_LF12_QNAME, "lf12 data");
}
+ @Test
public void testPutFailure() throws IOException {
doReturn(immediateFailedFluentFuture(new TransactionCommitFailedException("mock")))
.when(mockReadWriteTx).commit();
doReturn(Optional.of(mockDOMDataBroker)).when(mockMountPoint).getService(DOMDataBroker.class);
doReturn(Optional.empty()).when(mockMountPoint).getService(NetconfDataTreeService.class);
-
doReturn(Optional.of(mockMountPoint)).when(mockMountPointService).getMountPoint(notNull());
return mockMountPoint;
new InstanceIdentifierContext<>(this.iidBase, this.schemaNode, null, this.contextRef);
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
- doReturn(immediateTrueFluentFuture()).when(this.readWrite)
+ doReturn(immediateTrueFluentFuture()).when(this.read)
.exists(LogicalDatastoreType.CONFIGURATION, this.iidBase);
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, this.iidBase, payload.getData());
final Response response = this.dataService.putData(null, payload, this.uriInfo);
new InstanceIdentifierContext<>(this.iidBase, this.schemaNode, mountPoint, this.contextRef);
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
- doReturn(immediateTrueFluentFuture()).when(this.readWrite)
+ doReturn(immediateTrueFluentFuture()).when(this.read)
.exists(LogicalDatastoreType.CONFIGURATION, this.iidBase);
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, this.iidBase, payload.getData());
final Response response = this.dataService.putData(null, payload, this.uriInfo);
final YangInstanceIdentifier node =
payload.getInstanceIdentifierContext().getInstanceIdentifier().node(identifier);
doReturn(immediateFalseFluentFuture())
- .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
+ .when(this.read).exists(LogicalDatastoreType.CONFIGURATION, node);
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, node, entryNode);
doReturn(UriBuilder.fromUri("http://localhost:8181/restconf/15/")).when(this.uriInfo).getBaseUriBuilder();
}
@Test
- public void testPatchData() throws Exception {
+ public void testPatchData() {
final InstanceIdentifierContext<? extends SchemaNode> iidContext =
new InstanceIdentifierContext<>(this.iidBase, this.schemaNode, null, this.contextRef);
final List<PatchEntity> entity = new ArrayList<>();
}
@Test
- public void testPatchDataDeleteNotExist() throws Exception {
+ public void testPatchDataDeleteNotExist() {
final InstanceIdentifierContext<? extends SchemaNode> iidContext =
new InstanceIdentifierContext<>(this.iidBase, this.schemaNode, null, this.contextRef);
final List<PatchEntity> entity = new ArrayList<>();
@Test
public void deleteData() {
// assert that data to delete exists
- Mockito.when(this.transactionChain.newReadWriteTransaction().exists(LogicalDatastoreType.CONFIGURATION,
- YangInstanceIdentifier.empty())).thenReturn(immediateTrueFluentFuture());
+ Mockito.when(readWrite.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.empty()))
+ .thenReturn(immediateTrueFluentFuture());
// test
delete(new MdsalRestconfStrategy(transactionChainHandler));
delete(new NetconfRestconfStrategy(netconfService));
@Test
public void deleteDataNegativeTest() {
// assert that data to delete does NOT exist
- Mockito.when(this.transactionChain.newReadWriteTransaction().exists(LogicalDatastoreType.CONFIGURATION,
- YangInstanceIdentifier.empty())).thenReturn(immediateFalseFluentFuture());
+ Mockito.when(readWrite.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.empty()))
+ .thenReturn(immediateFalseFluentFuture());
final NetconfDocumentedException exception = new NetconfDocumentedException("id",
DocumentedException.ErrorType.RPC, DocumentedException.ErrorTag.from("data-missing"),
DocumentedException.ErrorSeverity.ERROR);
import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
-import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
}
@Test
- public void testPostListData() throws UnsupportedEncodingException {
+ public void testPostListData() {
final InstanceIdentifierContext<? extends SchemaNode> iidContext =
new InstanceIdentifierContext<>(this.iidList, null, null, this.schema);
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildList);
final NodeIdentifierWithPredicates identifier = entryNode.getIdentifier();
final YangInstanceIdentifier node =
payload.getInstanceIdentifierContext().getInstanceIdentifier().node(identifier);
- doReturn(immediateFalseFluentFuture()).when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
+ doReturn(read).when(this.transactionChain).newReadOnlyTransaction();
+ doReturn(immediateFalseFluentFuture()).when(this.read).exists(LogicalDatastoreType.CONFIGURATION, node);
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, node, entryNode);
doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
assertEquals(201, response.getStatus());
assertThat(URLDecoder.decode(response.getLocation().toString(), StandardCharsets.UTF_8),
containsString(identifier.getValue(identifier.keySet().iterator().next()).toString()));
- verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
+ verify(this.read).exists(LogicalDatastoreType.CONFIGURATION, node);
verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, node, entryNode);
response = PostDataTransactionUtil.postData(this.uriInfo, payload,
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
doReturn(this.readWrite).when(this.transactionChain).newReadWriteTransaction();
+ doReturn(this.read).when(this.transactionChain).newReadOnlyTransaction();
doReturn(immediateFalseFluentFuture())
- .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
+ .when(this.read).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
PutDataTransactionUtil.putData(payload, this.schema, new MdsalRestconfStrategy(transactionChainHandler),
null, null);
- verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION,
+ verify(this.read).exists(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier());
verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
doReturn(this.readWrite).when(this.transactionChain).newReadWriteTransaction();
+ doReturn(this.read).when(this.transactionChain).newReadOnlyTransaction();
doReturn(immediateFalseFluentFuture())
- .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid);
+ .when(this.read).exists(LogicalDatastoreType.CONFIGURATION, this.iid);
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
PutDataTransactionUtil.putData(payload, this.schema, new MdsalRestconfStrategy(transactionChainHandler),
null, null);
- verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION,
+ verify(this.read).exists(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier());
verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseContWithList);
doReturn(this.readWrite).when(this.transactionChain).newReadWriteTransaction();
+ doReturn(this.read).when(this.transactionChain).newReadOnlyTransaction();
doReturn(immediateFalseFluentFuture())
- .when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
+ .when(this.read).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
PutDataTransactionUtil.putData(payload, this.schema, new MdsalRestconfStrategy(transactionChainHandler),
null, null);
- verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
+ verify(this.read).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, this.iid2, payload.getData());
}