Eliminate LockChangeListener
[netconf.git] / netconf / netconf-topology-singleton / src / main / java / org / opendaylight / netconf / topology / singleton / impl / NetconfTopologyContext.java
1 /*
2  * Copyright (c) 2016 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.netconf.topology.singleton.impl;
9
10 import static com.google.common.base.Verify.verifyNotNull;
11 import static java.util.Objects.requireNonNull;
12
13 import akka.actor.ActorRef;
14 import akka.cluster.Cluster;
15 import akka.dispatch.OnComplete;
16 import akka.pattern.Patterns;
17 import akka.util.Timeout;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import java.util.concurrent.atomic.AtomicBoolean;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
22 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
23 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
24 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
25 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
26 import org.opendaylight.netconf.topology.singleton.api.RemoteDeviceConnector;
27 import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
28 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
29 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
30 import org.opendaylight.netconf.topology.singleton.messages.RefreshSetupMasterActorData;
31 import org.opendaylight.netconf.topology.spi.NetconfNodeUtils;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.NetconfNode;
33 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 class NetconfTopologyContext implements ClusterSingletonService, AutoCloseable {
38     private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyContext.class);
39
40     private final @NonNull ServiceGroupIdentifier serviceGroupIdent;
41     private final Timeout actorResponseWaitTime;
42     private final DOMMountPointService mountService;
43     private final DeviceActionFactory deviceActionFactory;
44     private final boolean lockDatastore;
45
46     private NetconfTopologySetup netconfTopologyDeviceSetup;
47     private RemoteDeviceId remoteDeviceId;
48     private RemoteDeviceConnector remoteDeviceConnector;
49     private NetconfNodeManager netconfNodeManager;
50     private ActorRef masterActorRef;
51
52     private final AtomicBoolean closed = new AtomicBoolean(false);
53     private final AtomicBoolean stopped = new AtomicBoolean(false);
54     private volatile boolean isMaster;
55
56     NetconfTopologyContext(final NetconfTopologySetup netconfTopologyDeviceSetup,
57             final ServiceGroupIdentifier serviceGroupIdent, final Timeout actorResponseWaitTime,
58             final DOMMountPointService mountService, final DeviceActionFactory deviceActionFactory) {
59         this.netconfTopologyDeviceSetup = requireNonNull(netconfTopologyDeviceSetup);
60         this.serviceGroupIdent = requireNonNull(serviceGroupIdent);
61         this.actorResponseWaitTime = actorResponseWaitTime;
62         this.mountService = mountService;
63         this.deviceActionFactory = deviceActionFactory;
64
65         final var node = netconfTopologyDeviceSetup.getNode();
66         final var netconfNode = verifyNotNull(node.augmentation(NetconfNode.class));
67         remoteDeviceId = NetconfNodeUtils.toRemoteDeviceId(node.getNodeId(), netconfNode);
68         remoteDeviceConnector = new RemoteDeviceConnectorImpl(netconfTopologyDeviceSetup, remoteDeviceId,
69             deviceActionFactory);
70         netconfNodeManager = createNodeDeviceManager();
71         lockDatastore = netconfNode.requireLockDatastore();
72     }
73
74     @Override
75     public void instantiateServiceInstance() {
76         LOG.info("Master was selected: {}", remoteDeviceId.getHost().getIpAddress());
77
78         isMaster = true;
79
80         // master should not listen on netconf-node operational datastore
81         if (netconfNodeManager != null) {
82             netconfNodeManager.close();
83             netconfNodeManager = null;
84         }
85
86         if (!closed.get()) {
87             final String masterAddress =
88                     Cluster.get(netconfTopologyDeviceSetup.getActorSystem()).selfAddress().toString();
89             masterActorRef = netconfTopologyDeviceSetup.getActorSystem().actorOf(NetconfNodeActor.props(
90                     netconfTopologyDeviceSetup, remoteDeviceId, actorResponseWaitTime, mountService),
91                     NetconfTopologyUtils.createMasterActorName(remoteDeviceId.getName(), masterAddress));
92
93             remoteDeviceConnector.startRemoteDeviceConnection(newMasterSalFacade());
94         }
95
96     }
97
98     // called when master is down/changed to slave
99     @Override
100     public ListenableFuture<?> closeServiceInstance() {
101
102         if (!closed.get()) {
103             // in case that master changes role to slave, new NodeDeviceManager must be created and listener registered
104             netconfNodeManager = createNodeDeviceManager();
105         }
106         stopDeviceConnectorAndActor();
107
108         return FluentFutures.immediateNullFluentFuture();
109     }
110
111     @Override
112     public ServiceGroupIdentifier getIdentifier() {
113         return serviceGroupIdent;
114     }
115
116     private NetconfNodeManager createNodeDeviceManager() {
117         final NetconfNodeManager ndm =
118                 new NetconfNodeManager(netconfTopologyDeviceSetup, remoteDeviceId, actorResponseWaitTime, mountService);
119         ndm.registerDataTreeChangeListener(netconfTopologyDeviceSetup.getTopologyId(),
120                 netconfTopologyDeviceSetup.getNode().key());
121
122         return ndm;
123     }
124
125     @Override
126     public void close() {
127         if (!closed.compareAndSet(false, true)) {
128             return;
129         }
130
131         if (netconfNodeManager != null) {
132             netconfNodeManager.close();
133         }
134         stopDeviceConnectorAndActor();
135
136     }
137
138     /**
139      * Refresh, if configuration data was changed.
140      * @param setup new setup
141      */
142     void refresh(final @NonNull NetconfTopologySetup setup) {
143         netconfTopologyDeviceSetup = requireNonNull(setup);
144         final var node = netconfTopologyDeviceSetup.getNode();
145         remoteDeviceId = NetconfNodeUtils.toRemoteDeviceId(node.getNodeId(), node.augmentation(NetconfNode.class));
146
147         if (isMaster) {
148             remoteDeviceConnector.stopRemoteDeviceConnection();
149         } else {
150             netconfNodeManager.refreshDevice(netconfTopologyDeviceSetup, remoteDeviceId);
151         }
152         remoteDeviceConnector = new RemoteDeviceConnectorImpl(netconfTopologyDeviceSetup, remoteDeviceId,
153             deviceActionFactory);
154
155         if (isMaster) {
156             Patterns.ask(masterActorRef, new RefreshSetupMasterActorData(netconfTopologyDeviceSetup, remoteDeviceId),
157                 actorResponseWaitTime).onComplete(new OnComplete<>() {
158                     @Override
159                     public void onComplete(final Throwable failure, final Object success) {
160                         if (failure != null) {
161                             LOG.error("Failed to refresh master actor data", failure);
162                             return;
163                         }
164                         remoteDeviceConnector.startRemoteDeviceConnection(newMasterSalFacade());
165                     }
166                 }, netconfTopologyDeviceSetup.getActorSystem().dispatcher());
167         }
168     }
169
170     private void stopDeviceConnectorAndActor() {
171         if (!stopped.compareAndSet(false, true)) {
172             return;
173         }
174         if (remoteDeviceConnector != null) {
175             remoteDeviceConnector.stopRemoteDeviceConnection();
176         }
177
178         if (masterActorRef != null) {
179             netconfTopologyDeviceSetup.getActorSystem().stop(masterActorRef);
180             masterActorRef = null;
181         }
182     }
183
184     protected MasterSalFacade newMasterSalFacade() {
185         return new MasterSalFacade(remoteDeviceId, netconfTopologyDeviceSetup.getActorSystem(), masterActorRef,
186                 actorResponseWaitTime, mountService, netconfTopologyDeviceSetup.getDataBroker(), lockDatastore);
187     }
188 }