Merge "Bug 1073: Implemented Transaction chain on InMemoryDOMDataStore level."
[controller.git] / opendaylight / md-sal / sal-netconf-connector / src / main / java / org / opendaylight / controller / sal / connect / netconf / NetconfDevice.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.sal.connect.netconf;
9
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;
17
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;
38
39 import com.google.common.annotations.VisibleForTesting;
40 import com.google.common.base.Preconditions;
41
42 /**
43  *  This is a mediator between NetconfDeviceCommunicator and NetconfDeviceSalFacade
44  */
45 public final class NetconfDevice implements RemoteDevice<NetconfSessionCapabilities, NetconfMessage> {
46
47     private static final Logger logger = LoggerFactory.getLogger(NetconfDevice.class);
48
49     private final RemoteDeviceId id;
50
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;
56
57     public static NetconfDevice createNetconfDevice(final RemoteDeviceId id,
58             final AbstractCachingSchemaSourceProvider<String, InputStream> schemaSourceProvider,
59             final ExecutorService executor, final RemoteDeviceHandler<NetconfSessionCapabilities> salFacade) {
60
61         return new NetconfDevice(id, salFacade, executor, new NetconfMessageTransformer(),
62                 new NetconfDeviceSchemaProviderFactory(id), new SchemaSourceProviderFactory<InputStream>() {
63                     @Override
64                     public SchemaSourceProvider<InputStream> createSourceProvider(final RpcImplementation deviceRpc) {
65                         return schemaSourceProvider.createInstanceFor(new NetconfRemoteSchemaSourceProvider(id,
66                                 deviceRpc));
67                     }
68                 });
69     }
70
71     @VisibleForTesting
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) {
76         this.id = id;
77         this.messageTransformer = messageTransformer;
78         this.salFacade = salFacade;
79         this.sourceProviderFactory = sourceProviderFactory;
80         this.processingExecutor = MoreExecutors.listeningDecorator(processingExecutor);
81         this.schemaContextProviderFactory = schemaContextProviderFactory;
82     }
83
84     @Override
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);
93
94         final ListenableFuture<?> salInitializationFuture = processingExecutor.submit(new Runnable() {
95             @Override
96             public void run() {
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);
102             }
103         });
104
105         Futures.addCallback(salInitializationFuture, new FutureCallback<Object>() {
106             @Override
107             public void onSuccess(final Object result) {
108                 logger.debug("{}: Initialization in sal successful", id);
109                 logger.info("{}: Netconf connector initialized successfully", id);
110             }
111
112             @Override
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();
117             }
118         });
119     }
120
121     /**
122      * Update initial message transformer to use retrieved schema
123      */
124     private void updateMessageTransformer(final SchemaContextProvider schemaContextProvider) {
125         messageTransformer.onGlobalContextUpdated(schemaContextProvider.getSchemaContext());
126     }
127
128     private SchemaContextProvider setUpSchemaContext(final SchemaSourceProvider<InputStream> sourceProvider, final NetconfSessionCapabilities capabilities) {
129         return schemaContextProviderFactory.createContextProvider(capabilities.getModuleBasedCaps(), sourceProvider);
130     }
131
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);
136     }
137
138     @Override
139     public void onRemoteSessionDown() {
140         salFacade.onDeviceDisconnected();
141     }
142
143     @Override
144     public void onNotification(final NetconfMessage notification) {
145         final CompositeNode parsedNotification = messageTransformer.toNotification(notification);
146         salFacade.onNotification(parsedNotification);
147     }
148 }