import static java.util.Objects.requireNonNull;
-import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.CheckedFuture;
+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.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
+import io.netty.util.concurrent.EventExecutor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.GuardedBy;
-import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.api.DOMNotification;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
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.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev190614.NetconfNodeAugmentedOptional;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapabilityBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
protected final SchemaSourceRegistry schemaRegistry;
protected final SchemaRepository schemaRepository;
- protected final List<SchemaSourceRegistration<? extends SchemaSourceRepresentation>> sourceRegistrations =
- new ArrayList<>();
+ protected final List<SchemaSourceRegistration<?>> sourceRegistrations = new ArrayList<>();
private final RemoteDeviceHandler<NetconfSessionPreferences> salFacade;
private final ListeningExecutorService processingExecutor;
private final NetconfDeviceSchemasResolver stateSchemasResolver;
private final NotificationHandler notificationHandler;
private final boolean reconnectOnSchemasChange;
+ private final NetconfNode node;
+ private final EventExecutor eventExecutor;
+ private final NetconfNodeAugmentedOptional nodeOptional;
@GuardedBy("this")
private boolean connected = false;
*/
static NetconfDeviceRpc getRpcForInitialization(final NetconfDeviceCommunicator listener,
final boolean notificationSupport) {
- final BaseSchema baseSchema = notificationSupport
- ? BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS
- : BaseSchema.BASE_NETCONF_CTX;
+ final BaseSchema baseSchema = resolveBaseSchema(notificationSupport);
return new NetconfDeviceRpc(baseSchema.getSchemaContext(), listener,
new NetconfMessageTransformer(baseSchema.getSchemaContext(), false, baseSchema));
}
+ private static BaseSchema resolveBaseSchema(final boolean notificationSupport) {
+ return notificationSupport ? BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS : BaseSchema.BASE_NETCONF_CTX;
+ }
+
public NetconfDevice(final SchemaResourcesDTO schemaResourcesDTO, final RemoteDeviceId id,
final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
final ListeningExecutorService globalProcessingExecutor,
final boolean reconnectOnSchemasChange) {
- this(schemaResourcesDTO, id, salFacade, globalProcessingExecutor, reconnectOnSchemasChange, null);
+ this(schemaResourcesDTO, id, salFacade, globalProcessingExecutor, reconnectOnSchemasChange, null, null, null,
+ null);
}
public NetconfDevice(final SchemaResourcesDTO schemaResourcesDTO, final RemoteDeviceId id,
final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
final ListeningExecutorService globalProcessingExecutor, final boolean reconnectOnSchemasChange,
- final DeviceActionFactory deviceActionFactory) {
+ final DeviceActionFactory deviceActionFactory, final NetconfNode node, final EventExecutor eventExecutor,
+ final NetconfNodeAugmentedOptional nodeOptional) {
this.id = id;
this.reconnectOnSchemasChange = reconnectOnSchemasChange;
this.deviceActionFactory = deviceActionFactory;
+ this.node = node;
+ this.eventExecutor = eventExecutor;
+ this.nodeOptional = nodeOptional;
this.schemaRegistry = schemaResourcesDTO.getSchemaRegistry();
this.schemaRepository = schemaResourcesDTO.getSchemaRepository();
this.schemaContextFactory = schemaResourcesDTO.getSchemaContextFactory();
final NetconfDeviceRpc initRpc =
getRpcForInitialization(listener, remoteSessionCapabilities.isNotificationsSupported());
final DeviceSourcesResolver task =
- new DeviceSourcesResolver(remoteSessionCapabilities, id, stateSchemasResolver, initRpc);
+ new DeviceSourcesResolver(remoteSessionCapabilities, id, stateSchemasResolver, initRpc,
+ resolveBaseSchema(remoteSessionCapabilities.isNotificationsSupported()).getSchemaContext());
final ListenableFuture<DeviceSources> sourceResolverFuture = processingExecutor.submit(task);
if (shouldListenOnSchemaChange(remoteSessionCapabilities)) {
// 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 CheckedFuture<DOMRpcResult, DOMRpcException> rpcResultListenableFuture = deviceRpc.invokeRpc(
+ final FluentFuture<DOMRpcResult> rpcResultListenableFuture = deviceRpc.invokeRpc(
NetconfMessageTransformUtil.toPath(NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_QNAME),
NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_CONTENT);
// Only disconnect is enough,
// the reconnecting nature of the connector will take care of reconnecting
listener.disconnect();
- return Optional.absent();
+ return Optional.empty();
}
return Optional.of(notification);
}
notificationHandler.onRemoteSchemaDown();
salFacade.onDeviceDisconnected();
- for (final SchemaSourceRegistration<? extends SchemaSourceRepresentation> sourceRegistration
- : sourceRegistrations) {
- sourceRegistration.close();
- }
+ sourceRegistrations.forEach(SchemaSourceRegistration::close);
+ sourceRegistrations.clear();
resetMessageTransformer();
}
private final NetconfSessionPreferences remoteSessionCapabilities;
private final RemoteDeviceId id;
private final NetconfDeviceSchemasResolver stateSchemasResolver;
+ private final SchemaContext schemaContext;
DeviceSourcesResolver(final NetconfDeviceRpc deviceRpc,
final NetconfSessionPreferences remoteSessionCapabilities,
- final RemoteDeviceId id, final NetconfDeviceSchemasResolver stateSchemasResolver) {
+ final RemoteDeviceId id, final NetconfDeviceSchemasResolver stateSchemasResolver,
+ final SchemaContext schemaContext) {
this.deviceRpc = deviceRpc;
this.remoteSessionCapabilities = remoteSessionCapabilities;
this.id = id;
this.stateSchemasResolver = stateSchemasResolver;
+ this.schemaContext = schemaContext;
}
DeviceSourcesResolver(final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id,
final NetconfDeviceSchemasResolver stateSchemasResolver,
- final NetconfDeviceRpc rpcForMonitoring) {
- this(rpcForMonitoring, remoteSessionCapabilities, id, stateSchemasResolver);
+ final NetconfDeviceRpc rpcForMonitoring, final SchemaContext schemaCtx) {
+ this(rpcForMonitoring, remoteSessionCapabilities, id, stateSchemasResolver, schemaCtx);
}
@Override
public DeviceSources call() {
final NetconfDeviceSchemas availableSchemas =
- stateSchemasResolver.resolve(deviceRpc, remoteSessionCapabilities, id);
+ stateSchemasResolver.resolve(deviceRpc, remoteSessionCapabilities, id, schemaContext);
LOG.debug("{}: Schemas exposed by ietf-netconf-monitoring: {}", id,
availableSchemas.getAvailableYangSchemasQNames());
return;
}
}
- // No more sources, fail
- final IllegalStateException cause = new IllegalStateException(id + ": No more sources for schema context");
- handleSalInitializationFailure(cause, listener);
- salFacade.onDeviceFailed(cause);
+ // No more sources, fail or try to reconnect
+ if (nodeOptional != null && nodeOptional.getIgnoreMissingSchemaSources().isAllowed()) {
+ eventExecutor.schedule(() -> {
+ LOG.warn("Reconnection is allowed! This can lead to unexpected errors at runtime.");
+ LOG.warn("{} : No more sources for schema context.", id);
+ LOG.info("{} : Try to remount device.", id);
+ onRemoteSessionDown();
+ salFacade.onDeviceReconnected(remoteSessionCapabilities, node);
+ }, nodeOptional.getIgnoreMissingSchemaSources().getReconnectTime(), TimeUnit.MILLISECONDS);
+ } else {
+ final IllegalStateException cause =
+ new IllegalStateException(id + ": No more sources for schema context");
+ handleSalInitializationFailure(cause, listener);
+ salFacade.onDeviceFailed(cause);
+ }
}
private Collection<SourceIdentifier> handleMissingSchemaSourceException(