BGPCEP-730: Fix ModifiedNodeDoesNotExistException
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / config / BgpDeployerImpl.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.protocol.bgp.rib.impl.config;
10
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.annotations.VisibleForTesting;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.util.Collection;
19 import java.util.HashMap;
20 import java.util.Map;
21 import javax.annotation.concurrent.GuardedBy;
22 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
25 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
26 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
27 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
30 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
31 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
32 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
33 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
34 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.NetworkInstances;
35 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance;
36 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceBuilder;
37 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceKey;
38 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.Protocols;
39 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.ProtocolsBuilder;
40 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev171207.Protocol1;
42 import org.opendaylight.yangtools.concepts.ListenerRegistration;
43 import org.opendaylight.yangtools.yang.binding.DataObject;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.osgi.framework.BundleContext;
46 import org.osgi.service.blueprint.container.BlueprintContainer;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 public final class BgpDeployerImpl implements ClusteredDataTreeChangeListener<Bgp>, AutoCloseable {
51     private static final Logger LOG = LoggerFactory.getLogger(BgpDeployerImpl.class);
52     private final InstanceIdentifier<NetworkInstance> networkInstanceIId;
53     private final BlueprintContainer container;
54     private final BundleContext bundleContext;
55     private final BGPTableTypeRegistryConsumer tableTypeRegistry;
56     private final ClusterSingletonServiceProvider provider;
57     private ListenerRegistration<BgpDeployerImpl> registration;
58     @GuardedBy("this")
59     private final Map<InstanceIdentifier<Bgp>, BGPClusterSingletonService> bgpCss = new HashMap<>();
60     private final DataBroker dataBroker;
61     private final String networkInstanceName;
62     @GuardedBy("this")
63     private boolean closed;
64
65     public BgpDeployerImpl(final String networkInstanceName, final ClusterSingletonServiceProvider provider,
66             final BlueprintContainer container,
67             final BundleContext bundleContext, final DataBroker dataBroker,
68             final BGPTableTypeRegistryConsumer mappingService) {
69         this.dataBroker = requireNonNull(dataBroker);
70         this.provider = requireNonNull(provider);
71         this.networkInstanceName = requireNonNull(networkInstanceName);
72         this.container = requireNonNull(container);
73         this.bundleContext = requireNonNull(bundleContext);
74         this.tableTypeRegistry = requireNonNull(mappingService);
75         this.networkInstanceIId = InstanceIdentifier.create(NetworkInstances.class)
76                 .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
77         Futures.addCallback(initializeNetworkInstance(dataBroker, this.networkInstanceIId), new FutureCallback<Void>() {
78             @Override
79             public void onSuccess(final Void result) {
80                 LOG.debug("Network Instance {} initialized successfully.", networkInstanceName);
81             }
82
83             @Override
84             public void onFailure(final Throwable t) {
85                 LOG.error("Failed to initialize Network Instance {}.", networkInstanceName, t);
86             }
87         }, MoreExecutors.directExecutor());
88     }
89
90     public synchronized void init() {
91         this.registration = this.dataBroker.registerDataTreeChangeListener(
92                 new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
93                         this.networkInstanceIId.child(Protocols.class)
94                                 .child(Protocol.class).augmentation(Protocol1.class).child(Bgp.class)), this);
95         LOG.info("BGP Deployer {} started.", this.networkInstanceName);
96     }
97
98     @Override
99     public synchronized void onDataTreeChanged(final Collection<DataTreeModification<Bgp>> changes) {
100         if (this.closed) {
101             LOG.trace("BGP Deployer was already closed, skipping changes.");
102             return;
103         }
104         for (final DataTreeModification<Bgp> dataTreeModification : changes) {
105             final InstanceIdentifier<Bgp> rootIdentifier = dataTreeModification.getRootPath().getRootIdentifier();
106             final DataObjectModification<Bgp> rootNode = dataTreeModification.getRootNode();
107             LOG.trace("BGP configuration has changed: {}", rootNode);
108             for (final DataObjectModification<? extends DataObject> dataObjectModification :
109                     rootNode.getModifiedChildren()) {
110                 if (dataObjectModification.getDataType().equals(Global.class)) {
111                     onGlobalChanged((DataObjectModification<Global>) dataObjectModification, rootIdentifier);
112                 } else if (dataObjectModification.getDataType().equals(Neighbors.class)) {
113                     onNeighborsChanged((DataObjectModification<Neighbors>) dataObjectModification, rootIdentifier);
114                 }
115             }
116         }
117     }
118
119     @Override
120     public synchronized void close() throws Exception {
121         LOG.info("Closing BGP Deployer.");
122         if (this.registration != null) {
123             this.registration.close();
124             this.registration = null;
125         }
126         this.closed = true;
127
128         this.bgpCss.values().iterator().forEachRemaining(service -> {
129             try {
130                 service.close();
131             } catch (Exception e) {
132                 LOG.warn("Failed to close BGP Cluster Singleton Service.");
133             }
134         });
135
136     }
137
138     private static ListenableFuture<Void> initializeNetworkInstance(
139             final DataBroker dataBroker, final InstanceIdentifier<NetworkInstance> networkInstance) {
140         final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
141         wTx.merge(LogicalDatastoreType.CONFIGURATION, networkInstance,
142                 new NetworkInstanceBuilder().setName(networkInstance.firstKeyOf(NetworkInstance.class).getName())
143                         .setProtocols(new ProtocolsBuilder().build()).build());
144         return wTx.submit();
145     }
146
147     @VisibleForTesting
148     synchronized void onGlobalChanged(final DataObjectModification<Global> dataObjectModification,
149             final InstanceIdentifier<Bgp> rootIdentifier) {
150         BGPClusterSingletonService old = this.bgpCss.get(rootIdentifier);
151         if (old == null) {
152             old = new BGPClusterSingletonService(this.provider, this.tableTypeRegistry, this.container,
153                     this.bundleContext, rootIdentifier);
154             this.bgpCss.put(rootIdentifier, old);
155         }
156         old.onGlobalChanged(dataObjectModification);
157     }
158
159     @VisibleForTesting
160     synchronized void onNeighborsChanged(final DataObjectModification<Neighbors> dataObjectModification,
161             final InstanceIdentifier<Bgp> rootIdentifier) {
162         BGPClusterSingletonService old = this.bgpCss.get(rootIdentifier);
163         if (old == null) {
164             old = new BGPClusterSingletonService(this.provider, this.tableTypeRegistry, this.container,
165                     this.bundleContext, rootIdentifier);
166             this.bgpCss.put(rootIdentifier, old);
167         }
168         old.onNeighborsChanged(dataObjectModification);
169     }
170
171
172     @VisibleForTesting
173     BGPTableTypeRegistryConsumer getTableTypeRegistry() {
174         return this.tableTypeRegistry;
175     }
176 }