import java.util.Collection;
import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
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.client.mdsal.api.RemoteDeviceId;
-import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs;
import org.opendaylight.netconf.topology.singleton.impl.utils.ClusteringRpcException;
import org.opendaylight.netconf.topology.singleton.messages.NormalizedNodeMessage;
import org.opendaylight.netconf.topology.singleton.messages.SchemaPathMessage;
import org.slf4j.LoggerFactory;
import scala.concurrent.Future;
-public class ProxyDOMRpcService implements Rpcs.Normalized {
+public class ProxyDOMRpcService implements DOMRpcService {
private static final Logger LOG = LoggerFactory.getLogger(ProxyDOMRpcService.class);
private final ActorRef masterActorRef;
readTxActor = context().actorOf(ReadTransactionActor.props(tx));
final var deviceServices = masterActorData.getDeviceServices();
- deviceRpc = deviceServices.rpcs() instanceof Rpcs.Normalized normalized ? normalized : null;
+ deviceRpc = deviceServices.rpcs() instanceof Rpcs.Normalized normalized ? normalized.domRpcService() : null;
deviceAction = deviceServices.actions() instanceof Actions.Normalized normalized ? normalized : null;
sender().tell(new MasterActorDataInitialized(), self());
}
private void sendYangTextSchemaSourceProxy(final SourceIdentifier sourceIdentifier, final ActorRef sender) {
- final ListenableFuture<YangTextSchemaSource> schemaSourceFuture =
- schemaRepository.getSchemaSource(sourceIdentifier, YangTextSchemaSource.class);
-
- Futures.addCallback(schemaSourceFuture, new FutureCallback<YangTextSchemaSource>() {
+ final var schemaSourceFuture = schemaRepository.getSchemaSource(sourceIdentifier, YangTextSchemaSource.class);
+ Futures.addCallback(schemaSourceFuture, new FutureCallback<>() {
@Override
public void onSuccess(final YangTextSchemaSource yangTextSchemaSource) {
try {
final SlaveSalFacade localSlaveSalManager, final ActorRef masterReference, final int tries) {
final ListenableFuture<EffectiveModelContext> schemaContextFuture =
schemaContextFactory.createEffectiveModelContext(sourceIdentifiers);
- Futures.addCallback(schemaContextFuture, new FutureCallback<EffectiveModelContext>() {
+ Futures.addCallback(schemaContextFuture, new FutureCallback<>() {
@Override
public void onSuccess(final EffectiveModelContext result) {
executeInSelf(() -> {
LOG.info("{}: Schema context resolved: {} - registering slave mount point",
id, result.getModules());
final var actorSystem = setup.getActorSystem();
+ final var rpcProxy = new ProxyDOMRpcService(actorSystem, masterReference, id,
+ actorResponseWaitTime);
slaveSalManager.registerSlaveMountPoint(result, masterReference, new RemoteDeviceServices(
- new ProxyDOMRpcService(actorSystem, masterReference, id, actorResponseWaitTime),
+ (Rpcs.Normalized) () -> rpcProxy,
new ProxyDOMActionService(actorSystem, masterReference, id, actorResponseWaitTime)));
}
});
import org.opendaylight.mdsal.dom.api.DOMMountPoint;
import org.opendaylight.mdsal.dom.api.DOMMountPointListener;
import org.opendaylight.mdsal.dom.api.DOMMountPointService;
-import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
import org.opendaylight.mdsal.dom.api.DOMRpcImplementation;
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.util.concurrent.FluentFutures;
import org.opendaylight.yangtools.yang.binding.DataObject;
DOMRpcIdentifier.create(putTopRpcSchemaPath), DOMRpcIdentifier.create(getTopRpcSchemaPath));
final var rpcService = router.getRpcService();
- deviceRpcService = new Rpcs.Normalized() {
- @Override
- public ListenableFuture<? extends DOMRpcResult> invokeRpc(final QName type, final ContainerNode input) {
- return rpcService.invokeRpc(type, input);
- }
-
- @Override
- public <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(
- final T listener) {
- return rpcService.registerRpcListener(listener);
- }
- };
+ deviceRpcService = () -> rpcService;
builderFactory = new NetconfClientConfigurationBuilderFactoryImpl(mockEncryptionService, credentialProvider,
sslHandlerFactoryProvider);
private final SharedSchemaRepository masterSchemaRepository = new SharedSchemaRepository("master");
@Mock
- private Rpcs.Normalized mockDOMRpcService;
+ private Rpcs.Normalized mockRpc;
+ @Mock
+ private DOMRpcService mockDOMRpcService;
@Mock
private Actions.Normalized mockDOMActionService;
@Mock
doReturn(mockSchemaSourceReg1).when(mockRegistry).registerSchemaSource(any(), withSourceId(SOURCE_IDENTIFIER1));
doReturn(mockSchemaSourceReg2).when(mockRegistry).registerSchemaSource(any(), withSourceId(SOURCE_IDENTIFIER2));
- doReturn(mockSchemaContextFactory).when(mockSchemaRepository)
- .createEffectiveModelContextFactory();
+ doReturn(mockSchemaContextFactory).when(mockSchemaRepository).createEffectiveModelContextFactory();
+
+ doReturn(mockDOMRpcService).when(mockRpc).domRpcService();
+
}
@After
initializeMaster(List.of());
registerSlaveMountPoint();
- ArgumentCaptor<DOMDataBroker> domDataBrokerCaptor = ArgumentCaptor.forClass(DOMDataBroker.class);
+ final var domDataBrokerCaptor = ArgumentCaptor.forClass(DOMDataBroker.class);
verify(mockMountPointBuilder).addService(eq(DOMDataBroker.class), domDataBrokerCaptor.capture());
final DOMDataBroker slaveDOMDataBroker = domDataBrokerCaptor.getValue();
private void initializeMaster(final List<SourceIdentifier> sourceIdentifiers) {
masterRef.tell(new CreateInitialMasterActorData(mockDOMDataBroker, netconfService, sourceIdentifiers,
- new RemoteDeviceServices(mockDOMRpcService, mockDOMActionService)), testKit.getRef());
+ new RemoteDeviceServices(mockRpc, mockDOMActionService)), testKit.getRef());
testKit.expectMsgClass(MasterActorDataInitialized.class);
}
final var sourceProvider = availableSchemas instanceof LibraryModulesSchemas libraryModule
? new LibrarySchemaSourceProvider(id, libraryModule.getAvailableModels())
- : new MonitoringSchemaSourceProvider(id, deviceRpc);
+ : new MonitoringSchemaSourceProvider(id, deviceRpc.domRpcService());
return new DeviceSources(requiredSources, providedSources, sourceProvider);
}
}
\ No newline at end of file
public static LibraryModulesSchemas create(final NetconfDeviceRpc deviceRpc, final RemoteDeviceId deviceId) {
final DOMRpcResult moduleListNodeResult;
try {
- moduleListNodeResult = deviceRpc.invokeRpc(Get.QNAME, GET_MODULES_STATE_MODULE_LIST_RPC).get();
+ moduleListNodeResult = deviceRpc.domRpcService().invokeRpc(Get.QNAME, GET_MODULES_STATE_MODULE_LIST_RPC)
+ .get();
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(deviceId + ": Interrupted while waiting for response to "
// TODO check whether the model describing create subscription is present in schema
// Perhaps add a default schema context to support create-subscription if the model was not provided
// (same as what we do for base netconf operations in transformer)
- final var rpcResultListenableFuture = deviceRpc.invokeRpc(CreateSubscription.QNAME, Builders.containerBuilder()
- .withNodeIdentifier(NodeIdentifier.create(CreateSubscriptionInput.QNAME))
- // Note: default 'stream' is 'NETCONF', we do not need to create an explicit leaf
- .build());
+ final var rpcResultListenableFuture = deviceRpc.domRpcService()
+ .invokeRpc(CreateSubscription.QNAME, Builders.containerBuilder()
+ .withNodeIdentifier(NodeIdentifier.create(CreateSubscriptionInput.QNAME))
+ // Note: default 'stream' is 'NETCONF', we do not need to create an explicit leaf
+ .build());
Futures.addCallback(rpcResultListenableFuture, new FutureCallback<DOMRpcResult>() {
@Override
final NetconfDeviceRpc deviceRpc = new NetconfDeviceRpc(schemaContext, listener,
new NetconfMessageTransformer(emptyContext, false, baseSchema));
- return Futures.transform(deviceRpc.invokeRpc(Get.QNAME, Builders.containerBuilder()
+ return Futures.transform(deviceRpc.domRpcService().invokeRpc(Get.QNAME, Builders.containerBuilder()
.withNodeIdentifier(NETCONF_GET_NODEID)
.withChild(NetconfMessageTransformUtil.toFilterStructure(RFC8528_SCHEMA_MOUNTS, schemaContext))
.build()), rpcResult -> processSchemaMounts(rpcResult, emptyContext), MoreExecutors.directExecutor());
final RemoteDeviceId id, final EffectiveModelContext schemaContext) {
// FIXME: I think we should prefer YANG library here
if (remoteSessionCapabilities.isMonitoringSupported()) {
- return NetconfStateSchemas.create(deviceRpc, remoteSessionCapabilities, id, schemaContext);
+ return NetconfStateSchemas.create(deviceRpc.domRpcService(), remoteSessionCapabilities, id, schemaContext);
}
if (remoteSessionCapabilities.containsModuleCapability(RFC8525_YANG_LIBRARY_CAPABILITY)
|| remoteSessionCapabilities.containsModuleCapability(RFC7895_YANG_LIBRARY_CAPABILITY)) {
import org.opendaylight.mdsal.dom.api.DOMActionService;
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
import org.opendaylight.mdsal.dom.api.DOMRpcService;
-import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Actions;
-import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
/**
* NETCONF device RPCs operating just as any other {@link DOMRpcService}.
*/
- non-sealed interface Normalized extends Rpcs, DOMRpcService {
+ non-sealed interface Normalized extends Rpcs {
@Override
default ListenableFuture<? extends DOMRpcResult> invokeNetconf(final QName type,
final ContainerNode input) {
- return invokeRpc(type, input);
+ return domRpcService().invokeRpc(type, input);
}
+
+ @NonNull DOMRpcService domRpcService();
}
/**
* NETCONF device RPCs operating in terms of {@link SchemalessRpcService}.
*/
- non-sealed interface Schemaless extends Rpcs, SchemalessRpcService {
- // Just an interface combination
+ non-sealed interface Schemaless extends Rpcs {
+
+ @NonNull SchemalessRpcService schemalessRpcService();
}
}
import org.opendaylight.mdsal.dom.api.DOMNotification;
import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
import org.opendaylight.netconf.client.mdsal.NetconfDeviceCommunicator;
import org.opendaylight.netconf.client.mdsal.NetconfDeviceSchema;
import org.opendaylight.netconf.client.mdsal.api.NetconfSessionPreferences;
import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices;
import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs;
+import org.opendaylight.netconf.client.mdsal.api.SchemalessRpcService;
import org.opendaylight.netconf.client.mdsal.impl.NetconfMessageTransformUtil;
import org.opendaylight.netconf.common.NetconfTimer;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.GetConfig;
* invocation. Version for {@link Rpcs.Normalized}.
*/
private final class NormalizedKeepaliveRpcs implements Rpcs.Normalized {
+ private final @NonNull KeepaliveDOMRpcService domRpcService;
private final Rpcs.Normalized delegate;
NormalizedKeepaliveRpcs(final Rpcs.Normalized delegate) {
this.delegate = requireNonNull(delegate);
+ domRpcService = new KeepaliveDOMRpcService(delegate.domRpcService());
+ }
+
+ @Override
+ public ListenableFuture<? extends DOMRpcResult> invokeNetconf(final QName type, final ContainerNode input) {
+ // FIXME: what happens if we disable keepalive and then invokeRpc() throws?
+ disableKeepalive();
+ return scheduleTimeout(delegate.invokeNetconf(type, input));
+ }
+
+ @Override
+ public DOMRpcService domRpcService() {
+ return domRpcService;
+ }
+ }
+
+ private final class KeepaliveDOMRpcService implements DOMRpcService {
+ private final @NonNull DOMRpcService delegate;
+
+ KeepaliveDOMRpcService(final DOMRpcService delegate) {
+ this.delegate = requireNonNull(delegate);
}
@Override
@Override
public <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(
- final T rpcListener) {
+ final T rpcListener) {
// There is no real communication with the device (yet), hence no recordActivity() or anything
return delegate.registerRpcListener(rpcListener);
}
+
}
/**
* invocation. Version for {@link Rpcs.Schemaless}.
*/
private final class SchemalessKeepaliveRpcs implements Rpcs.Schemaless {
+ private final @NonNull KeepaliveSchemalessRpcService schemalessRpcService;
private final Rpcs.Schemaless delegate;
SchemalessKeepaliveRpcs(final Rpcs.Schemaless delegate) {
this.delegate = requireNonNull(delegate);
+ schemalessRpcService = new KeepaliveSchemalessRpcService(delegate.schemalessRpcService());
}
@Override
}
@Override
- public ListenableFuture<? extends DOMSource> invokeRpc(final QName type, final DOMSource input) {
+ public SchemalessRpcService schemalessRpcService() {
+ return schemalessRpcService;
+ }
+ }
+
+ private final class KeepaliveSchemalessRpcService implements SchemalessRpcService {
+ private final SchemalessRpcService delegate;
+
+ KeepaliveSchemalessRpcService(final SchemalessRpcService delegate) {
+ this.delegate = requireNonNull(delegate);
+ }
+
+ @Override
+ public ListenableFuture<? extends DOMSource> invokeRpc(final QName type, final DOMSource payload) {
// FIXME: what happens if we disable keepalive and then invokeRpc() throws?
disableKeepalive();
- return scheduleTimeout(delegate.invokeRpc(type, input));
+ return scheduleTimeout(delegate.invokeRpc(type, payload));
}
}
}
--- /dev/null
+/*
+ * Copyright (c) 2024 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.client.mdsal.spi;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.Collections2;
+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 org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
+import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
+import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.api.DefaultDOMRpcException;
+import org.opendaylight.netconf.api.messages.NetconfMessage;
+import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceCommunicator;
+import org.opendaylight.netconf.client.mdsal.api.RpcTransformer;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.NoOpListenerRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+record NetconfDeviceDOMRpcService(
+ EffectiveModelContext modelContext,
+ RemoteDeviceCommunicator communicator,
+ RpcTransformer<ContainerNode, DOMRpcResult> transformer) implements DOMRpcService {
+ NetconfDeviceDOMRpcService {
+ requireNonNull(modelContext);
+ }
+
+ @Override
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ public ListenableFuture<DOMRpcResult> invokeRpc(final QName type, final ContainerNode input) {
+ final var delegateFuture = communicator.sendRequest(transformer.toRpcRequest(type, input), type);
+
+ final var ret = SettableFuture.<DOMRpcResult>create();
+ Futures.addCallback(delegateFuture, new FutureCallback<>() {
+ @Override
+ public void onSuccess(final RpcResult<NetconfMessage> result) {
+ final DOMRpcResult rpcResult;
+ try {
+ rpcResult = transformer.toRpcResult(result, type);
+ } catch (Exception cause) {
+ ret.setException(new DefaultDOMRpcException(
+ "Unable to parse rpc reply. type: " + type + " input: " + input, cause));
+ return;
+ }
+
+ ret.set(rpcResult);
+ }
+
+ @Override
+ public void onFailure(final Throwable cause) {
+ ret.setException(new DOMRpcImplementationNotAvailableException(cause, "Unable to invoke rpc %s",
+ type));
+ }
+
+ }, MoreExecutors.directExecutor());
+ return ret;
+ }
+
+ @Override
+ public <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(final T listener) {
+ listener.onRpcAvailable(Collections2.transform(modelContext.getOperations(),
+ input -> DOMRpcIdentifier.create(input.getQName())));
+ return NoOpListenerRegistration.of(listener);
+ }
+}
\ No newline at end of file
final var rpcs = services.rpcs();
mountBuilder.addService(NetconfRpcService.class, rpcs);
if (rpcs instanceof Rpcs.Normalized normalized) {
- mountBuilder.addService(DOMRpcService.class, normalized);
+ mountBuilder.addService(DOMRpcService.class, normalized.domRpcService());
} else if (rpcs instanceof Rpcs.Schemaless schemaless) {
- mountBuilder.addService(SchemalessRpcService.class, schemaless);
+ mountBuilder.addService(SchemalessRpcService.class, schemaless.schemalessRpcService());
}
if (services.actions() instanceof Actions.Normalized normalized) {
mountBuilder.addService(DOMActionService.class, normalized);
*/
package org.opendaylight.netconf.client.mdsal.spi;
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.collect.Collections2;
-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 org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
-import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
-import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
-import org.opendaylight.mdsal.dom.api.DefaultDOMRpcException;
-import org.opendaylight.netconf.api.messages.NetconfMessage;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceCommunicator;
import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs;
import org.opendaylight.netconf.client.mdsal.api.RpcTransformer;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.concepts.NoOpListenerRegistration;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
* {@link ContainerNode}.
*/
public final class NetconfDeviceRpc implements Rpcs.Normalized {
- private final RemoteDeviceCommunicator communicator;
- private final RpcTransformer<ContainerNode, DOMRpcResult> transformer;
- private final EffectiveModelContext modelContext;
+ private final @NonNull NetconfDeviceDOMRpcService domRpcService;
public NetconfDeviceRpc(final EffectiveModelContext modelContext, final RemoteDeviceCommunicator communicator,
final RpcTransformer<ContainerNode, DOMRpcResult> transformer) {
- this.modelContext = requireNonNull(modelContext);
- this.communicator = communicator;
- this.transformer = transformer;
+ domRpcService = new NetconfDeviceDOMRpcService(modelContext, communicator, transformer);
}
@Override
- @SuppressWarnings("checkstyle:IllegalCatch")
- public ListenableFuture<DOMRpcResult> invokeRpc(final QName type, final ContainerNode input) {
- final var delegateFuture = communicator.sendRequest(transformer.toRpcRequest(type, input), type);
-
- final var ret = SettableFuture.<DOMRpcResult>create();
- Futures.addCallback(delegateFuture, new FutureCallback<>() {
- @Override
- public void onSuccess(final RpcResult<NetconfMessage> result) {
- final DOMRpcResult rpcResult;
- try {
- rpcResult = transformer.toRpcResult(result, type);
- } catch (Exception cause) {
- ret.setException(new DefaultDOMRpcException(
- "Unable to parse rpc reply. type: " + type + " input: " + input, cause));
- return;
- }
-
- ret.set(rpcResult);
- }
-
- @Override
- public void onFailure(final Throwable cause) {
- ret.setException(new DOMRpcImplementationNotAvailableException(cause, "Unable to invoke rpc %s", type));
- }
-
- }, MoreExecutors.directExecutor());
- return ret;
- }
-
- @Override
- public <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(final T listener) {
- listener.onRpcAvailable(Collections2.transform(modelContext.getOperations(),
- input -> DOMRpcIdentifier.create(input.getQName())));
-
- // NOOP, no rpcs appear and disappear in this implementation
- return NoOpListenerRegistration.of(listener);
+ public DOMRpcService domRpcService() {
+ return domRpcService;
}
}
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
-import javax.xml.transform.dom.DOMSource;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs;
import org.opendaylight.netconf.client.mdsal.api.RpcTransformer;
+import org.opendaylight.netconf.client.mdsal.api.SchemalessRpcService;
import org.opendaylight.netconf.client.mdsal.impl.BaseRpcSchemalessTransformer;
import org.opendaylight.netconf.client.mdsal.impl.SchemalessMessageTransformer;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
/**
- * Invokes RPC by sending netconf message via listener. Also transforms result from NetconfMessage to CompositeNode.
+ * Invokes RPC by sending NETCONF message via listener. Also transforms result from NetconfMessage to CompositeNode.
*/
public final class SchemalessNetconfDeviceRpc implements Rpcs.Schemaless {
+ private final @NonNull SchemalessRpcService schemalessRpcService;
private final RemoteDeviceCommunicator listener;
private final BaseRpcSchemalessTransformer baseRpcTransformer;
private final SchemalessMessageTransformer schemalessTransformer;
this.listener = listener;
this.baseRpcTransformer = baseRpcTransformer;
schemalessTransformer = messageTransformer;
+ schemalessRpcService = (type, input) -> handleRpc(type, input, schemalessTransformer);
}
@Override
}
@Override
- public ListenableFuture<? extends DOMSource> invokeRpc(final QName type, final DOMSource input) {
- return handleRpc(type, input, schemalessTransformer);
+ public SchemalessRpcService schemalessRpcService() {
+ return schemalessRpcService;
}
private @NonNull <I, R> ListenableFuture<R> handleRpc(final @NonNull QName type,
import org.mockito.junit.jupiter.MockitoExtension;
import org.opendaylight.mdsal.dom.api.DOMNotification;
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.client.mdsal.NetconfDeviceCommunicator;
import org.opendaylight.netconf.client.mdsal.NetconfDeviceSchema;
@Mock
private Rpcs.Normalized deviceRpc;
@Mock
+ private DOMRpcService deviceDomRpc;
+ @Mock
private NetconfDeviceCommunicator listener;
private DefaultNetconfTimer timer;
//This settable future object will be never set to any value. The test wants to simulate waiting for the result
//of the future object.
final var settableFuture = SettableFuture.<DOMRpcResult>create();
- doReturn(settableFuture).when(deviceRpc).invokeRpc(null, null);
+ doReturn(settableFuture).when(deviceDomRpc).invokeRpc(null, null);
+ doReturn(deviceDomRpc).when(deviceRpc).domRpcService();
//This settable future will be used to check the invokation of keepalive RPC. Should be never invoked.
final var keepaliveSettableFuture = SettableFuture.<DOMRpcResult>create();
underlyingSalFacade.invokeNullRpc();
//Invoking of general RPC.
- verify(deviceRpc, after(2000).times(1)).invokeRpc(null, null);
+ verify(deviceDomRpc, after(2000).times(1)).invokeRpc(null, null);
//verify the keepalive RPC invoke. Should be never happen.
- verify(deviceRpc, after(2000).never()).invokeRpc(GetConfig.QNAME, KEEPALIVE_PAYLOAD);
+ verify(deviceDomRpc, after(2000).never()).invokeRpc(GetConfig.QNAME, KEEPALIVE_PAYLOAD);
}
private static final class LocalNetconfSalFacade implements RemoteDeviceHandler {
public void invokeNullRpc() {
final var local = rpcs;
if (local != null) {
- local.invokeRpc(null, null);
+ local.domRpcService().invokeRpc(null, null);
}
}
}
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
import org.opendaylight.netconf.client.mdsal.NetconfDeviceCommunicator;
import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceHandler;
private NetconfDeviceCommunicator listener;
@Mock
private Rpcs.Normalized deviceRpc;
+ @Mock
+ private DOMRpcService deviceDomRpc;
private DefaultNetconfTimer timer;
private KeepaliveSalFacade keepaliveSalFacade;
timer = new DefaultNetconfTimer();
keepaliveSalFacade = new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, timer, 1L, 1L);
keepaliveSalFacade.setListener(listener);
+ doReturn(deviceDomRpc).when(deviceRpc).domRpcService();
}
@AfterEach
doAnswer(invocation -> proxyRpc = invocation.getArgument(2, RemoteDeviceServices.class).rpcs())
.when(underlyingSalFacade).onDeviceConnected(isNull(), isNull(), any(RemoteDeviceServices.class));
doReturn(Futures.immediateFailedFuture(new IllegalStateException("illegal-state")))
- .when(deviceRpc).invokeRpc(any(), any());
+ .when(deviceDomRpc).invokeRpc(any(), any());
keepaliveSalFacade = new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, timer, 100L, 1L);
keepaliveSalFacade.setListener(listener);
keepaliveSalFacade.onDeviceConnected(null, null, new RemoteDeviceServices(deviceRpc, null));
- assertInstanceOf(Rpcs.Normalized.class, proxyRpc)
+ assertInstanceOf(Rpcs.Normalized.class, proxyRpc).domRpcService()
.invokeRpc(QName.create("foo", "bar"), mock(ContainerNode.class));
verify(listener, times(1)).disconnect();
notificationService, broker, null);
verify(mountPointBuilder).addService(eq(DOMSchemaService.class), any());
verify(mountPointBuilder).addService(DOMDataBroker.class, broker);
- verify(mountPointBuilder).addService(DOMRpcService.class, rpcService);
+ verify(mountPointBuilder).addService(DOMRpcService.class, rpcService.domRpcService());
verify(mountPointBuilder).addService(DOMNotificationService.class, notificationService);
}
notificationService, null, netconfService);
verify(mountPointBuilder).addService(eq(DOMSchemaService.class), any());
verify(mountPointBuilder).addService(NetconfDataTreeService.class, netconfService);
- verify(mountPointBuilder).addService(DOMRpcService.class, rpcService);
+ verify(mountPointBuilder).addService(DOMRpcService.class, rpcService.domRpcService());
verify(mountPointBuilder).addService(DOMNotificationService.class, notificationService);
}
final RpcResult<NetconfMessage> result = RpcResultBuilder.success(msg).build();
when(communicatorMock.sendRequest(any(), any())).thenReturn(Futures.immediateFuture(result));
when(failingTransformer.toRpcResult(any(), any())).thenThrow(new RuntimeException("FAIL"));
- final NetconfDeviceRpc failingRpc = new NetconfDeviceRpc(SCHEMA_CONTEXT, communicatorMock, failingTransformer);
+ final var failingRpc = new NetconfDeviceRpc(SCHEMA_CONTEXT, communicatorMock, failingTransformer)
+ .domRpcService();
assertThrows(ExecutionException.class, () -> failingRpc.invokeRpc(type, mock(ContainerNode.class)).get());
assertThrows(ExecutionException.class, () -> failingRpc.invokeRpc(type, null).get());
}
@Test
public void testInvokeRpc() throws Exception {
ContainerNode input = createNode("urn:ietf:params:xml:ns:netconf:base:1.0", "2011-06-01", "filter");
- final DOMRpcResult result = rpc.invokeRpc(type, input).get();
+ final DOMRpcResult result = rpc.domRpcService().invokeRpc(type, input).get();
assertEquals(expectedReply.value().name(), result.value().name());
assertEquals(resolveNode(expectedReply), resolveNode(result));
}
@Test
public void testRegisterRpcListener() throws Exception {
- ArgumentCaptor<Collection> argument = ArgumentCaptor.forClass(Collection.class);
+ final var argument = ArgumentCaptor.forClass(Collection.class);
- rpc.registerRpcListener(listener);
+ rpc.domRpcService().registerRpcListener(listener);
verify(listener).onRpcAvailable(argument.capture());
final Collection<DOMRpcIdentifier> argValue = argument.getValue();
+ " </mainroot>\n"
+ " </filter>\n"
+ " </get-config>"));
- deviceRpc.invokeRpc(qName, src);
- ArgumentCaptor<NetconfMessage> msgCaptor = ArgumentCaptor.forClass(NetconfMessage.class);
- ArgumentCaptor<QName> qnameCaptor = ArgumentCaptor.forClass(QName.class);
+ deviceRpc.schemalessRpcService().invokeRpc(qName, src);
+ final var msgCaptor = ArgumentCaptor.forClass(NetconfMessage.class);
+ final var qnameCaptor = ArgumentCaptor.forClass(QName.class);
verify(listener).sendRequest(msgCaptor.capture(), qnameCaptor.capture());
LOG.info(XmlUtil.toString(msgCaptor.getValue().getDocument()));
}