RemoteDeviceDataBroker proxy
[netconf.git] / opendaylight / 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.yangtools.yang.model.api.SchemaContext;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 public class TopologyMountPointFacade implements AutoCloseable, RemoteDeviceHandler<NetconfSessionPreferences> {
36
37     private static final Logger LOG = LoggerFactory.getLogger(TopologyMountPointFacade.class);
38
39     private static final String MOUNT_POINT = "mountpoint";
40
41     private final String topologyId;
42     private final RemoteDeviceId id;
43     private final Broker domBroker;
44     private final BindingAwareBroker bindingBroker;
45     private final long defaultRequestTimeoutMillis;
46
47     private SchemaContext remoteSchemaContext = null;
48     private NetconfSessionPreferences netconfSessionPreferences = null;
49     private DOMRpcService deviceRpc = null;
50     private final ClusteredNetconfDeviceMountInstanceProxy salProvider;
51
52     private ActorSystem actorSystem;
53     private DOMDataBroker deviceDataBroker = null;
54
55     private final ArrayList<RemoteDeviceHandler<NetconfSessionPreferences>> connectionStatusListeners = new ArrayList<>();
56
57     public TopologyMountPointFacade(final String topologyId,
58                                     final RemoteDeviceId id,
59                                     final Broker domBroker,
60                                     final BindingAwareBroker bindingBroker,
61                                     long defaultRequestTimeoutMillis) {
62         this.topologyId = topologyId;
63         this.id = id;
64         this.domBroker = domBroker;
65         this.bindingBroker = bindingBroker;
66         this.defaultRequestTimeoutMillis = defaultRequestTimeoutMillis;
67         this.salProvider = new ClusteredNetconfDeviceMountInstanceProxy(id);
68         registerToSal(domBroker);
69     }
70
71     public void registerToSal(final Broker domRegistryDependency) {
72         domRegistryDependency.registerProvider(salProvider);
73     }
74
75     @Override
76     public void onDeviceConnected(final SchemaContext remoteSchemaContext,
77                                   final NetconfSessionPreferences netconfSessionPreferences,
78                                   final DOMRpcService deviceRpc) {
79         // prepare our prerequisites for mountpoint
80         this.remoteSchemaContext = remoteSchemaContext;
81         this.netconfSessionPreferences = netconfSessionPreferences;
82         this.deviceRpc = deviceRpc;
83         for (RemoteDeviceHandler<NetconfSessionPreferences> listener : connectionStatusListeners) {
84             listener.onDeviceConnected(remoteSchemaContext, netconfSessionPreferences, deviceRpc);
85         }
86     }
87
88     @Override
89     public void onDeviceDisconnected() {
90         // do not unregister mount point here, this gets handle by the underlying call from role change callback
91         for (RemoteDeviceHandler<NetconfSessionPreferences> listener : connectionStatusListeners) {
92             listener.onDeviceDisconnected();
93         }
94     }
95
96     @Override
97     public void onDeviceFailed(Throwable throwable) {
98         // do not unregister mount point here, this gets handle by the underlying call from role change callback
99         for (RemoteDeviceHandler<NetconfSessionPreferences> listener : connectionStatusListeners) {
100             listener.onDeviceFailed(throwable);
101         }
102     }
103
104     @Override
105     public void onNotification(DOMNotification domNotification) {
106         salProvider.getMountInstance().publish(domNotification);
107     }
108
109     public void registerMountPoint(final ActorSystem actorSystem, final ActorContext context) {
110         Preconditions.checkNotNull(id);
111         Preconditions.checkNotNull(remoteSchemaContext, "Device has no remote schema context yet. Probably not fully connected.");
112         Preconditions.checkNotNull(netconfSessionPreferences, "Device has no capabilities yet. Probably not fully connected.");
113         this.actorSystem = actorSystem;
114         final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
115
116         LOG.warn("Creating master data broker for device {}", id);
117         deviceDataBroker = TypedActor.get(context).typedActorOf(new TypedProps<>(ProxyNetconfDeviceDataBroker.class, new Creator<NetconfDeviceMasterDataBroker>() {
118             @Override
119             public NetconfDeviceMasterDataBroker create() throws Exception {
120                 return new NetconfDeviceMasterDataBroker(actorSystem, id, remoteSchemaContext, deviceRpc, netconfSessionPreferences, defaultRequestTimeoutMillis);
121             }
122         }), MOUNT_POINT);
123         LOG.warn("Master data broker registered on path {}", TypedActor.get(actorSystem).getActorRefFor(deviceDataBroker).path());
124         salProvider.getMountInstance().onTopologyDeviceConnected(remoteSchemaContext, deviceDataBroker, deviceRpc, notificationService);
125         final Cluster cluster = Cluster.get(actorSystem);
126         final Iterable<Member> members = cluster.state().getMembers();
127         final ActorRef deviceDataBrokerRef = TypedActor.get(actorSystem).getActorRefFor(deviceDataBroker);
128         for (final Member member : members) {
129             if (!member.address().equals(cluster.selfAddress())) {
130                 final String path = member.address() + "/user/" + topologyId + "/" + id.getName();
131                 actorSystem.actorSelection(path).tell(new AnnounceMasterMountPoint(), deviceDataBrokerRef);
132             }
133         }
134     }
135
136     public void registerMountPoint(final ActorSystem actorSystem, final ActorContext context, final ActorRef masterRef) {
137         Preconditions.checkNotNull(id);
138         Preconditions.checkNotNull(remoteSchemaContext, "Device has no remote schema context yet. Probably not fully connected.");
139         Preconditions.checkNotNull(netconfSessionPreferences, "Device has no capabilities yet. Probably not fully connected.");
140         this.actorSystem = actorSystem;
141         final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
142
143         LOG.warn("Creating a proxy for master data broker");
144         final ProxyNetconfDeviceDataBroker masterDataBroker = TypedActor.get(actorSystem).typedActorOf(new TypedProps<>(ProxyNetconfDeviceDataBroker.class, NetconfDeviceMasterDataBroker.class), masterRef);
145         LOG.warn("Creating slave data broker for device {}", id);
146         final DOMDataBroker deviceDataBroker = new NetconfDeviceSlaveDataBroker(actorSystem, id, masterDataBroker);
147         salProvider.getMountInstance().onTopologyDeviceConnected(remoteSchemaContext, deviceDataBroker, deviceRpc, notificationService);
148     }
149
150     public void unregisterMountPoint() {
151         salProvider.getMountInstance().onTopologyDeviceDisconnected();
152         if (deviceDataBroker != null) {
153             LOG.warn("Stopping master data broker for device {}", id.getName());
154             TypedActor.get(actorSystem).stop(deviceDataBroker);
155             deviceDataBroker = null;
156         }
157     }
158
159     public ConnectionStatusListenerRegistration registerConnectionStatusListener(final RemoteDeviceHandler<NetconfSessionPreferences> listener) {
160         connectionStatusListeners.add(listener);
161         return new ConnectionStatusListenerRegistration(listener);
162     }
163
164     @Override
165     public void close() {
166         closeGracefully(salProvider);
167     }
168
169     private void closeGracefully(final AutoCloseable resource) {
170         if (resource != null) {
171             try {
172                 resource.close();
173             } catch (final Exception e) {
174                 LOG.warn("{}: Ignoring exception while closing {}", id, resource, e);
175             }
176         }
177     }
178
179     public class ConnectionStatusListenerRegistration{
180
181         private final RemoteDeviceHandler<NetconfSessionPreferences> listener;
182
183         public ConnectionStatusListenerRegistration(final RemoteDeviceHandler<NetconfSessionPreferences> listener) {
184             this.listener = listener;
185         }
186
187         public void close() {
188             connectionStatusListeners.remove(listener);
189         }
190     }
191 }