Service provided by netconf mountpoints. It provides an api for all netconf operations, instead of mapping mdsal api to netconf requests. Restconf now uses the new NetconfDataTreeService when available. If no - fall back to DOMDataBroker.
JIRA: NETCONF-312
Signed-off-by: Vladyslav Marchenko <vladyslav.marchenko@pantheon.tech>
Change-Id: I354449883b54c8a3a4e7ffdc12d7d532c8120b6a
<artifactId>netconf-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-dom-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-auth</artifactId>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-parent</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+ <relativePath>../../parent</relativePath>
+ </parent>
+
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-dom-api</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+ <name>${project.artifactId}</name>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-dom-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-api</artifactId>
+ </dependency>
+ </dependencies>
+</project>
--- /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.netconf.dom.api;
+
+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.mdsal.dom.api.DOMService;
+import org.opendaylight.netconf.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Interface for base and additional operations for netconf (e.g. get, get-config, edit-config, (un)lock, commit etc).
+ * <edit-config> operation is extended according it's attributes (merge, replace, create, delete, remove).
+ * According to RFC-6241.
+ */
+public interface NetconfDataTreeService extends DOMService {
+
+ /**
+ * The <lock> operation.
+ * Allows the client to lock the entire configuration datastore system of a device.
+ *
+ * @return result of <lock> operation
+ */
+ List<ListenableFuture<? extends DOMRpcResult>> lock();
+
+ /**
+ * The <unlock> operation.
+ * Used to release a configuration lock, previously obtained with the <lock> operation.
+ */
+ void unlock();
+
+ /**
+ * The <discard-changes> operation.
+ * If device supports :candidate capability, discards any uncommitted changes by resetting
+ * the candidate configuration with the content of the running configuration.
+ */
+ void discardChanges();
+
+ /**
+ * The <get> operation.
+ * Retrieve running configuration and device state information.
+ *
+ * @return result of <get> operation
+ */
+ ListenableFuture<Optional<NormalizedNode<?, ?>>> get(YangInstanceIdentifier path);
+
+ /**
+ * The <get-config> operation.
+ * Retrieve all or part of a specified configuration datastore.
+ *
+ * @return result of <get-config> operation
+ */
+ ListenableFuture<Optional<NormalizedNode<?, ?>>> getConfig(YangInstanceIdentifier path);
+
+ /**
+ * The <edit-config> operation with "merge" attribute.
+ * The configuration data identified by the element containing this attribute is merged with the configuration
+ * at the corresponding level in the configuration datastore.
+ *
+ * @return result of <edit-config> operation
+ */
+ ListenableFuture<? extends DOMRpcResult> merge(LogicalDatastoreType store, YangInstanceIdentifier path,
+ NormalizedNode<?, ?> data,
+ Optional<ModifyAction> defaultOperation);
+
+ /**
+ * The <edit-config> operation with "replace" attribute.
+ * The configuration data identified by the element containing this attribute replaces any related configuration
+ * in the configuration datastore.
+ *
+ * @return result of <edit-config> operation
+ */
+ ListenableFuture<? extends DOMRpcResult> replace(LogicalDatastoreType store, YangInstanceIdentifier path,
+ NormalizedNode<?, ?> data,
+ Optional<ModifyAction> defaultOperation);
+
+ /**
+ * The <edit-config> operation with "create" attribute.
+ * The configuration data identified by the element containing this attribute is added to the configuration if
+ * and only if the configuration data does not already exist in the configuration datastore.
+ *
+ * @return result of <edit-config> operation
+ */
+ ListenableFuture<? extends DOMRpcResult> create(LogicalDatastoreType store, YangInstanceIdentifier path,
+ NormalizedNode<?, ?> data,
+ Optional<ModifyAction> defaultOperation);
+
+ /**
+ * The <edit-config> operation with "create" attribute.
+ * The configuration data identified by the element containing this attribute is deleted from the configuration
+ * if and only if the configuration data currently exists in the configuration datastore.
+ *
+ * @return result of <edit-config> operation
+ */
+ ListenableFuture<? extends DOMRpcResult> delete(LogicalDatastoreType store, YangInstanceIdentifier path);
+
+ /**
+ * The <edit-config> operation with "create" attribute.
+ * The configuration data identified by the element containing this attribute is deleted from the configuration
+ * if the configuration data currently exists in the configuration datastore.
+ *
+ * @return result of <edit-config> operation
+ */
+ ListenableFuture<? extends DOMRpcResult> remove(LogicalDatastoreType store, YangInstanceIdentifier path);
+
+ /**
+ * The <commit> operation.
+ * If device supports :candidate capability, commit the candidate configuration as the device's
+ * new current configuration.
+ *
+ * @return result of <commit> operation
+ */
+ ListenableFuture<? extends CommitInfo> commit(List<ListenableFuture<? extends DOMRpcResult>> resultsFutures);
+
+ /**
+ * Return device identifier.
+ *
+ * @return Device's identifier, must not be null.
+ */
+ @NonNull Object getDeviceId();
+}
\ No newline at end of file
final ProxyDOMDataBroker proxyDataBroker = new ProxyDOMDataBroker(id, masterActorRef, actorSystem.dispatcher(),
actorResponseWaitTime);
salProvider.getMountInstance().onTopologyDeviceConnected(currentMountContext.getEffectiveModelContext(),
- proxyDataBroker, deviceRpc, notificationService, deviceAction);
+ proxyDataBroker, null, deviceRpc, notificationService, deviceAction);
}
protected DOMDataBroker newDeviceDataBroker() {
actorSystem.dispatcher(), actorResponseWaitTime);
salProvider.getMountInstance().onTopologyDeviceConnected(remoteSchemaContext, netconfDeviceDataBroker,
- deviceRpc, notificationService, deviceAction);
+ null, deviceRpc, notificationService, deviceAction);
LOG.info("{}: Slave mount point registered.", id);
}
<modules>
<module>netconf-api</module>
+ <module>netconf-dom-api</module>
<module>netconf-config</module>
<module>netconf-impl</module>
<module>mdsal-netconf-ssh</module>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-binding-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-dom-api</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-binding-runtime-spi</artifactId>
import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
import org.opendaylight.mdsal.binding.api.DataTreeModification;
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev190614.netconf.node.fields.optional.topology.node.DatastoreLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger LOG = LoggerFactory.getLogger(LockChangeListener.class);
private final NetconfDeviceDataBroker netconfDeviceDataBroker;
+ private final NetconfDataTreeServiceImpl netconfDataTreeService;
- LockChangeListener(final DOMDataBroker netconfDeviceDataBrokder) {
+ LockChangeListener(final DOMDataBroker netconfDeviceDataBrokder,
+ final NetconfDataTreeService netconfDataTreeService) {
this.netconfDeviceDataBroker = (NetconfDeviceDataBroker)netconfDeviceDataBrokder;
+ this.netconfDataTreeService = (NetconfDataTreeServiceImpl) netconfDataTreeService;
}
@Override
+ "the data store may interfere with data consistency.");
}
netconfDeviceDataBroker.setLockAllowed(rootNode.getDataAfter().isDatastoreLockAllowed());
+ netconfDataTreeService.setLockAllowed(rootNode.getDataAfter().isDatastoreLockAllowed());
break;
case DELETE:
netconfDeviceDataBroker.setLockAllowed(true);
+ netconfDataTreeService.setLockAllowed(true);
break;
default:
LOG.debug("Unsupported modification type: {}.", rootNode.getModificationType());
--- /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.netconf.sal.connect.netconf.sal;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.SettableFuture;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.netconf.api.DocumentedException;
+import org.opendaylight.netconf.api.ModifyAction;
+import org.opendaylight.netconf.api.NetconfDocumentedException;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps;
+import org.opendaylight.netconf.sal.connect.netconf.util.NetconfRpcFutureCallback;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfDataTreeServiceImpl implements NetconfDataTreeService {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfDataTreeServiceImpl.class);
+
+ private final RemoteDeviceId id;
+ private final NetconfBaseOps netconfOps;
+ private final boolean rollbackSupport;
+ private final boolean candidateSupported;
+ private final boolean runningWritable;
+
+ private boolean isLockAllowed = true;
+
+ public NetconfDataTreeServiceImpl(final RemoteDeviceId id, final MountPointContext mountContext,
+ final DOMRpcService rpc,
+ final NetconfSessionPreferences netconfSessionPreferences) {
+ this.id = id;
+ this.netconfOps = new NetconfBaseOps(rpc, mountContext);
+ // get specific attributes from netconf preferences and get rid of it
+ // no need to keep the entire preferences object, its quite big with all the capability QNames
+ candidateSupported = netconfSessionPreferences.isCandidateSupported();
+ runningWritable = netconfSessionPreferences.isRunningWritable();
+ rollbackSupport = netconfSessionPreferences.isRollbackSupported();
+ Preconditions.checkArgument(candidateSupported || runningWritable,
+ "Device %s has advertised neither :writable-running nor :candidate capability."
+ + "At least one of these should be advertised. Failed to establish a session.", id.getName());
+ }
+
+ @Override
+ public synchronized List<ListenableFuture<? extends DOMRpcResult>> lock() {
+ final List<ListenableFuture<? extends DOMRpcResult>> resultsFutures = new ArrayList<>();
+ if (candidateSupported) {
+ lockCandidate(resultsFutures);
+ if (runningWritable) {
+ lockRunning(resultsFutures);
+ }
+ } else {
+ lockRunning(resultsFutures);
+ }
+ return resultsFutures;
+ }
+
+ @Override
+ public synchronized void unlock() {
+ if (candidateSupported) {
+ unlockCandidate();
+ if (runningWritable) {
+ unlockRunning();
+ }
+ } else {
+ unlockRunning();
+ }
+ }
+
+ /**
+ * This has to be non blocking since it is called from a callback on commit
+ * and its netty threadpool that is really sensitive to blocking calls.
+ */
+ @Override
+ public void discardChanges() {
+ if (candidateSupported) {
+ netconfOps.discardChanges(new NetconfRpcFutureCallback("Discarding candidate", id));
+ }
+ }
+
+ @Override
+ public ListenableFuture<Optional<NormalizedNode<?, ?>>> get(YangInstanceIdentifier path) {
+ return netconfOps.getData(new NetconfRpcFutureCallback("Data read", id), Optional.ofNullable(path));
+ }
+
+ @Override
+ public ListenableFuture<Optional<NormalizedNode<?, ?>>> getConfig(final YangInstanceIdentifier path) {
+ return netconfOps.getConfigRunningData(
+ new NetconfRpcFutureCallback("Data read", id), Optional.ofNullable(path));
+ }
+
+ @Override
+ public synchronized ListenableFuture<? extends DOMRpcResult> merge(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data,
+ final Optional<ModifyAction> defaultOperation) {
+ checkEditable(store);
+ final DataContainerChild<?, ?> editStructure = netconfOps.createEditConfigStrcture(Optional.ofNullable(data),
+ Optional.of(ModifyAction.MERGE), path);
+
+ return editConfig(defaultOperation, editStructure);
+ }
+
+ @Override
+ public synchronized ListenableFuture<? extends DOMRpcResult> replace(
+ final LogicalDatastoreType store,
+ final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data,
+ final Optional<ModifyAction> defaultOperation) {
+ checkEditable(store);
+ final DataContainerChild<?, ?> editStructure = netconfOps.createEditConfigStrcture(Optional.ofNullable(data),
+ Optional.of(ModifyAction.REPLACE), path);
+
+ return editConfig(defaultOperation, editStructure);
+ }
+
+ @Override
+ public synchronized ListenableFuture<? extends DOMRpcResult> create(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data,
+ final Optional<ModifyAction> defaultOperation) {
+ checkEditable(store);
+ final DataContainerChild<?, ?> editStructure = netconfOps.createEditConfigStrcture(Optional.ofNullable(data),
+ Optional.of(ModifyAction.CREATE), path);
+
+ return editConfig(defaultOperation, editStructure);
+ }
+
+ @Override
+ public synchronized ListenableFuture<? extends DOMRpcResult> delete(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+ final DataContainerChild<?, ?> editStructure = netconfOps.createEditConfigStrcture(Optional.empty(),
+ Optional.of(ModifyAction.DELETE), path);
+
+ return editConfig(Optional.empty(), editStructure);
+ }
+
+ @Override
+ public synchronized ListenableFuture<? extends DOMRpcResult> remove(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+ final DataContainerChild<?, ?> editStructure = netconfOps.createEditConfigStrcture(Optional.empty(),
+ Optional.of(ModifyAction.REMOVE), path);
+
+ return editConfig(Optional.empty(), editStructure);
+ }
+
+ @Override
+ public ListenableFuture<? extends CommitInfo> commit(
+ List<ListenableFuture<? extends DOMRpcResult>> resultsFutures) {
+ final SettableFuture<CommitInfo> resultFuture = SettableFuture.create();
+ Futures.addCallback(performCommit(resultsFutures), new FutureCallback<>() {
+ @Override
+ public void onSuccess(final RpcResult<Void> result) {
+ if (!result.isSuccessful()) {
+ final Collection<RpcError> errors = result.getErrors();
+ resultFuture.setException(new TransactionCommitFailedException(
+ String.format("Commit of transaction %s failed", this),
+ errors.toArray(new RpcError[errors.size()])));
+ return;
+ }
+ resultFuture.set(CommitInfo.empty());
+ }
+
+ @Override
+ public void onFailure(final Throwable failure) {
+ resultFuture.setException(new TransactionCommitFailedException(
+ String.format("Commit of transaction %s failed", this), failure));
+ }
+ }, MoreExecutors.directExecutor());
+ return resultFuture;
+ }
+
+ @Override
+ public Object getDeviceId() {
+ return id;
+ }
+
+ void setLockAllowed(final boolean isLockAllowedOrig) {
+ this.isLockAllowed = isLockAllowedOrig;
+ }
+
+ private ListenableFuture<? extends DOMRpcResult> editConfig(final Optional<ModifyAction> defaultOperation,
+ final DataContainerChild<?, ?> editStructure) {
+ if (candidateSupported) {
+ return editConfigCandidate(defaultOperation, editStructure);
+ } else {
+ return editConfigRunning(defaultOperation, editStructure);
+ }
+ }
+
+ private ListenableFuture<? extends DOMRpcResult> editConfigRunning(final Optional<ModifyAction> defaultOperation,
+ final DataContainerChild<?, ?> editStructure) {
+ final NetconfRpcFutureCallback callback = new NetconfRpcFutureCallback("Edit running", id);
+ if (defaultOperation.isPresent()) {
+ return netconfOps.editConfigRunning(callback, editStructure, defaultOperation.get(), rollbackSupport);
+ } else {
+ return netconfOps.editConfigRunning(callback, editStructure, rollbackSupport);
+ }
+ }
+
+ private ListenableFuture<? extends DOMRpcResult> editConfigCandidate(final Optional<ModifyAction> defaultOperation,
+ final DataContainerChild<?, ?> editStructure) {
+ final NetconfRpcFutureCallback callback = new NetconfRpcFutureCallback("Edit candidate", id);
+ if (defaultOperation.isPresent()) {
+ return netconfOps.editConfigCandidate(callback, editStructure, defaultOperation.get(), rollbackSupport);
+ } else {
+ return netconfOps.editConfigCandidate(callback, editStructure, rollbackSupport);
+ }
+ }
+
+ private void lockRunning(List<ListenableFuture<? extends DOMRpcResult>> resultsFutures) {
+ if (isLockAllowed) {
+ resultsFutures.add(netconfOps.lockRunning(new NetconfRpcFutureCallback("Lock running", id)));
+ } else {
+ LOG.trace("Lock is not allowed: {}", id);
+ }
+ }
+
+ private void unlockRunning() {
+ if (isLockAllowed) {
+ netconfOps.unlockRunning(new NetconfRpcFutureCallback("Unlock running", id));
+ } else {
+ LOG.trace("Unlock is not allowed: {}", id);
+ }
+ }
+
+ private void lockCandidate(List<ListenableFuture<? extends DOMRpcResult>> resultsFutures) {
+ if (isLockAllowed) {
+ resultsFutures.add(netconfOps.lockCandidate(new NetconfRpcFutureCallback("Lock candidate", id) {
+ @Override
+ public void onFailure(Throwable throwable) {
+ super.onFailure(throwable);
+ discardChanges();
+ }
+ }));
+ } else {
+ LOG.trace("Lock is not allowed: {}", id);
+ }
+ }
+
+ private void unlockCandidate() {
+ if (isLockAllowed) {
+ netconfOps.unlockCandidate(new NetconfRpcFutureCallback("Unlock candidate", id));
+ } else {
+ LOG.trace("Unlock is not allowed: {}", id);
+ }
+ }
+
+ private void checkEditable(final LogicalDatastoreType store) {
+ checkArgument(store == LogicalDatastoreType.CONFIGURATION,
+ "Can edit only configuration data, not %s", store);
+ }
+
+ private synchronized ListenableFuture<RpcResult<Void>> performCommit(
+ final List<ListenableFuture<? extends DOMRpcResult>> resultsFutures) {
+ resultsFutures.add(netconfOps.commit(new NetconfRpcFutureCallback("Commit", id)));
+
+ final ListenableFuture<RpcResult<Void>> txResult = resultsToTxStatus(id, resultsFutures);
+ Futures.addCallback(txResult, new FutureCallback<>() {
+ @Override
+ public void onSuccess(final RpcResult<Void> result) {
+ unlock();
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ discardChanges();
+ unlock();
+ }
+ }, MoreExecutors.directExecutor());
+
+ return txResult;
+ }
+
+ private static ListenableFuture<RpcResult<Void>> resultsToTxStatus(
+ final RemoteDeviceId id, List<ListenableFuture<? extends DOMRpcResult>> resultsFutures) {
+ final SettableFuture<RpcResult<Void>> transformed = SettableFuture.create();
+
+ Futures.addCallback(Futures.allAsList(resultsFutures), new FutureCallback<>() {
+ @Override
+ public void onSuccess(final List<DOMRpcResult> domRpcResults) {
+ if (!transformed.isDone()) {
+ extractResult(domRpcResults, transformed, id);
+ }
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ final NetconfDocumentedException exception =
+ new NetconfDocumentedException(
+ id + ":RPC during tx returned an exception" + throwable.getMessage(),
+ new Exception(throwable),
+ DocumentedException.ErrorType.APPLICATION,
+ DocumentedException.ErrorTag.OPERATION_FAILED,
+ DocumentedException.ErrorSeverity.ERROR);
+ transformed.setException(exception);
+ }
+ }, MoreExecutors.directExecutor());
+
+ return transformed;
+ }
+
+ @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
+ justification = "https://github.com/spotbugs/spotbugs/issues/811")
+ private static void extractResult(final List<DOMRpcResult> domRpcResults,
+ final SettableFuture<RpcResult<Void>> transformed,
+ final RemoteDeviceId id) {
+ DocumentedException.ErrorType errType = DocumentedException.ErrorType.APPLICATION;
+ DocumentedException.ErrorSeverity errSeverity = DocumentedException.ErrorSeverity.ERROR;
+ StringBuilder msgBuilder = new StringBuilder();
+ boolean errorsEncouneterd = false;
+ String errorTag = "operation-failed";
+
+ for (final DOMRpcResult domRpcResult : domRpcResults) {
+ if (!domRpcResult.getErrors().isEmpty()) {
+ errorsEncouneterd = true;
+ final RpcError error = domRpcResult.getErrors().iterator().next();
+ final RpcError.ErrorType errorType = error.getErrorType();
+ switch (errorType) {
+ case RPC:
+ errType = DocumentedException.ErrorType.RPC;
+ break;
+ case PROTOCOL:
+ errType = DocumentedException.ErrorType.PROTOCOL;
+ break;
+ case TRANSPORT:
+ errType = DocumentedException.ErrorType.TRANSPORT;
+ break;
+ case APPLICATION:
+ default:
+ errType = DocumentedException.ErrorType.APPLICATION;
+ break;
+ }
+ final RpcError.ErrorSeverity severity = error.getSeverity();
+ switch (severity) {
+ case WARNING:
+ errSeverity = DocumentedException.ErrorSeverity.WARNING;
+ break;
+ case ERROR:
+ default:
+ errSeverity = DocumentedException.ErrorSeverity.ERROR;
+ break;
+ }
+ msgBuilder.append(error.getMessage());
+ msgBuilder.append(error.getInfo());
+ errorTag = error.getTag();
+ }
+ }
+ if (errorsEncouneterd) {
+ final NetconfDocumentedException exception = new NetconfDocumentedException(id
+ + ":RPC during tx failed. " + msgBuilder.toString(),
+ errType,
+ DocumentedException.ErrorTag.from(errorTag),
+ errSeverity);
+ transformed.setException(exception);
+ return;
+ }
+ transformed.set(RpcResultBuilder.<Void>success().build());
+ }
+}
import org.opendaylight.mdsal.dom.api.DOMMountPointService;
import org.opendaylight.mdsal.dom.api.DOMNotification;
import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
final EffectiveModelContext schemaContext = mountContext.getEffectiveModelContext();
final NetconfDeviceDataBroker netconfDeviceDataBroker =
new NetconfDeviceDataBroker(id, mountContext, deviceRpc, netconfSessionPreferences);
- registerLockListener(netconfDeviceDataBroker);
+ final NetconfDataTreeService netconfService =
+ new NetconfDataTreeServiceImpl(id, mountContext, deviceRpc, netconfSessionPreferences);
+ registerLockListener(netconfDeviceDataBroker, netconfService);
final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
salProvider.getMountInstance()
- .onTopologyDeviceConnected(schemaContext, netconfDeviceDataBroker, deviceRpc, notificationService,
- deviceAction);
+ .onTopologyDeviceConnected(schemaContext, netconfDeviceDataBroker, netconfService,
+ deviceRpc, notificationService, deviceAction);
salProvider.getTopologyDatastoreAdapter()
.updateDeviceData(true, netconfSessionPreferences.getNetconfDeviceCapabilities());
}
}
}
- private void registerLockListener(final NetconfDeviceDataBroker netconfDeviceDataBroker) {
+ private void registerLockListener(final NetconfDeviceDataBroker netconfDeviceDataBroker,
+ final NetconfDataTreeService netconfDataTreeService) {
listenerRegistration = dataBroker.registerDataTreeChangeListener(
DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION, createTopologyListPath()),
- new LockChangeListener(netconfDeviceDataBroker));
+ new LockChangeListener(netconfDeviceDataBroker, netconfDataTreeService));
}
private InstanceIdentifier<DatastoreLock> createTopologyListPath() {
import org.opendaylight.mdsal.dom.api.DOMNotification;
import org.opendaylight.mdsal.dom.api.DOMNotificationService;
import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.opendaylight.yangtools.concepts.ObjectRegistration;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
public void onTopologyDeviceConnected(final EffectiveModelContext initialCtx,
final DOMDataBroker broker, final DOMRpcService rpc,
final NetconfDeviceNotificationService newNotificationService) {
- onTopologyDeviceConnected(initialCtx, broker, rpc, newNotificationService, null);
+ onTopologyDeviceConnected(initialCtx, broker, null, rpc, newNotificationService, null);
}
public synchronized void onTopologyDeviceConnected(final EffectiveModelContext initialCtx,
- final DOMDataBroker broker, final DOMRpcService rpc,
+ final DOMDataBroker broker, final NetconfDataTreeService netconfService, final DOMRpcService rpc,
final NetconfDeviceNotificationService newNotificationService, final DOMActionService deviceAction) {
requireNonNull(mountService, "Closed");
checkState(topologyRegistration == null, "Already initialized");
mountService.createMountPoint(id.getTopologyPath());
mountBuilder.addInitialSchemaContext(initialCtx);
- mountBuilder.addService(DOMDataBroker.class, broker);
+ if (broker != null) {
+ mountBuilder.addService(DOMDataBroker.class, broker);
+ }
mountBuilder.addService(DOMRpcService.class, rpc);
mountBuilder.addService(DOMNotificationService.class, newNotificationService);
if (deviceAction != null) {
mountBuilder.addService(DOMActionService.class, deviceAction);
}
+ if (netconfService != null) {
+ mountBuilder.addService(NetconfDataTreeService.class, netconfService);
+ }
this.notificationService = newNotificationService;
topologyRegistration = mountBuilder.register();
import org.opendaylight.mdsal.dom.api.DOMNotification;
import org.opendaylight.mdsal.dom.api.DOMNotificationService;
import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.IetfNetconfService;
import org.opendaylight.yangtools.concepts.ObjectRegistration;
@Mock
private DOMDataBroker broker;
@Mock
+ private NetconfDataTreeService netconfService;
+ @Mock
private DOMRpcService rpcService;
@Mock
private NetconfDeviceNotificationService notificationService;
@Test
- public void testOnTopologyDeviceConnected() throws Exception {
+ public void testOnTopologyDeviceConnected() {
mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, broker, rpcService, notificationService);
verify(mountPointBuilder).addInitialSchemaContext(SCHEMA_CONTEXT);
verify(mountPointBuilder).addService(DOMDataBroker.class, broker);
verify(mountPointBuilder).addService(DOMNotificationService.class, notificationService);
}
+ @Test
+ public void testOnTopologyDeviceConnectedWithNetconfService() {
+ mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, null, netconfService, rpcService,
+ notificationService, null);
+ verify(mountPointBuilder).addInitialSchemaContext(SCHEMA_CONTEXT);
+ verify(mountPointBuilder).addService(NetconfDataTreeService.class, netconfService);
+ verify(mountPointBuilder).addService(DOMRpcService.class, rpcService);
+ verify(mountPointBuilder).addService(DOMNotificationService.class, notificationService);
+ }
+
@Test
public void testOnTopologyDeviceDisconnected() throws Exception {
mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, broker, rpcService, notificationService);
--- /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.netconf.sal.connect.netconf.sal;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_LOCK_QNAME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.binding.runtime.spi.BindingRuntimeHelpers;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.netconf.api.NetconfMessage;
+import org.opendaylight.netconf.sal.connect.netconf.AbstractTestModelTest;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.netconf.sal.connect.netconf.sal.tx.TxTestUtils;
+import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
+import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.IetfNetconfService;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
+import org.opendaylight.yangtools.rcf8528.data.util.EmptyMountPointContext;
+import org.opendaylight.yangtools.util.concurrent.FluentFutures;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class NetconfDataTreeServiceImplTest extends AbstractTestModelTest {
+ @Mock
+ private DOMRpcService rpcService;
+ private NetconfDataTreeServiceImpl netconService;
+ private NetconfMessageTransformer netconfMessageTransformer;
+ ArgumentCaptor<ContainerNode> captor = ArgumentCaptor.forClass(ContainerNode.class);
+
+ @Before
+ public void setUp() {
+ doReturn(FluentFutures.immediateFluentFuture(new DefaultDOMRpcResult())).when(rpcService)
+ .invokeRpc(any(), any());
+ netconService = getNetconService();
+ final EffectiveModelContext model = BindingRuntimeHelpers.createEffectiveModel(IetfNetconfService.class,
+ NetconfState.class);
+ netconfMessageTransformer = new NetconfMessageTransformer(new EmptyMountPointContext(model), true,
+ BASE_SCHEMAS.getBaseSchema());
+ }
+
+ @Test
+ public void lock() {
+ netconService.lock();
+ verify(rpcService).invokeRpc(eq(toPath(NETCONF_LOCK_QNAME)), any(ContainerNode.class));
+ }
+
+ @Test
+ public void unlock() {
+ netconService.unlock();
+ verify(rpcService).invokeRpc(eq(toPath(NETCONF_UNLOCK_QNAME)), any(ContainerNode.class));
+ }
+
+ @Test
+ public void discardChanges() {
+ doReturn(FluentFutures.immediateFluentFuture(new DefaultDOMRpcResult())).when(rpcService)
+ .invokeRpc(any(SchemaPath.class), isNull());
+ netconService.discardChanges();
+ verify(rpcService).invokeRpc(eq(toPath(NETCONF_DISCARD_CHANGES_QNAME)), isNull());
+ }
+
+ @Test
+ public void get() {
+ netconService.get(null);
+ verify(rpcService).invokeRpc(eq(toPath(NETCONF_GET_QNAME)), any(ContainerNode.class));
+ }
+
+ @Test
+ public void getConfig() {
+ netconService.getConfig(null);
+ verify(rpcService).invokeRpc(eq(toPath(NETCONF_GET_CONFIG_QNAME)), any(ContainerNode.class));
+ }
+
+ @Test
+ public void merge() {
+ netconService.merge(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getLeafId(), TxTestUtils.getLeafNode(),
+ Optional.empty());
+ verify(rpcService).invokeRpc(eq(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME)),
+ captor.capture());
+
+ final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(
+ toPath(NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME), captor.getValue());
+ Assert.assertTrue(netconfMessage.toString().contains("operation=\"merge\""));
+ }
+
+ @Test
+ public void replace() {
+ netconService.replace(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getLeafId(), TxTestUtils.getLeafNode(),
+ Optional.empty());
+ verify(rpcService).invokeRpc(
+ eq(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME)), captor.capture());
+
+ final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(
+ toPath(NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME), captor.getValue());
+ Assert.assertTrue(netconfMessage.toString().contains("operation=\"replace\""));
+ }
+
+ @Test
+ public void create() {
+ netconService.create(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getLeafId(), TxTestUtils.getLeafNode(),
+ Optional.empty());
+ verify(rpcService).invokeRpc(
+ eq(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME)), captor.capture());
+
+ final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(
+ toPath(NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME), captor.getValue());
+ Assert.assertTrue(netconfMessage.toString().contains("operation=\"create\""));
+ }
+
+ @Test
+ public void delete() {
+ netconService.delete(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getLeafId().getParent());
+ verify(rpcService).invokeRpc(
+ eq(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME)), captor.capture());
+
+ final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(
+ toPath(NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME), captor.getValue());
+ Assert.assertTrue(netconfMessage.toString().contains("operation=\"delete\""));
+ }
+
+ @Test
+ public void remove() {
+ netconService.remove(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getLeafId().getParent());
+ verify(rpcService).invokeRpc(
+ eq(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME)), captor.capture());
+
+ final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(
+ toPath(NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME), captor.getValue());
+ Assert.assertTrue(netconfMessage.toString().contains("operation=\"remove\""));
+ }
+
+ @Test
+ public void commit() {
+ List<ListenableFuture<? extends DOMRpcResult>> resultsFutures = new ArrayList<>();
+ netconService.commit(resultsFutures);
+ verify(rpcService).invokeRpc(eq(toPath(NETCONF_COMMIT_QNAME)), any(ContainerNode.class));
+ }
+
+ private NetconfDataTreeServiceImpl getNetconService() {
+ NetconfSessionPreferences prefs = NetconfSessionPreferences.fromStrings(
+ Collections.singletonList(NetconfMessageTransformUtil.NETCONF_CANDIDATE_URI.toString()));
+ final RemoteDeviceId id =
+ new RemoteDeviceId("device-1", InetSocketAddress.createUnresolved("localhost", 17830));
+ return new NetconfDataTreeServiceImpl(id, new EmptyMountPointContext(SCHEMA_CONTEXT), rpcService, prefs);
+ }
+}
\ No newline at end of file
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
import org.opendaylight.mdsal.dom.api.DOMNotification;
import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
null);
verify(mountInstance, times(1)).onTopologyDeviceConnected(eq(schemaContext),
- any(DOMDataBroker.class), eq(deviceRpc), any(NetconfDeviceNotificationService.class),
- isNull());
+ any(DOMDataBroker.class), any(NetconfDataTreeService.class), eq(deviceRpc),
+ any(NetconfDeviceNotificationService.class), isNull());
verify(netconfDeviceTopologyAdapter,
times(1)).updateDeviceData(true, netconfSessionPreferences.getNetconfDeviceCapabilities());
}
import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-final class TxTestUtils {
+public final class TxTestUtils {
private static final QName Q_NAME_1 = QName.create("test:namespace", "2013-07-22", "c");
private static final QName Q_NAME_2 = QName.create(Q_NAME_1, "a");
.build();
}
- static YangInstanceIdentifier getLeafId() {
+ public static YangInstanceIdentifier getLeafId() {
return YangInstanceIdentifier.builder()
.node(Q_NAME_1)
.node(Q_NAME_2)
.build();
}
- static LeafNode<String> getLeafNode() {
+ public static LeafNode<String> getLeafNode() {
return Builders.<String>leafBuilder()
.withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(Q_NAME_2))
.withValue("data")
.build();
}
-
}
<groupId>org.opendaylight.netconf</groupId>
<artifactId>netconf-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-dom-api</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
jsonWriter.endObject();
jsonWriter.flush();
}
+
+ if (httpHeaders != null) {
+ for (final Map.Entry<String, Object> entry : context.getNewHeaders().entrySet()) {
+ httpHeaders.add(entry.getKey(), entry.getValue());
+ }
+ }
}
private static void writeNormalizedNode(final JsonWriter jsonWriter,
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javanet.staxutils.IndentingXMLStreamWriter;
import javax.ws.rs.Produces;
if (context.getData() == null) {
return;
}
+ if (httpHeaders != null) {
+ for (final Map.Entry<String, Object> entry : context.getNewHeaders().entrySet()) {
+ httpHeaders.add(entry.getKey(), entry.getValue());
+ }
+ }
XMLStreamWriter xmlWriter;
try {
import java.util.List;
import java.util.Map.Entry;
import java.util.Optional;
+import java.util.concurrent.ExecutionException;
import javax.ws.rs.Path;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.dom.api.DOMActionResult;
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.common.context.WriterParameters;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
import org.opendaylight.restconf.common.patch.PatchContext;
import org.opendaylight.restconf.common.patch.PatchStatusContext;
+import org.opendaylight.restconf.nb.rfc8040.Rfc8040;
import org.opendaylight.restconf.nb.rfc8040.handlers.ActionServiceHandler;
import org.opendaylight.restconf.nb.rfc8040.handlers.DOMMountPointServiceHandler;
import org.opendaylight.restconf.nb.rfc8040.handlers.SchemaContextHandler;
import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
import org.opendaylight.restconf.nb.rfc8040.rests.services.api.RestconfDataService;
import org.opendaylight.restconf.nb.rfc8040.rests.services.api.RestconfStreamsSubscriptionService;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
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;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfInvokeOperationsUtil;
import org.opendaylight.restconf.nb.rfc8040.streams.listeners.NotificationListenerAdapter;
import org.opendaylight.restconf.nb.rfc8040.utils.mapping.RestconfMappingNodeUtil;
+import org.opendaylight.restconf.nb.rfc8040.utils.parser.IdentifierCodec;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
import org.opendaylight.yangtools.concepts.Immutable;
final WriterParameters parameters = ReadDataTransactionUtil.parseUriParameters(instanceIdentifier, uriInfo);
final DOMMountPoint mountPoint = instanceIdentifier.getMountPoint();
- final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
- instanceIdentifier, mountPoint, getTransactionChainHandler(mountPoint));
+ final RestconfStrategy strategy = getRestconfStrategy(instanceIdentifier, mountPoint);
final NormalizedNode<?, ?> node = readData(identifier, parameters.getContent(),
- transactionNode, parameters.getWithDefault(), schemaContextRef, uriInfo);
+ strategy, parameters.getWithDefault(), schemaContextRef, uriInfo);
if (identifier != null && identifier.contains(STREAM_PATH) && identifier.contains(STREAM_ACCESS_PATH_PART)
&& identifier.contains(STREAM_LOCATION_PATH_PART)) {
final String value = (String) node.getValue();
return Response.status(200).entity(new NormalizedNodeContext(instanceIdentifier, node, parameters)).build();
}
-
/**
* Read specific type of data from data store via transaction and if identifier read data from
* streams then put streams from actual schema context to datastore.
*
- * @param identifier
- * identifier of data to read
- * @param content
- * type of data to read (config, state, all)
- * @param transactionNode
- * {@link TransactionVarsWrapper} - wrapper for variables
- * @param withDefa
- * vaule of with-defaults parameter
- * @param schemaContext
- * schema context
- * @param uriInfo
- * uri info
+ * @param identifier identifier of data to read
+ * @param content type of data to read (config, state, all)
+ * @param strategy {@link RestconfStrategy} - object that perform the actual DS operations
+ * @param withDefa vaule of with-defaults parameter
+ * @param schemaContext schema context
+ * @param uriInfo uri info
* @return {@link NormalizedNode}
*/
- private static NormalizedNode<?, ?> readData(final String identifier, final String content,
- final TransactionVarsWrapper transactionNode, final String withDefa,
+ public static NormalizedNode<?, ?> readData(final String identifier, final String content,
+ final RestconfStrategy strategy, final String withDefa,
final EffectiveModelContext schemaContext, final UriInfo uriInfo) {
if (identifier != null && identifier.contains(STREAMS_PATH) && !identifier.contains(STREAM_PATH_PART)) {
- createAllYangNotificationStreams(transactionNode, schemaContext, uriInfo);
+ createAllYangNotificationStreams(strategy, schemaContext, uriInfo);
}
- return ReadDataTransactionUtil.readData(content, transactionNode, withDefa, schemaContext);
+ return ReadDataTransactionUtil.readData(content, strategy, withDefa, schemaContext);
}
- private static void createAllYangNotificationStreams(final TransactionVarsWrapper transactionNode,
- final EffectiveModelContext schemaContext, final UriInfo uriInfo) {
- final DOMDataTreeReadWriteTransaction wTx = transactionNode.getTransactionChain().newReadWriteTransaction();
- final boolean exist = SubscribeToStreamUtil.checkExist(schemaContext, wTx);
+ private static void createAllYangNotificationStreams(final RestconfStrategy strategy,
+ final EffectiveModelContext schemaContext,
+ final UriInfo uriInfo) {
+ strategy.prepareReadWriteExecution();
+ final boolean exist = checkExist(schemaContext, strategy);
for (final NotificationDefinition notificationDefinition : schemaContext.getNotifications()) {
final NotificationListenerAdapter notifiStreamXML =
- CreateStreamUtil.createYangNotifiStream(notificationDefinition, schemaContext,
- NotificationOutputType.XML);
+ CreateStreamUtil.createYangNotifiStream(notificationDefinition, schemaContext,
+ NotificationOutputType.XML);
final NotificationListenerAdapter notifiStreamJSON =
- CreateStreamUtil.createYangNotifiStream(notificationDefinition, schemaContext,
- NotificationOutputType.JSON);
- writeNotificationStreamToDatastore(schemaContext, uriInfo, wTx, exist, notifiStreamXML);
- writeNotificationStreamToDatastore(schemaContext, uriInfo, wTx, exist, notifiStreamJSON);
+ CreateStreamUtil.createYangNotifiStream(notificationDefinition, schemaContext,
+ NotificationOutputType.JSON);
+ writeNotificationStreamToDatastore(schemaContext, uriInfo, strategy, exist, notifiStreamXML);
+ writeNotificationStreamToDatastore(schemaContext, uriInfo, strategy, exist, notifiStreamJSON);
+ }
+ try {
+ strategy.commit().get();
+ } catch (final InterruptedException | ExecutionException e) {
+ throw new RestconfDocumentedException("Problem while putting data to DS.", e);
}
- SubscribeToStreamUtil.submitData(wTx);
}
private static void writeNotificationStreamToDatastore(final EffectiveModelContext schemaContext,
- final UriInfo uriInfo, final DOMDataTreeReadWriteTransaction readWriteTransaction, final boolean exist,
- final NotificationListenerAdapter listener) {
+ final UriInfo uriInfo, final RestconfStrategy strategy,
+ final boolean exist,
+ final NotificationListenerAdapter listener) {
final URI uri = SubscribeToStreamUtil.prepareUriByStreamName(uriInfo, listener.getStreamName());
final NormalizedNode<?, ?> mapToStreams =
- RestconfMappingNodeUtil.mapYangNotificationStreamByIetfRestconfMonitoring(
- listener.getSchemaPath().getLastComponent(), schemaContext.getNotifications(), null,
- listener.getOutputType(), uri, SubscribeToStreamUtil.getMonitoringModule(schemaContext), exist);
- SubscribeToStreamUtil.writeDataToDS(schemaContext,
- listener.getSchemaPath().getLastComponent().getLocalName(), readWriteTransaction, exist, mapToStreams);
+ RestconfMappingNodeUtil.mapYangNotificationStreamByIetfRestconfMonitoring(
+ listener.getSchemaPath().getLastComponent(), schemaContext.getNotifications(), null,
+ listener.getOutputType(), uri, SubscribeToStreamUtil.getMonitoringModule(schemaContext), exist);
+ writeDataToDS(schemaContext,
+ listener.getSchemaPath().getLastComponent().getLocalName(), strategy, exist, mapToStreams);
+ }
+
+ private static boolean checkExist(final EffectiveModelContext schemaContext, final RestconfStrategy strategy) {
+ try {
+ return strategy.exists(LogicalDatastoreType.OPERATIONAL,
+ IdentifierCodec.deserialize(Rfc8040.MonitoringModule.PATH_TO_STREAMS, schemaContext)).get();
+ } catch (final InterruptedException | ExecutionException exception) {
+ throw new RestconfDocumentedException("Problem while checking data if exists", exception);
+ }
+ }
+
+ private static void writeDataToDS(final EffectiveModelContext schemaContext, final String name,
+ final RestconfStrategy strategy, final boolean exist,
+ final NormalizedNode mapToStreams) {
+ String pathId;
+ if (exist) {
+ pathId = Rfc8040.MonitoringModule.PATH_TO_STREAM_WITHOUT_KEY + name;
+ } else {
+ pathId = Rfc8040.MonitoringModule.PATH_TO_STREAMS;
+ }
+ strategy.merge(LogicalDatastoreType.OPERATIONAL,
+ IdentifierCodec.deserialize(pathId, schemaContext), mapToStreams);
}
@Override
PutDataTransactionUtil.validateListKeysEqualityInPayloadAndUri(payload);
final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
- final TransactionChainHandler localTransactionChainHandler;
- final EffectiveModelContext ref;
- if (mountPoint == null) {
- localTransactionChainHandler = this.transactionChainHandler;
- ref = this.schemaContextHandler.get();
- } else {
- localTransactionChainHandler = transactionChainOfMountPoint(mountPoint);
- ref = mountPoint.getEffectiveModelContext();
- }
+ final EffectiveModelContext ref = mountPoint == null
+ ? this.schemaContextHandler.get()
+ : mountPoint.getEffectiveModelContext();
- final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
- payload.getInstanceIdentifierContext(), mountPoint, localTransactionChainHandler);
- return PutDataTransactionUtil.putData(payload, ref, transactionNode, checkedParms.insert, checkedParms.point);
+ final RestconfStrategy strategy = getRestconfStrategy(payload.getInstanceIdentifierContext(), mountPoint);
+ return PutDataTransactionUtil.putData(payload, ref, strategy, checkedParms.insert, checkedParms.point);
}
private static QueryParams checkQueryParameters(final UriInfo uriInfo) {
}
final QueryParams checkedParms = checkQueryParameters(uriInfo);
-
final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
- final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
- payload.getInstanceIdentifierContext(), mountPoint, getTransactionChainHandler(mountPoint));
- return PostDataTransactionUtil.postData(uriInfo, payload, transactionNode,
+ final RestconfStrategy strategy = getRestconfStrategy(payload.getInstanceIdentifierContext(),
+ payload.getInstanceIdentifierContext().getMountPoint());
+ return PostDataTransactionUtil.postData(uriInfo, payload, strategy,
getSchemaContext(mountPoint), checkedParms.insert, checkedParms.point);
}
identifier, this.schemaContextHandler.get(), Optional.of(this.mountPointServiceHandler.get()));
final DOMMountPoint mountPoint = instanceIdentifier.getMountPoint();
- final TransactionChainHandler localTransactionChainHandler;
- if (mountPoint == null) {
- localTransactionChainHandler = this.transactionChainHandler;
- } else {
- localTransactionChainHandler = transactionChainOfMountPoint(mountPoint);
- }
-
- final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(instanceIdentifier, mountPoint,
- localTransactionChainHandler);
- return DeleteDataTransactionUtil.deleteData(transactionNode);
+ final RestconfStrategy strategy = getRestconfStrategy(instanceIdentifier, mountPoint);
+ return DeleteDataTransactionUtil.deleteData(strategy);
}
@Override
@Override
public PatchStatusContext patchData(final PatchContext context, final UriInfo uriInfo) {
final DOMMountPoint mountPoint = requireNonNull(context).getInstanceIdentifierContext().getMountPoint();
- final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
- context.getInstanceIdentifierContext(), mountPoint, getTransactionChainHandler(mountPoint));
- return PatchDataTransactionUtil.patchData(context, transactionNode, getSchemaContext(mountPoint));
+ final RestconfStrategy strategy = getRestconfStrategy(context.getInstanceIdentifierContext(), mountPoint);
+ return PatchDataTransactionUtil.patchData(context, strategy, getSchemaContext(mountPoint));
}
@Override
PutDataTransactionUtil.validateListKeysEqualityInPayloadAndUri(payload);
final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
- final TransactionChainHandler localTransactionChainHandler;
- final EffectiveModelContext ref;
- if (mountPoint == null) {
- localTransactionChainHandler = this.transactionChainHandler;
- ref = this.schemaContextHandler.get();
- } else {
- localTransactionChainHandler = transactionChainOfMountPoint(mountPoint);
- ref = mountPoint.getEffectiveModelContext();
- }
-
- final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
- payload.getInstanceIdentifierContext(), mountPoint, localTransactionChainHandler);
-
- return PlainPatchDataTransactionUtil.patchData(payload, transactionNode, ref);
- }
+ final EffectiveModelContext ref = mountPoint == null
+ ? this.schemaContextHandler.get()
+ : mountPoint.getEffectiveModelContext();
+ final RestconfStrategy strategy = getRestconfStrategy(payload.getInstanceIdentifierContext(), mountPoint);
- private TransactionChainHandler getTransactionChainHandler(final DOMMountPoint mountPoint) {
- return mountPoint == null ? transactionChainHandler : transactionChainOfMountPoint(mountPoint);
+ return PlainPatchDataTransactionUtil.patchData(payload, strategy, ref);
}
private EffectiveModelContext getSchemaContext(final DOMMountPoint mountPoint) {
return mountPoint == null ? schemaContextHandler.get() : mountPoint.getEffectiveModelContext();
}
+ public synchronized RestconfStrategy getRestconfStrategy(final InstanceIdentifierContext<?> instanceIdentifier,
+ final DOMMountPoint mountPoint) {
+ if (mountPoint != null) {
+ final Optional<NetconfDataTreeService> service = mountPoint.getService(NetconfDataTreeService.class);
+ if (service.isPresent()) {
+ return new NetconfRestconfStrategy(service.get(), instanceIdentifier);
+ }
+ }
+ final TransactionChainHandler transactionChain = mountPoint == null
+ ? transactionChainHandler : transactionChainOfMountPoint(mountPoint);
+ return new MdsalRestconfStrategy(instanceIdentifier, transactionChain);
+ }
+
/**
* Prepare transaction chain to access data of mount point.
- * @param mountPoint
- * mount point reference
+ *
+ * @param mountPoint mount point reference
* @return {@link TransactionChainHandler}
*/
private static TransactionChainHandler transactionChainOfMountPoint(final @NonNull DOMMountPoint mountPoint) {
/**
* Invoke Action operation.
*
- * @param payload
- * {@link NormalizedNodeContext} - the body of the operation
- * @param uriInfo
- * URI info
+ * @param payload {@link NormalizedNodeContext} - the body of the operation
+ * @param uriInfo URI info
* @return {@link NormalizedNodeContext} wrapped in {@link Response}
*/
public Response invokeAction(final NormalizedNodeContext payload, final UriInfo uriInfo) {
static boolean checkExist(final SchemaContext schemaContext,
final DOMDataTreeReadOperations readWriteTransaction) {
- boolean exist;
try {
return readWriteTransaction.exists(LogicalDatastoreType.OPERATIONAL,
IdentifierCodec.deserialize(MonitoringModule.PATH_TO_STREAMS, schemaContext)).get();
--- /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.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.DOMDataTreeReadTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+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;
+
+/**
+ * Strategy that allow to communicate with netconf devices in terms of md-sal transactions.
+ *
+ * @see DOMTransactionChain
+ * @see DOMDataTreeReadWriteTransaction
+ */
+public class MdsalRestconfStrategy implements RestconfStrategy {
+ private final InstanceIdentifierContext<?> instanceIdentifier;
+ private final DOMTransactionChain transactionChain;
+ private DOMDataTreeReadWriteTransaction rwTx;
+ private final TransactionChainHandler transactionChainHandler;
+
+ public MdsalRestconfStrategy(final InstanceIdentifierContext<?> instanceIdentifier,
+ final TransactionChainHandler transactionChainHandler) {
+ this.instanceIdentifier = requireNonNull(instanceIdentifier);
+ this.transactionChainHandler = requireNonNull(transactionChainHandler);
+ transactionChain = transactionChainHandler.get();
+ }
+
+ @Override
+ public void prepareReadWriteExecution() {
+ rwTx = transactionChain.newReadWriteTransaction();
+ }
+
+ @Override
+ public void cancel() {
+ if (rwTx != null) {
+ rwTx.cancel();
+ }
+ transactionChain.close();
+ }
+
+ @Override
+ public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+ try (DOMDataTreeReadTransaction tx = transactionChain.newReadOnlyTransaction()) {
+ return tx.read(store, path);
+ }
+ }
+
+ @Override
+ public FluentFuture<Boolean> exists(LogicalDatastoreType store, YangInstanceIdentifier path) {
+ return rwTx.exists(store, path);
+ }
+
+ @Override
+ public void delete(LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ rwTx.delete(store, path);
+ }
+
+ @Override
+ public void merge(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data) {
+ rwTx.merge(store, path, data);
+ }
+
+ @Override
+ public void create(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data) {
+ rwTx.put(store, path, data);
+ }
+
+ @Override
+ public void replace(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data) {
+ create(store, path, data);
+ }
+
+ @Override
+ public FluentFuture<? extends @NonNull CommitInfo> commit() {
+ return rwTx.commit();
+ }
+
+ @Override
+ public DOMTransactionChain getTransactionChain() {
+ return transactionChain;
+ }
+
+ @Override
+ public InstanceIdentifierContext<?> getInstanceIdentifier() {
+ return instanceIdentifier;
+ }
+
+ @Override
+ public TransactionChainHandler getTransactionChainHandler() {
+ return transactionChainHandler;
+ }
+
+ @Override
+ public RestconfStrategy buildStrategy(final InstanceIdentifierContext<?> instanceIdentifierContext) {
+ return new MdsalRestconfStrategy(instanceIdentifierContext, this.transactionChainHandler);
+ }
+}
--- /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.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+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.common.context.InstanceIdentifierContext;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Strategy that allow to communicate with netconf devices using pure netconf operations.
+ */
+public class NetconfRestconfStrategy implements RestconfStrategy {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfRestconfStrategy.class);
+
+ private final NetconfDataTreeService netconfService;
+ private final InstanceIdentifierContext<?> instanceIdentifier;
+
+ private List<ListenableFuture<? extends DOMRpcResult>> resultsFutures;
+
+ public NetconfRestconfStrategy(final NetconfDataTreeService netconfService,
+ final InstanceIdentifierContext<?> instanceIdentifier) {
+ this.netconfService = requireNonNull(netconfService);
+ this.instanceIdentifier = requireNonNull(instanceIdentifier);
+ }
+
+ @Override
+ public void prepareReadWriteExecution() {
+ resultsFutures = netconfService.lock();
+ }
+
+ @Override
+ public void cancel() {
+ netconfService.discardChanges();
+ netconfService.unlock();
+ }
+
+ @Override
+ public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+ switch (store) {
+ case CONFIGURATION:
+ return netconfService.getConfig(path);
+ case OPERATIONAL:
+ return netconfService.get(path);
+ default:
+ LOG.info("Unknown datastore type: {}.", store);
+ throw new IllegalArgumentException(String.format(
+ "%s, Cannot read data %s for %s datastore, unknown datastore type",
+ netconfService.getDeviceId(), path, store));
+ }
+ }
+
+ @Override
+ public FluentFuture<Boolean> exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ return remapException(read(store, path))
+ .transform(optionalNode -> optionalNode != null && optionalNode.isPresent(),
+ MoreExecutors.directExecutor());
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ resultsFutures.add(netconfService.delete(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) {
+ resultsFutures.add(netconfService.create(store, path, data, Optional.empty()));
+ }
+
+ @Override
+ public void replace(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data) {
+ 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;
+ }
+
+ @Override
+ public InstanceIdentifierContext<?> getInstanceIdentifier() {
+ return instanceIdentifier;
+ }
+
+ /**
+ * As we are not using any transactions here, always return null.
+ */
+ @Override
+ public TransactionChainHandler getTransactionChainHandler() {
+ return null;
+ }
+
+ @Override
+ public RestconfStrategy buildStrategy(final InstanceIdentifierContext<?> instanceIdentifierContext) {
+ return new NetconfRestconfStrategy(this.netconfService, instanceIdentifierContext);
+ }
+
+ private static <T> FluentFuture<T> remapException(final ListenableFuture<T> input) {
+ final SettableFuture<T> ret = SettableFuture.create();
+ Futures.addCallback(input, new FutureCallback<T>() {
+
+ @Override
+ public void onSuccess(final T result) {
+ ret.set(result);
+ }
+
+ @Override
+ public void onFailure(final Throwable cause) {
+ ret.setException(cause instanceof ReadFailedException ? cause
+ : new ReadFailedException("NETCONF operation failed", cause));
+ }
+ }, MoreExecutors.directExecutor());
+ return FluentFuture.from(ret);
+ }
+}
--- /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.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.DOMTransactionChain;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+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;
+
+/**
+ * This interface allows interact with netconf operations in different ways.
+ *
+ * @see NetconfRestconfStrategy
+ * @see MdsalRestconfStrategy
+ */
+public interface RestconfStrategy {
+
+ /**
+ * Lock the entire datastore.
+ */
+ void prepareReadWriteExecution();
+
+ /**
+ * Rollback changes and unlock the datastore.
+ */
+ void cancel();
+
+ /**
+ * Read data from the datastore.
+ *
+ * @param store the logical data store which should be modified
+ * @param path the data object path
+ * @return a ListenableFuture containing the result of the read
+ */
+ ListenableFuture<Optional<NormalizedNode<?, ?>>> read(LogicalDatastoreType store, YangInstanceIdentifier path);
+
+ /**
+ * Check if data already exists in the datastore.
+ *
+ * @param store the logical data store which should be modified
+ * @param path the data object path
+ * @return a FluentFuture containing the result of the check
+ */
+ 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
+ */
+ void delete(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
+ */
+ 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
+ */
+ void create(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data);
+
+ /**
+ * 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
+ */
+ void replace(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data);
+
+ /**
+ * Confirm previous operations.
+ *
+ * @return a FluentFuture containing the result of the commit information
+ */
+ FluentFuture<? extends @NonNull CommitInfo> commit();
+
+ /**
+ * Get transaction chain for creating specific transaction for specific operation.
+ *
+ * @return transaction chain or null
+ */
+ @Nullable DOMTransactionChain getTransactionChain();
+
+ /**
+ * Get instance identifier of data.
+ *
+ * @return {@link InstanceIdentifierContext}
+ */
+ InstanceIdentifierContext<?> getInstanceIdentifier();
+
+ /**
+ * Get transaction chain handler for creating new transaction chain.
+ *
+ * @return {@link TransactionChainHandler} or null
+ */
+ @Nullable TransactionChainHandler getTransactionChainHandler();
+
+ /**
+ * Create a new and same type strategy for communication with netconf interface with
+ * a new {@link InstanceIdentifierContext}.
+ *
+ * @return {@link RestconfStrategy}
+ */
+ RestconfStrategy buildStrategy(InstanceIdentifierContext<?> instanceIdentifierContext);
+}
+++ /dev/null
-/*
- * Copyright (c) 2016 Cisco Systems, Inc. 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 org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DOMMountPoint;
-import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
-import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
-import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
-
-/**
- * This class represent delegation wrapper for transaction variables.
- *
- */
-public final class TransactionVarsWrapper {
-
- private final InstanceIdentifierContext<?> instanceIdentifier;
- private final DOMMountPoint mountPoint;
- private LogicalDatastoreType configuration = null;
- private final DOMTransactionChain transactionChain;
- private final TransactionChainHandler transactionChainHandler;
-
- /**
- * Set base type of variables, which ones we need for transaction.
- * {@link LogicalDatastoreType} is default set to null (to read all data
- * from DS - config + state).
- *
- * @param instanceIdentifier
- * {@link InstanceIdentifierContext} of data for transaction
- * @param mountPoint
- * mount point if is present
- * @param transactionChainHandler
- * used to obtain the transaction chain for creating specific type of transaction
- * in specific operation
- */
- public TransactionVarsWrapper(final InstanceIdentifierContext<?> instanceIdentifier, final DOMMountPoint mountPoint,
- final TransactionChainHandler transactionChainHandler) {
- this.instanceIdentifier = instanceIdentifier;
- this.mountPoint = mountPoint;
- this.transactionChainHandler = transactionChainHandler;
- transactionChain = transactionChainHandler.get();
- }
-
- /**
- * Get instance identifier of data.
- *
- * @return {@link InstanceIdentifierContext}
- */
- public InstanceIdentifierContext<?> getInstanceIdentifier() {
- return this.instanceIdentifier;
- }
-
- /**
- * Get mount point.
- *
- * @return {@link DOMMountPoint}
- */
- public DOMMountPoint getMountPoint() {
- return this.mountPoint;
- }
-
- /**
- * Set {@link LogicalDatastoreType} of data for transaction.
- *
- * @param datastoreType
- * {@link LogicalDatastoreType}
- */
- public void setLogicalDatastoreType(final LogicalDatastoreType datastoreType) {
- this.configuration = datastoreType;
- }
-
- /**
- * Get type of data.
- *
- * @return {@link LogicalDatastoreType}
- */
- public LogicalDatastoreType getLogicalDatastoreType() {
- return this.configuration;
- }
-
- /**
- * Get transaction chain for creating specific transaction for specific
- * operation.
- *
- * @return transaction chain
- */
- public DOMTransactionChain getTransactionChain() {
- return this.transactionChain;
- }
-
- public TransactionChainHandler getTransactionChainHandler() {
- return transactionChainHandler;
- }
-}
import javax.ws.rs.core.Response.Status;
import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
-import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
/**
* Util class for delete specific data in config DS.
- *
*/
public final class DeleteDataTransactionUtil {
/**
* Delete data from DS via transaction.
*
- * @param transactionNode
- * Wrapper for data of transaction
+ * @param strategy object that perform the actual DS operations
* @return {@link Response}
*/
- public static Response deleteData(final TransactionVarsWrapper transactionNode) {
- final DOMTransactionChain transactionChain = transactionNode.getTransactionChainHandler().get();
- final FluentFuture<? extends CommitInfo> future = submitData(transactionChain,
- transactionNode.getInstanceIdentifier().getInstanceIdentifier());
+ public static Response deleteData(final RestconfStrategy strategy) {
+ strategy.prepareReadWriteExecution();
+ final YangInstanceIdentifier path = strategy.getInstanceIdentifier().getInstanceIdentifier();
+ TransactionUtil.checkItemExists(strategy, LogicalDatastoreType.CONFIGURATION, path,
+ RestconfDataServiceConstant.DeleteData.DELETE_TX_TYPE);
+ strategy.delete(LogicalDatastoreType.CONFIGURATION, path);
+ final FluentFuture<? extends CommitInfo> future = strategy.commit();
final ResponseFactory response = new ResponseFactory(Status.NO_CONTENT);
- //This method will close transactionChain
+ //This method will close transactionChain if any
FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.DeleteData.DELETE_TX_TYPE, response,
- transactionChain);
+ strategy.getTransactionChain());
return response.build();
}
-
- /**
- * Delete data via transaction. Return error if data to delete does not exist.
- *
- * @param transactionChain
- * transaction chain
- * @param path
- * path of data to delete
- * @return {@link FluentFuture}
- */
- private static FluentFuture<? extends CommitInfo> submitData(
- final DOMTransactionChain transactionChain, final YangInstanceIdentifier path) {
- final DOMDataTreeReadWriteTransaction readWriteTx = transactionChain.newReadWriteTransaction();
- TransactionUtil.checkItemExists(transactionChain, readWriteTx, LogicalDatastoreType.CONFIGURATION, path,
- RestconfDataServiceConstant.DeleteData.DELETE_TX_TYPE);
- readWriteTx.delete(LogicalDatastoreType.CONFIGURATION, path);
- return readWriteTx.commit();
- }
}
import javax.ws.rs.core.Response.Status;
import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeReadOperations;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
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.common.patch.PatchEntity;
import org.opendaylight.restconf.common.patch.PatchStatusContext;
import org.opendaylight.restconf.common.patch.PatchStatusEntity;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfDataServiceConstant.PatchData;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
}
/**
- * Process edit operations of one {@link PatchContext}. Close {@link DOMTransactionChain} inside of object
- * {@link TransactionVarsWrapper} provided as a parameter.
- * @param context Patch context to be processed
- * @param transactionNode Wrapper for transaction
+ * Process edit operations of one {@link PatchContext}. Close {@link DOMTransactionChain} if any inside of object
+ * {@link RestconfStrategy} provided as a parameter.
+ *
+ * @param context Patch context to be processed
+ * @param strategy object that perform the actual DS operations
* @param schemaContext Global schema context
* @return {@link PatchStatusContext}
*/
- public static PatchStatusContext patchData(final PatchContext context, final TransactionVarsWrapper transactionNode,
+ public static PatchStatusContext patchData(final PatchContext context, final RestconfStrategy strategy,
final EffectiveModelContext schemaContext) {
final List<PatchStatusEntity> editCollection = new ArrayList<>();
boolean noError = true;
- final DOMTransactionChain transactionChain = transactionNode.getTransactionChain();
- final DOMDataTreeReadWriteTransaction tx = transactionChain.newReadWriteTransaction();
+ strategy.prepareReadWriteExecution();
for (final PatchEntity patchEntity : context.getData()) {
if (noError) {
case CREATE:
try {
createDataWithinTransaction(LogicalDatastoreType.CONFIGURATION,
- patchEntity.getTargetNode(), patchEntity.getNode(), tx, schemaContext);
+ patchEntity.getTargetNode(), patchEntity.getNode(), strategy, schemaContext);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
case DELETE:
try {
deleteDataWithinTransaction(LogicalDatastoreType.CONFIGURATION, patchEntity.getTargetNode(),
- tx);
+ strategy);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
case MERGE:
try {
mergeDataWithinTransaction(LogicalDatastoreType.CONFIGURATION,
- patchEntity.getTargetNode(), patchEntity.getNode(), tx, schemaContext);
+ patchEntity.getTargetNode(), patchEntity.getNode(), strategy, schemaContext);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
case REPLACE:
try {
replaceDataWithinTransaction(LogicalDatastoreType.CONFIGURATION,
- patchEntity.getTargetNode(), patchEntity.getNode(), schemaContext, tx);
+ patchEntity.getTargetNode(), patchEntity.getNode(), schemaContext, strategy);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
case REMOVE:
try {
removeDataWithinTransaction(LogicalDatastoreType.CONFIGURATION, patchEntity.getTargetNode(),
- tx);
+ strategy);
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 = tx.commit();
+ final FluentFuture<? extends CommitInfo> future = strategy.commit();
try {
- //This method will close transactionChain
- FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response, transactionChain);
+ //This method will close transactionChain if any
+ FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response, strategy.getTransactionChain());
} 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,
Lists.newArrayList(e.getErrors()));
}
- return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), true, null);
+ return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection),
+ true, null);
} else {
- tx.cancel();
- transactionChain.close();
+ strategy.cancel();
return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection),
false, null);
}
/**
* Create data within one transaction, return error if already exists.
- * @param dataStore Datastore to write data to
- * @param path Path for data to be created
- * @param payload Data to be created
- * @param rwTransaction Transaction
+ *
+ * @param dataStore Datastore to write data to
+ * @param path Path for data to be created
+ * @param payload Data to be created
+ * @param strategy Object that perform the actual DS operations
* @param schemaContext Global schema context
*/
private static void createDataWithinTransaction(final LogicalDatastoreType dataStore,
final YangInstanceIdentifier path,
final NormalizedNode<?, ?> payload,
- final DOMDataTreeReadWriteTransaction rwTransaction,
+ final RestconfStrategy strategy,
final EffectiveModelContext schemaContext) {
LOG.trace("POST {} within Restconf Patch: {} with payload {}", dataStore.name(), path, payload);
- createData(payload, schemaContext, path, rwTransaction, dataStore, true);
+ createData(payload, schemaContext, path, strategy, dataStore, true);
}
/**
* Check if data exists and remove it within one transaction.
- * @param dataStore Datastore to delete data from
- * @param path Path for data to be deleted
- * @param readWriteTransaction Transaction
+ *
+ * @param dataStore Datastore to delete data from
+ * @param path Path for data to be deleted
+ * @param strategy Object that perform the actual DS operations
*/
private static void deleteDataWithinTransaction(final LogicalDatastoreType dataStore,
final YangInstanceIdentifier path,
- final DOMDataTreeReadWriteTransaction readWriteTransaction) {
+ final RestconfStrategy strategy) {
LOG.trace("Delete {} within Restconf Patch: {}", dataStore.name(), path);
- checkItemExistsWithinTransaction(readWriteTransaction, dataStore, path);
- readWriteTransaction.delete(dataStore, path);
+ checkItemExistsWithinTransaction(strategy, dataStore, path);
+ strategy.delete(dataStore, path);
}
/**
* Merge data within one transaction.
- * @param dataStore Datastore to merge data to
- * @param path Path for data to be merged
- * @param payload Data to be merged
- * @param writeTransaction Transaction
+ *
+ * @param dataStore Datastore to merge data to
+ * @param path Path for data to be merged
+ * @param payload Data to be merged
+ * @param strategy Object that perform the actual DS operations
* @param schemaContext Global schema context
*/
private static void mergeDataWithinTransaction(final LogicalDatastoreType dataStore,
final YangInstanceIdentifier path,
final NormalizedNode<?, ?> payload,
- final DOMDataTreeWriteTransaction writeTransaction,
+ final RestconfStrategy strategy,
final EffectiveModelContext schemaContext) {
LOG.trace("Merge {} within Restconf Patch: {} with payload {}", dataStore.name(), path, payload);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTransaction);
- writeTransaction.merge(dataStore, path, payload);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
+ strategy.merge(dataStore, path, payload);
}
/**
* Do NOT check if data exists and remove it within one transaction.
- * @param dataStore Datastore to delete data from
- * @param path Path for data to be deleted
- * @param writeTransaction Transaction
+ *
+ * @param dataStore Datastore to delete data from
+ * @param path Path for data to be deleted
+ * @param strategy Object that perform the actual DS operations
*/
private static void removeDataWithinTransaction(final LogicalDatastoreType dataStore,
final YangInstanceIdentifier path,
- final DOMDataTreeWriteTransaction writeTransaction) {
+ final RestconfStrategy strategy) {
LOG.trace("Remove {} within Restconf Patch: {}", dataStore.name(), path);
- writeTransaction.delete(dataStore, path);
+ strategy.delete(dataStore, path);
}
/**
* Create data within one transaction, replace if already exists.
- * @param dataStore Datastore to write data to
- * @param path Path for data to be created
- * @param payload Data to be created
- * @param path Path for data to be created
- * @param rwTransaction Transaction
+ *
+ * @param dataStore Datastore to write data to
+ * @param path Path for data to be created
+ * @param payload Data to be created
+ * @param schemaContext Global schema context
+ * @param strategy Object that perform the actual DS operations
*/
private static void replaceDataWithinTransaction(final LogicalDatastoreType dataStore,
final YangInstanceIdentifier path,
final NormalizedNode<?, ?> payload,
final EffectiveModelContext schemaContext,
- final DOMDataTreeReadWriteTransaction rwTransaction) {
+ final RestconfStrategy strategy) {
LOG.trace("PUT {} within Restconf Patch: {} with payload {}", dataStore.name(), path, payload);
- createData(payload, schemaContext, path, rwTransaction, dataStore, false);
+ createData(payload, schemaContext, path, strategy, dataStore, 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 payload Data to be created
+ *
+ * @param payload Data to be created
* @param schemaContext Global schema context
- * @param path Path for data to be created
- * @param rwTransaction Transaction
- * @param dataStore Datastore to write data to
+ * @param path Path for data to be created
+ * @param strategy Object that perform the actual DS operations
+ * @param dataStore Datastore to write data to
* @param errorIfExists Enable checking for existence of data (throws error if already exists)
*/
private static void createData(final NormalizedNode<?, ?> payload, final EffectiveModelContext schemaContext,
final YangInstanceIdentifier path,
- final DOMDataTreeReadWriteTransaction rwTransaction,
+ final RestconfStrategy strategy,
final LogicalDatastoreType dataStore, final boolean errorIfExists) {
if (payload instanceof MapNode) {
final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
- rwTransaction.merge(dataStore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
+ strategy.merge(dataStore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
for (final MapEntryNode child : ((MapNode) payload).getValue()) {
final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
if (errorIfExists) {
- checkItemDoesNotExistsWithinTransaction(rwTransaction, dataStore, childPath);
+ checkItemDoesNotExistsWithinTransaction(strategy, dataStore, childPath);
}
- rwTransaction.put(dataStore, childPath, child);
+ if (errorIfExists) {
+ strategy.create(dataStore, childPath, child);
+ } else {
+ strategy.replace(dataStore, childPath, child);
+ }
}
} else {
if (errorIfExists) {
- checkItemDoesNotExistsWithinTransaction(rwTransaction, dataStore, path);
+ checkItemDoesNotExistsWithinTransaction(strategy, dataStore, path);
}
- TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
- rwTransaction.put(dataStore, path, payload);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
+ if (errorIfExists) {
+ strategy.create(dataStore, path, payload);
+ } else {
+ strategy.replace(dataStore, path, payload);
+ }
}
}
/**
* Check if items already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
* data does NOT already exists.
- * @param rwTransaction Transaction
- * @param store Datastore
- * @param path Path to be checked
+ *
+ * @param strategy Object that perform the actual DS operations
+ * @param store Datastore
+ * @param path Path to be checked
*/
- public static void checkItemExistsWithinTransaction(final DOMDataTreeReadOperations rwTransaction,
- final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- final FluentFuture<Boolean> future = rwTransaction.exists(store, path);
+ public static void checkItemExistsWithinTransaction(final RestconfStrategy strategy,
+ final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+ final FluentFuture<Boolean> future = strategy.exists(store, path);
final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response);
if (!response.result) {
LOG.trace("Operation via Restconf was not executed because data at {} does not exist", path);
throw new RestconfDocumentedException("Data does not exist", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING,
- path);
+ path);
}
}
/**
* Check if items do NOT already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
* data already exists.
- * @param rwTransaction Transaction
- * @param store Datastore
- * @param path Path to be checked
+ *
+ * @param strategy Object that perform the actual DS operations
+ * @param store Datastore
+ * @param path Path to be checked
*/
- public static void checkItemDoesNotExistsWithinTransaction(final DOMDataTreeReadOperations rwTransaction,
- final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- final FluentFuture<Boolean> future = rwTransaction.exists(store, path);
+ public static void checkItemDoesNotExistsWithinTransaction(final RestconfStrategy strategy,
+ final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+ final FluentFuture<Boolean> future = strategy.exists(store, path);
final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response);
if (response.result) {
LOG.trace("Operation via Restconf was not executed because data at {} already exists", path);
throw new RestconfDocumentedException("Data already exists", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS,
- path);
+ path);
}
}
}
import javax.ws.rs.core.Response.Status;
import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
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;
}
/**
- * Prepare variables for put data to DS. Close {@link DOMTransactionChain} inside of object
- * {@link TransactionVarsWrapper} provided as a parameter.
+ * Prepare variables for put data to DS. Close {@link DOMTransactionChain} if any inside of object
+ * {@link RestconfStrategy} provided as a parameter if any.
*
- * @param payload
- * data to put
- * @param schemaContext
- * reference to {@link EffectiveModelContext}
- * @param transactionNode
- * wrapper of variables for transaction
+ * @param payload data to put
+ * @param schemaContext reference to {@link EffectiveModelContext}
+ * @param strategy object that perform the actual DS operations
* @return {@link Response}
*/
public static Response patchData(final NormalizedNodeContext payload,
- final TransactionVarsWrapper transactionNode,
+ final RestconfStrategy strategy,
final EffectiveModelContext schemaContext) {
- final DOMTransactionChain transactionChain = transactionNode.getTransactionChain();
- final DOMDataTreeReadWriteTransaction tx = transactionChain.newReadWriteTransaction();
-
+ strategy.prepareReadWriteExecution();
YangInstanceIdentifier path = payload.getInstanceIdentifierContext().getInstanceIdentifier();
NormalizedNode<?, ?> data = payload.getData();
try {
- mergeDataWithinTransaction(LogicalDatastoreType.CONFIGURATION, path, data, tx, schemaContext);
+ mergeDataWithinTransaction(LogicalDatastoreType.CONFIGURATION, path, data, strategy, schemaContext);
} catch (final RestconfDocumentedException e) {
- tx.cancel();
- transactionChain.close();
-
+ strategy.cancel();
throw new IllegalArgumentException(e);
}
- final FluentFuture<? extends CommitInfo> future = tx.commit();
+ final FluentFuture<? extends CommitInfo> future = strategy.commit();
final ResponseFactory response = new ResponseFactory(Status.OK);
- FutureCallbackTx.addCallback(future,
- RestconfDataServiceConstant.PatchData.PATCH_TX_TYPE,
- response,
- transactionChain); // closes transactionChain, may throw
+ FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PatchData.PATCH_TX_TYPE, response,
+ strategy.getTransactionChain()); // closes transactionChain if any, may throw
return response.build();
}
/**
* Merge data within one transaction.
- * @param dataStore Datastore to merge data to
- * @param path Path for data to be merged
- * @param payload Data to be merged
- * @param writeTransaction Transaction
+ *
+ * @param dataStore Datastore to merge data to
+ * @param path Path for data to be merged
+ * @param payload Data to be merged
+ * @param strategy Object that perform the actual DS operations
* @param schemaContext global schema context
*/
private static void mergeDataWithinTransaction(final LogicalDatastoreType dataStore,
final YangInstanceIdentifier path,
final NormalizedNode<?, ?> payload,
- final DOMDataTreeWriteTransaction writeTransaction,
+ final RestconfStrategy strategy,
final EffectiveModelContext schemaContext) {
LOG.trace("Merge {} within Restconf Patch: {} with payload {}", dataStore.name(), path, payload);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTransaction);
- writeTransaction.merge(dataStore, path, payload);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
+ strategy.merge(dataStore, path, payload);
}
}
import javax.ws.rs.core.UriInfo;
import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
}
/**
- * Check mount point and prepare variables for post data. Close {@link DOMTransactionChain} inside of object
- * {@link TransactionVarsWrapper} provided as a parameter.
+ * Check mount point and prepare variables for post data. Close {@link DOMTransactionChain} if any inside of object
+ * {@link RestconfStrategy} provided as a parameter.
*
- * @param uriInfo
- *
- * @param payload
- * data
- * @param transactionNode
- * wrapper for transaction data
- * @param schemaContext
- * reference to current {@link EffectiveModelContext}
- * @param point
- * point
- * @param insert
- * insert
+ * @param uriInfo uri info
+ * @param payload data
+ * @param strategy Object that perform the actual DS operations
+ * @param schemaContext reference to actual {@link EffectiveModelContext}
+ * @param point point
+ * @param insert insert
* @return {@link Response}
*/
public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload,
- final TransactionVarsWrapper transactionNode, final EffectiveModelContext schemaContext,
- final String insert, final String point) {
+ final RestconfStrategy strategy,
+ final EffectiveModelContext schemaContext, final String insert,
+ final String point) {
final FluentFuture<? extends CommitInfo> future = submitData(
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(),
- transactionNode, schemaContext, insert, point);
- final URI location = resolveLocation(uriInfo, transactionNode, schemaContext, payload.getData());
+ strategy, schemaContext, insert, point);
+ final URI location = resolveLocation(uriInfo, strategy.getInstanceIdentifier(),
+ schemaContext, payload.getData());
final ResponseFactory dataFactory = new ResponseFactory(Status.CREATED).location(location);
- //This method will close transactionChain
+ //This method will close transactionChain if any
FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory,
- transactionNode.getTransactionChain());
+ strategy.getTransactionChain());
return dataFactory.build();
}
/**
* Post data by type.
*
- * @param path
- * path
- * @param data
- * data
- * @param transactionNode
- * wrapper for data to transaction
- * @param schemaContext
- * schema context of data
- * @param point
- * query parameter
- * @param insert
- * query parameter
+ * @param path path
+ * @param data data
+ * @param strategy object that perform the actual DS operations
+ * @param schemaContext schema context of data
+ * @param point query parameter
+ * @param insert query parameter
* @return {@link FluentFuture}
*/
private static FluentFuture<? extends CommitInfo> submitData(final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> data, final TransactionVarsWrapper transactionNode,
- final EffectiveModelContext schemaContext, final String insert, final String point) {
- final DOMTransactionChain transactionChain = transactionNode.getTransactionChain();
- final DOMDataTreeReadWriteTransaction newReadWriteTransaction = transactionChain.newReadWriteTransaction();
+ final NormalizedNode<?, ?> data,
+ final RestconfStrategy strategy,
+ final EffectiveModelContext schemaContext,
+ final String insert, final String point) {
+ strategy.prepareReadWriteExecution();
if (insert == null) {
- makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
- return newReadWriteTransaction.commit();
+ makePost(path, data, schemaContext, strategy);
+ return strategy.commit();
}
final DataSchemaNode schemaNode = PutDataTransactionUtil.checkListAndOrderedType(schemaContext, path);
case "first":
if (schemaNode instanceof ListSchemaNode) {
final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
- schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
+ schemaContext, strategy, schemaNode);
final OrderedMapNode readList = (OrderedMapNode) readData;
if (readList == null || readList.getValue().isEmpty()) {
- makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
- return newReadWriteTransaction.commit();
+ makePost(path, data, schemaContext, strategy);
+ return strategy.commit();
}
- newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
- simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data, schemaContext,
- transactionChain);
- makePost(path, readData, schemaContext, transactionChain, newReadWriteTransaction);
- return newReadWriteTransaction.commit();
+ strategy.delete(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
+ simplePost(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext, strategy);
+ makePost(path, readData, schemaContext, strategy);
+ return strategy.commit();
} else {
final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
- schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
+ schemaContext, strategy, schemaNode);
final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
if (readLeafList == null || readLeafList.getValue().isEmpty()) {
- makePost(path, data, schemaContext, transactionChain,
- newReadWriteTransaction);
- return newReadWriteTransaction.commit();
+ makePost(path, data, schemaContext, strategy);
+ return strategy.commit();
}
- newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
- simplePost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data, schemaContext,
- transactionChain);
- makePost(path, readData, schemaContext, transactionChain, newReadWriteTransaction);
- return newReadWriteTransaction.commit();
+ strategy.delete(LogicalDatastoreType.CONFIGURATION, path.getParent().getParent());
+ simplePost(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext, strategy);
+ makePost(path, readData, schemaContext, strategy);
+ return strategy.commit();
}
case "last":
- makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
- return newReadWriteTransaction.commit();
+ makePost(path, data, schemaContext, strategy);
+ return strategy.commit();
case "before":
if (schemaNode instanceof ListSchemaNode) {
final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
- schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
+ schemaContext, strategy, schemaNode);
final OrderedMapNode readList = (OrderedMapNode) readData;
if (readList == null || readList.getValue().isEmpty()) {
- makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
- return newReadWriteTransaction.commit();
+ makePost(path, data, schemaContext, strategy);
+ return strategy.commit();
}
- insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
- data, schemaContext, point, readList, true, transactionChain);
- return newReadWriteTransaction.commit();
+ insertWithPointListPost(LogicalDatastoreType.CONFIGURATION, path,
+ data, schemaContext, point, readList, true, strategy);
+ return strategy.commit();
} else {
final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
- schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
+ schemaContext, strategy, schemaNode);
final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
if (readLeafList == null || readLeafList.getValue().isEmpty()) {
- makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
- return newReadWriteTransaction.commit();
+ makePost(path, data, schemaContext, strategy);
+ return strategy.commit();
}
- insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
- path, data, schemaContext, point, readLeafList, true, transactionChain);
- return newReadWriteTransaction.commit();
+ insertWithPointLeafListPost(LogicalDatastoreType.CONFIGURATION,
+ path, data, schemaContext, point, readLeafList, true, strategy);
+ return strategy.commit();
}
case "after":
if (schemaNode instanceof ListSchemaNode) {
final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
- schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
+ schemaContext, strategy, schemaNode);
final OrderedMapNode readList = (OrderedMapNode) readData;
if (readList == null || readList.getValue().isEmpty()) {
- makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
- return newReadWriteTransaction.commit();
+ makePost(path, data, schemaContext, strategy);
+ return strategy.commit();
}
- insertWithPointListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
- data, schemaContext, point, readList, false,
- transactionChain);
- return newReadWriteTransaction.commit();
+ insertWithPointListPost(LogicalDatastoreType.CONFIGURATION, path,
+ data, schemaContext, point, readList, false, strategy);
+ return strategy.commit();
} else {
final NormalizedNode<?, ?> readData = PutDataTransactionUtil.readList(path.getParent(),
- schemaContext, transactionNode.getTransactionChainHandler(), schemaNode);
+ schemaContext, strategy, schemaNode);
final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
if (readLeafList == null || readLeafList.getValue().isEmpty()) {
- makePost(path, data, schemaContext, transactionChain, newReadWriteTransaction);
- return newReadWriteTransaction.commit();
+ makePost(path, data, schemaContext, strategy);
+ return strategy.commit();
}
- insertWithPointLeafListPost(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION,
- path, data, schemaContext, point, readLeafList, true, transactionChain);
- return newReadWriteTransaction.commit();
+ insertWithPointLeafListPost(LogicalDatastoreType.CONFIGURATION,
+ path, data, schemaContext, point, readLeafList, true, strategy);
+ return strategy.commit();
}
default:
throw new RestconfDocumentedException(
}
}
- private static void insertWithPointLeafListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
- final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
- final EffectiveModelContext schemaContext, final String point, final OrderedLeafSetNode<?> readLeafList,
- final boolean before, final DOMTransactionChain transactionChain) {
- rwTransaction.delete(datastore, path.getParent().getParent());
+ private static void insertWithPointLeafListPost(final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> payload,
+ final EffectiveModelContext schemaContext, final String point,
+ final OrderedLeafSetNode<?> readLeafList,
+ final boolean before, final RestconfStrategy strategy) {
+ strategy.delete(datastore, path.getParent().getParent());
final InstanceIdentifierContext<?> instanceIdentifier =
ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
int lastItemPosition = 0;
int lastInsertedPosition = 0;
final NormalizedNode<?, ?> emptySubtree =
ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
- rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ strategy.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
if (lastInsertedPosition == lastItemPosition) {
- TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
+ TransactionUtil.checkItemDoesNotExists(strategy, datastore, path,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
- rwTransaction.put(datastore, path, payload);
+ strategy.create(datastore, path, payload);
}
final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
- TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, childPath,
+ TransactionUtil.checkItemDoesNotExists(strategy, datastore, childPath,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
- rwTransaction.put(datastore, childPath, nodeChild);
+ strategy.create(datastore, childPath, nodeChild);
lastInsertedPosition++;
}
}
- private static void insertWithPointListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
- final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
- final EffectiveModelContext schemaContext, final String point, final MapNode readList, final boolean before,
- final DOMTransactionChain transactionChain) {
- rwTransaction.delete(datastore, path.getParent().getParent());
+ private static void insertWithPointListPost(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> payload,
+ final EffectiveModelContext schemaContext, final String point,
+ final MapNode readList, final boolean before,
+ final RestconfStrategy strategy) {
+ strategy.delete(datastore, path.getParent().getParent());
final InstanceIdentifierContext<?> instanceIdentifier =
ParserIdentifier.toInstanceIdentifier(point, schemaContext, Optional.empty());
int lastItemPosition = 0;
int lastInsertedPosition = 0;
final NormalizedNode<?, ?> emptySubtree =
ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
- rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ strategy.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
for (final MapEntryNode mapEntryNode : readList.getValue()) {
if (lastInsertedPosition == lastItemPosition) {
- TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
+ TransactionUtil.checkItemDoesNotExists(strategy, datastore, path,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
- rwTransaction.put(datastore, path, payload);
+ strategy.create(datastore, path, payload);
}
final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
- TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, childPath,
+ TransactionUtil.checkItemDoesNotExists(strategy, datastore, childPath,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
- rwTransaction.put(datastore, childPath, mapEntryNode);
+ strategy.create(datastore, childPath, mapEntryNode);
lastInsertedPosition++;
}
}
private static void makePost(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
- final SchemaContext schemaContext, final DOMTransactionChain transactionChain,
- final DOMDataTreeReadWriteTransaction transaction) {
+ final SchemaContext schemaContext, final RestconfStrategy strategy) {
if (data instanceof MapNode) {
boolean merge = false;
for (final MapEntryNode child : ((MapNode) data).getValue()) {
final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
- TransactionUtil.checkItemDoesNotExists(
- transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
+ TransactionUtil.checkItemDoesNotExists(strategy, LogicalDatastoreType.CONFIGURATION, childPath,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
if (!merge) {
merge = true;
- TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
- transaction.merge(LogicalDatastoreType.CONFIGURATION,
+ strategy.merge(LogicalDatastoreType.CONFIGURATION,
YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
}
- transaction.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
+ strategy.create(LogicalDatastoreType.CONFIGURATION, childPath, child);
}
} else {
- TransactionUtil.checkItemDoesNotExists(
- transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, path,
+ TransactionUtil.checkItemDoesNotExists(strategy, LogicalDatastoreType.CONFIGURATION, path,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
- transaction.put(LogicalDatastoreType.CONFIGURATION, path, data);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
+ strategy.create(LogicalDatastoreType.CONFIGURATION, path, data);
}
}
/**
* Get location from {@link YangInstanceIdentifier} and {@link UriInfo}.
*
- * @param uriInfo
- * uri info
- * @param transactionNode
- * wrapper for data of transaction
- * @param schemaContext
- * reference to {@link SchemaContext}
+ * @param uriInfo uri info
+ * @param yangInstanceIdentifier reference to {@link InstanceIdentifierContext}
+ * @param schemaContext reference to {@link SchemaContext}
* @return {@link URI}
*/
- private static URI resolveLocation(final UriInfo uriInfo, final TransactionVarsWrapper transactionNode,
- final EffectiveModelContext schemaContext, final NormalizedNode<?, ?> data) {
+ private static URI resolveLocation(final UriInfo uriInfo, final InstanceIdentifierContext<?> yangInstanceIdentifier,
+ final EffectiveModelContext schemaContext, final NormalizedNode<?, ?> data) {
if (uriInfo == null) {
return null;
}
- YangInstanceIdentifier path = transactionNode.getInstanceIdentifier().getInstanceIdentifier();
+ YangInstanceIdentifier path = yangInstanceIdentifier.getInstanceIdentifier();
if (data instanceof MapNode) {
final Collection<MapEntryNode> children = ((MapNode) data).getValue();
.build();
}
- private static void simplePost(final DOMDataTreeReadWriteTransaction rwTransaction,
- final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload,
- final SchemaContext schemaContext, final DOMTransactionChain transactionChain) {
- TransactionUtil.checkItemDoesNotExists(transactionChain, rwTransaction, datastore, path,
+ private static void simplePost(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> payload,
+ final SchemaContext schemaContext, final RestconfStrategy strategy) {
+ TransactionUtil.checkItemDoesNotExists(strategy, datastore, path,
RestconfDataServiceConstant.PostData.POST_TX_TYPE);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
- rwTransaction.put(datastore, path, payload);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
+ strategy.create(datastore, path, payload);
}
}
import javax.ws.rs.core.Response.Status;
import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
-import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
public final class PutDataTransactionUtil {
private PutDataTransactionUtil() {
-
}
/**
* Valid input data with {@link SchemaNode}.
*
- * @param schemaNode
- * {@link SchemaNode}
- * @param payload
- * input data
+ * @param schemaNode {@link SchemaNode}
+ * @param payload input data
*/
public static void validInputData(final SchemaNode schemaNode, final NormalizedNodeContext payload) {
if (schemaNode != null && payload.getData() == null) {
/**
* Valid top level node name.
*
- * @param path
- * path of node
- * @param payload
- * data
+ * @param path path of node
+ * @param payload data
*/
public static void validTopLevelNodeName(final YangInstanceIdentifier path, final NormalizedNodeContext payload) {
final String payloadName = payload.getData().getNodeType().getLocalName();
* Validates whether keys in {@code payload} are equal to values of keys in
* {@code iiWithData} for list schema node.
*
- * @throws RestconfDocumentedException
- * if key values or key count in payload and URI isn't equal
+ * @throws RestconfDocumentedException if key values or key count in payload and URI isn't equal
*/
public static void validateListKeysEqualityInPayloadAndUri(final NormalizedNodeContext payload) {
final InstanceIdentifierContext<?> iiWithData = payload.getInstanceIdentifierContext();
}
private static void isEqualUriAndPayloadKeyValues(final Map<QName, Object> uriKeyValues, final MapEntryNode payload,
- final List<QName> keyDefinitions) {
+ final List<QName> keyDefinitions) {
final Map<QName, Object> mutableCopyUriKeyValues = new HashMap<>(uriKeyValues);
for (final QName keyDefinition : keyDefinitions) {
final Object uriKeyValue = RestconfDocumentedException.throwIfNull(
- mutableCopyUriKeyValues.remove(keyDefinition), ErrorType.PROTOCOL, ErrorTag.DATA_MISSING,
- "Missing key %s in URI.", keyDefinition);
+ mutableCopyUriKeyValues.remove(keyDefinition), ErrorType.PROTOCOL, ErrorTag.DATA_MISSING,
+ "Missing key %s in URI.", keyDefinition);
final Object dataKeyValue = payload.getIdentifier().getValue(keyDefinition);
}
/**
- * Check mount point and prepare variables for put data to DS. Close {@link DOMTransactionChain} inside of object
- * {@link TransactionVarsWrapper} provided as a parameter.
+ * Check mount point and prepare variables for put data to DS. Close {@link DOMTransactionChain} if any
+ * inside of object {@link RestconfStrategy} provided as a parameter if any.
*
- * @param payload
- * data to put
- * @param schemaContext
- * reference to {@link EffectiveModelContext}
- * @param transactionNode
- * wrapper of variables for transaction
- * @param point
- * query parameter
- * @param insert
- * query parameter
+ * @param payload data to put
+ * @param schemaContext reference to {@link EffectiveModelContext}
+ * @param strategy object that perform the actual DS operations
+ * @param point query parameter
+ * @param insert query parameter
* @return {@link Response}
*/
public static Response putData(final NormalizedNodeContext payload, final EffectiveModelContext schemaContext,
- final TransactionVarsWrapper transactionNode, final String insert, final String point) {
+ final RestconfStrategy strategy, final String insert, final String point) {
final YangInstanceIdentifier path = payload.getInstanceIdentifierContext().getInstanceIdentifier();
- final DOMDataTreeReadWriteTransaction readWriteTransaction =
- transactionNode.getTransactionChain().newReadWriteTransaction();
-
- final FluentFuture<Boolean> existsFuture = readWriteTransaction.exists(LogicalDatastoreType.CONFIGURATION,
- path);
+ strategy.prepareReadWriteExecution();
+ final FluentFuture<Boolean> existsFuture = strategy.exists(LogicalDatastoreType.CONFIGURATION, path);
final FutureDataFactory<Boolean> existsResponse = new FutureDataFactory<>();
FutureCallbackTx.addCallback(existsFuture, RestconfDataServiceConstant.PutData.PUT_TX_TYPE, existsResponse);
final ResponseFactory responseFactory =
new ResponseFactory(existsResponse.result ? Status.NO_CONTENT : Status.CREATED);
- final FluentFuture<? extends CommitInfo> submitData = submitData(path, schemaContext,
- transactionNode.getTransactionChainHandler(), readWriteTransaction, payload.getData(), insert, point);
- //This method will close transactionChain
+ final FluentFuture<? extends CommitInfo> submitData = submitData(path, schemaContext, strategy,
+ payload.getData(), insert, point, existsResponse.result);
+ //This method will close transactionChain if any
FutureCallbackTx.addCallback(submitData, RestconfDataServiceConstant.PutData.PUT_TX_TYPE, responseFactory,
- transactionNode.getTransactionChain());
+ strategy.getTransactionChain());
return responseFactory.build();
}
/**
* Put data to DS.
*
- * @param path
- * path of data
- * @param schemaContext
- * {@link SchemaContext}
- * @param transactionChainHandler
- * write transaction
- * @param data
- * data
- * @param point
- * query parameter
- * @param insert
- * query parameter
+ * @param path path of data
+ * @param schemaContext {@link SchemaContext}
+ * @param strategy object that perform the actual DS operations
+ * @param data data
+ * @param point query parameter
+ * @param insert query parameter
* @return {@link FluentFuture}
*/
- private static FluentFuture<? extends CommitInfo> submitData(final YangInstanceIdentifier path,
- final EffectiveModelContext schemaContext, final TransactionChainHandler transactionChainHandler,
- final DOMDataTreeReadWriteTransaction readWriteTransaction,
- final NormalizedNode<?, ?> data, final String insert, final String point) {
+ private static FluentFuture<? extends CommitInfo> submitData(
+ final YangInstanceIdentifier path,
+ final EffectiveModelContext schemaContext,
+ final RestconfStrategy strategy,
+ final NormalizedNode<?, ?> data, final String insert, final String point, final boolean exists) {
if (insert == null) {
- return makePut(path, schemaContext, readWriteTransaction, data);
+ return makePut(path, schemaContext, strategy, data, exists);
}
final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
switch (insert) {
case "first":
if (schemaNode instanceof ListSchemaNode) {
- final NormalizedNode<?, ?> readData =
- readList(path, schemaContext, transactionChainHandler, schemaNode);
+ final NormalizedNode<?, ?> readData = readList(path, schemaContext, strategy, schemaNode);
final OrderedMapNode readList = (OrderedMapNode) readData;
if (readList == null || readList.getValue().isEmpty()) {
- return makePut(path, schemaContext, readWriteTransaction, data);
+ return makePut(path, schemaContext, strategy, data, exists);
} else {
- readWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, path.getParent());
- simplePut(LogicalDatastoreType.CONFIGURATION, path, readWriteTransaction,
- schemaContext, data);
- listPut(LogicalDatastoreType.CONFIGURATION, path.getParent(), readWriteTransaction,
- schemaContext, readList);
- return readWriteTransaction.commit();
+ strategy.delete(LogicalDatastoreType.CONFIGURATION, path.getParent());
+ simplePut(LogicalDatastoreType.CONFIGURATION, path, strategy, schemaContext, data, exists);
+ listPut(LogicalDatastoreType.CONFIGURATION, path.getParent(), strategy,
+ schemaContext, readList, exists);
+ return strategy.commit();
}
} else {
- final NormalizedNode<?, ?> readData =
- readList(path, schemaContext, transactionChainHandler, schemaNode);
+ final NormalizedNode<?, ?> readData = readList(path, schemaContext, strategy, schemaNode);
final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
if (readLeafList == null || readLeafList.getValue().isEmpty()) {
- return makePut(path, schemaContext, readWriteTransaction, data);
+ return makePut(path, schemaContext, strategy, data, exists);
} else {
- readWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, path.getParent());
- simplePut(LogicalDatastoreType.CONFIGURATION, path, readWriteTransaction,
- schemaContext, data);
- listPut(LogicalDatastoreType.CONFIGURATION, path.getParent(), readWriteTransaction,
- schemaContext, readLeafList);
- return readWriteTransaction.commit();
+ strategy.delete(LogicalDatastoreType.CONFIGURATION, path.getParent());
+ simplePut(LogicalDatastoreType.CONFIGURATION, path, strategy,
+ schemaContext, data, exists);
+ listPut(LogicalDatastoreType.CONFIGURATION, path.getParent(), strategy,
+ schemaContext, readLeafList, exists);
+ return strategy.commit();
}
}
case "last":
- return makePut(path, schemaContext, readWriteTransaction, data);
+ return makePut(path, schemaContext, strategy, data, exists);
case "before":
if (schemaNode instanceof ListSchemaNode) {
- final NormalizedNode<?, ?> readData =
- readList(path, schemaContext, transactionChainHandler, schemaNode);
+ final NormalizedNode<?, ?> readData = readList(path, schemaContext, strategy, schemaNode);
final OrderedMapNode readList = (OrderedMapNode) readData;
if (readList == null || readList.getValue().isEmpty()) {
- return makePut(path, schemaContext, readWriteTransaction, data);
+ return makePut(path, schemaContext, strategy, data, exists);
} else {
- insertWithPointListPut(readWriteTransaction, LogicalDatastoreType.CONFIGURATION, path,
- data, schemaContext, point, readList, true);
- return readWriteTransaction.commit();
+ insertWithPointListPut(strategy, LogicalDatastoreType.CONFIGURATION, path,
+ data, schemaContext, point, readList, true, exists);
+ return strategy.commit();
}
} else {
- final NormalizedNode<?, ?> readData =
- readList(path, schemaContext, transactionChainHandler, schemaNode);
+ final NormalizedNode<?, ?> readData = readList(path, schemaContext, strategy, schemaNode);
final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
if (readLeafList == null || readLeafList.getValue().isEmpty()) {
- return makePut(path, schemaContext, readWriteTransaction, data);
+ return makePut(path, schemaContext, strategy, data, exists);
} else {
- insertWithPointLeafListPut(readWriteTransaction, LogicalDatastoreType.CONFIGURATION,
- path, data, schemaContext, point, readLeafList, true);
- return readWriteTransaction.commit();
+ insertWithPointLeafListPut(strategy, LogicalDatastoreType.CONFIGURATION,
+ path, data, schemaContext, point, readLeafList, true, exists);
+ return strategy.commit();
}
}
case "after":
if (schemaNode instanceof ListSchemaNode) {
- final NormalizedNode<?, ?> readData =
- readList(path, schemaContext, transactionChainHandler, schemaNode);
+ final NormalizedNode<?, ?> readData = readList(path, schemaContext, strategy, schemaNode);
final OrderedMapNode readList = (OrderedMapNode) readData;
if (readList == null || readList.getValue().isEmpty()) {
- return makePut(path, schemaContext, readWriteTransaction, data);
+ return makePut(path, schemaContext, strategy, data, exists);
} else {
- insertWithPointListPut(readWriteTransaction, LogicalDatastoreType.CONFIGURATION,
- path, data, schemaContext, point, readList, false);
- return readWriteTransaction.commit();
+ insertWithPointListPut(strategy, LogicalDatastoreType.CONFIGURATION,
+ path, data, schemaContext, point, readList, false, exists);
+ return strategy.commit();
}
} else {
- final NormalizedNode<?, ?> readData =
- readList(path, schemaContext, transactionChainHandler, schemaNode);
+ final NormalizedNode<?, ?> readData = readList(path, schemaContext, strategy, schemaNode);
final OrderedLeafSetNode<?> readLeafList = (OrderedLeafSetNode<?>) readData;
if (readLeafList == null || readLeafList.getValue().isEmpty()) {
- return makePut(path, schemaContext, readWriteTransaction, data);
+ return makePut(path, schemaContext, strategy, data, exists);
} else {
- insertWithPointLeafListPut(readWriteTransaction, LogicalDatastoreType.CONFIGURATION,
- path, data, schemaContext, point, readLeafList, true);
- return readWriteTransaction.commit();
+ insertWithPointLeafListPut(strategy, LogicalDatastoreType.CONFIGURATION,
+ path, data, schemaContext, point, readLeafList, true, exists);
+ return strategy.commit();
}
}
default:
}
public static NormalizedNode<?, ?> readList(final YangInstanceIdentifier path,
- final EffectiveModelContext schemaContext, final TransactionChainHandler transactionChainHandler,
- final DataSchemaNode schemaNode) {
+ final EffectiveModelContext schemaContext,
+ final RestconfStrategy strategy,
+ final DataSchemaNode schemaNode) {
final InstanceIdentifierContext<?> iid = new InstanceIdentifierContext<SchemaNode>(
path.getParent(), schemaNode, null, schemaContext);
- final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(iid, null, transactionChainHandler);
- final NormalizedNode<?, ?> readData = ReadDataTransactionUtil
- .readData(RestconfDataServiceConstant.ReadData.CONFIG, transactionNode, schemaContext);
- return readData;
+ final RestconfStrategy restconfStrategy = strategy.buildStrategy(iid);
+ return ReadDataTransactionUtil.readData(
+ RestconfDataServiceConstant.ReadData.CONFIG, restconfStrategy, schemaContext);
}
- private static void insertWithPointLeafListPut(final DOMDataTreeReadWriteTransaction rwTransaction,
- final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> data, final EffectiveModelContext schemaContext, final String point,
- final OrderedLeafSetNode<?> readLeafList, final boolean before) {
- rwTransaction.delete(datastore, path.getParent());
+ private static void insertWithPointLeafListPut(final RestconfStrategy strategy,
+ final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data,
+ final EffectiveModelContext schemaContext, final String point,
+ final OrderedLeafSetNode<?> readLeafList, final boolean before,
+ final boolean exists) {
+ strategy.delete(datastore, 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());
- rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ strategy.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
for (final LeafSetEntryNode<?> nodeChild : readLeafList.getValue()) {
if (lastInsertedPosition == lastItemPosition) {
- simplePut(datastore, path, rwTransaction, schemaContext, data);
+ simplePut(datastore, path, strategy, schemaContext, data, exists);
}
final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
- rwTransaction.put(datastore, childPath, nodeChild);
+ if (exists) {
+ strategy.replace(datastore, childPath, nodeChild);
+ } else {
+ strategy.create(datastore, childPath, nodeChild);
+ }
lastInsertedPosition++;
}
}
- private static void insertWithPointListPut(final DOMDataTreeReadWriteTransaction writeTx,
- final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> data, final EffectiveModelContext schemaContext, final String point,
- final OrderedMapNode readList, final boolean before) {
- writeTx.delete(datastore, path.getParent());
+ private static void insertWithPointListPut(final RestconfStrategy strategy,
+ final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data,
+ final EffectiveModelContext schemaContext, final String point,
+ final OrderedMapNode readList, final boolean before,
+ final boolean exists) {
+ strategy.delete(datastore, 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());
- writeTx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ strategy.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
for (final MapEntryNode mapEntryNode : readList.getValue()) {
if (lastInsertedPosition == lastItemPosition) {
- simplePut(datastore, path, writeTx, schemaContext, data);
+ simplePut(datastore, path, strategy, schemaContext, data, exists);
}
final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
- writeTx.put(datastore, childPath, mapEntryNode);
+ if (exists) {
+ strategy.replace(datastore, childPath, mapEntryNode);
+ } else {
+ strategy.create(datastore, childPath, mapEntryNode);
+ }
lastInsertedPosition++;
}
}
private static void listPut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
- final DOMDataTreeWriteTransaction writeTx, final SchemaContext schemaContext,
- final OrderedLeafSetNode<?> payload) {
+ final RestconfStrategy strategy, final SchemaContext schemaContext,
+ final OrderedLeafSetNode<?> payload, final boolean exists) {
final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
- writeTx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTx);
+ strategy.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
for (final LeafSetEntryNode<?> child : ((LeafSetNode<?>) payload).getValue()) {
final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
- writeTx.put(datastore, childPath, child);
+ if (exists) {
+ strategy.replace(datastore, childPath, child);
+ } else {
+ strategy.create(datastore, childPath, child);
+ }
}
}
private static void listPut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
- final DOMDataTreeWriteTransaction writeTx, final SchemaContext schemaContext,
- final OrderedMapNode payload) {
+ final RestconfStrategy strategy, final SchemaContext schemaContext,
+ final OrderedMapNode payload, final boolean exists) {
final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
- writeTx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTx);
+ strategy.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
for (final MapEntryNode child : payload.getValue()) {
final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
- writeTx.put(datastore, childPath, child);
+ if (exists) {
+ strategy.replace(datastore, childPath, child);
+ } else {
+ strategy.create(datastore, childPath, child);
+ }
}
}
private static void simplePut(final LogicalDatastoreType configuration, final YangInstanceIdentifier path,
- final DOMDataTreeWriteTransaction writeTx, final SchemaContext schemaContext,
- final NormalizedNode<?, ?> data) {
- TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTx);
- writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data);
+ final RestconfStrategy strategy, final SchemaContext schemaContext,
+ final NormalizedNode<?, ?> data, final boolean exists) {
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
+ if (exists) {
+ strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data);
+ } else {
+ strategy.create(LogicalDatastoreType.CONFIGURATION, path, data);
+ }
}
private static FluentFuture<? extends CommitInfo> makePut(final YangInstanceIdentifier path,
- final SchemaContext schemaContext, final DOMDataTreeWriteTransaction writeTx,
- final NormalizedNode<?, ?> data) {
- TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTx);
- writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data);
- return writeTx.commit();
+ final SchemaContext schemaContext,
+ final RestconfStrategy strategy,
+ final NormalizedNode<?, ?> data,
+ final boolean exists) {
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy);
+ if (exists) {
+ strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data);
+ } else {
+ strategy.create(LogicalDatastoreType.CONFIGURATION, path, data);
+ }
+ return strategy.commit();
}
public static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) {
package org.opendaylight.restconf.nb.rfc8040.rests.utils;
import com.google.common.primitives.Ints;
-import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.ListenableFuture;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.context.WriterParameters;
import org.opendaylight.restconf.common.context.WriterParameters.WriterParametersBuilder;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserFieldsParameter;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
/**
* Parse parameters from URI request and check their types and values.
*
- * @param identifier
- * {@link InstanceIdentifierContext}
- * @param uriInfo
- * URI info
+ * @param identifier {@link InstanceIdentifierContext}
+ * @param uriInfo URI info
* @return {@link WriterParameters}
*/
public static WriterParameters parseUriParameters(final InstanceIdentifierContext<?> identifier,
builder.setWithDefault(withDefaults.get(0));
}
}
-
return builder.build();
}
/**
* Read specific type of data from data store via transaction.
*
- * @param valueOfContent
- * type of data to read (config, state, all)
- * @param transactionNode
- * {@link TransactionVarsWrapper} - wrapper for variables
- * @param schemaContext
- * schema context
+ * @param valueOfContent type of data to read (config, state, all)
+ * @param strategy {@link RestconfStrategy} - wrapper for variables
+ * @param schemaContext schema context
* @return {@link NormalizedNode}
*/
public static @Nullable NormalizedNode<?, ?> readData(final @NonNull String valueOfContent,
- final @NonNull TransactionVarsWrapper transactionNode, final SchemaContext schemaContext) {
- return readData(valueOfContent, transactionNode, null, schemaContext);
+ final @NonNull RestconfStrategy strategy, final SchemaContext schemaContext) {
+ return readData(valueOfContent, strategy, null, schemaContext);
}
/**
- * Read specific type of data from data store via transaction. Close {@link DOMTransactionChain} inside of object
- * {@link TransactionVarsWrapper} provided as a parameter.
+ * Read specific type of data from data store via transaction. Close {@link DOMTransactionChain} if any
+ * inside of object {@link RestconfStrategy} provided as a parameter.
*
- * @param valueOfContent
- * type of data to read (config, state, all)
- * @param transactionNode
- * {@link TransactionVarsWrapper} - wrapper for variables
- * @param withDefa
- * value of with-defaults parameter
- * @param ctx
- * schema context
+ * @param valueOfContent type of data to read (config, state, all)
+ * @param strategy {@link RestconfStrategy} - object that perform the actual DS operations
+ * @param withDefa vaule of with-defaults parameter
+ * @param ctx schema context
* @return {@link NormalizedNode}
*/
public static @Nullable NormalizedNode<?, ?> readData(final @NonNull String valueOfContent,
- final @NonNull TransactionVarsWrapper transactionNode, final String withDefa, final SchemaContext ctx) {
+ final @NonNull RestconfStrategy strategy,
+ final String withDefa, final SchemaContext ctx) {
switch (valueOfContent) {
case RestconfDataServiceConstant.ReadData.CONFIG:
- transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
if (withDefa == null) {
- return readDataViaTransaction(transactionNode);
+ return readDataViaTransaction(strategy, LogicalDatastoreType.CONFIGURATION, true);
} else {
- return prepareDataByParamWithDef(readDataViaTransaction(transactionNode),
- transactionNode.getInstanceIdentifier().getInstanceIdentifier(), withDefa, ctx);
+ return prepareDataByParamWithDef(
+ readDataViaTransaction(strategy, LogicalDatastoreType.CONFIGURATION, true),
+ strategy.getInstanceIdentifier().getInstanceIdentifier(), withDefa, ctx);
}
case RestconfDataServiceConstant.ReadData.NONCONFIG:
- transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
- return readDataViaTransaction(transactionNode);
-
+ return readDataViaTransaction(strategy, LogicalDatastoreType.OPERATIONAL, true);
case RestconfDataServiceConstant.ReadData.ALL:
- return readAllData(transactionNode, withDefa, ctx);
-
+ return readAllData(strategy, withDefa, ctx);
default:
- transactionNode.getTransactionChain().close();
+ strategy.cancel();
throw new RestconfDocumentedException(
new RestconfError(RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.INVALID_VALUE,
"Invalid content parameter: " + valueOfContent, null,
}
/**
- * If is set specific {@link LogicalDatastoreType} in
- * {@link TransactionVarsWrapper}, then read this type of data from DS. If
- * don't, we have to read all data from DS (state + config).
- * This method will close {@link org.opendaylight.mdsal.dom.api.DOMTransactionChain} inside of
- * {@link TransactionVarsWrapper}.
- *
- * @param transactionNode
- * {@link TransactionVarsWrapper} - wrapper for variables
- * @return {@link NormalizedNode}
- */
- private static @Nullable NormalizedNode<?, ?> readDataViaTransaction(
- final @NonNull TransactionVarsWrapper transactionNode) {
- return readDataViaTransaction(transactionNode, true);
- }
-
-
- /**
- * If is set specific {@link LogicalDatastoreType} in
- * {@link TransactionVarsWrapper}, then read this type of data from DS. If
- * don't, we have to read all data from DS (state + config)
+ * If is set specific {@link LogicalDatastoreType} in {@link RestconfStrategy}, then read this type of data from DS.
+ * If don't, we have to read all data from DS (state + config)
*
- * @param transactionNode
- * {@link TransactionVarsWrapper} - wrapper for variables
- * @param closeTransactionChain
- * If is set to true, after transaction it will close transactionChain in {@link TransactionVarsWrapper}
+ * @param strategy {@link RestconfStrategy} - object that perform the actual DS operations
+ * @param closeTransactionChain If is set to true, after transaction it will close transactionChain
+ * in {@link RestconfStrategy} if any
* @return {@link NormalizedNode}
*/
private static @Nullable NormalizedNode<?, ?> readDataViaTransaction(
- final @NonNull TransactionVarsWrapper transactionNode, final boolean closeTransactionChain) {
+ final @NonNull RestconfStrategy strategy,
+ final LogicalDatastoreType store,
+ final boolean closeTransactionChain) {
final NormalizedNodeFactory dataFactory = new NormalizedNodeFactory();
- try (DOMDataTreeReadTransaction tx = transactionNode.getTransactionChain().newReadOnlyTransaction()) {
- final FluentFuture<Optional<NormalizedNode<?, ?>>> listenableFuture = tx.read(
- transactionNode.getLogicalDatastoreType(),
- transactionNode.getInstanceIdentifier().getInstanceIdentifier());
- if (closeTransactionChain) {
- //Method close transactionChain inside of TransactionVarsWrapper, if is provide as a parameter.
- FutureCallbackTx.addCallback(listenableFuture, RestconfDataServiceConstant.ReadData.READ_TYPE_TX,
- dataFactory, transactionNode.getTransactionChain());
- } else {
- FutureCallbackTx.addCallback(listenableFuture, RestconfDataServiceConstant.ReadData.READ_TYPE_TX,
- dataFactory);
- }
+ final ListenableFuture<Optional<NormalizedNode<?, ?>>> listenableFuture = strategy.read(
+ store, strategy.getInstanceIdentifier().getInstanceIdentifier());
+ if (closeTransactionChain) {
+ //Method close transactionChain if any
+ FutureCallbackTx.addCallback(listenableFuture, RestconfDataServiceConstant.ReadData.READ_TYPE_TX,
+ dataFactory, strategy.getTransactionChain());
+ } else {
+ FutureCallbackTx.addCallback(listenableFuture, RestconfDataServiceConstant.ReadData.READ_TYPE_TX,
+ dataFactory);
}
return dataFactory.build();
}
/**
* Read config and state data, then map them. Close {@link DOMTransactionChain} inside of object
- * {@link TransactionVarsWrapper} provided as a parameter.
+ * {@link RestconfStrategy} provided as a parameter if any.
*
- * @param transactionNode
- * {@link TransactionVarsWrapper} - wrapper for variables
- * @param withDefa
- * with-defaults parameter
- * @param ctx
- * schema context
+ * @param strategy {@link RestconfStrategy} - object that perform the actual DS operations
+ * @param withDefa with-defaults parameter
+ * @param ctx schema context
* @return {@link NormalizedNode}
*/
- private static @Nullable NormalizedNode<?, ?> readAllData(final @NonNull TransactionVarsWrapper transactionNode,
+ private static @Nullable NormalizedNode<?, ?> readAllData(final @NonNull RestconfStrategy strategy,
final String withDefa, final SchemaContext ctx) {
// PREPARE STATE DATA NODE
- transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
- final NormalizedNode<?, ?> stateDataNode = readDataViaTransaction(transactionNode, false);
+ final NormalizedNode<?, ?> stateDataNode = readDataViaTransaction(
+ strategy, LogicalDatastoreType.OPERATIONAL, false);
// PREPARE CONFIG DATA NODE
- transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
final NormalizedNode<?, ?> configDataNode;
- //Here will be closed transactionChain
+ //Here will be closed transactionChain if any
if (withDefa == null) {
- configDataNode = readDataViaTransaction(transactionNode);
+ configDataNode = readDataViaTransaction(
+ strategy, LogicalDatastoreType.CONFIGURATION, true);
} else {
- configDataNode = prepareDataByParamWithDef(readDataViaTransaction(transactionNode),
- transactionNode.getInstanceIdentifier().getInstanceIdentifier(), withDefa, ctx);
+ configDataNode = prepareDataByParamWithDef(
+ readDataViaTransaction(strategy, LogicalDatastoreType.CONFIGURATION, true),
+ strategy.getInstanceIdentifier().getInstanceIdentifier(), withDefa, ctx);
}
// if no data exists
/**
* Merge state and config data into a single NormalizedNode.
*
- * @param stateDataNode
- * data node of state data
- * @param configDataNode
- * data node of config data
+ * @param stateDataNode data node of state data
+ * @param configDataNode data node of config data
* @return {@link NormalizedNode}
*/
private static @NonNull NormalizedNode<?, ?> mergeStateAndConfigData(
/**
* Validates whether the two NormalizedNodes can be merged.
*
- * @param stateDataNode
- * data node of state data
- * @param configDataNode
- * data node of config data
+ * @param stateDataNode data node of state data
+ * @param configDataNode data node of config data
*/
private static void validateNodeMerge(final @NonNull NormalizedNode<?, ?> stateDataNode,
final @NonNull NormalizedNode<?, ?> configDataNode) {
/**
* Prepare and map data for rpc.
*
- * @param configDataNode
- * data node of config data
- * @param stateDataNode
- * data node of state data
+ * @param configDataNode data node of config data
+ * @param stateDataNode data node of state data
* @return {@link NormalizedNode}
*/
private static @NonNull NormalizedNode<?, ?> prepareRpcData(final @NonNull NormalizedNode<?, ?> configDataNode,
/**
* Map node to map entry builder.
*
- * @param dataNode
- * data node
- * @param mapEntryBuilder
- * builder for mapping data
+ * @param dataNode data node
+ * @param mapEntryBuilder builder for mapping data
*/
private static void mapRpcDataNode(final @NonNull NormalizedNode<?, ?> dataNode,
final @NonNull DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
/**
* Prepare and map all data from DS.
*
- * @param configDataNode
- * data node of config data
- * @param stateDataNode
- * data node of state data
+ * @param configDataNode data node of config data
+ * @param stateDataNode data node of state data
* @return {@link NormalizedNode}
*/
@SuppressWarnings("unchecked")
/**
* Map value from container node to builder.
*
- * @param configData
- * collection of config data nodes
- * @param stateData
- * collection of state data nodes
- * @param builder
- * builder
+ * @param configData collection of config data nodes
+ * @param stateData collection of state data nodes
+ * @param builder builder
*/
private static <T extends NormalizedNode<? extends PathArgument, ?>> void mapValueToBuilder(
final @NonNull Collection<T> configData, final @NonNull Collection<T> stateData,
* Map data with different identifiers to builder. Data with different identifiers can be just added
* as childs to parent node.
*
- * @param configMap
- * map of config data nodes
- * @param stateMap
- * map of state data nodes
- * @param builder
- * - builder
+ * @param configMap map of config data nodes
+ * @param stateMap map of state data nodes
+ * @param builder - builder
*/
private static <T extends NormalizedNode<? extends PathArgument, ?>> void mapDataToBuilder(
final @NonNull Map<PathArgument, T> configMap, final @NonNull Map<PathArgument, T> stateMap,
* Map data with the same identifiers to builder. Data with the same identifiers cannot be just added but we need to
* go one level down with {@code prepareData} method.
*
- * @param configMap
- * immutable config data
- * @param stateMap
- * immutable state data
- * @param builder
- * - builder
+ * @param configMap immutable config data
+ * @param stateMap immutable state data
+ * @param builder - builder
*/
@SuppressWarnings("unchecked")
private static <T extends NormalizedNode<? extends PathArgument, ?>> void mergeDataToBuilder(
*/
package org.opendaylight.restconf.nb.rfc8040.rests.utils;
-import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.FluentFuture;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
-import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
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.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
/**
* Merged parents of data.
*
- * @param path
- * path of data
- * @param schemaContext
- * {@link SchemaContext}
- * @param writeTx
- * write transaction
+ * @param path path of data
+ * @param schemaContext {@link SchemaContext}
+ * @param strategy object that perform the actual DS operations
*/
public static void ensureParentsByMerge(final YangInstanceIdentifier path, final SchemaContext schemaContext,
- final DOMDataTreeWriteTransaction writeTx) {
+ final RestconfStrategy strategy) {
final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
YangInstanceIdentifier rootNormalizedPath = null;
return;
}
- Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
-
final NormalizedNode<?, ?> parentStructure = ImmutableNodes.fromInstanceId(schemaContext,
YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
- writeTx.merge(LogicalDatastoreType.CONFIGURATION, rootNormalizedPath, parentStructure);
+ strategy.merge(LogicalDatastoreType.CONFIGURATION, rootNormalizedPath, parentStructure);
}
/**
* Check if items already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
* data does NOT already exists.
- * @param transactionChain Transaction chain
- * @param rwTransaction Transaction
- * @param store Datastore
- * @param path Path to be checked
+ *
+ * @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...)
*/
- public static void checkItemExists(final DOMTransactionChain transactionChain,
- final DOMDataTreeReadWriteTransaction rwTransaction,
+ public static void checkItemExists(final RestconfStrategy strategy,
final LogicalDatastoreType store, final YangInstanceIdentifier path,
final String operationType) {
- final FluentFuture<Boolean> future = rwTransaction.exists(store, path);
+ final FluentFuture<Boolean> future = strategy.exists(store, path);
final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
FutureCallbackTx.addCallback(future, operationType, response);
if (!response.result) {
// close transaction
- rwTransaction.cancel();
- transactionChain.close();
+ strategy.cancel();
// throw error
LOG.trace("Operation via Restconf was not executed because data at {} does not exist", path);
throw new RestconfDocumentedException(
/**
* Check if items do NOT already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
* data already exists.
- * @param transactionChain Transaction chain
- * @param rwTransaction Transaction
- * @param store Datastore
- * @param path Path to be checked
+ *
+ * @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...)
*/
- public static void checkItemDoesNotExists(final DOMTransactionChain transactionChain,
- final DOMDataTreeReadWriteTransaction rwTransaction,
+ public static void checkItemDoesNotExists(final RestconfStrategy strategy,
final LogicalDatastoreType store, final YangInstanceIdentifier path,
final String operationType) {
- final FluentFuture<Boolean> future = rwTransaction.exists(store, path);
+ final FluentFuture<Boolean> future = strategy.exists(store, path);
final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
FutureCallbackTx.addCallback(future, operationType, response);
if (response.result) {
// close transaction
- rwTransaction.cancel();
- transactionChain.close();
+ strategy.cancel();
// throw error
LOG.trace("Operation via Restconf was not executed because data at {} already exists", path);
throw new RestconfDocumentedException(
import org.opendaylight.mdsal.dom.api.DOMSchemaService;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.nb.rfc8040.handlers.SchemaContextHandler;
import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
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.NetconfRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
@Mock
private DOMDataBroker mountDataBroker;
@Mock
+ private NetconfDataTreeService netconfService;
+ @Mock
private ActionServiceHandler actionServiceHandler;
@Mock
private DOMTransactionChain mountTransactionChain;
final String errorMessage = status.getEditCollection().get(2).getEditErrors().get(0).getErrorMessage();
assertEquals("Data does not exist", errorMessage);
}
+
+ @Test
+ public void testGetRestconfStrategy() {
+ final InstanceIdentifierContext<? extends SchemaNode> iidContext = new InstanceIdentifierContext<>(
+ this.iidBase, this.schemaNode, this.mountPoint, this.contextRef);
+
+ RestconfStrategy restconfStrategy = this.dataService.getRestconfStrategy(iidContext, this.mountPoint);
+ assertTrue(restconfStrategy instanceof MdsalRestconfStrategy);
+
+ doReturn(Optional.of(this.netconfService)).when(this.mountPoint).getService(NetconfDataTreeService.class);
+ restconfStrategy = this.dataService.getRestconfStrategy(iidContext, this.mountPoint);
+ assertTrue(restconfStrategy instanceof NetconfRestconfStrategy);
+ }
}
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateTrueFluentFuture;
+import java.util.Optional;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.junit.Before;
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
public class DeleteDataTransactionUtilTest {
@Mock
private DOMDataTreeReadWriteTransaction readWrite;
@Mock
private DOMDataBroker mockDataBroker;
+ @Mock
+ private NetconfDataTreeService netconfService;
private TransactionChainHandler transactionChainHandler;
@Before
- public void init() throws Exception {
+ public void init() {
MockitoAnnotations.initMocks(this);
Mockito.when(this.transactionChain.newReadWriteTransaction()).thenReturn(this.readWrite);
Mockito.doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
+ Mockito.doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
Mockito.when(this.context.getInstanceIdentifier()).thenReturn(YangInstanceIdentifier.empty());
Mockito.doReturn(transactionChain).when(mockDataBroker).createTransactionChain(Mockito.any());
* Test of successful DELETE operation.
*/
@Test
- public void deleteData() throws Exception {
+ public void deleteData() {
// assert that data to delete exists
Mockito.when(this.transactionChain.newReadWriteTransaction().exists(LogicalDatastoreType.CONFIGURATION,
YangInstanceIdentifier.empty())).thenReturn(immediateTrueFluentFuture());
-
+ Mockito.when(this.netconfService.getConfig(YangInstanceIdentifier.empty()))
+ .thenReturn(immediateFluentFuture(Optional.of(mock(NormalizedNode.class))));
// test
- final Response response = DeleteDataTransactionUtil.deleteData(
- new TransactionVarsWrapper(this.context, null, transactionChainHandler));
-
- // assert success
- assertEquals("Not expected response received", Status.NO_CONTENT.getStatusCode(), response.getStatus());
+ delete(new MdsalRestconfStrategy(this.context, transactionChainHandler));
+ delete(new NetconfRestconfStrategy(netconfService, this.context));
}
/**
* Negative test for DELETE operation when data to delete does not exist. Error DATA_MISSING is expected.
*/
@Test
- public void deleteDataNegativeTest() throws Exception {
+ 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(this.netconfService.getConfig(YangInstanceIdentifier.empty()))
+ .thenReturn(immediateFluentFuture(Optional.empty()));
// test and assert error
+ deleteFail(new MdsalRestconfStrategy(this.context, transactionChainHandler));
+ deleteFail(new NetconfRestconfStrategy(netconfService, this.context));
+ }
+
+ private void delete(final RestconfStrategy strategy) {
+ final Response response = DeleteDataTransactionUtil.deleteData(strategy);
+ // assert success
+ assertEquals("Not expected response received", Status.NO_CONTENT.getStatusCode(), response.getStatus());
+ }
+
+ private void deleteFail(final RestconfStrategy strategy) {
try {
- DeleteDataTransactionUtil.deleteData(new TransactionVarsWrapper(this.context, null,
- transactionChainHandler));
+ DeleteDataTransactionUtil.deleteData(strategy);
fail("Delete operation should fail due to missing data");
} catch (final RestconfDocumentedException e) {
assertEquals(ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.opendaylight.restconf.common.patch.PatchEditOperation.CREATE;
import static org.opendaylight.restconf.common.patch.PatchEditOperation.DELETE;
import static org.opendaylight.restconf.common.patch.PatchEditOperation.REMOVE;
import static org.opendaylight.restconf.common.patch.PatchEditOperation.REPLACE;
import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateTrueFluentFuture;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
+import org.mockito.Mockito;
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.DOMDataTreeReadWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.restconf.common.patch.PatchContext;
import org.opendaylight.restconf.common.patch.PatchStatusEntity;
import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
public class PatchDataTransactionUtilTest {
-
private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/jukebox";
-
@Mock
private DOMTransactionChain transactionChain;
-
@Mock
private DOMDataTreeReadWriteTransaction rwTransaction;
-
@Mock
private DOMDataBroker mockDataBroker;
+ @Mock
+ private NetconfDataTreeService netconfService;
private TransactionChainHandler transactionChainHandler;
private EffectiveModelContext refSchemaCtx;
/* Mocks */
doReturn(this.rwTransaction).when(this.transactionChain).newReadWriteTransaction();
doReturn(CommitInfo.emptyFluentFuture()).when(this.rwTransaction).commit();
+ doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
}
@Test
final InstanceIdentifierContext<? extends SchemaNode> iidContext =
new InstanceIdentifierContext<>(this.instanceIdMerge, null, null, this.refSchemaCtx);
final PatchContext patchContext = new PatchContext(iidContext, entities, "patchRMRm");
- final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
- final PatchStatusContext patchStatusContext =
- PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
- for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
- assertTrue(entity.isOk());
- }
- assertTrue(patchStatusContext.isOk());
+ patch(patchContext, new MdsalRestconfStrategy(iidContext, transactionChainHandler), false);
+ patch(patchContext, new NetconfRestconfStrategy(netconfService, iidContext), false);
}
@Test
- public void testPatchDataCreateAndDelete() throws Exception {
+ public void testPatchDataCreateAndDelete() {
doReturn(immediateFalseFluentFuture()).when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION,
this.instanceIdContainer);
+ Mockito.when(this.netconfService.getConfig(this.instanceIdContainer))
+ .thenReturn(immediateFluentFuture(Optional.empty()));
doReturn(immediateTrueFluentFuture()).when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION,
this.targetNodeForCreateAndDelete);
+ Mockito.when(this.netconfService.getConfig(this.targetNodeForCreateAndDelete))
+ .thenReturn(immediateFluentFuture(Optional.of(mock(NormalizedNode.class))));
final PatchEntity entityCreate =
new PatchEntity("edit1", CREATE, this.instanceIdContainer, this.buildBaseContainerForTests);
final InstanceIdentifierContext<? extends SchemaNode> iidContext =
new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx);
final PatchContext patchContext = new PatchContext(iidContext, entities, "patchCD");
- final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
- final PatchStatusContext patchStatusContext =
- PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
-
- for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
- assertTrue("Edit " + entity.getEditId() + " failed", entity.isOk());
- }
- assertTrue(patchStatusContext.isOk());
+ patch(patchContext, new MdsalRestconfStrategy(iidContext, transactionChainHandler), true);
+ patch(patchContext, new NetconfRestconfStrategy(netconfService, iidContext), true);
}
@Test
public void deleteNonexistentDataTest() {
doReturn(immediateFalseFluentFuture()).when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION,
this.targetNodeForCreateAndDelete);
+ Mockito.when(this.netconfService.getConfig(this.targetNodeForCreateAndDelete))
+ .thenReturn(immediateFluentFuture(Optional.empty()));
final PatchEntity entityDelete = new PatchEntity("edit", DELETE, this.targetNodeForCreateAndDelete);
final List<PatchEntity> entities = new ArrayList<>();
final InstanceIdentifierContext<? extends SchemaNode> iidContext =
new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx);
final PatchContext patchContext = new PatchContext(iidContext, entities, "patchD");
- final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
- final PatchStatusContext patchStatusContext =
- PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
-
- assertFalse(patchStatusContext.isOk());
- assertEquals(RestconfError.ErrorType.PROTOCOL,
- patchStatusContext.getEditCollection().get(0).getEditErrors().get(0).getErrorType());
- assertEquals(RestconfError.ErrorTag.DATA_MISSING,
- patchStatusContext.getEditCollection().get(0).getEditErrors().get(0).getErrorTag());
+ delete(patchContext, new MdsalRestconfStrategy(iidContext, transactionChainHandler));
+ delete(patchContext, new NetconfRestconfStrategy(netconfService, iidContext));
}
@Test
- public void testPatchMergePutContainer() throws Exception {
+ public void testPatchMergePutContainer() {
doReturn(immediateFalseFluentFuture()).doReturn(immediateTrueFluentFuture())
.when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
final InstanceIdentifierContext<? extends SchemaNode> iidContext =
new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx);
final PatchContext patchContext = new PatchContext(iidContext, entities, "patchM");
- final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
- final PatchStatusContext patchStatusContext =
- PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
+ patch(patchContext, new MdsalRestconfStrategy(iidContext, transactionChainHandler), false);
+ patch(patchContext, new NetconfRestconfStrategy(netconfService, iidContext), false);
+ }
+ private void patch(final PatchContext patchContext, final RestconfStrategy strategy,
+ final boolean failed) {
+ final PatchStatusContext patchStatusContext =
+ PatchDataTransactionUtil.patchData(patchContext, strategy, this.refSchemaCtx);
for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
- assertTrue(entity.isOk());
+ if (failed) {
+ assertTrue("Edit " + entity.getEditId() + " failed", entity.isOk());
+ } else {
+ assertTrue(entity.isOk());
+ }
}
assertTrue(patchStatusContext.isOk());
}
+
+ private void delete(PatchContext patchContext, RestconfStrategy strategy) {
+ final PatchStatusContext patchStatusContext =
+ PatchDataTransactionUtil.patchData(patchContext, strategy, this.refSchemaCtx);
+
+ assertFalse(patchStatusContext.isOk());
+ assertEquals(RestconfError.ErrorType.PROTOCOL,
+ patchStatusContext.getEditCollection().get(0).getEditErrors().get(0).getErrorType());
+ assertEquals(RestconfError.ErrorTag.DATA_MISSING,
+ patchStatusContext.getEditCollection().get(0).getEditErrors().get(0).getErrorTag());
+ }
}
import static org.mockito.Mockito.verify;
import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
public class PlainPatchDataTransactionUtilTest {
-
private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/jukebox";
-
@Mock
private DOMTransactionChain transactionChain;
@Mock
private DOMDataTreeWriteTransaction write;
@Mock
private DOMDataBroker mockDataBroker;
+ @Mock
+ private NetconfDataTreeService netconfService;
private TransactionChainHandler transactionChainHandler;
private LeafNode<?> leafGap;
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
+ doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
PlainPatchDataTransactionUtil.patchData(payload,
- new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, transactionChainHandler),
+ new MdsalRestconfStrategy(iidContext, transactionChainHandler),
this.schema);
-
verify(this.readWrite).merge(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
+
+ PlainPatchDataTransactionUtil.patchData(payload,
+ new NetconfRestconfStrategy(netconfService, iidContext),
+ this.schema);
+ verify(this.netconfService).merge(LogicalDatastoreType.CONFIGURATION,
+ payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
}
@Test
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
+ doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
- PlainPatchDataTransactionUtil.patchData(payload,
- new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, transactionChainHandler),
+ PlainPatchDataTransactionUtil.patchData(payload, new MdsalRestconfStrategy(iidContext, transactionChainHandler),
this.schema);
-
verify(this.readWrite).merge(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
+
+ PlainPatchDataTransactionUtil.patchData(payload, new NetconfRestconfStrategy(netconfService, iidContext),
+ this.schema);
+ verify(this.netconfService).merge(LogicalDatastoreType.CONFIGURATION,
+ payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
}
@Test
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
+ doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
PlainPatchDataTransactionUtil.patchData(payload,
- new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, transactionChainHandler),
+ new MdsalRestconfStrategy(iidContext, transactionChainHandler),
this.schema);
-
verify(this.readWrite).merge(LogicalDatastoreType.CONFIGURATION, this.iidJukebox, payload.getData());
+
+ PlainPatchDataTransactionUtil.patchData(payload, new NetconfRestconfStrategy(netconfService, iidContext),
+ this.schema);
+ verify(this.netconfService).merge(LogicalDatastoreType.CONFIGURATION, this.iidJukebox, payload.getData(),
+ Optional.empty());
}
}
import static org.mockito.Mockito.verify;
import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Collection;
+import java.util.Optional;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
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.DOMTransactionChain;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
@Mock
private DOMDataTreeReadTransaction read;
@Mock
- private DOMDataTreeWriteTransaction write;
- @Mock
private UriInfo uriInfo;
@Mock
- private UriBuilder uriBuilder;
- @Mock
private DOMDataBroker mockDataBroker;
+ @Mock
+ private NetconfDataTreeService netconfService;
private TransactionChainHandler transactionChainHandler;
private ContainerNode buildBaseCont;
doReturn(immediateFalseFluentFuture()).when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION,
this.iid2);
+ doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService).getConfig(this.iid2);
final NodeIdentifier identifier =
((ContainerNode) ((Collection<?>) payload.getData().getValue()).iterator().next()).getIdentifier();
final YangInstanceIdentifier node =
doReturn(immediateFalseFluentFuture()).when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, node, payload.getData());
doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
- final TransactionVarsWrapper wrapper =
- new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, transactionChainHandler);
- final Response response =
- PostDataTransactionUtil.postData(this.uriInfo, payload, wrapper, this.schema, null, null);
+ doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
+
+ Response response = PostDataTransactionUtil.postData(this.uriInfo, payload,
+ new MdsalRestconfStrategy(iidContext, transactionChainHandler), this.schema, null, null);
assertEquals(201, response.getStatus());
verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
+
+ response = PostDataTransactionUtil.postData(this.uriInfo, payload,
+ new NetconfRestconfStrategy(netconfService, iidContext), this.schema, null, null);
+ assertEquals(201, response.getStatus());
+ verify(this.netconfService).getConfig(this.iid2);
+ verify(this.netconfService).create(LogicalDatastoreType.CONFIGURATION,
+ payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
}
@Test
final YangInstanceIdentifier node =
payload.getInstanceIdentifierContext().getInstanceIdentifier().node(identifier);
doReturn(immediateFalseFluentFuture()).when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
+ doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService).getConfig(node);
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, node, payload.getData());
doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
- final TransactionVarsWrapper wrapper =
- new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, transactionChainHandler);
- final Response response =
- PostDataTransactionUtil.postData(this.uriInfo, payload, wrapper, this.schema, null, null);
+ doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
+
+ Response response = PostDataTransactionUtil.postData(this.uriInfo, payload,
+ new MdsalRestconfStrategy(iidContext, transactionChainHandler), this.schema, null, null);
assertEquals(201, response.getStatus());
assertThat(URLDecoder.decode(response.getLocation().toString(), "UTF-8"),
containsString(identifier.getValue(identifier.keySet().iterator().next()).toString()));
verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, node, data.getValue().iterator().next());
+
+ response = PostDataTransactionUtil.postData(this.uriInfo, payload,
+ new NetconfRestconfStrategy(netconfService, iidContext), this.schema, null, null);
+ assertEquals(201, response.getStatus());
+ assertThat(URLDecoder.decode(response.getLocation().toString(), "UTF-8"),
+ containsString(identifier.getValue(identifier.keySet().iterator().next()).toString()));
+ verify(this.netconfService).getConfig(node);
+ verify(this.netconfService).create(LogicalDatastoreType.CONFIGURATION, node, data.getValue().iterator().next(),
+ Optional.empty());
}
@Test
doReturn(immediateFalseFluentFuture()).when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION,
this.iid2);
+ doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService).getConfig(this.iid2);
final NodeIdentifier identifier =
((ContainerNode) ((Collection<?>) payload.getData().getValue()).iterator().next()).getIdentifier();
final YangInstanceIdentifier node =
payload.getInstanceIdentifierContext().getInstanceIdentifier().node(identifier);
doReturn(immediateFalseFluentFuture()).when(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, node);
+ doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService).getConfig(node);
doNothing().when(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, node, payload.getData());
final DOMException domException = new DOMException((short) 414, "Post request failed");
doReturn(immediateFailedFluentFuture(domException)).when(this.readWrite).commit();
- final TransactionVarsWrapper wrapper =
- new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, transactionChainHandler);
+ doReturn(immediateFailedFluentFuture(domException)).when(this.netconfService).commit(Mockito.any());
try {
- PostDataTransactionUtil.postData(this.uriInfo, payload, wrapper, this.schema, null, null);
+ PostDataTransactionUtil.postData(this.uriInfo, payload,
+ new MdsalRestconfStrategy(iidContext, transactionChainHandler), this.schema, null, null);
fail("Expected RestconfDocumentedException");
} catch (final RestconfDocumentedException e) {
assertEquals(1, e.getErrors().size());
verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
+
+ try {
+ PostDataTransactionUtil.postData(this.uriInfo, payload,
+ new NetconfRestconfStrategy(netconfService, iidContext), this.schema, null, null);
+ fail("Expected RestconfDocumentedException");
+ } catch (final RestconfDocumentedException e) {
+ assertEquals(1, e.getErrors().size());
+ assertTrue(e.getErrors().get(0).getErrorInfo().contains(domException.getMessage()));
+ }
+
+ verify(this.netconfService).getConfig(this.iid2);
+ verify(this.netconfService).create(LogicalDatastoreType.CONFIGURATION,
+ payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
}
}
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
public class PutDataTransactionUtilTest {
-
private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/jukebox";
-
@Mock
private DOMTransactionChain transactionChain;
@Mock
private DOMDataTreeWriteTransaction write;
@Mock
private DOMDataBroker mockDataBroker;
+ @Mock
+ private NetconfDataTreeService netconfService;
private TransactionChainHandler transactionChainHandler;
private LeafNode<?> buildLeaf;
}
@Test
- public void testValidInputData() throws Exception {
+ public void testValidInputData() {
final InstanceIdentifierContext<DataSchemaNode> iidContext =
new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
}
@Test
- public void testValidTopLevelNodeName() throws Exception {
+ public void testValidTopLevelNodeName() {
InstanceIdentifierContext<DataSchemaNode> iidContext =
new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
}
@Test(expected = RestconfDocumentedException.class)
- public void testValidTopLevelNodeNamePathEmpty() throws Exception {
+ public void testValidTopLevelNodeNamePathEmpty() {
final InstanceIdentifierContext<DataSchemaNode> iidContext =
new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
}
@Test(expected = RestconfDocumentedException.class)
- public void testValidTopLevelNodeNameWrongTopIdentifier() throws Exception {
+ public void testValidTopLevelNodeNameWrongTopIdentifier() {
final InstanceIdentifierContext<DataSchemaNode> iidContext =
new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
}
@Test
- public void testValidateListKeysEqualityInPayloadAndUri() throws Exception {
+ public void testValidateListKeysEqualityInPayloadAndUri() {
final InstanceIdentifierContext<DataSchemaNode> iidContext =
new InstanceIdentifierContext<>(this.iid3, this.schemaNode3, null, this.schema);
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildListEntry);
}
@Test
- public void testPutContainerData() throws Exception {
+ public void testPutContainerData() {
final InstanceIdentifierContext<DataSchemaNode> iidContext =
new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
PutDataTransactionUtil.putData(payload, this.schema,
- new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, transactionChainHandler), null,
- null);
+ new MdsalRestconfStrategy(iidContext, transactionChainHandler), null, null);
verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier());
verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
}
@Test
- public void testPutleafData() throws Exception {
+ public void testPutCreateContainerData() {
+ final InstanceIdentifierContext<DataSchemaNode> iidContext =
+ new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
+ final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
+
+ doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService).getConfig(this.iid2);
+ doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
+
+ PutDataTransactionUtil.putData(payload, this.schema,
+ new NetconfRestconfStrategy(netconfService, iidContext), null, null);
+ verify(this.netconfService).getConfig(payload.getInstanceIdentifierContext().getInstanceIdentifier());
+ verify(this.netconfService).create(LogicalDatastoreType.CONFIGURATION,
+ payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
+ }
+
+ @Test
+ public void testPutReplaceContainerData() {
+ final InstanceIdentifierContext<DataSchemaNode> iidContext =
+ new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
+ final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseCont);
+
+ doReturn(immediateFluentFuture(Optional.of(mock(NormalizedNode.class))))
+ .when(this.netconfService).getConfig(this.iid2);
+ doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
+
+ PutDataTransactionUtil.putData(payload, this.schema,
+ new NetconfRestconfStrategy(netconfService, iidContext), null, null);
+ verify(this.netconfService).getConfig(payload.getInstanceIdentifierContext().getInstanceIdentifier());
+ verify(this.netconfService).replace(LogicalDatastoreType.CONFIGURATION,
+ payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
+ }
+
+ @Test
+ public void testPutLeafData() {
final InstanceIdentifierContext<DataSchemaNode> iidContext =
new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
PutDataTransactionUtil.putData(payload, this.schema,
- new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, transactionChainHandler), null,
- null);
+ new MdsalRestconfStrategy(iidContext, transactionChainHandler), null, null);
verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION,
payload.getInstanceIdentifierContext().getInstanceIdentifier());
verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION,
}
@Test
- public void testPutListData() throws Exception {
+ public void testPutCreateLeafData() {
+ final InstanceIdentifierContext<DataSchemaNode> iidContext =
+ new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
+ final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
+
+ doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService).getConfig(this.iid);
+ doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
+
+ PutDataTransactionUtil.putData(payload, this.schema,
+ new NetconfRestconfStrategy(netconfService, iidContext), null, null);
+ verify(this.netconfService).getConfig(payload.getInstanceIdentifierContext().getInstanceIdentifier());
+ verify(this.netconfService).create(LogicalDatastoreType.CONFIGURATION,
+ payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
+ }
+
+ @Test
+ public void testPutReplaceLeafData() {
+ final InstanceIdentifierContext<DataSchemaNode> iidContext =
+ new InstanceIdentifierContext<>(this.iid, this.schemaNode, null, this.schema);
+ final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildLeaf);
+
+ doReturn(immediateFluentFuture(Optional.of(mock(NormalizedNode.class))))
+ .when(this.netconfService).getConfig(this.iid);
+ doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
+
+ PutDataTransactionUtil.putData(payload, this.schema,
+ new NetconfRestconfStrategy(netconfService, iidContext), null, null);
+ verify(this.netconfService).getConfig(payload.getInstanceIdentifierContext().getInstanceIdentifier());
+ verify(this.netconfService).replace(LogicalDatastoreType.CONFIGURATION,
+ payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
+ }
+
+ @Test
+ public void testPutListData() {
final InstanceIdentifierContext<DataSchemaNode> iidContext =
new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseContWithList);
payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
doReturn(CommitInfo.emptyFluentFuture()).when(this.readWrite).commit();
PutDataTransactionUtil.putData(payload, this.schema,
- new TransactionVarsWrapper(payload.getInstanceIdentifierContext(), null, transactionChainHandler), null,
- null);
+ new MdsalRestconfStrategy(iidContext, transactionChainHandler), null, null);
verify(this.readWrite).exists(LogicalDatastoreType.CONFIGURATION, this.iid2);
verify(this.readWrite).put(LogicalDatastoreType.CONFIGURATION, this.iid2, payload.getData());
}
+
+ @Test
+ public void testPutCreateListData() {
+ final InstanceIdentifierContext<DataSchemaNode> iidContext =
+ new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
+ final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseContWithList);
+
+ doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService)
+ .getConfig(this.iid2);
+ doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
+
+ PutDataTransactionUtil.putData(payload, this.schema,
+ new NetconfRestconfStrategy(netconfService, iidContext), null, null);
+ verify(this.netconfService).getConfig(this.iid2);
+ verify(this.netconfService).create(LogicalDatastoreType.CONFIGURATION, this.iid2,
+ payload.getData(), Optional.empty());
+ }
+
+ @Test
+ public void testPutReplaceListData() {
+ final InstanceIdentifierContext<DataSchemaNode> iidContext =
+ new InstanceIdentifierContext<>(this.iid2, this.schemaNode2, null, this.schema);
+ final NormalizedNodeContext payload = new NormalizedNodeContext(iidContext, this.buildBaseContWithList);
+
+ doReturn(immediateFluentFuture(Optional.of(mock(NormalizedNode.class)))).when(this.netconfService)
+ .getConfig(this.iid2);
+ doReturn(CommitInfo.emptyFluentFuture()).when(this.netconfService).commit(Mockito.any());
+
+ PutDataTransactionUtil.putData(payload, this.schema,
+ new NetconfRestconfStrategy(netconfService, iidContext), null, null);
+ verify(this.netconfService).getConfig(this.iid2);
+ verify(this.netconfService).replace(LogicalDatastoreType.CONFIGURATION, this.iid2,
+ payload.getData(), Optional.empty());
+ }
}
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.context.WriterParameters;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfDataServiceConstant.ReadData;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
private static final YangInstanceIdentifier.NodeIdentifier NODE_IDENTIFIER = new YangInstanceIdentifier
.NodeIdentifier(QName.create("ns", "2016-02-28", "container"));
- private TransactionVarsWrapper wrapper;
+ private RestconfStrategy mdsalStrategy;
+ private RestconfStrategy netconfStrategy;
+ @Mock
+ private NetconfDataTreeService netconfService;
@Mock
private DOMTransactionChain transactionChain;
@Mock
DOMDataBroker mockDataBroker = Mockito.mock(DOMDataBroker.class);
Mockito.doReturn(transactionChain).when(mockDataBroker).createTransactionChain(Mockito.any());
- wrapper = new TransactionVarsWrapper(this.context, null, new TransactionChainHandler(mockDataBroker));
+ mdsalStrategy = new MdsalRestconfStrategy(this.context, new TransactionChainHandler(mockDataBroker));
+ netconfStrategy = new NetconfRestconfStrategy(this.netconfService, this.context);
}
@Test
public void readDataConfigTest() {
doReturn(immediateFluentFuture(Optional.of(DATA.data3))).when(read)
.read(LogicalDatastoreType.CONFIGURATION, DATA.path);
+ doReturn(immediateFluentFuture(Optional.of(DATA.data3))).when(this.netconfService).getConfig(DATA.path);
doReturn(DATA.path).when(context).getInstanceIdentifier();
final String valueOfContent = RestconfDataServiceConstant.ReadData.CONFIG;
- final NormalizedNode<?, ?> normalizedNode =
- ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
+ NormalizedNode<?, ?> normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, mdsalStrategy, schemaContext);
+ assertEquals(DATA.data3, normalizedNode);
+
+ normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, netconfStrategy, schemaContext);
assertEquals(DATA.data3, normalizedNode);
}
.read(LogicalDatastoreType.CONFIGURATION, DATA.path);
doReturn(immediateFluentFuture(Optional.empty())).when(read)
.read(LogicalDatastoreType.OPERATIONAL, DATA.path);
+ doReturn(immediateFluentFuture(Optional.of(DATA.data3))).when(this.netconfService).getConfig(DATA.path);
+ doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService).get(DATA.path);
doReturn(DATA.path).when(context).getInstanceIdentifier();
final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
- final NormalizedNode<?, ?> normalizedNode =
- ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
+ NormalizedNode<?, ?> normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, mdsalStrategy, schemaContext);
+ assertEquals(DATA.data3, normalizedNode);
+
+ normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, netconfStrategy, schemaContext);
assertEquals(DATA.data3, normalizedNode);
}
.read(LogicalDatastoreType.OPERATIONAL, DATA.path2);
doReturn(immediateFluentFuture(Optional.empty())).when(read)
.read(LogicalDatastoreType.CONFIGURATION, DATA.path2);
+ doReturn(immediateFluentFuture(Optional.of(DATA.data2))).when(this.netconfService).get(DATA.path2);
+ doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService).getConfig(DATA.path2);
doReturn(DATA.path2).when(context).getInstanceIdentifier();
final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
- final NormalizedNode<?, ?> normalizedNode =
- ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
+ NormalizedNode<?, ?> normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, mdsalStrategy, schemaContext);
+ assertEquals(DATA.data2, normalizedNode);
+
+ normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, netconfStrategy, schemaContext);
assertEquals(DATA.data2, normalizedNode);
}
public void readDataNonConfigTest() {
doReturn(immediateFluentFuture(Optional.of(DATA.data2))).when(read)
.read(LogicalDatastoreType.OPERATIONAL, DATA.path2);
+ doReturn(immediateFluentFuture(Optional.of(DATA.data2))).when(this.netconfService).get(DATA.path2);
doReturn(DATA.path2).when(context).getInstanceIdentifier();
final String valueOfContent = RestconfDataServiceConstant.ReadData.NONCONFIG;
- final NormalizedNode<?, ?> normalizedNode =
- ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
+ NormalizedNode<?, ?> normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, mdsalStrategy, schemaContext);
+ assertEquals(DATA.data2, normalizedNode);
+
+ normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, netconfStrategy, schemaContext);
assertEquals(DATA.data2, normalizedNode);
}
.read(LogicalDatastoreType.CONFIGURATION, DATA.path);
doReturn(immediateFluentFuture(Optional.of(DATA.data4))).when(read)
.read(LogicalDatastoreType.OPERATIONAL, DATA.path);
+ doReturn(immediateFluentFuture(Optional.of(DATA.data3))).when(this.netconfService).getConfig(DATA.path);
+ doReturn(immediateFluentFuture(Optional.of(DATA.data4))).when(this.netconfService).get(DATA.path);
doReturn(DATA.path).when(context).getInstanceIdentifier();
final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
- final NormalizedNode<?, ?> normalizedNode =
- ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
final ContainerNode checkingData = Builders
.containerBuilder()
.withNodeIdentifier(NODE_IDENTIFIER)
.withChild(DATA.contentLeaf)
.withChild(DATA.contentLeaf2)
.build();
+ NormalizedNode<?, ?> normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, mdsalStrategy, schemaContext);
+ assertEquals(checkingData, normalizedNode);
+
+ normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, netconfStrategy, schemaContext);
assertEquals(checkingData, normalizedNode);
}
.read(LogicalDatastoreType.CONFIGURATION, DATA.path);
doReturn(immediateFluentFuture(Optional.of(DATA.data4))).when(read)
.read(LogicalDatastoreType.OPERATIONAL, DATA.path);
+ doReturn(immediateFluentFuture(Optional.of(DATA.data3))).when(this.netconfService).getConfig(DATA.path);
+ doReturn(immediateFluentFuture(Optional.of(DATA.data4))).when(this.netconfService).get(DATA.path);
doReturn(DATA.path).when(context).getInstanceIdentifier();
- final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(
- RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
final ContainerNode checkingData = Builders
.containerBuilder()
.withNodeIdentifier(NODE_IDENTIFIER)
.withChild(DATA.contentLeaf)
.withChild(DATA.contentLeaf2)
.build();
+ NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(
+ RestconfDataServiceConstant.ReadData.ALL, mdsalStrategy, schemaContext);
+ assertEquals(checkingData, normalizedNode);
+
+ normalizedNode = ReadDataTransactionUtil.readData(
+ RestconfDataServiceConstant.ReadData.ALL, netconfStrategy, schemaContext);
assertEquals(checkingData, normalizedNode);
}
.read(LogicalDatastoreType.OPERATIONAL, DATA.path3);
doReturn(immediateFluentFuture(Optional.of(DATA.listData2))).when(read)
.read(LogicalDatastoreType.CONFIGURATION, DATA.path3);
+ doReturn(immediateFluentFuture(Optional.of(DATA.listData))).when(this.netconfService).get(DATA.path3);
+ doReturn(immediateFluentFuture(Optional.of(DATA.listData2))).when(this.netconfService).getConfig(DATA.path3);
doReturn(DATA.path3).when(context).getInstanceIdentifier();
final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
- final NormalizedNode<?, ?> normalizedNode =
- ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
final MapNode checkingData = Builders
.mapBuilder()
.withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create("ns", "2016-02-28", "list")))
.withChild(DATA.checkData)
.build();
+ NormalizedNode<?, ?> normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, mdsalStrategy, schemaContext);
+ assertEquals(checkingData, normalizedNode);
+
+ normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, netconfStrategy, schemaContext);
assertEquals(checkingData, normalizedNode);
}
.read(LogicalDatastoreType.OPERATIONAL, DATA.path3);
doReturn(immediateFluentFuture(Optional.of(DATA.orderedMapNode2))).when(read)
.read(LogicalDatastoreType.CONFIGURATION, DATA.path3);
+ doReturn(immediateFluentFuture(Optional.of(DATA.orderedMapNode1))).when(this.netconfService).get(DATA.path3);
+ doReturn(immediateFluentFuture(Optional.of(DATA.orderedMapNode2))).when(this.netconfService)
+ .getConfig(DATA.path3);
doReturn(DATA.path3).when(context).getInstanceIdentifier();
-
- final NormalizedNode<?, ?> normalizedNode =
- ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
-
final MapNode expectedData = Builders.orderedMapBuilder()
.withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DATA.listQname)).withChild(DATA.checkData)
.build();
+ NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil
+ .readData(RestconfDataServiceConstant.ReadData.ALL, mdsalStrategy, schemaContext);
+ assertEquals(expectedData, normalizedNode);
+
+ normalizedNode = ReadDataTransactionUtil
+ .readData(RestconfDataServiceConstant.ReadData.ALL, netconfStrategy, schemaContext);
assertEquals(expectedData, normalizedNode);
}
.read(LogicalDatastoreType.OPERATIONAL, DATA.path3);
doReturn(immediateFluentFuture(Optional.of(DATA.unkeyedListNode2))).when(read)
.read(LogicalDatastoreType.CONFIGURATION, DATA.path3);
+ doReturn(immediateFluentFuture(Optional.of(DATA.unkeyedListNode1))).when(this.netconfService).get(DATA.path3);
+ doReturn(immediateFluentFuture(Optional.of(DATA.unkeyedListNode2))).when(this.netconfService)
+ .getConfig(DATA.path3);
doReturn(DATA.path3).when(context).getInstanceIdentifier();
-
- final NormalizedNode<?, ?> normalizedNode =
- ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
-
final UnkeyedListNode expectedData = Builders.unkeyedListBuilder()
.withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DATA.listQname))
.withChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(
new YangInstanceIdentifier.NodeIdentifier(DATA.listQname))
.withChild(DATA.unkeyedListEntryNode1.getValue().iterator().next())
.withChild(DATA.unkeyedListEntryNode2.getValue().iterator().next()).build()).build();
+ NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil
+ .readData(RestconfDataServiceConstant.ReadData.ALL, mdsalStrategy, schemaContext);
+ assertEquals(expectedData, normalizedNode);
+
+ normalizedNode = ReadDataTransactionUtil
+ .readData(RestconfDataServiceConstant.ReadData.ALL, netconfStrategy, schemaContext);
assertEquals(expectedData, normalizedNode);
}
.read(LogicalDatastoreType.OPERATIONAL, DATA.leafSetNodePath);
doReturn(immediateFluentFuture(Optional.of(DATA.leafSetNode2))).when(read)
.read(LogicalDatastoreType.CONFIGURATION, DATA.leafSetNodePath);
+ doReturn(immediateFluentFuture(Optional.of(DATA.leafSetNode1))).when(this.netconfService)
+ .get(DATA.leafSetNodePath);
+ doReturn(immediateFluentFuture(Optional.of(DATA.leafSetNode2))).when(this.netconfService)
+ .getConfig(DATA.leafSetNodePath);
doReturn(DATA.leafSetNodePath).when(context).getInstanceIdentifier();
-
- final NormalizedNode<?, ?> normalizedNode =
- ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
-
final LeafSetNode<String> expectedData = Builders.<String>leafSetBuilder().withNodeIdentifier(
new YangInstanceIdentifier.NodeIdentifier(DATA.leafListQname)).withValue(
ImmutableList.<LeafSetEntryNode<String>>builder().addAll(DATA.leafSetNode1.getValue())
.addAll(DATA.leafSetNode2.getValue()).build()).build();
+ NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil
+ .readData(RestconfDataServiceConstant.ReadData.ALL, mdsalStrategy, schemaContext);
+ assertEquals(expectedData, normalizedNode);
+
+ normalizedNode = ReadDataTransactionUtil
+ .readData(RestconfDataServiceConstant.ReadData.ALL, netconfStrategy, schemaContext);
assertEquals(expectedData, normalizedNode);
}
.read(LogicalDatastoreType.OPERATIONAL, DATA.leafSetNodePath);
doReturn(immediateFluentFuture(Optional.of(DATA.orderedLeafSetNode2))).when(read)
.read(LogicalDatastoreType.CONFIGURATION, DATA.leafSetNodePath);
+ doReturn(immediateFluentFuture(Optional.of(DATA.orderedLeafSetNode1))).when(this.netconfService)
+ .get(DATA.leafSetNodePath);
+ doReturn(immediateFluentFuture(Optional.of(DATA.orderedLeafSetNode2))).when(this.netconfService)
+ .getConfig(DATA.leafSetNodePath);
doReturn(DATA.leafSetNodePath).when(context).getInstanceIdentifier();
-
- final NormalizedNode<?, ?> normalizedNode =
- ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
-
final LeafSetNode<String> expectedData = Builders.<String>orderedLeafSetBuilder().withNodeIdentifier(
new YangInstanceIdentifier.NodeIdentifier(DATA.leafListQname)).withValue(
ImmutableList.<LeafSetEntryNode<String>>builder().addAll(DATA.orderedLeafSetNode1.getValue())
.addAll(DATA.orderedLeafSetNode2.getValue()).build()).build();
+ NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil
+ .readData(RestconfDataServiceConstant.ReadData.ALL, mdsalStrategy, schemaContext);
+ assertEquals(expectedData, normalizedNode);
+
+ normalizedNode = ReadDataTransactionUtil
+ .readData(RestconfDataServiceConstant.ReadData.ALL, netconfStrategy, schemaContext);
assertEquals(expectedData, normalizedNode);
}
public void readDataWrongPathOrNoContentTest() {
doReturn(immediateFluentFuture(Optional.empty())).when(read)
.read(LogicalDatastoreType.CONFIGURATION, DATA.path2);
+ doReturn(immediateFluentFuture(Optional.empty())).when(this.netconfService).getConfig(DATA.path2);
doReturn(DATA.path2).when(context).getInstanceIdentifier();
final String valueOfContent = RestconfDataServiceConstant.ReadData.CONFIG;
- final NormalizedNode<?, ?> normalizedNode =
- ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
+ NormalizedNode<?, ?> normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, mdsalStrategy, schemaContext);
+ assertNull(normalizedNode);
+
+ normalizedNode =
+ ReadDataTransactionUtil.readData(valueOfContent, netconfStrategy, schemaContext);
assertNull(normalizedNode);
}
@Test(expected = RestconfDocumentedException.class)
public void readDataFailTest() {
final String valueOfContent = RestconfDataServiceConstant.ReadData.READ_TYPE_TX;
- final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(
- valueOfContent, wrapper, schemaContext);
+ NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(
+ valueOfContent, mdsalStrategy, schemaContext);
+ assertNull(normalizedNode);
+
+ normalizedNode = ReadDataTransactionUtil.readData(
+ valueOfContent, netconfStrategy, schemaContext);
assertNull(normalizedNode);
}