Add 'protocol-framework/' from commit '5d015c2c5f800d136406c15fcb64fd531d4ffc26'
[netconf.git] / netconf / netconf-topology-singleton / src / main / java / org / opendaylight / netconf / topology / singleton / impl / NetconfNodeManager.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
9 package org.opendaylight.netconf.topology.singleton.impl;
10
11 import akka.actor.ActorRef;
12 import akka.actor.PoisonPill;
13 import akka.util.Timeout;
14 import java.util.Collection;
15 import javax.annotation.Nonnull;
16 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
17 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
18 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
19 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
22 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
23 import org.opendaylight.netconf.topology.singleton.api.NetconfTopologySingletonService;
24 import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
25 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
26 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
27 import org.opendaylight.netconf.topology.singleton.messages.AskForMasterMountPoint;
28 import org.opendaylight.netconf.topology.singleton.messages.RefreshSlaveActor;
29 import org.opendaylight.netconf.topology.singleton.messages.UnregisterSlaveMountPoint;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus;
32 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
35 import org.opendaylight.yangtools.concepts.ListenerRegistration;
36 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
37 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * Managing and reacting on data tree changes in specific netconf node when master writes status to the operational
43  * data store (e.g. handling lifecycle of slave mount point).
44  */
45 class NetconfNodeManager
46         implements ClusteredDataTreeChangeListener<Node>, NetconfTopologySingletonService, AutoCloseable {
47
48     private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeManager.class);
49
50     private final Timeout actorResponseWaitTime;
51     private final DOMMountPointService mountPointService;
52     private final SchemaSourceRegistry schemaRegistry;
53     private final SchemaRepository schemaRepository;
54
55     private NetconfTopologySetup setup;
56     private ListenerRegistration<NetconfNodeManager> dataChangeListenerRegistration;
57     private RemoteDeviceId id;
58     private ActorRef slaveActorRef;
59
60
61     NetconfNodeManager(final NetconfTopologySetup setup,
62                        final RemoteDeviceId id, final Timeout actorResponseWaitTime,
63                        final DOMMountPointService mountPointService) {
64         this.setup = setup;
65         this.id = id;
66         this.schemaRegistry = setup.getSchemaResourcesDTO().getSchemaRegistry();
67         this.schemaRepository = setup.getSchemaResourcesDTO().getSchemaRepository();
68         this.actorResponseWaitTime = actorResponseWaitTime;
69         this.mountPointService = mountPointService;
70     }
71
72     @Override
73     public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<Node>> changes) {
74         for (final DataTreeModification<Node> change : changes) {
75             final DataObjectModification<Node> rootNode = change.getRootNode();
76             final NodeId nodeId = NetconfTopologyUtils.getNodeId(rootNode.getIdentifier());
77             switch (rootNode.getModificationType()) {
78                 case SUBTREE_MODIFIED:
79                     LOG.debug("{}: Operational for node {} updated. Trying to register slave mount point", id, nodeId);
80                     handleSlaveMountPoint(rootNode);
81                     break;
82                 case WRITE:
83                     if (rootNode.getDataBefore() != null) {
84                         LOG.debug("{}: Operational for node {} rewrited. Trying to register slave mount point",
85                                 id, nodeId);
86                     } else {
87                         LOG.debug("{}: Operational for node {} created. Trying to register slave mount point",
88                                 id, nodeId);
89                     }
90                     handleSlaveMountPoint(rootNode);
91                     break;
92                 case DELETE:
93                     LOG.debug("{}: Operational for node {} deleted.", id, nodeId);
94                     unregisterSlaveMountpoint();
95                     break;
96                 default:
97                     LOG.debug("{}: Uknown operation for node: {}", id, nodeId);
98             }
99         }
100     }
101
102     @Override
103     public void close() {
104         unregisterSlaveMountpoint();
105         closeActor();
106         if (dataChangeListenerRegistration != null) {
107             dataChangeListenerRegistration.close();
108             dataChangeListenerRegistration = null;
109         }
110     }
111
112     private void closeActor() {
113         if (slaveActorRef != null) {
114             LOG.debug("{}: Sending poison pill to {}", id, slaveActorRef);
115             slaveActorRef.tell(PoisonPill.getInstance(), ActorRef.noSender());
116             slaveActorRef = null;
117         }
118     }
119
120     private void unregisterSlaveMountpoint() {
121         if (slaveActorRef != null) {
122             LOG.debug("{}: Sending message to unregister slave mountpoint to {}", id, slaveActorRef);
123             slaveActorRef.tell(new UnregisterSlaveMountPoint(), ActorRef.noSender());
124         }
125     }
126
127     void registerDataTreeChangeListener(final String topologyId, final NodeKey key) {
128         LOG.debug("{}: Registering data tree change listener on node {}", id, key);
129         dataChangeListenerRegistration = setup.getDataBroker().registerDataTreeChangeListener(
130                 new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
131                         NetconfTopologyUtils.createTopologyNodeListPath(key, topologyId)), this);
132     }
133
134     private void handleSlaveMountPoint(final DataObjectModification<Node> rootNode) {
135         @SuppressWarnings("ConstantConditions")
136         final NetconfNode netconfNodeAfter = rootNode.getDataAfter().getAugmentation(NetconfNode.class);
137
138         if (NetconfNodeConnectionStatus.ConnectionStatus.Connected.equals(netconfNodeAfter.getConnectionStatus())) {
139             createOrUpdateActorRef();
140             final String masterAddress = netconfNodeAfter.getClusteredConnectionStatus().getNetconfMasterNode();
141             final String path = NetconfTopologyUtils.createActorPath(masterAddress,
142                     NetconfTopologyUtils.createMasterActorName(id.getName(),
143                             netconfNodeAfter.getClusteredConnectionStatus().getNetconfMasterNode()));
144             setup.getActorSystem().actorSelection(path).tell(new AskForMasterMountPoint(), slaveActorRef);
145         } else {
146             unregisterSlaveMountpoint();
147         }
148     }
149
150     private void createOrUpdateActorRef() {
151         if (slaveActorRef == null) {
152             slaveActorRef = setup.getActorSystem().actorOf(NetconfNodeActor.props(setup, id, schemaRegistry,
153                     schemaRepository, actorResponseWaitTime, mountPointService));
154             LOG.debug("{}: Slave actor created with name {}", id, slaveActorRef);
155         } else {
156             slaveActorRef
157                     .tell(new RefreshSlaveActor(setup, id, schemaRegistry, schemaRepository, actorResponseWaitTime),
158                             ActorRef.noSender());
159         }
160     }
161
162     void refreshDevice(final NetconfTopologySetup netconfTopologyDeviceSetup, final RemoteDeviceId remoteDeviceId) {
163         setup = netconfTopologyDeviceSetup;
164         id = remoteDeviceId;
165     }
166 }