Bug 8608 - quick fix for async transaction creation
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / iface / VppEndpointLocationProvider.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.groupbasedpolicy.renderer.vpp.iface;
10
11 import static com.google.common.base.Preconditions.checkNotNull;
12
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.locks.ReentrantLock;
20 import java.util.stream.Collectors;
21
22 import javax.annotation.Nonnull;
23
24 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
27 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
28 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
29 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
30 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
31 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
32 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
33 import org.opendaylight.groupbasedpolicy.renderer.util.AddressEndpointUtils;
34 import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.VppNodeManager;
35 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.CloseOnFailTransactionChain;
36 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
37 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
38 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
39 import org.opendaylight.groupbasedpolicy.util.DataTreeChangeHandler;
40 import org.opendaylight.groupbasedpolicy.util.EndpointUtils;
41 import org.opendaylight.groupbasedpolicy.util.IidFactory;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.Endpoints;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.AddressEndpoints;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocationBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCaseBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpoint;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpointKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.RelativeLocations;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.RelativeLocationsBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.relative.locations.ExternalLocation;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.relative.locations.ExternalLocationBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpoint;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpointKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.ProviderName;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProvider;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProviderBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocation;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocationBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocationKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocationKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
70 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 import com.google.common.annotations.VisibleForTesting;
75 import com.google.common.base.Function;
76 import com.google.common.base.Optional;
77 import com.google.common.util.concurrent.CheckedFuture;
78 import com.google.common.util.concurrent.FutureCallback;
79 import com.google.common.util.concurrent.Futures;
80 import com.google.common.util.concurrent.ListenableFuture;
81
82 public class VppEndpointLocationProvider extends DataTreeChangeHandler<AddressEndpoint> {
83
84     private static final Logger LOG = LoggerFactory.getLogger(VppEndpointLocationProvider.class);
85     public static final ProviderName VPP_ENDPOINT_LOCATION_PROVIDER =
86             new ProviderName("VPP endpoint location provider");
87     public static final long PROVIDER_PRIORITY = 10L;
88     private final BindingTransactionChain txChain;
89     private final Map<VppEndpointKey, VppEndpoint> vppEndpoints = new HashMap<>();
90     private final Map<VppEndpointKey, DataObjectModification<AddressEndpoint>> cachedVppEndpoints = new HashMap<>();
91
92     public static final ReentrantLock REENTRANT_LOCK = new ReentrantLock();
93
94     public VppEndpointLocationProvider(DataBroker dataProvider) {
95         super(dataProvider);
96         LocationProvider locationProvider = new LocationProviderBuilder().setProvider(VPP_ENDPOINT_LOCATION_PROVIDER)
97             .setPriority(PROVIDER_PRIORITY)
98             .build();
99         txChain = checkNotNull(dataProvider)
100             .createTransactionChain(new CloseOnFailTransactionChain(VppEndpointLocationProvider.class.getSimpleName()));
101         WriteTransaction wTx = txChain.newWriteOnlyTransaction();
102         wTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.locationProviderIid(VPP_ENDPOINT_LOCATION_PROVIDER),
103                 locationProvider, true);
104         Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
105
106             @Override
107             public void onSuccess(Void result) {
108                 LOG.debug("{} was created", VPP_ENDPOINT_LOCATION_PROVIDER.getValue());
109             }
110
111             @Override
112             public void onFailure(Throwable t) {
113                 LOG.error("{} was NOT created", VPP_ENDPOINT_LOCATION_PROVIDER.getValue());
114             }
115         });
116         registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
117                 InstanceIdentifier.builder(Endpoints.class).child(AddressEndpoints.class).child(AddressEndpoint.class).build()));
118     }
119
120     @Override
121     protected void onWrite(DataObjectModification<AddressEndpoint> rootNode,
122             InstanceIdentifier<AddressEndpoint> rootIdentifier) {
123         LOG.debug("onWrite triggered by {}", rootNode.getDataAfter());
124         try {
125             if (EndpointUtils.isExternalEndpoint(dataProvider, rootNode.getDataAfter())) {
126                 writeLocation(createRelativeAddressEndpointLocation(rootNode.getDataAfter().getKey(),
127                         VppNodeManager.resolvePublicInterfaces(dataProvider))).get();
128             } else {
129                 createAbsoluteAddressEndpointLocation(null, rootNode).get();
130             }
131         } catch (InterruptedException | ExecutionException e) {
132             LOG.error("Failed to write location for endpoint {}. {}", rootNode.getDataAfter().getKey(), e.getMessage());
133         }
134     }
135
136     @Override
137     protected void onDelete(DataObjectModification<AddressEndpoint> rootNode,
138             InstanceIdentifier<AddressEndpoint> rootIdentifier) {
139         LOG.debug("onDelete triggered by {}", rootNode.getDataBefore());
140         try {
141             if (EndpointUtils.isExternalEndpoint(dataProvider, rootNode.getDataBefore())) {
142                 deleteLocation(createProviderAddressEndpointLocationKey(rootNode.getDataBefore().getKey())).get();
143             } else {
144                 createAbsoluteAddressEndpointLocation(null, rootNode).get();
145             }
146         } catch (InterruptedException | ExecutionException e) {
147             LOG.error("Failed to delete location for endpoint {}. {}", rootNode.getDataBefore().getKey(),
148                     e.getMessage());
149         }
150     }
151
152     @Override
153     protected void onSubtreeModified(DataObjectModification<AddressEndpoint> rootNode,
154             InstanceIdentifier<AddressEndpoint> rootIdentifier) {
155         LOG.debug("onSubtreeModified triggered by change: before={} after={}", rootNode.getDataBefore(),
156                 rootNode.getDataAfter());
157         if (rootNode.getDataBefore() != null) {
158             onDelete(rootNode, rootIdentifier);
159         }
160         if (rootNode.getDataAfter() != null) {
161             onWrite(rootNode, rootIdentifier);
162         }
163     }
164
165     public ListenableFuture<Void> createLocationForVppEndpoint(VppEndpoint vppEndpoint) {
166         return createAbsoluteAddressEndpointLocation(vppEndpoint, null);
167     }
168
169     public ListenableFuture<Void> deleteLocationForVppEndpoint(VppEndpoint vppEndpoint) {
170         // removing VPP EP from cache out of since block, it's not needed for the other thread.
171         vppEndpoints.remove(vppEndpoint.getKey());
172         return deleteLocation(createProviderAddressEndpointLocationKey(vppEndpoint));
173     }
174
175     /**
176      * There are two inputs from which we need to resolve location - {@link AddressEndpoint} and {@link VppEndpoint}
177      * These data are delivered by different threads which meet here.
178      */
179     @VisibleForTesting
180     synchronized ListenableFuture<Void> createAbsoluteAddressEndpointLocation(VppEndpoint vppEndpoint,
181             DataObjectModification<AddressEndpoint> rootNode) {
182         if (vppEndpoint != null) {
183             LOG.debug("Saving VPP endpoint {}" + vppEndpoint.getKey());
184             vppEndpoints.put(vppEndpoint.getKey(), vppEndpoint);
185             if (cachedVppEndpoints.get(vppEndpoint.getKey()) != null) {
186                 try {
187                     processAddrEp(cachedVppEndpoints.get(vppEndpoint.getKey())).get();
188                 } catch (InterruptedException | ExecutionException e) {
189                     LOG.error("Failed to resolve location for cached endpoint {}. {}", vppEndpoint.getKey(), e);
190                 }
191                 return Futures.immediateFuture(null);
192             }
193         } else if (rootNode != null) {
194             try {
195             processAddrEp(rootNode).get();
196             } catch (InterruptedException | ExecutionException e) {
197                 LOG.error("Failed to resolve location for changed endpoint before={} after={}. {}",
198                         rootNode.getDataAfter(), rootNode.getDataAfter(), e);
199             }
200             return Futures.immediateFuture(null);
201         }
202         return Futures.immediateFuture(null);
203     }
204
205     private ListenableFuture<Void> processAddrEp(DataObjectModification<AddressEndpoint> rootNode) {
206         if (rootNode != null) {
207             AddressEndpointChange aec = new AddressEndpointChange(rootNode, txChain);
208             switch (rootNode.getModificationType()) {
209                 case WRITE:
210                 case SUBTREE_MODIFIED: {
211                     VppEndpoint vpp = vppEndpoints.get(vppEndpointKeyFrom(rootNode.getDataAfter().getKey()));
212                     if (vpp == null) {
213                         VppEndpointKey key = vppEndpointKeyFrom(rootNode.getDataAfter().getKey());
214                         LOG.debug("Caching VPP endpoint {}" + key);
215                         cachedVppEndpoints.put(key, rootNode);
216                         return Futures.immediateFuture(null);
217                     }
218                     if (aec.hasMoreParents()) {
219                         return aec.syncMultiparents();
220                     }
221                         return aec.write();
222                 }
223                 case DELETE: {
224                     if (aec.hasMoreParents()) {
225                         return aec.syncMultiparents();
226                     } else {
227                         return aec.delete();
228                     }
229                 }
230             }
231         }
232         return Futures.immediateFuture(null);
233     }
234
235     private ProviderAddressEndpointLocation createAbsoluteLocationFromVppEndpoint(VppEndpoint vppEndpoint) {
236         InstanceIdentifier<Node> vppNodeIid = VppIidFactory.getNetconfNodeIid(vppEndpoint.getVppNodeId());
237         String restIfacePath = VppPathMapper.interfaceToRestPath(vppEndpoint.getVppInterfaceName());
238         AbsoluteLocation absoluteLocation =
239                 new AbsoluteLocationBuilder().setLocationType(new ExternalLocationCaseBuilder()
240                     .setExternalNodeMountPoint(vppNodeIid).setExternalNodeConnector(restIfacePath).build()).build();
241         return new ProviderAddressEndpointLocationBuilder()
242             .setKey(createProviderAddressEndpointLocationKey(vppEndpoint))
243             .setAbsoluteLocation(absoluteLocation)
244             .build();
245     }
246
247     public ProviderAddressEndpointLocation createRelativeAddressEndpointLocation(@Nonnull AddressEndpointKey addrEp,
248             @Nonnull Map<NodeId, String> publicIntfNamesByNodes) {
249         RelativeLocations relLocations =
250                 new RelativeLocationsBuilder()
251                     .setExternalLocation(publicIntfNamesByNodes.keySet()
252                         .stream()
253                         .filter(nodeId -> publicIntfNamesByNodes.get(nodeId) != null)
254                         .map(nodeId -> new ExternalLocationBuilder()
255                             .setExternalNodeMountPoint(VppIidFactory.getNetconfNodeIid(nodeId))
256                             .setExternalNodeConnector(
257                                     VppPathMapper.interfaceToRestPath(publicIntfNamesByNodes.get(nodeId)))
258                             .build())
259                         .collect(Collectors.toList()))
260                     .build();
261         return new ProviderAddressEndpointLocationBuilder().setKey(createProviderAddressEndpointLocationKey(addrEp))
262             .setRelativeLocations(relLocations)
263             .build();
264     }
265
266     public ListenableFuture<Void> writeLocation(ProviderAddressEndpointLocation location) {
267         REENTRANT_LOCK.lock();
268         WriteTransaction wTx = txChain.newWriteOnlyTransaction();
269         wTx.put(LogicalDatastoreType.CONFIGURATION,
270                 IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER, location.getKey()),
271                 location, true);
272         CheckedFuture<Void, TransactionCommitFailedException> submit = wTx.submit();
273         REENTRANT_LOCK.unlock();
274         return Futures.transform(submit, new Function<Void, Void>() {
275
276             @Override
277             public Void apply(Void input) {
278                 LOG.debug("{} provided location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(), location);
279                 return null;
280             }
281         });
282     }
283
284     public ListenableFuture<Void> deleteLocation(ProviderAddressEndpointLocationKey key) {
285         REENTRANT_LOCK.lock();
286         ReadWriteTransaction rwTx = txChain.newReadWriteTransaction();
287         LOG.debug("Deleting location for {}", key);
288         DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
289                 IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER, key), rwTx);
290         CheckedFuture<Void, TransactionCommitFailedException> submit = rwTx.submit();
291         REENTRANT_LOCK.unlock();
292         return Futures.transform(submit, new Function<Void, Void>() {
293
294             @Override
295             public Void apply(Void input) {
296                 LOG.debug("{} removed location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(), key);
297                 return null;
298             }
299         });
300     }
301
302     public ListenableFuture<Void> replaceLocationForEndpoint(@Nonnull ExternalLocationCase location, @Nonnull AddressEndpointWithLocationKey addrEpWithLocKey) {
303         InstanceIdentifier<ProviderAddressEndpointLocation> iid = IidFactory.providerAddressEndpointLocationIid(
304                 VPP_ENDPOINT_LOCATION_PROVIDER, createProviderAddressEndpointLocationKey(addrEpWithLocKey));
305         ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
306         Optional<ProviderAddressEndpointLocation> optLoc = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, iid, rTx);
307         rTx.close();
308         ProviderAddressEndpointLocationKey provAddrEpLocKey =
309                 KeyFactory.providerAddressEndpointLocationKey(addrEpWithLocKey);
310         ProviderAddressEndpointLocationBuilder builder = new ProviderAddressEndpointLocationBuilder().setKey(provAddrEpLocKey);
311         if(optLoc.isPresent() && optLoc.get().getAbsoluteLocation() != null) {
312             AbsoluteLocation absoluteLocation = optLoc.get().getAbsoluteLocation();
313             builder.setAbsoluteLocation(new AbsoluteLocationBuilder(absoluteLocation).setLocationType(location).build());
314         } else if (optLoc.isPresent() && optLoc.get().getRelativeLocations() != null) {
315             ExternalLocation extLoc = new ExternalLocationBuilder().setExternalNode(location.getExternalNode())
316             .setExternalNodeConnector(location.getExternalNodeConnector())
317             .setExternalNodeMountPoint(location.getExternalNodeMountPoint())
318             .build();
319             List<ExternalLocation> externalLocation = optLoc.get()
320                 .getRelativeLocations()
321                 .getExternalLocation();
322             externalLocation.add(extLoc);
323             RelativeLocations relativeLocation = new RelativeLocationsBuilder(optLoc.get().getRelativeLocations()).setExternalLocation(externalLocation).build();
324             builder.setRelativeLocations(relativeLocation);
325         }
326         else {
327             LOG.warn("Cannot replace location for endpoint {}", addrEpWithLocKey);
328             return Futures.immediateFuture(null);
329         }
330         ProviderAddressEndpointLocation providerLocation = builder.build();
331         REENTRANT_LOCK.lock();
332         WriteTransaction wTx = txChain.newWriteOnlyTransaction();
333         wTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.providerAddressEndpointLocationIid(
334                 VPP_ENDPOINT_LOCATION_PROVIDER, providerLocation.getKey()), providerLocation);
335         LOG.debug("Updating location for {}", builder.build().getKey());
336         CheckedFuture<Void, TransactionCommitFailedException> submit = wTx.submit();
337         REENTRANT_LOCK.unlock();
338         return Futures.transform(submit, new Function<Void, Void>() {
339
340             @Override
341             public Void apply(Void input) {
342                 LOG.debug("{} replaced location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(),
343                         providerLocation.getKey());
344                 return null;
345             }
346         });
347     }
348
349     static ProviderAddressEndpointLocationKey createProviderAddressEndpointLocationKey(VppEndpoint vpp) {
350         return new ProviderAddressEndpointLocationKey(vpp.getAddress(), vpp.getAddressType(), vpp.getContextId(),
351                 vpp.getContextType());
352     }
353
354     static ProviderAddressEndpointLocationKey createProviderAddressEndpointLocationKey(AddressEndpointKey key) {
355         return new ProviderAddressEndpointLocationKey(key.getAddress(), key.getAddressType(), key.getContextId(),
356                 key.getContextType());
357     }
358
359     static ProviderAddressEndpointLocationKey createProviderAddressEndpointLocationKey(AddressEndpointWithLocationKey key) {
360         return new ProviderAddressEndpointLocationKey(key.getAddress(), key.getAddressType(), key.getContextId(),
361                 key.getContextType());
362     }
363
364     private static ProviderAddressEndpointLocationKey createProviderAddressEndpointLocationKey(ParentEndpointKey key) {
365         return new ProviderAddressEndpointLocationKey(key.getAddress(), key.getAddressType(), key.getContextId(),
366                 key.getContextType());
367     }
368
369     private VppEndpointKey vppEndpointKeyFrom(AddressEndpointKey key) {
370         return new VppEndpointKey(key.getAddress(), key.getAddressType(), key.getContextId(), key.getContextType());
371     }
372
373     private VppEndpointKey vppEndpointKeyFrom(ParentEndpointKey key) {
374         return new VppEndpointKey(key.getAddress(), key.getAddressType(), key.getContextId(), key.getContextType());
375     }
376
377     private VppEndpointKey vppEndpointKeyFrom(ChildEndpointKey key) {
378         return new VppEndpointKey(key.getAddress(), key.getAddressType(), key.getContextId(), key.getContextType());
379     }
380
381     @Override
382     public void close() {
383         super.closeRegisteredListener();
384         WriteTransaction wTx = txChain.newWriteOnlyTransaction();
385         wTx.delete(LogicalDatastoreType.CONFIGURATION, IidFactory.locationProviderIid(VPP_ENDPOINT_LOCATION_PROVIDER));
386         wTx.submit();
387     }
388
389     private class AddressEndpointChange {
390
391         private final AddressEndpoint before;
392         private final AddressEndpoint after;
393         private final BindingTransactionChain transactionChain;
394
395         public AddressEndpointChange(DataObjectModification<AddressEndpoint> addrEp, @Nonnull BindingTransactionChain txChain) {
396             this.before = addrEp.getDataBefore();
397             this.after = addrEp.getDataAfter();
398             this.transactionChain = txChain;
399         }
400
401         boolean hasMoreParents() {
402             return (before != null && EndpointUtils.getParentEndpoints(before.getParentEndpointChoice()).size() > 1)
403                     || (after != null && EndpointUtils.getParentEndpoints(after.getParentEndpointChoice()).size() > 1);
404         }
405
406         ListenableFuture<Void> syncMultiparents() {
407             REENTRANT_LOCK.lock();
408             ReadWriteTransaction rwTx = transactionChain.newReadWriteTransaction();
409             if (before != null) {
410                 for (ParentEndpoint pe : EndpointUtils.getParentEndpoints(before.getParentEndpointChoice())) {
411                     InstanceIdentifier<ProviderAddressEndpointLocation> iid =
412                             IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER,
413                                     createProviderAddressEndpointLocationKey(pe.getKey()));
414                     DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, iid, rwTx);
415                 }
416             }
417             if (after != null) {
418                 for (ParentEndpoint pe : EndpointUtils.getParentEndpoints(after.getParentEndpointChoice())) {
419                     VppEndpoint vppEndpoint = vppEndpoints.get(vppEndpointKeyFrom(after.getKey()));
420                     InstanceIdentifier<ProviderAddressEndpointLocation> iid =
421                             IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER,
422                                     createProviderAddressEndpointLocationKey(pe.getKey()));
423
424                     List<ChildEndpoint> childs = abc(rwTx, pe);
425                         List<VppEndpoint> vppEps = new ArrayList<>();
426                         for (ChildEndpoint che : childs) {
427                             VppEndpoint cheVppEp = vppEndpoints.get(vppEndpointKeyFrom(che.getKey()));
428                             if (cheVppEp != null) {
429                                 vppEps.add(cheVppEp);
430                             } else {
431                             }
432                         }
433                         if (vppEps.size() > 1) {
434                         ProviderAddressEndpointLocation location = createRelativeLocationFromVppEndpoint(
435                                 createProviderAddressEndpointLocationKey(pe.getKey()), vppEps);
436                         rwTx.put(LogicalDatastoreType.CONFIGURATION, iid, location, true);
437                     } else {
438                         ProviderAddressEndpointLocation location = createAbsoluteLocationFromVppEndpoint(
439                                 new VppEndpointBuilder(vppEndpoint).setKey(vppEndpointKeyFrom(pe.getKey())).build());
440                         rwTx.put(LogicalDatastoreType.CONFIGURATION, iid, location, true);
441                     }
442
443                 }
444             }
445             CheckedFuture<Void, TransactionCommitFailedException> submit = rwTx.submit();
446             REENTRANT_LOCK.unlock();
447             return submit;
448         }
449
450         private List<ChildEndpoint> abc(ReadWriteTransaction rTx, ParentEndpoint pe) {
451             AddressEndpointKey addrEpKey = new AddressEndpointKey(AddressEndpointUtils.fromParentEndpointKey(pe.getKey()));
452             Optional<AddressEndpoint> optParent = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(addrEpKey), rTx);
453             return (optParent.isPresent()) ? optParent.get().getChildEndpoint() : Collections.emptyList();
454         }
455
456         private ProviderAddressEndpointLocation createRelativeLocationFromVppEndpoint(
457                 ProviderAddressEndpointLocationKey key, List<VppEndpoint> vppEndpoints) {
458             List<ExternalLocation> extLocations = vppEndpoints.stream().map(vppEndpoint -> {
459                 InstanceIdentifier<Node> vppNodeIid = VppIidFactory.getNetconfNodeIid(vppEndpoint.getVppNodeId());
460                 String restIfacePath = VppPathMapper.interfaceToRestPath(vppEndpoint.getVppInterfaceName());
461                 return new ExternalLocationBuilder().setExternalNodeMountPoint(vppNodeIid)
462                     .setExternalNodeConnector(restIfacePath)
463                     .build();
464             }).collect(Collectors.toList());
465             RelativeLocations relativeLocations =
466                     new RelativeLocationsBuilder().setExternalLocation(extLocations).build();
467             return new ProviderAddressEndpointLocationBuilder().setRelativeLocations(relativeLocations)
468                 .setKey(key)
469                 .build();
470         }
471
472         ListenableFuture<Void> write() {
473             VppEndpoint vpp = vppEndpoints.get(vppEndpointKeyFrom(after.getKey()));
474             WriteTransaction wTx = transactionChain.newWriteOnlyTransaction();
475             ProviderAddressEndpointLocation location =
476                     createAbsoluteLocationFromVppEndpoint(vpp);
477             InstanceIdentifier<ProviderAddressEndpointLocation> iid = IidFactory.providerAddressEndpointLocationIid(
478                     VPP_ENDPOINT_LOCATION_PROVIDER, createProviderAddressEndpointLocationKey(vpp));
479             wTx.put(LogicalDatastoreType.CONFIGURATION, iid, location, true);
480             return wTx.submit();
481         }
482
483         ListenableFuture<Void> delete() {
484             ReadWriteTransaction rwTx = transactionChain.newReadWriteTransaction();
485             InstanceIdentifier<ProviderAddressEndpointLocation> iid = IidFactory.providerAddressEndpointLocationIid(
486                     VPP_ENDPOINT_LOCATION_PROVIDER, createProviderAddressEndpointLocationKey(before.getKey()));
487             DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, iid, rwTx);
488             return rwTx.submit();
489         }
490     }
491 }