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