*/
package org.opendaylight.netconf.sal.connect.netconf;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
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 org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.$YangModuleInfoImpl;
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.topology.rev150114.netconf.node.fields.unavailable.capabilities.UnavailableCapability;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability;
import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
/**
* This is a mediator between NetconfDeviceCommunicator and NetconfDeviceSalFacade
*/
-public final class NetconfDevice implements RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> {
+public class NetconfDevice implements RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> {
private static final Logger LOG = LoggerFactory.getLogger(NetconfDevice.class);
}
};
- private final RemoteDeviceId id;
+ protected final RemoteDeviceId id;
private final boolean reconnectOnSchemasChange;
- private final SchemaContextFactory schemaContextFactory;
+ protected final SchemaContextFactory schemaContextFactory;
private final RemoteDeviceHandler<NetconfSessionPreferences> salFacade;
private final ListeningExecutorService processingExecutor;
- private final SchemaSourceRegistry schemaRegistry;
+ protected final SchemaSourceRegistry schemaRegistry;
private final NetconfStateSchemas.NetconfStateSchemasResolver stateSchemasResolver;
private final NotificationHandler notificationHandler;
- private final List<SchemaSourceRegistration<? extends SchemaSourceRepresentation>> sourceRegistrations = Lists.newArrayList();
+ protected final List<SchemaSourceRegistration<? extends SchemaSourceRepresentation>> sourceRegistrations = Lists.newArrayList();
// Message transformer is constructed once the schemas are available
private MessageTransformer<NetconfMessage> messageTransformer;
return remoteSessionCapabilities.isNotificationsSupported() && reconnectOnSchemasChange;
}
- @VisibleForTesting
- void handleSalInitializationSuccess(final SchemaContext result, final NetconfSessionPreferences remoteSessionCapabilities, final DOMRpcService deviceRpc) {
+ protected void handleSalInitializationSuccess(final SchemaContext result, final NetconfSessionPreferences remoteSessionCapabilities, final DOMRpcService deviceRpc) {
messageTransformer = new NetconfMessageTransformer(result, true);
updateTransformer(messageTransformer);
LOG.info("{}: Netconf connector initialized successfully", id);
}
- private void handleSalInitializationFailure(final Throwable t, final RemoteDeviceCommunicator<NetconfMessage> listener) {
+ protected void handleSalInitializationFailure(final Throwable t, final RemoteDeviceCommunicator<NetconfMessage> listener) {
LOG.error("{}: Initialization in sal failed, disconnecting from device", id, t);
listener.close();
onRemoteSessionDown();
@Override
public void onSuccess(final SchemaContext result) {
LOG.debug("{}: Schema context built successfully from {}", id, requiredSources);
- final Collection<QName> filteredQNames = Sets.difference(deviceSources.getProvidedSourcesQName(), capabilities.getUnresolvedCapabilites().keySet());
+ final Collection<QName> filteredQNames = Sets.difference(deviceSources.getRequiredSourcesQName(), capabilities.getUnresolvedCapabilites().keySet());
capabilities.addCapabilities(filteredQNames);
capabilities.addNonModuleBasedCapabilities(remoteSessionCapabilities.getNonModuleCaps());
handleSalInitializationSuccess(result, remoteSessionCapabilities, getDeviceSpecificRpc(result));
if (t instanceof MissingSchemaSourceException) {
final SourceIdentifier missingSource = ((MissingSchemaSourceException) t).getSourceId();
LOG.warn("{}: Unable to build schema context, missing source {}, will reattempt without it", id, missingSource);
- capabilities.addUnresolvedCapabilities(getQNameFromSourceIdentifiers(Sets.newHashSet(missingSource)), UnavailableCapability.FailureReason.MissingSource);
+ LOG.debug("{}: Unable to build schema context, missing source {}, will reattempt without it", t);
+ final Collection<QName> qNameOfMissingSource = getQNameFromSourceIdentifiers(Sets.newHashSet(missingSource));
+ if (!qNameOfMissingSource.isEmpty()) {
+ capabilities.addUnresolvedCapabilities(qNameOfMissingSource, UnavailableCapability.FailureReason.MissingSource);
+ }
setUpSchema(stripMissingSource(requiredSources, missingSource));
// In case resolution error, try only with resolved sources
final Set<SourceIdentifier> unresolvedSources = resolutionException.getUnsatisfiedImports().keySet();
capabilities.addUnresolvedCapabilities(getQNameFromSourceIdentifiers(unresolvedSources), UnavailableCapability.FailureReason.UnableToResolve);
LOG.warn("{}: Unable to build schema context, unsatisfied imports {}, will reattempt with resolved only", id, resolutionException.getUnsatisfiedImports());
+ LOG.debug("{}: Unable to build schema context, unsatisfied imports {}, will reattempt with resolved only", resolutionException);
setUpSchema(resolutionException.getResolvedSources());
// unknown error, fail
} else {
Futures.addCallback(schemaBuilderFuture, RecursiveSchemaBuilderCallback);
}
- private NetconfDeviceRpc getDeviceSpecificRpc(final SchemaContext result) {
+ protected NetconfDeviceRpc getDeviceSpecificRpc(final SchemaContext result) {
return new NetconfDeviceRpc(result, listener, new NetconfMessageTransformer(result, true));
}
});
if (qNames.isEmpty()) {
- LOG.debug("{}: Unable to map any source identfiers to a capability reported by device : {}", id, identifiers);
+ LOG.debug("{}: Unable to map any source identifiers to a capability reported by device : {}", id, identifiers);
}
- return qNames;
+ return Collections2.filter(qNames, Predicates.notNull());
}
private QName getQNameFromSourceIdentifier(final SourceIdentifier identifier) {
return qname;
}
}
- throw new IllegalArgumentException("Unable to map identifier to a devices reported capability: " + identifier + " Available: " + deviceSources.getRequiredSourcesQName());
+ LOG.warn("Unable to map identifier to a devices reported capability: {} Available: {}",identifier, deviceSources.getRequiredSourcesQName());
+ // return null since we cannot find the QName, this capability will be removed from required sources and not reported as unresolved-capability
+ return null;
}
}
}