Simplify NetconfDeviceTopologyAdapter datastore interactions
[netconf.git] / netconf / netconf-topology-impl / src / main / java / org / opendaylight / netconf / topology / impl / NetconfTopologyImpl.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 package org.opendaylight.netconf.topology.impl;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.VisibleForTesting;
13 import io.netty.util.concurrent.EventExecutor;
14 import java.util.Collection;
15 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
16 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
17 import org.opendaylight.controller.config.threadpool.ThreadPool;
18 import org.opendaylight.mdsal.binding.api.DataBroker;
19 import org.opendaylight.mdsal.binding.api.DataObjectModification;
20 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
21 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
22 import org.opendaylight.mdsal.binding.api.DataTreeModification;
23 import org.opendaylight.mdsal.binding.api.RpcProviderService;
24 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
25 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
26 import org.opendaylight.netconf.client.NetconfClientDispatcher;
27 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
28 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
29 import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
30 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalFacade;
31 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseNetconfSchemas;
32 import org.opendaylight.netconf.sal.connect.util.NetconfTopologyRPCProvider;
33 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
34 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
35 import org.opendaylight.netconf.topology.spi.NetconfConnectorDTO;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeTopologyService;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
44 import org.opendaylight.yangtools.concepts.ListenerRegistration;
45 import org.opendaylight.yangtools.concepts.ObjectRegistration;
46 import org.opendaylight.yangtools.yang.binding.Identifier;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 public class NetconfTopologyImpl extends AbstractNetconfTopology
53         implements DataTreeChangeListener<Node>, AutoCloseable {
54
55     private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyImpl.class);
56
57     private final RpcProviderService rpcProviderService;
58     private ListenerRegistration<NetconfTopologyImpl> datastoreListenerRegistration = null;
59     private ObjectRegistration<?> rpcReg = null;
60
61     public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
62             final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
63             final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
64             final DataBroker dataBroker, final DOMMountPointService mountPointService,
65             final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
66             final BaseNetconfSchemas baseSchemas) {
67         this(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
68                 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, rpcProviderService,
69                 baseSchemas, null);
70     }
71
72     public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
73             final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
74             final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
75             final DataBroker dataBroker, final DOMMountPointService mountPointService,
76             final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
77             final BaseNetconfSchemas baseSchemas, final DeviceActionFactory deviceActionFactory) {
78         super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
79                 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, deviceActionFactory,
80                 baseSchemas);
81         this.rpcProviderService = requireNonNull(rpcProviderService);
82     }
83
84     @Override
85     public void close() {
86         if (rpcReg != null) {
87             rpcReg.close();
88             rpcReg = null;
89         }
90
91         // close all existing connectors, delete whole topology in datastore?
92         for (final NetconfConnectorDTO connectorDTO : activeConnectors.values()) {
93             connectorDTO.close();
94         }
95         activeConnectors.clear();
96
97         if (datastoreListenerRegistration != null) {
98             datastoreListenerRegistration.close();
99             datastoreListenerRegistration = null;
100         }
101     }
102
103     @Override
104     protected RemoteDeviceHandler createSalFacade(final RemoteDeviceId id) {
105         return new NetconfDeviceSalFacade(id, mountPointService, dataBroker, topologyId);
106     }
107
108     /**
109      * Invoked by blueprint.
110      */
111     public void init() {
112         LOG.debug("Registering datastore listener");
113         datastoreListenerRegistration = dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(
114             LogicalDatastoreType.CONFIGURATION, createTopologyListPath(topologyId).child(Node.class)), this);
115         rpcReg = rpcProviderService.registerRpcImplementation(NetconfNodeTopologyService.class,
116             new NetconfTopologyRPCProvider(dataBroker, encryptionService, topologyId));
117     }
118
119     @Override
120     public void onDataTreeChanged(final Collection<DataTreeModification<Node>> collection) {
121         for (final DataTreeModification<Node> change : collection) {
122             final DataObjectModification<Node> rootNode = change.getRootNode();
123             final NodeId nodeId;
124             switch (rootNode.getModificationType()) {
125                 case SUBTREE_MODIFIED:
126                     nodeId = getNodeId(rootNode.getIdentifier());
127                     LOG.debug("Config for node {} updated", nodeId);
128                     disconnectNode(nodeId);
129                     connectNode(nodeId, rootNode.getDataAfter());
130                     break;
131                 case WRITE:
132                     nodeId = getNodeId(rootNode.getIdentifier());
133                     LOG.debug("Config for node {} created", nodeId);
134                     if (activeConnectors.containsKey(nodeId)) {
135                         LOG.warn("RemoteDevice{{}} was already configured, reconfiguring..", nodeId);
136                         disconnectNode(nodeId);
137                     }
138                     connectNode(nodeId, rootNode.getDataAfter());
139                     break;
140                 case DELETE:
141                     nodeId = getNodeId(rootNode.getIdentifier());
142                     LOG.debug("Config for node {} deleted", nodeId);
143                     disconnectNode(nodeId);
144                     break;
145                 default:
146                     LOG.debug("Unsupported modification type: {}.", rootNode.getModificationType());
147             }
148         }
149     }
150
151     /**
152      * Determines the Netconf Node Node ID, given the node's instance
153      * identifier.
154      *
155      * @param pathArgument Node's path argument
156      * @return     NodeId for the node
157      */
158     @VisibleForTesting
159     static NodeId getNodeId(final InstanceIdentifier.PathArgument pathArgument) {
160         if (pathArgument instanceof InstanceIdentifier.IdentifiableItem<?, ?>) {
161             final Identifier<?> key = ((InstanceIdentifier.IdentifiableItem<?, ?>) pathArgument).getKey();
162             if (key instanceof NodeKey) {
163                 return ((NodeKey) key).getNodeId();
164             }
165         }
166         throw new IllegalStateException("Unable to create NodeId from: " + pathArgument);
167     }
168
169     @VisibleForTesting
170     static KeyedInstanceIdentifier<Topology, TopologyKey> createTopologyListPath(final String topologyId) {
171         final InstanceIdentifier<NetworkTopology> networkTopology = InstanceIdentifier.create(NetworkTopology.class);
172         return networkTopology.child(Topology.class, new TopologyKey(new TopologyId(topologyId)));
173     }
174 }