2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.sal.connect.netconf;
10 import com.google.common.util.concurrent.FutureCallback;
11 import com.google.common.util.concurrent.Futures;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.ListeningExecutorService;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import java.io.InputStream;
16 import java.util.concurrent.ExecutorService;
18 import org.opendaylight.controller.netconf.api.NetconfMessage;
19 import org.opendaylight.controller.sal.connect.api.MessageTransformer;
20 import org.opendaylight.controller.sal.connect.api.RemoteDevice;
21 import org.opendaylight.controller.sal.connect.api.RemoteDeviceCommunicator;
22 import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler;
23 import org.opendaylight.controller.sal.connect.api.SchemaContextProviderFactory;
24 import org.opendaylight.controller.sal.connect.api.SchemaSourceProviderFactory;
25 import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionCapabilities;
26 import org.opendaylight.controller.sal.connect.netconf.sal.NetconfDeviceRpc;
27 import org.opendaylight.controller.sal.connect.netconf.schema.NetconfDeviceSchemaProviderFactory;
28 import org.opendaylight.controller.sal.connect.netconf.schema.NetconfRemoteSchemaSourceProvider;
29 import org.opendaylight.controller.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
30 import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
31 import org.opendaylight.controller.sal.core.api.RpcImplementation;
32 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
33 import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
34 import org.opendaylight.yangtools.yang.model.util.repo.AbstractCachingSchemaSourceProvider;
35 import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 import com.google.common.annotations.VisibleForTesting;
40 import com.google.common.base.Preconditions;
43 * This is a mediator between NetconfDeviceCommunicator and NetconfDeviceSalFacade
45 public final class NetconfDevice implements RemoteDevice<NetconfSessionCapabilities, NetconfMessage> {
47 private static final Logger logger = LoggerFactory.getLogger(NetconfDevice.class);
49 private final RemoteDeviceId id;
51 private final RemoteDeviceHandler<NetconfSessionCapabilities> salFacade;
52 private final ListeningExecutorService processingExecutor;
53 private final MessageTransformer<NetconfMessage> messageTransformer;
54 private final SchemaContextProviderFactory schemaContextProviderFactory;
55 private final SchemaSourceProviderFactory<InputStream> sourceProviderFactory;
57 public static NetconfDevice createNetconfDevice(final RemoteDeviceId id,
58 final AbstractCachingSchemaSourceProvider<String, InputStream> schemaSourceProvider,
59 final ExecutorService executor, final RemoteDeviceHandler<NetconfSessionCapabilities> salFacade) {
61 return new NetconfDevice(id, salFacade, executor, new NetconfMessageTransformer(),
62 new NetconfDeviceSchemaProviderFactory(id), new SchemaSourceProviderFactory<InputStream>() {
64 public SchemaSourceProvider<InputStream> createSourceProvider(final RpcImplementation deviceRpc) {
65 return schemaSourceProvider.createInstanceFor(new NetconfRemoteSchemaSourceProvider(id,
72 protected NetconfDevice(final RemoteDeviceId id, final RemoteDeviceHandler<NetconfSessionCapabilities> salFacade,
73 final ExecutorService processingExecutor, final MessageTransformer<NetconfMessage> messageTransformer,
74 final SchemaContextProviderFactory schemaContextProviderFactory,
75 final SchemaSourceProviderFactory<InputStream> sourceProviderFactory) {
77 this.messageTransformer = messageTransformer;
78 this.salFacade = salFacade;
79 this.sourceProviderFactory = sourceProviderFactory;
80 this.processingExecutor = MoreExecutors.listeningDecorator(processingExecutor);
81 this.schemaContextProviderFactory = schemaContextProviderFactory;
85 public void onRemoteSessionUp(final NetconfSessionCapabilities remoteSessionCapabilities,
86 final RemoteDeviceCommunicator<NetconfMessage> listener) {
87 // SchemaContext setup has to be performed in a dedicated thread since
88 // we are in a netty thread in this method
89 // Yang models are being downloaded in this method and it would cause a
90 // deadlock if we used the netty thread
91 // http://netty.io/wiki/thread-model.html
92 logger.debug("{}: Session to remote device established with {}", id, remoteSessionCapabilities);
94 final ListenableFuture<?> salInitializationFuture = processingExecutor.submit(new Runnable() {
97 final NetconfDeviceRpc deviceRpc = setUpDeviceRpc(remoteSessionCapabilities, listener);
98 final SchemaSourceProvider<InputStream> delegate = sourceProviderFactory.createSourceProvider(deviceRpc);
99 final SchemaContextProvider schemaContextProvider = setUpSchemaContext(delegate, remoteSessionCapabilities);
100 updateMessageTransformer(schemaContextProvider);
101 salFacade.onDeviceConnected(schemaContextProvider, remoteSessionCapabilities, deviceRpc);
105 Futures.addCallback(salInitializationFuture, new FutureCallback<Object>() {
107 public void onSuccess(final Object result) {
108 logger.debug("{}: Initialization in sal successful", id);
109 logger.info("{}: Netconf connector initialized successfully", id);
113 public void onFailure(final Throwable t) {
114 // Unable to initialize device, set as disconnected
115 logger.error("{}: Initialization failed", id, t);
116 salFacade.onDeviceDisconnected();
122 * Update initial message transformer to use retrieved schema
124 private void updateMessageTransformer(final SchemaContextProvider schemaContextProvider) {
125 messageTransformer.onGlobalContextUpdated(schemaContextProvider.getSchemaContext());
128 private SchemaContextProvider setUpSchemaContext(final SchemaSourceProvider<InputStream> sourceProvider, final NetconfSessionCapabilities capabilities) {
129 return schemaContextProviderFactory.createContextProvider(capabilities.getModuleBasedCaps(), sourceProvider);
132 private NetconfDeviceRpc setUpDeviceRpc(final NetconfSessionCapabilities capHolder, final RemoteDeviceCommunicator<NetconfMessage> listener) {
133 Preconditions.checkArgument(capHolder.isMonitoringSupported(),
134 "%s: Netconf device does not support netconf monitoring, yang schemas cannot be acquired. Netconf device capabilities", capHolder);
135 return new NetconfDeviceRpc(listener, messageTransformer);
139 public void onRemoteSessionDown() {
140 salFacade.onDeviceDisconnected();
144 public void onNotification(final NetconfMessage notification) {
145 final CompositeNode parsedNotification = messageTransformer.toNotification(notification);
146 salFacade.onNotification(parsedNotification);