builder class for path creating
[netconf.git] / netconf / netconf-topology / src / main / java / org / opendaylight / netconf / topology / pipeline / TopologyMountPointFacade.java
1 /*
2  * Copyright (c) 2015 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
9 package org.opendaylight.netconf.topology.pipeline;
10
11 import akka.actor.ActorContext;
12 import akka.actor.ActorRef;
13 import akka.actor.ActorSystem;
14 import akka.actor.TypedActor;
15 import akka.actor.TypedProps;
16 import akka.cluster.Cluster;
17 import akka.cluster.Member;
18 import akka.japi.Creator;
19 import com.google.common.base.Preconditions;
20 import java.util.ArrayList;
21 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
22 import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
23 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
24 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
25 import org.opendaylight.controller.sal.core.api.Broker;
26 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
27 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
28 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceNotificationService;
29 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
30 import org.opendaylight.netconf.topology.util.messages.AnnounceMasterMountPoint;
31 import org.opendaylight.netconf.topology.util.messages.AnnounceMasterMountPointDown;
32 import org.opendaylight.netconf.util.NetconfTopologyPathCreator;
33 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 public class TopologyMountPointFacade implements AutoCloseable, RemoteDeviceHandler<NetconfSessionPreferences> {
38
39     private static final Logger LOG = LoggerFactory.getLogger(TopologyMountPointFacade.class);
40
41     private static final String MOUNT_POINT = "mountpoint";
42
43     private final String topologyId;
44     private final RemoteDeviceId id;
45     private final Broker domBroker;
46     private final BindingAwareBroker bindingBroker;
47     private final long defaultRequestTimeoutMillis;
48
49     private SchemaContext remoteSchemaContext = null;
50     private NetconfSessionPreferences netconfSessionPreferences = null;
51     private DOMRpcService deviceRpc = null;
52     private final ClusteredNetconfDeviceMountInstanceProxy salProvider;
53
54     private ActorSystem actorSystem;
55     private DOMDataBroker deviceDataBroker = null;
56
57     private final ArrayList<RemoteDeviceHandler<NetconfSessionPreferences>> connectionStatusListeners = new ArrayList<>();
58
59     public TopologyMountPointFacade(final String topologyId,
60                                     final RemoteDeviceId id,
61                                     final Broker domBroker,
62                                     final BindingAwareBroker bindingBroker,
63                                     long defaultRequestTimeoutMillis) {
64         this.topologyId = topologyId;
65         this.id = id;
66         this.domBroker = domBroker;
67         this.bindingBroker = bindingBroker;
68         this.defaultRequestTimeoutMillis = defaultRequestTimeoutMillis;
69         this.salProvider = new ClusteredNetconfDeviceMountInstanceProxy(id);
70         registerToSal(domBroker);
71     }
72
73     public void registerToSal(final Broker domRegistryDependency) {
74         domRegistryDependency.registerProvider(salProvider);
75     }
76
77     @Override
78     public void onDeviceConnected(final SchemaContext remoteSchemaContext,
79                                   final NetconfSessionPreferences netconfSessionPreferences,
80                                   final DOMRpcService deviceRpc) {
81         // prepare our prerequisites for mountpoint
82         LOG.debug("Mount point facade onConnected capabilities {}", netconfSessionPreferences);
83         this.remoteSchemaContext = remoteSchemaContext;
84         this.netconfSessionPreferences = netconfSessionPreferences;
85         this.deviceRpc = deviceRpc;
86         for (RemoteDeviceHandler<NetconfSessionPreferences> listener : connectionStatusListeners) {
87             listener.onDeviceConnected(remoteSchemaContext, netconfSessionPreferences, deviceRpc);
88         }
89     }
90
91     @Override
92     public void onDeviceDisconnected() {
93         // do not unregister mount point here, this gets handle by the underlying call from role change callback
94         for (RemoteDeviceHandler<NetconfSessionPreferences> listener : connectionStatusListeners) {
95             listener.onDeviceDisconnected();
96         }
97     }
98
99     @Override
100     public void onDeviceFailed(Throwable throwable) {
101         // do not unregister mount point here, this gets handle by the underlying call from role change callback
102         for (RemoteDeviceHandler<NetconfSessionPreferences> listener : connectionStatusListeners) {
103             listener.onDeviceFailed(throwable);
104         }
105     }
106
107     @Override
108     public void onNotification(DOMNotification domNotification) {
109         salProvider.getMountInstance().publish(domNotification);
110     }
111
112     public void registerMountPoint(final ActorSystem actorSystem, final ActorContext context) {
113         if (remoteSchemaContext == null || netconfSessionPreferences == null) {
114             LOG.debug("Master mount point does not have schemas ready yet, delaying registration");
115             return;
116         }
117
118         Preconditions.checkNotNull(id);
119         Preconditions.checkNotNull(remoteSchemaContext, "Device has no remote schema context yet. Probably not fully connected.");
120         Preconditions.checkNotNull(netconfSessionPreferences, "Device has no capabilities yet. Probably not fully connected.");
121         this.actorSystem = actorSystem;
122         final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
123
124         LOG.warn("Creating master data broker for device {}", id);
125         deviceDataBroker = TypedActor.get(context).typedActorOf(new TypedProps<>(ProxyNetconfDeviceDataBroker.class, new Creator<NetconfDeviceMasterDataBroker>() {
126             @Override
127             public NetconfDeviceMasterDataBroker create() throws Exception {
128                 return new NetconfDeviceMasterDataBroker(actorSystem, id, remoteSchemaContext, deviceRpc, netconfSessionPreferences, defaultRequestTimeoutMillis);
129             }
130         }), MOUNT_POINT);
131         LOG.debug("Master data broker registered on path {}", TypedActor.get(actorSystem).getActorRefFor(deviceDataBroker).path());
132         salProvider.getMountInstance().onTopologyDeviceConnected(remoteSchemaContext, deviceDataBroker, deviceRpc, notificationService);
133         final Cluster cluster = Cluster.get(actorSystem);
134         final Iterable<Member> members = cluster.state().getMembers();
135         final ActorRef deviceDataBrokerRef = TypedActor.get(actorSystem).getActorRefFor(deviceDataBroker);
136         for (final Member member : members) {
137             if (!member.address().equals(cluster.selfAddress())) {
138                 final NetconfTopologyPathCreator pathCreator = new NetconfTopologyPathCreator(member.address().toString(),topologyId);
139                 final String path = pathCreator.withSuffix(id.getName()).build();
140                 actorSystem.actorSelection(path).tell(new AnnounceMasterMountPoint(), deviceDataBrokerRef);
141             }
142         }
143     }
144
145     public void registerMountPoint(final ActorSystem actorSystem, final ActorContext context, final ActorRef masterRef) {
146         if (remoteSchemaContext == null || netconfSessionPreferences == null) {
147             LOG.debug("Slave mount point does not have schemas ready yet, delaying registration");
148             return;
149         }
150
151         Preconditions.checkNotNull(id);
152         Preconditions.checkNotNull(remoteSchemaContext, "Device has no remote schema context yet. Probably not fully connected.");
153         Preconditions.checkNotNull(netconfSessionPreferences, "Device has no capabilities yet. Probably not fully connected.");
154         this.actorSystem = actorSystem;
155         final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
156
157         final ProxyNetconfDeviceDataBroker masterDataBroker = TypedActor.get(actorSystem).typedActorOf(new TypedProps<>(ProxyNetconfDeviceDataBroker.class, NetconfDeviceMasterDataBroker.class), masterRef);
158         LOG.warn("Creating slave data broker for device {}", id);
159         final DOMDataBroker deviceDataBroker = new NetconfDeviceSlaveDataBroker(actorSystem, id, masterDataBroker);
160         salProvider.getMountInstance().onTopologyDeviceConnected(remoteSchemaContext, deviceDataBroker, deviceRpc, notificationService);
161     }
162
163     public void unregisterMountPoint() {
164         salProvider.getMountInstance().onTopologyDeviceDisconnected();
165         if (deviceDataBroker != null) {
166             LOG.debug("Stopping master data broker for device {}", id.getName());
167             for (final Member member : Cluster.get(actorSystem).state().getMembers()) {
168                 if (member.address().equals(Cluster.get(actorSystem).selfAddress())) {
169                     continue;
170                 }
171                 final NetconfTopologyPathCreator pathCreator = new NetconfTopologyPathCreator(member.address().toString(), topologyId);
172                 final String path = pathCreator.withSuffix(id.getName()).build();
173                 actorSystem.actorSelection(path).tell(new AnnounceMasterMountPointDown(), null);
174             }
175             TypedActor.get(actorSystem).stop(deviceDataBroker);
176             deviceDataBroker = null;
177         }
178     }
179
180     public ConnectionStatusListenerRegistration registerConnectionStatusListener(final RemoteDeviceHandler<NetconfSessionPreferences> listener) {
181         connectionStatusListeners.add(listener);
182         return new ConnectionStatusListenerRegistration(listener);
183     }
184
185     @Override
186     public void close() {
187         closeGracefully(salProvider);
188     }
189
190     private void closeGracefully(final AutoCloseable resource) {
191         if (resource != null) {
192             try {
193                 resource.close();
194             } catch (final Exception e) {
195                 LOG.warn("{}: Ignoring exception while closing {}", id, resource, e);
196             }
197         }
198     }
199
200     public class ConnectionStatusListenerRegistration{
201
202         private final RemoteDeviceHandler<NetconfSessionPreferences> listener;
203
204         public ConnectionStatusListenerRegistration(final RemoteDeviceHandler<NetconfSessionPreferences> listener) {
205             this.listener = listener;
206         }
207
208         public void close() {
209             connectionStatusListeners.remove(listener);
210         }
211     }
212 }