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