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