import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.eclipse.jdt.annotation.Nullable;
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.ModifyAction;
+import org.opendaylight.netconf.api.EffectiveOperation;
import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices.Rpcs;
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.ErrorSeverity;
import org.opendaylight.yangtools.yang.common.RpcError;
-import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
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 abstract class AbstractNetconfDataTreeService implements NetconfDataTreeService {
+public abstract sealed class AbstractNetconfDataTreeService implements NetconfDataTreeService {
private static final class Candidate extends AbstractNetconfDataTreeService {
- Candidate(final RemoteDeviceId id, final NetconfBaseOps netconfOps, final boolean rollbackSupport) {
- super(id, netconfOps, rollbackSupport);
+ Candidate(final RemoteDeviceId id, final NetconfBaseOps netconfOps, final boolean rollbackSupport,
+ final boolean lockDatastore) {
+ super(id, netconfOps, rollbackSupport, lockDatastore);
}
/**
}
@Override
- ListenableFuture<? extends DOMRpcResult> editConfig(final DataContainerChild<?, ?> editStructure,
- final ModifyAction defaultOperation) {
+ ListenableFuture<? extends DOMRpcResult> editConfig(final DataContainerChild editStructure,
+ final EffectiveOperation defaultOperation) {
final NetconfRpcFutureCallback callback = new NetconfRpcFutureCallback("Edit candidate", id);
return defaultOperation == null ? netconfOps.editConfigCandidate(callback, editStructure, rollbackSupport)
: netconfOps.editConfigCandidate(callback, editStructure, defaultOperation, rollbackSupport);
}
private static final class Running extends AbstractNetconfDataTreeService {
- Running(final RemoteDeviceId id, final NetconfBaseOps netconfOps, final boolean rollbackSupport) {
- super(id, netconfOps, rollbackSupport);
+ Running(final RemoteDeviceId id, final NetconfBaseOps netconfOps, final boolean rollbackSupport,
+ final boolean lockDatastore) {
+ super(id, netconfOps, rollbackSupport, lockDatastore);
}
@Override
return RPC_SUCCESS;
}
+ @Override
+ public ListenableFuture<DOMRpcResult> commit() {
+ // No candidate, hence we commit immediately
+ return RPC_SUCCESS;
+ }
+
@Override
ListenableFuture<? extends DOMRpcResult> lockSingle() {
return netconfOps.lockRunning(new NetconfRpcFutureCallback("Lock running", id));
}
@Override
- ListenableFuture<? extends DOMRpcResult> editConfig(final DataContainerChild<?, ?> editStructure,
- final ModifyAction defaultOperation) {
+ ListenableFuture<? extends DOMRpcResult> editConfig(final DataContainerChild editStructure,
+ final EffectiveOperation defaultOperation) {
final NetconfRpcFutureCallback callback = new NetconfRpcFutureCallback("Edit running", id);
return defaultOperation == null ? netconfOps.editConfigRunning(callback, editStructure, rollbackSupport)
: netconfOps.editConfigRunning(callback, editStructure, defaultOperation, rollbackSupport);
private final Running running;
CandidateWithRunning(final RemoteDeviceId id, final NetconfBaseOps netconfOps,
- final boolean rollbackSupport) {
- super(id, netconfOps, rollbackSupport);
- candidate = new Candidate(id, netconfOps, rollbackSupport);
- running = new Running(id, netconfOps, rollbackSupport);
+ final boolean rollbackSupport, final boolean lockDatastore) {
+ super(id, netconfOps, rollbackSupport, lockDatastore);
+ candidate = new Candidate(id, netconfOps, rollbackSupport, lockDatastore);
+ running = new Running(id, netconfOps, rollbackSupport, lockDatastore);
}
@Override
}
@Override
- ListenableFuture<? extends DOMRpcResult> editConfig(final DataContainerChild<?, ?> editStructure,
- final ModifyAction defaultOperation) {
+ ListenableFuture<? extends DOMRpcResult> editConfig(final DataContainerChild editStructure,
+ final EffectiveOperation defaultOperation) {
return candidate.editConfig(editStructure, defaultOperation);
}
-
}
private static final Logger LOG = LoggerFactory.getLogger(AbstractNetconfDataTreeService.class);
final NetconfBaseOps netconfOps;
final boolean rollbackSupport;
- // FIXME: what do we do with locks acquired before this got flipped?
- private volatile boolean isLockAllowed = true;
+ private final boolean lockDatastore;
AbstractNetconfDataTreeService(final RemoteDeviceId id, final NetconfBaseOps netconfOps,
- final boolean rollbackSupport) {
+ final boolean rollbackSupport, final boolean lockDatastore) {
this.id = requireNonNull(id);
this.netconfOps = requireNonNull(netconfOps);
this.rollbackSupport = rollbackSupport;
+ this.lockDatastore = lockDatastore;
}
public static @NonNull AbstractNetconfDataTreeService of(final RemoteDeviceId id,
- final MountPointContext mountContext, final DOMRpcService rpc,
- final NetconfSessionPreferences netconfSessionPreferences) {
- final NetconfBaseOps netconfOps = new NetconfBaseOps(rpc, mountContext);
- final boolean rollbackSupport = netconfSessionPreferences.isRollbackSupported();
+ final MountPointContext mountContext, final Rpcs rpcs,
+ final NetconfSessionPreferences sessionPreferences, final boolean lockDatastore) {
+ final var netconfOps = new NetconfBaseOps(rpcs, mountContext);
+ final boolean rollbackSupport = sessionPreferences.isRollbackSupported();
// Examine preferences and decide which implementation to use
- if (netconfSessionPreferences.isCandidateSupported()) {
- return netconfSessionPreferences.isRunningWritable()
- ? new CandidateWithRunning(id, netconfOps, rollbackSupport)
- : new Candidate(id, netconfOps, rollbackSupport);
- } else if (netconfSessionPreferences.isRunningWritable()) {
- return new Running(id, netconfOps, rollbackSupport);
+ if (sessionPreferences.isCandidateSupported()) {
+ return sessionPreferences.isRunningWritable()
+ ? new CandidateWithRunning(id, netconfOps, rollbackSupport, lockDatastore)
+ : new Candidate(id, netconfOps, rollbackSupport, lockDatastore);
+ } else if (sessionPreferences.isRunningWritable()) {
+ return new Running(id, netconfOps, rollbackSupport, lockDatastore);
} else {
throw new IllegalArgumentException("Device " + id.getName() + " has advertised neither :writable-running "
+ "nor :candidate capability. Failed to establish session, as at least one of these must be "
@Override
public synchronized ListenableFuture<DOMRpcResult> lock() {
- if (!isLockAllowed) {
+ if (!lockDatastore) {
LOG.trace("Lock is not allowed by device configuration, ignoring lock results: {}", id);
return RPC_SUCCESS;
}
final ListenableFuture<DOMRpcResult> result = mergeFutures(lockImpl());
- Futures.addCallback(result, new FutureCallback<DOMRpcResult>() {
+ Futures.addCallback(result, new FutureCallback<>() {
@Override
public void onSuccess(final DOMRpcResult result) {
- final var errors = result.getErrors();
+ final var errors = result.errors();
if (errors.isEmpty()) {
LOG.debug("{}: Lock successful.", id);
return;
@Override
public synchronized ListenableFuture<DOMRpcResult> unlock() {
- // FIXME: deal with lock with lifecycle?
- if (!isLockAllowed) {
+ if (!lockDatastore) {
LOG.trace("Unlock is not allowed: {}", id);
return RPC_SUCCESS;
}
final ListenableFuture<DOMRpcResult> result = mergeFutures(unlockImpl());
- Futures.addCallback(result, new FutureCallback<DOMRpcResult>() {
+ Futures.addCallback(result, new FutureCallback<>() {
@Override
public void onSuccess(final DOMRpcResult result) {
- final var errors = result.getErrors();
+ final var errors = result.errors();
if (errors.isEmpty()) {
LOG.debug("{}: Unlock successful.", id);
return;
abstract List<ListenableFuture<? extends DOMRpcResult>> unlockImpl();
@Override
- public ListenableFuture<Optional<NormalizedNode<?, ?>>> get(final YangInstanceIdentifier path) {
+ public ListenableFuture<Optional<NormalizedNode>> get(final YangInstanceIdentifier path) {
return netconfOps.getData(new NetconfRpcFutureCallback("Data read", id), Optional.ofNullable(path));
}
@Override
- public ListenableFuture<Optional<NormalizedNode<?, ?>>> get(final YangInstanceIdentifier path,
+ public ListenableFuture<Optional<NormalizedNode>> get(final YangInstanceIdentifier path,
final List<YangInstanceIdentifier> fields) {
return netconfOps.getData(new NetconfRpcFutureCallback("Data read", id), Optional.ofNullable(path), fields);
}
@Override
- public ListenableFuture<Optional<NormalizedNode<?, ?>>> getConfig(final YangInstanceIdentifier path) {
+ public ListenableFuture<Optional<NormalizedNode>> getConfig(final YangInstanceIdentifier path) {
return netconfOps.getConfigRunningData(new NetconfRpcFutureCallback("Data read", id),
Optional.ofNullable(path));
}
@Override
- public ListenableFuture<Optional<NormalizedNode<?, ?>>> getConfig(final YangInstanceIdentifier path,
+ public ListenableFuture<Optional<NormalizedNode>> getConfig(final YangInstanceIdentifier path,
final List<YangInstanceIdentifier> fields) {
return netconfOps.getConfigRunningData(new NetconfRpcFutureCallback("Data read", id),
Optional.ofNullable(path), fields);
@Override
public synchronized ListenableFuture<? extends DOMRpcResult> merge(final LogicalDatastoreType store,
- final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
- final Optional<ModifyAction> defaultOperation) {
+ final YangInstanceIdentifier path, final NormalizedNode data,
+ final Optional<EffectiveOperation> defaultOperation) {
checkEditable(store);
return editConfig(
- netconfOps.createEditConfigStrcture(Optional.ofNullable(data), Optional.of(ModifyAction.MERGE), path),
+ netconfOps.createEditConfigStructure(Optional.ofNullable(data), Optional.of(EffectiveOperation.MERGE),
+ path),
defaultOperation.orElse(null));
}
@Override
public synchronized ListenableFuture<? extends DOMRpcResult> replace(final LogicalDatastoreType store,
- final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
- final Optional<ModifyAction> defaultOperation) {
+ final YangInstanceIdentifier path, final NormalizedNode data,
+ final Optional<EffectiveOperation> defaultOperation) {
checkEditable(store);
return editConfig(
- netconfOps.createEditConfigStrcture(Optional.ofNullable(data), Optional.of(ModifyAction.REPLACE), path),
+ netconfOps.createEditConfigStructure(Optional.ofNullable(data), Optional.of(EffectiveOperation.REPLACE),
+ path),
defaultOperation.orElse(null));
}
@Override
public synchronized ListenableFuture<? extends DOMRpcResult> create(final LogicalDatastoreType store,
- final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
- final Optional<ModifyAction> defaultOperation) {
+ final YangInstanceIdentifier path, final NormalizedNode data,
+ final Optional<EffectiveOperation> defaultOperation) {
checkEditable(store);
return editConfig(
- netconfOps.createEditConfigStrcture(Optional.ofNullable(data), Optional.of(ModifyAction.CREATE), path),
+ netconfOps.createEditConfigStructure(Optional.ofNullable(data), Optional.of(EffectiveOperation.CREATE),
+ path),
defaultOperation.orElse(null));
}
@Override
public synchronized ListenableFuture<? extends DOMRpcResult> delete(final LogicalDatastoreType store,
final YangInstanceIdentifier path) {
- return editConfig(netconfOps.createEditConfigStrcture(Optional.empty(), Optional.of(ModifyAction.DELETE), path),
- null);
+ return editConfig(netconfOps.createEditConfigStructure(Optional.empty(),
+ Optional.of(EffectiveOperation.DELETE), path), null);
}
@Override
public synchronized ListenableFuture<? extends DOMRpcResult> remove(final LogicalDatastoreType store,
final YangInstanceIdentifier path) {
- return editConfig(netconfOps.createEditConfigStrcture(Optional.empty(), Optional.of(ModifyAction.REMOVE), path),
- null);
+ return editConfig(netconfOps.createEditConfigStructure(Optional.empty(),
+ Optional.of(EffectiveOperation.REMOVE), path), null);
}
@Override
return id;
}
- final void setLockAllowed(final boolean isLockAllowedOrig) {
- this.isLockAllowed = isLockAllowedOrig;
- }
-
- abstract ListenableFuture<? extends DOMRpcResult> editConfig(DataContainerChild<?, ?> editStructure,
- @Nullable ModifyAction defaultOperation);
+ abstract ListenableFuture<? extends DOMRpcResult> editConfig(DataContainerChild editStructure,
+ @Nullable EffectiveOperation defaultOperation);
private static void checkEditable(final LogicalDatastoreType store) {
checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can only edit configuration data, not %s", store);
final var builder = ImmutableList.<RpcError>builder();
for (ListenableFuture<? extends DOMRpcResult> future : futures) {
- builder.addAll(Futures.getDone(future).getErrors());
+ builder.addAll(Futures.getDone(future).errors());
}
return new DefaultDOMRpcResult(null, builder.build());
}, MoreExecutors.directExecutor());
}
- @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
- justification = "https://github.com/spotbugs/spotbugs/issues/811")
private static boolean allWarnings(final Collection<? extends @NonNull RpcError> errors) {
return errors.stream().allMatch(error -> error.getSeverity() == ErrorSeverity.WARNING);
}