2 * Copyright (c) 2015 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
9 package org.opendaylight.netconf.topology.pipeline;
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;
37 public class TopologyMountPointFacade implements AutoCloseable, RemoteDeviceHandler<NetconfSessionPreferences> {
39 private static final Logger LOG = LoggerFactory.getLogger(TopologyMountPointFacade.class);
41 private static final String MOUNT_POINT = "mountpoint";
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;
49 private SchemaContext remoteSchemaContext = null;
50 private NetconfSessionPreferences netconfSessionPreferences = null;
51 private DOMRpcService deviceRpc = null;
52 private final ClusteredNetconfDeviceMountInstanceProxy salProvider;
54 private ActorSystem actorSystem;
55 private DOMDataBroker deviceDataBroker = null;
57 private final ArrayList<RemoteDeviceHandler<NetconfSessionPreferences>> connectionStatusListeners = new ArrayList<>();
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;
66 this.domBroker = domBroker;
67 this.bindingBroker = bindingBroker;
68 this.defaultRequestTimeoutMillis = defaultRequestTimeoutMillis;
69 this.salProvider = new ClusteredNetconfDeviceMountInstanceProxy(id);
70 registerToSal(domBroker);
73 public void registerToSal(final Broker domRegistryDependency) {
74 domRegistryDependency.registerProvider(salProvider);
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);
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();
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);
108 public void onNotification(DOMNotification domNotification) {
109 salProvider.getMountInstance().publish(domNotification);
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");
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();
124 LOG.warn("Creating master data broker for device {}", id);
125 deviceDataBroker = TypedActor.get(context).typedActorOf(new TypedProps<>(ProxyNetconfDeviceDataBroker.class, new Creator<NetconfDeviceMasterDataBroker>() {
127 public NetconfDeviceMasterDataBroker create() throws Exception {
128 return new NetconfDeviceMasterDataBroker(actorSystem, id, remoteSchemaContext, deviceRpc, netconfSessionPreferences, defaultRequestTimeoutMillis);
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);
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");
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();
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);
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())) {
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);
175 TypedActor.get(actorSystem).stop(deviceDataBroker);
176 deviceDataBroker = null;
180 public ConnectionStatusListenerRegistration registerConnectionStatusListener(final RemoteDeviceHandler<NetconfSessionPreferences> listener) {
181 connectionStatusListeners.add(listener);
182 return new ConnectionStatusListenerRegistration(listener);
186 public void close() {
187 closeGracefully(salProvider);
190 private void closeGracefully(final AutoCloseable resource) {
191 if (resource != null) {
194 } catch (final Exception e) {
195 LOG.warn("{}: Ignoring exception while closing {}", id, resource, e);
200 public class ConnectionStatusListenerRegistration{
202 private final RemoteDeviceHandler<NetconfSessionPreferences> listener;
204 public ConnectionStatusListenerRegistration(final RemoteDeviceHandler<NetconfSessionPreferences> listener) {
205 this.listener = listener;
208 public void close() {
209 connectionStatusListeners.remove(listener);