Merge "BUG 9112: NPE in karaf cli when device is still connecting"
[netconf.git] / netconf / netconf-topology / 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
9 package org.opendaylight.netconf.topology.impl;
10
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import io.netty.util.concurrent.EventExecutor;
15 import java.util.Collection;
16 import javax.annotation.Nonnull;
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.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
22 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
23 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
24 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
25 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
28 import org.opendaylight.netconf.client.NetconfClientDispatcher;
29 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
30 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
31 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalFacade;
32 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
33 import org.opendaylight.netconf.topology.AbstractNetconfTopology;
34 import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
42 import org.opendaylight.yangtools.concepts.ListenerRegistration;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 public class NetconfTopologyImpl extends AbstractNetconfTopology
48         implements DataTreeChangeListener<Node>, AutoCloseable {
49
50     private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyImpl.class);
51
52     private ListenerRegistration<NetconfTopologyImpl> datastoreListenerRegistration = null;
53
54     public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
55                                final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
56                                final ThreadPool processingExecutor,
57                                final SchemaRepositoryProvider schemaRepositoryProvider,
58                                final DataBroker dataBroker, final DOMMountPointService mountPointService,
59                                final AAAEncryptionService encryptionService) {
60         super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
61                 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService);
62     }
63
64     @Override
65     public void close() throws Exception {
66         // close all existing connectors, delete whole topology in datastore?
67         for (final NetconfConnectorDTO connectorDTO : activeConnectors.values()) {
68             connectorDTO.close();
69         }
70         activeConnectors.clear();
71
72         if (datastoreListenerRegistration != null) {
73             datastoreListenerRegistration.close();
74             datastoreListenerRegistration = null;
75         }
76     }
77
78     @Override
79     protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id) {
80         return new NetconfDeviceSalFacade(id, mountPointService, dataBroker);
81     }
82
83     /**
84      * Invoked by blueprint.
85      */
86     public void init() {
87         final WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
88         initTopology(wtx, LogicalDatastoreType.CONFIGURATION);
89         initTopology(wtx, LogicalDatastoreType.OPERATIONAL);
90         Futures.addCallback(wtx.submit(), new FutureCallback<Void>() {
91             @Override
92             public void onSuccess(final Void result) {
93                 LOG.debug("topology initialization successful");
94             }
95
96             @Override
97             public void onFailure(final Throwable throwable) {
98                 LOG.error("Unable to initialize netconf-topology, {}", throwable);
99             }
100         }, MoreExecutors.directExecutor());
101
102         LOG.debug("Registering datastore listener");
103         datastoreListenerRegistration =
104                 dataBroker.registerDataTreeChangeListener(
105                         new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
106                                 TopologyUtil.createTopologyListPath(topologyId).child(Node.class)), this);
107     }
108
109     @Override
110     public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<Node>> collection) {
111         for (final DataTreeModification<Node> change : collection) {
112             final DataObjectModification<Node> rootNode = change.getRootNode();
113             switch (rootNode.getModificationType()) {
114                 case SUBTREE_MODIFIED:
115                     LOG.debug("Config for node {} updated", TopologyUtil.getNodeId(rootNode.getIdentifier()));
116                     disconnectNode(TopologyUtil.getNodeId(rootNode.getIdentifier()));
117                     connectNode(TopologyUtil.getNodeId(rootNode.getIdentifier()), rootNode.getDataAfter());
118                     break;
119                 case WRITE:
120                     LOG.debug("Config for node {} created", TopologyUtil.getNodeId(rootNode.getIdentifier()));
121                     if (activeConnectors.containsKey(TopologyUtil.getNodeId(rootNode.getIdentifier()))) {
122                         LOG.warn("RemoteDevice{{}} was already configured, reconfiguring..",
123                                 TopologyUtil.getNodeId(rootNode.getIdentifier()));
124                         disconnectNode(TopologyUtil.getNodeId(rootNode.getIdentifier()));
125                     }
126                     connectNode(TopologyUtil.getNodeId(rootNode.getIdentifier()), rootNode.getDataAfter());
127                     break;
128                 case DELETE:
129                     LOG.debug("Config for node {} deleted", TopologyUtil.getNodeId(rootNode.getIdentifier()));
130                     disconnectNode(TopologyUtil.getNodeId(rootNode.getIdentifier()));
131                     break;
132                 default:
133                     LOG.debug("Unsupported modification type: {}.", rootNode.getModificationType());
134             }
135         }
136     }
137
138     private void initTopology(final WriteTransaction wtx, final LogicalDatastoreType datastoreType) {
139         final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
140         final InstanceIdentifier<NetworkTopology> networkTopologyId =
141                 InstanceIdentifier.builder(NetworkTopology.class).build();
142         wtx.merge(datastoreType, networkTopologyId, networkTopology);
143         final Topology topology = new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).build();
144         wtx.merge(datastoreType,
145                 networkTopologyId.child(Topology.class, new TopologyKey(new TopologyId(topologyId))), topology);
146     }
147
148 }