import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
import org.opendaylight.netconf.api.CapabilityURN;
-import org.opendaylight.netconf.api.NetconfMessage;
+import org.opendaylight.netconf.api.messages.NetconfMessage;
import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
import org.opendaylight.netconf.client.mdsal.api.NetconfDeviceSchemasResolver;
@GuardedBy("this")
private boolean connected = false;
- // Message transformer is constructed once the schemas are available
- private NetconfMessageTransformer messageTransformer;
-
public NetconfDevice(final SchemaResourcesDTO schemaResourcesDTO, final BaseNetconfSchemas baseSchemas,
final RemoteDeviceId id, final RemoteDeviceHandler salFacade, final Executor globalProcessingExecutor,
final boolean reconnectOnSchemasChange) {
@Override
public void onRemoteSessionUp(final NetconfSessionPreferences remoteSessionCapabilities,
final NetconfDeviceCommunicator listener) {
- // SchemaContext setup has to be performed in a dedicated thread since
- // we are in a netty thread in this method
- // Yang models are being downloaded in this method and it would cause a
- // deadlock if we used the netty thread
- // http://netty.io/wiki/thread-model.html
+ // SchemaContext setup has to be performed in a dedicated thread since we are in a Netty thread in this method
+ // YANG models are being downloaded in this method and it would cause a deadlock if we used the netty thread
+ // https://netty.io/wiki/thread-model.html
setConnected(true);
LOG.debug("{}: Session to remote device established with {}", id, remoteSessionCapabilities);
@Override
public void onSuccess(final DOMRpcResult domRpcResult) {
notificationHandler.addNotificationFilter(notification -> {
- if (NetconfCapabilityChange.QNAME.equals(notification.getBody().getIdentifier().getNodeType())) {
+ if (NetconfCapabilityChange.QNAME.equals(notification.getBody().name().getNodeType())) {
LOG.info("{}: Schemas change detected, reconnecting", id);
// Only disconnect is enough,
// the reconnecting nature of the connector will take care of reconnecting
private synchronized void handleSalInitializationSuccess(final RemoteDeviceCommunicator listener,
final NetconfDeviceSchema deviceSchema, final NetconfSessionPreferences remoteSessionCapabilities,
final Rpcs deviceRpc) {
- //NetconfDevice.SchemaSetup can complete after NetconfDeviceCommunicator was closed. In that case do nothing,
- //since salFacade.onDeviceDisconnected was already called.
- if (connected) {
- final var mount = deviceSchema.mountContext();
- messageTransformer = new NetconfMessageTransformer(mount, true,
- resolveBaseSchema(remoteSessionCapabilities.isNotificationsSupported()));
-
- // salFacade.onDeviceConnected has to be called before the notification handler is initialized
- salFacade.onDeviceConnected(deviceSchema, remoteSessionCapabilities,
- new RemoteDeviceServices(deviceRpc, deviceActionFactory == null ? null
- : deviceActionFactory.createDeviceAction(messageTransformer, listener)));
- notificationHandler.onRemoteSchemaUp(messageTransformer);
-
- LOG.info("{}: Netconf connector initialized successfully", id);
- } else {
+ // NetconfDevice.SchemaSetup can complete after NetconfDeviceCommunicator was closed. In that case do nothing,
+ // since salFacade.onDeviceDisconnected was already called.
+ if (!connected) {
LOG.warn("{}: Device communicator was closed before schema setup finished.", id);
+ return;
}
+
+ final var messageTransformer = new NetconfMessageTransformer(deviceSchema.mountContext(), true,
+ resolveBaseSchema(remoteSessionCapabilities.isNotificationsSupported()));
+
+ // Order is important here: salFacade has to see the device come up and then the notificationHandler can deliver
+ // whatever notifications have been held back
+ salFacade.onDeviceConnected(deviceSchema, remoteSessionCapabilities,
+ new RemoteDeviceServices(deviceRpc, deviceActionFactory == null ? null
+ : deviceActionFactory.createDeviceAction(messageTransformer, listener)));
+ notificationHandler.onRemoteSchemaUp(messageTransformer);
+
+ LOG.info("{}: Netconf connector initialized successfully", id);
}
private void handleSalInitializationFailure(final RemoteDeviceCommunicator listener, final Throwable cause) {
- // FIXME: pick one of these messages
LOG.warn("{}: Unexpected error resolving device sources", id, cause);
- LOG.error("{}: Initialization in sal failed, disconnecting from device", id, cause);
listener.close();
- onRemoteSessionDown();
- resetMessageTransformer();
-
- // FIXME: this causes salFacade to see onDeviceDisconnected() and then onDeviceFailed(), which is quite weird
+ cleanupInitialization();
salFacade.onDeviceFailed(cause);
}
- /**
- * Set the transformer to null as is in initial state.
- */
- private void resetMessageTransformer() {
- updateTransformer(null);
- }
-
- private synchronized void updateTransformer(final NetconfMessageTransformer transformer) {
- messageTransformer = transformer;
+ private synchronized void cleanupInitialization() {
+ connected = false;
+ notificationHandler.onRemoteSchemaDown();
+ sourceRegistrations.forEach(Registration::close);
+ sourceRegistrations.clear();
}
private synchronized void setConnected(final boolean connected) {
@Override
public void onRemoteSessionDown() {
- setConnected(false);
- notificationHandler.onRemoteSchemaDown();
-
+ cleanupInitialization();
salFacade.onDeviceDisconnected();
- sourceRegistrations.forEach(Registration::close);
- sourceRegistrations.clear();
- resetMessageTransformer();
- }
-
- @Override
- public void onRemoteSessionFailed(final Throwable throwable) {
- setConnected(false);
- salFacade.onDeviceFailed(throwable);
}
@Override