Update of BaseEndpointRpcRegistry
[groupbasedpolicy.git] / groupbasedpolicy / src / main / java / org / opendaylight / groupbasedpolicy / base_endpoint / BaseEndpointRpcRegistry.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.base_endpoint;
10
11 import com.google.common.base.Function;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
18 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
19 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
22 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
23 import org.opendaylight.groupbasedpolicy.api.BaseEndpointRendererAugmentation;
24 import org.opendaylight.groupbasedpolicy.api.BaseEndpointRendererAugmentationRegistry;
25 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
26 import org.opendaylight.groupbasedpolicy.util.IidFactory;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.BaseEndpointService;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.RegisterEndpointInput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.UnregisterEndpointInput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.containment.endpoints.ContainmentEndpoint;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.containment.endpoints.ContainmentEndpointBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.containment.endpoints.ContainmentEndpointKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpoint;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpointBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.ParentEndpointChoice;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.ParentContainmentEndpointCase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.ParentContainmentEndpointCaseBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.ParentEndpointCase;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.ParentEndpointCaseBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.containment.endpoint._case.ParentContainmentEndpoint;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.containment.endpoint._case.ParentContainmentEndpointBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpoint;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpointBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointReg;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointRegKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.ContainmentEndpointReg;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.ContainmentEndpointRegKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.unregister.endpoint.input.AddressEndpointUnreg;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.unregister.endpoint.input.ContainmentEndpointUnreg;
53 import org.opendaylight.yangtools.yang.binding.Augmentation;
54 import org.opendaylight.yangtools.yang.common.RpcError;
55 import org.opendaylight.yangtools.yang.common.RpcResult;
56 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 import java.util.ArrayList;
61 import java.util.Collections;
62 import java.util.List;
63 import java.util.Map;
64 import java.util.concurrent.ConcurrentHashMap;
65 import java.util.concurrent.ConcurrentMap;
66 import java.util.concurrent.Future;
67
68 import javax.annotation.Nullable;
69
70 public class BaseEndpointRpcRegistry
71         implements BaseEndpointService, BaseEndpointRendererAugmentationRegistry, AutoCloseable {
72
73     static final ConcurrentMap<String, BaseEndpointRendererAugmentation> registeredRenderers =
74             new ConcurrentHashMap<>();
75     private static final Logger LOG = LoggerFactory.getLogger(BaseEndpointRpcRegistry.class);
76     private final DataBroker dataProvider;
77     private final BindingAwareBroker.RpcRegistration<BaseEndpointService> rpcRegistration;
78
79     private Function<Void, RpcResult<Void>> futureTrans = new Function<Void, RpcResult<Void>>() {
80
81         @Override
82         public RpcResult<Void> apply(Void input) {
83             return RpcResultBuilder.<Void>success().build();
84         }
85     };
86
87     public BaseEndpointRpcRegistry(DataBroker dataProvider, RpcProviderRegistry rpcRegistry) {
88         Preconditions.checkNotNull(dataProvider);
89         Preconditions.checkNotNull(rpcRegistry);
90
91         this.dataProvider = dataProvider;
92         this.rpcRegistration = rpcRegistry.addRpcImplementation(BaseEndpointService.class, this);
93     }
94
95     /**
96      * Registers renderer's endpoints augmentation.
97      *
98      * @param baseEndpointRendererAugmentation cannot be {@code null}
99      * @throws NullPointerException
100      */
101     @Override
102     public void register(BaseEndpointRendererAugmentation baseEndpointRendererAugmentation) {
103         if (baseEndpointRendererAugmentation != null) {
104             registeredRenderers.putIfAbsent(baseEndpointRendererAugmentation.getClass().getName(),
105                     baseEndpointRendererAugmentation);
106             LOG.info("Registered {}", baseEndpointRendererAugmentation.getClass().getName());
107         }
108     }
109
110     /**
111      * Unregisters renderer's endpoints augmentation.
112      *
113      * @param baseEndpointRendererAugmentation cannot be {@code null}
114      * @throws NullPointerException
115      */
116     @Override
117     public void unregister(BaseEndpointRendererAugmentation baseEndpointRendererAugmentation) {
118         if (baseEndpointRendererAugmentation == null
119                 || !registeredRenderers.containsKey(baseEndpointRendererAugmentation.getClass().getName())) {
120             return;
121         }
122         registeredRenderers.remove(baseEndpointRendererAugmentation.getClass().getName());
123         LOG.info("Unregistered {}", baseEndpointRendererAugmentation.getClass().getName());
124     }
125
126     /**
127      * Register a new endpoint into the registry. If there is already an existing
128      * endpoint with the same keys, they will be overwritten with the new information.
129      *
130      * @param input Endpoint to register
131      */
132     @Override
133     public Future<RpcResult<Void>> registerEndpoint(RegisterEndpointInput input) {
134         long timestamp = System.currentTimeMillis();
135
136         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
137
138         List<ContainmentEndpointReg> endpoints = input.getContainmentEndpointReg();
139         ListenableFuture<RpcResult<Void>> failResult = verifyRegisterEndpointInput(input);
140         if (failResult == null) {
141             for (ContainmentEndpointReg ce : nullToEmpty(endpoints)) {
142                 long stamp = (ce.getTimestamp() == null || ce.getTimestamp() == 0) ? timestamp : ce.getTimestamp();
143                 ContainmentEndpoint endpoint = buildContainmentEndpoint(ce).setTimestamp(stamp).build();
144                 t.put(LogicalDatastoreType.OPERATIONAL, IidFactory.containmentEndpointIid(endpoint.getKey()), endpoint,
145                         true);
146
147                 updateContainmentEndpointRegChilds(t, endpoint);
148             }
149
150             List<AddressEndpointReg> addressEndpoints = input.getAddressEndpointReg();
151             for (AddressEndpointReg ae : nullToEmpty(addressEndpoints)) {
152                 long stamp = (ae.getTimestamp() == null || ae.getTimestamp() == 0) ? timestamp : ae.getTimestamp();
153                 AddressEndpoint endpoint = buildAddressEndpoint(ae).setTimestamp(stamp).build();
154                 t.put(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(endpoint.getKey()), endpoint,
155                         true);
156
157                 updateAddressEndpointRegChilds(t, endpoint);
158
159                 updateAddressEndpointRegParents(t, endpoint);
160             }
161         } else {
162             return failResult;
163         }
164
165         ListenableFuture<Void> r = t.submit();
166         return Futures.transform(r, futureTrans);
167     }
168
169     private void updateContainmentEndpointRegChilds(WriteTransaction t, ContainmentEndpoint containmentEndpoint) {
170         ReadOnlyTransaction readTransaction = dataProvider.newReadOnlyTransaction();
171
172         for (ChildEndpoint child : nullToEmpty(containmentEndpoint.getChildEndpoint())) {
173             AddressEndpointKey key = new AddressEndpointKey(child.getAddress(), child.getAddressType(),
174                     child.getContextId(), child.getContextType());
175             Optional<AddressEndpoint> addressEndpointOptional = DataStoreHelper
176                 .readFromDs(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(key), readTransaction);
177
178             if (addressEndpointOptional.isPresent()) {
179                 ParentEndpointChoice parentEndpointChoice = addressEndpointOptional.get().getParentEndpointChoice();
180                 List<ParentContainmentEndpoint> parentContainmentEndpoints =
181                         getParentContainmentEndpoints(parentEndpointChoice);
182
183                 ParentContainmentEndpoint parentContainmentEndpoint =
184                         new ParentContainmentEndpointBuilder().setContextId(containmentEndpoint.getContextId())
185                             .setContextType(containmentEndpoint.getContextType())
186                             .build();
187
188                 if (!nullToEmpty(parentContainmentEndpoints).contains(parentContainmentEndpoint)) {
189                     parentContainmentEndpoints.add(parentContainmentEndpoint);
190                     AddressEndpoint updatedAddressEndpoint = new AddressEndpointBuilder(addressEndpointOptional.get())
191                         .setParentEndpointChoice(new ParentContainmentEndpointCaseBuilder()
192                             .setParentContainmentEndpoint(parentContainmentEndpoints).build())
193                         .build();
194
195                     t.put(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(key), updatedAddressEndpoint);
196                 }
197             }
198         }
199     }
200
201     private ListenableFuture<RpcResult<Void>> verifyRegisterEndpointInput(RegisterEndpointInput input) {
202         ListenableFuture<RpcResult<Void>> result;
203         List<AddressEndpointReg> addressEndpointRegs = nullToEmpty(input.getAddressEndpointReg());
204         List<ContainmentEndpointReg> containmentEndpointRegs = nullToEmpty(input.getContainmentEndpointReg());
205
206         for (AddressEndpointReg addressEndpointReg : nullToEmpty(addressEndpointRegs)) {
207             result = verifyAddressEndpointChilds(addressEndpointRegs, addressEndpointReg);
208             if (result != null) {
209                 return result;
210             }
211
212             result = verifyAddressEndpointParents(addressEndpointRegs, addressEndpointReg);
213             if (result != null) {
214                 return result;
215             }
216         }
217
218         result = verifyContainmentEndpointChilds(addressEndpointRegs, containmentEndpointRegs);
219         if (result != null) {
220             return result;
221         }
222
223         return null;
224     }
225
226     private ListenableFuture<RpcResult<Void>> verifyContainmentEndpointChilds(
227             List<AddressEndpointReg> addressEndpointRegs, List<ContainmentEndpointReg> containmentEndpointRegs) {
228         for (ContainmentEndpointReg containmentEndpointReg : nullToEmpty(containmentEndpointRegs)) {
229             for (ChildEndpoint childEndpoint : nullToEmpty(containmentEndpointReg.getChildEndpoint())) {
230                 AddressEndpointRegKey key = new AddressEndpointRegKey(childEndpoint.getAddress(),
231                         childEndpoint.getAddressType(), childEndpoint.getContextId(), childEndpoint.getContextType());
232                 AddressEndpointReg addressEndpointRegChild = findAddressEndpointReg(key, addressEndpointRegs);
233                 if (addressEndpointRegChild == null) {
234                     // todo this can be optimized if we move this to
235                     // updateContainmentEndpointRegChilds and verify child in one step with update.
236                     Optional<AddressEndpoint> addressEndpointOptional =
237                             DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
238                                     IidFactory.addressEndpointIid(new AddressEndpointKey(key.getAddress(),
239                                             key.getAddressType(), key.getContextId(), key.getContextType())),
240                                     dataProvider.newReadOnlyTransaction());
241                     if (!addressEndpointOptional.isPresent()) {
242                         LOG.debug("Child AddressEndpoint {} does not exist in RPC and DS.", childEndpoint);
243                         return buildFailFeature(
244                                 String.format("Child AddressEndpoint %s does not exist in RPC and DS.", childEndpoint));
245                     }
246                 } else {
247
248                     if (!containmentEndpointReg.getKey().equals(new ContainmentEndpointRegKey(
249                             addressEndpointRegChild.getContextId(), addressEndpointRegChild.getContextType()))) {
250                         LOG.debug(
251                                 "Child AddressEndpoint {} in ContainmentEndpoint->ChildEndpoints does not contain a valid ContainmentEndpointRegKey.",
252                                 addressEndpointRegChild);
253                         return buildFailFeature(String
254                             .format("AddressEndpoint in ContainmentEndpoint->ChildEndpoints does not contain a valid ContainmentEndpointRegKey."
255                                     + "\nChild element: %s", addressEndpointRegChild));
256                     }
257                 }
258             }
259         }
260         return null;
261     }
262
263     private ListenableFuture<RpcResult<Void>> verifyAddressEndpointParents(List<AddressEndpointReg> addressEndpointRegs,
264             AddressEndpointReg addressEndpointReg) {
265         ParentEndpointChoice parentEndpointChoice = addressEndpointReg.getParentEndpointChoice();
266         List<ParentEndpoint> parentEndpoints;
267         parentEndpoints =
268                 (parentEndpointChoice instanceof ParentEndpointCase) ? ((ParentEndpointCase) parentEndpointChoice)
269                     .getParentEndpoint() : null;
270
271         for (ParentEndpoint parentEndpoint : nullToEmpty(parentEndpoints)) {
272             AddressEndpointRegKey key = new AddressEndpointRegKey(parentEndpoint.getAddress(),
273                     parentEndpoint.getAddressType(), parentEndpoint.getContextId(), parentEndpoint.getContextType());
274             AddressEndpointReg addressEndpointRegParent = findAddressEndpointReg(key, addressEndpointRegs);
275
276             if (addressEndpointRegParent == null) {
277                 // todo this can be optimized if we move this to updateAddressEndpointRegParents and
278                 // verify child in one step with update.
279                 Optional<AddressEndpoint> addressEndpointOptional =
280                         DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
281                                 IidFactory.addressEndpointIid(new AddressEndpointKey(key.getAddress(),
282                                         key.getAddressType(), key.getContextId(), key.getContextType())),
283                                 dataProvider.newReadOnlyTransaction());
284                 if (!addressEndpointOptional.isPresent()) {
285                     LOG.debug("Parent AddressEndpoint {} does not exist in RPC and DS.", parentEndpoint);
286                     return buildFailFeature(
287                             String.format("Parent AddressEndpoint %s does not exist in RPC and DS.", parentEndpoint));
288                 }
289             } else {
290
291                 List<ChildEndpoint> childEndpoints = addressEndpointRegParent.getChildEndpoint();
292
293                 if (!nullToEmpty(childEndpoints).contains(new ChildEndpointBuilder(addressEndpointReg).build())) {
294                     LOG.debug("Parent AddressEndpoint {} does not contain a valid child AddressEndpoint.",
295                             addressEndpointRegParent);
296                     return buildFailFeature(String.format(
297                             "Parent AddressEndpoint does not contain a valid child AddressEndpoint."
298                                     + "\nParent AddressEndpoint: %s" + "\nChild AddressEndpoint: %s",
299                             addressEndpointRegParent, addressEndpointReg));
300                 }
301             }
302         }
303         return null;
304     }
305
306     private ListenableFuture<RpcResult<Void>> verifyAddressEndpointChilds(List<AddressEndpointReg> addressEndpointRegs,
307             AddressEndpointReg addressEndpointReg) {
308         for (ChildEndpoint childEndpoint : nullToEmpty(addressEndpointReg.getChildEndpoint())) {
309             AddressEndpointRegKey key = new AddressEndpointRegKey(childEndpoint.getAddress(),
310                     childEndpoint.getAddressType(), childEndpoint.getContextId(), childEndpoint.getContextType());
311             AddressEndpointReg addressEndpointRegChild = findAddressEndpointReg(key, addressEndpointRegs);
312             if (addressEndpointRegChild == null) {
313                 // todo this can be optimized if we move this to updateAddressEndpointRegChilds and
314                 // verify child in one step with update.
315                 Optional<AddressEndpoint> addressEndpointOptional =
316                         DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
317                                 IidFactory.addressEndpointIid(new AddressEndpointKey(key.getAddress(),
318                                         key.getAddressType(), key.getContextId(), key.getContextType())),
319                                 dataProvider.newReadOnlyTransaction());
320                 if (!addressEndpointOptional.isPresent()) {
321                     LOG.debug("Child AddressEndpoint {} does not exist in RPC and DS.", childEndpoint);
322                     return buildFailFeature(
323                             String.format("Child AddressEndpoint %s does not exist in RPC and DS.", childEndpoint));
324                 }
325             } else {
326
327                 ParentEndpointChoice parentEndpointChoice = addressEndpointRegChild.getParentEndpointChoice();
328
329                 if (!(parentEndpointChoice instanceof ParentEndpointCase)) {
330                     LOG.debug("Child AddressEndpoint {} does not contain list of parent elements.", childEndpoint);
331                     return buildFailFeature(String.format(
332                             "Child AddressEndpoint does not contain list of parent elements." + "\nChild element: %s",
333                             childEndpoint));
334                 }
335
336                 List<ParentEndpoint> parentEndpoints =
337                         nullToEmpty(((ParentEndpointCase) parentEndpointChoice).getParentEndpoint());
338                 if (!parentEndpoints.contains(new ParentEndpointBuilder(addressEndpointReg).build())) {
339                     LOG.debug("Child AddressEndpoint {} does not contain a valid parent AddressEndpoint.",
340                             addressEndpointRegChild);
341                     return buildFailFeature(String.format(
342                             "Child AddressEndpoint does not contain a valid parent AddressEndpoint."
343                                     + "\nChild element: %s" + "\nparent AddressEndpoint: %s",
344                             addressEndpointRegChild, addressEndpointReg));
345                 }
346             }
347         }
348         return null;
349     }
350
351     private AddressEndpointReg findAddressEndpointReg(AddressEndpointRegKey key, List<AddressEndpointReg> addressEndpointRegs) {
352         for (AddressEndpointReg addressEndpointReg : addressEndpointRegs) {
353             if (addressEndpointReg.getKey().equals(key)) {
354                 return addressEndpointReg;
355             }
356         }
357         return null;
358     }
359
360     private void updateAddressEndpointRegParents(WriteTransaction t, AddressEndpoint endpoint) {
361         ParentEndpointCase parentEndpointCase = (ParentEndpointCase) endpoint.getParentEndpointChoice();
362         List<ParentEndpoint> parentEndpoints;
363         ReadOnlyTransaction readTransaction = dataProvider.newReadOnlyTransaction();
364
365         parentEndpoints = getParentEndpoints(parentEndpointCase);
366
367         for (ParentEndpoint parent : nullToEmpty(parentEndpoints)) {
368             Optional<AddressEndpoint> addressEndpointOptional =
369                     DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
370                             IidFactory.addressEndpointIid(new AddressEndpointKey(parent.getAddress(),
371                                     parent.getAddressType(), parent.getContextId(), parent.getContextType())),
372                             readTransaction);
373
374             if (addressEndpointOptional.isPresent()) {
375
376                 List<ChildEndpoint> childEndpoints;
377
378                 childEndpoints = (addressEndpointOptional.get() == null || addressEndpointOptional.get()
379                     .getChildEndpoint() == null) ? new ArrayList<>() : addressEndpointOptional.get().getChildEndpoint();
380
381                 ChildEndpoint childEndpoint = new ChildEndpointBuilder(endpoint).build();
382                 if (!childEndpoints.contains(childEndpoint)) {
383                     childEndpoints.add(childEndpoint);
384                     AddressEndpoint parentAddressEndpoint = new AddressEndpointBuilder(addressEndpointOptional.get())
385                         .setChildEndpoint(childEndpoints).build();
386                     t.put(LogicalDatastoreType.OPERATIONAL,
387                             IidFactory.addressEndpointIid(parentAddressEndpoint.getKey()), parentAddressEndpoint);
388                 }
389             }
390         }
391     }
392
393     private void updateAddressEndpointRegChilds(WriteTransaction t, AddressEndpoint endpoint) {
394         ReadTransaction readTransaction = dataProvider.newReadOnlyTransaction();
395
396         for (ChildEndpoint child : nullToEmpty(endpoint.getChildEndpoint())) {
397             Optional<AddressEndpoint> addressEndpointOptional =
398                     DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
399                             IidFactory.addressEndpointIid(new AddressEndpointKey(child.getAddress(),
400                                     child.getAddressType(), child.getContextId(), child.getContextType())),
401                             readTransaction);
402
403             if (addressEndpointOptional.isPresent()) {
404                 ParentEndpointCase parentEndpointCase =
405                         (ParentEndpointCase) addressEndpointOptional.get().getParentEndpointChoice();
406                 List<ParentEndpoint> parentEndpoints;
407
408                 parentEndpoints = getParentEndpoints(parentEndpointCase);
409
410                 ParentEndpoint parentEndpoint = new ParentEndpointBuilder(endpoint).build();
411                 if (!parentEndpoints.contains(parentEndpoint)) {
412                     parentEndpoints.add(parentEndpoint);
413                     AddressEndpoint childAddressEndpoint =
414                             new AddressEndpointBuilder(addressEndpointOptional.get())
415                                 .setParentEndpointChoice(
416                                         new ParentEndpointCaseBuilder().setParentEndpoint(parentEndpoints).build())
417                                 .build();
418                     t.put(LogicalDatastoreType.OPERATIONAL,
419                             IidFactory.addressEndpointIid(childAddressEndpoint.getKey()), childAddressEndpoint);
420                 }
421             }
422         }
423     }
424
425     private ContainmentEndpointBuilder buildContainmentEndpoint(ContainmentEndpointReg input) {
426
427         ContainmentEndpointBuilder eb = new ContainmentEndpointBuilder().setChildEndpoint(input.getChildEndpoint())
428             .setCondition(input.getCondition())
429             .setContextType(input.getContextType())
430             .setContextId(input.getContextId())
431             .setEndpointGroup(input.getEndpointGroup())
432             .setKey(new ContainmentEndpointKey(input.getContextId(), input.getContextType()))
433             .setNetworkContainment(input.getNetworkContainment())
434             .setTenant(input.getTenant())
435             .setTimestamp(input.getTimestamp())
436             .setChildEndpoint(input.getChildEndpoint());
437
438         for (Map.Entry<String, BaseEndpointRendererAugmentation> entry : registeredRenderers.entrySet()) {
439             try {
440                 Map.Entry<Class<? extends Augmentation<ContainmentEndpoint>>, Augmentation<ContainmentEndpoint>> augmentationEntry =
441                         entry.getValue().buildContainmentEndpointAugmentation(input);
442                 if (augmentationEntry != null) {
443                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
444                 }
445             } catch (Exception e) {
446                 LOG.warn("AddressEndpoint Augmentation error while processing " + entry.getKey() + ". Reason: ", e);
447             }
448         }
449         return eb;
450     }
451
452     private AddressEndpointBuilder buildAddressEndpoint(AddressEndpointReg ae) {
453         AddressEndpointBuilder builder = new AddressEndpointBuilder().setTenant(ae.getTenant())
454             .setNetworkContainment(ae.getNetworkContainment())
455             .setEndpointGroup(ae.getEndpointGroup())
456             .setAddress(ae.getAddress())
457             .setAddressType(ae.getAddressType())
458             .setChildEndpoint(ae.getChildEndpoint())
459             .setCondition(ae.getCondition())
460             .setKey(new AddressEndpointKey(ae.getAddress(), ae.getAddressType(), ae.getContextId(),
461                     ae.getContextType()))
462             .setParentEndpointChoice(ae.getParentEndpointChoice())
463             .setTimestamp(ae.getTimestamp())
464             .setContextId(ae.getContextId())
465             .setContextType(ae.getContextType())
466             .setTenant(ae.getTenant());
467
468         for (Map.Entry<String, BaseEndpointRendererAugmentation> entry : registeredRenderers.entrySet()) {
469             try {
470                 Map.Entry<Class<? extends Augmentation<AddressEndpoint>>, Augmentation<AddressEndpoint>> augmentationEntry =
471                         entry.getValue().buildAddressEndpointAugmentation(ae);
472                 if (augmentationEntry != null) {
473                     builder.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
474                 }
475             } catch (Exception e) {
476                 LOG.warn("AddressEndpoint Augmentation error while processing " + entry.getKey() + ". Reason: ", e);
477             }
478         }
479         return builder;
480     }
481
482     /**
483      * Unregister an endpoint or endpoints from the registry.
484      *
485      * @param input Endpoint/endpoints to unregister
486      */
487     @Override
488     public Future<RpcResult<Void>> unregisterEndpoint(UnregisterEndpointInput input) {
489         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
490
491         List<AddressEndpointUnreg> addressEndpoints = input.getAddressEndpointUnreg();
492         for (AddressEndpointUnreg ae : nullToEmpty(addressEndpoints)) {
493             AddressEndpointKey key = new AddressEndpointKey(ae.getAddress(), ae.getAddressType(), ae.getContextId(),
494                     ae.getContextType());
495             t.delete(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(key));
496
497             updateAddressEndpointUnregChilds(t, ae);
498
499             updateAddressEndpointUnregParents(t, ae);
500         }
501
502         List<ContainmentEndpointUnreg> endpoints = input.getContainmentEndpointUnreg();
503         for (ContainmentEndpointUnreg ce : nullToEmpty(endpoints)) {
504             ContainmentEndpointKey key = new ContainmentEndpointKey(ce.getContextId(), ce.getContextType());
505             t.delete(LogicalDatastoreType.OPERATIONAL, IidFactory.containmentEndpointIid(key));
506
507             updateContainmentEndpointUnregChilds(t, ce);
508         }
509
510         ListenableFuture<Void> r = t.submit();
511         return Futures.transform(r, futureTrans);
512     }
513
514     private void updateAddressEndpointUnregParents(WriteTransaction t, AddressEndpointUnreg ae) {
515         ReadTransaction readTransaction = dataProvider.newReadOnlyTransaction();
516
517         Optional<AddressEndpoint> addressEndpointOptional = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
518                 IidFactory.addressEndpointIid(new AddressEndpointKey(ae.getAddress(), ae.getAddressType(),
519                         ae.getContextId(), ae.getContextType())),
520                 readTransaction);
521
522         if (addressEndpointOptional.isPresent()) {
523             ParentEndpointCase parentEndpointCase =
524                     (ParentEndpointCase) addressEndpointOptional.get().getParentEndpointChoice();
525             List<ParentEndpoint> parentEndpoints;
526
527             parentEndpoints = getParentEndpoints(parentEndpointCase);
528
529             for (ParentEndpoint parentEndpoint : parentEndpoints) {
530                 Optional<AddressEndpoint> parentAddressEndpointOptional =
531                         DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
532                                 IidFactory.addressEndpointIid(new AddressEndpointKey(parentEndpoint.getAddress(),
533                                         parentEndpoint.getAddressType(), parentEndpoint.getContextId(),
534                                         parentEndpoint.getContextType())),
535                                 readTransaction);
536
537                 AddressEndpoint parent =
538                         parentAddressEndpointOptional.isPresent() ? parentAddressEndpointOptional.get() : null;
539
540                 ChildEndpoint endpointToRemove = new ChildEndpointBuilder(addressEndpointOptional.get()).build();
541
542                 if (parent != null && nullToEmpty(parent.getChildEndpoint()).contains(endpointToRemove)) {
543                     parent.getChildEndpoint().remove(endpointToRemove);
544                     t.put(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(parent.getKey()), parent);
545                 }
546
547             }
548         }
549     }
550
551     private void updateAddressEndpointUnregChilds(WriteTransaction t, AddressEndpointUnreg ae) {
552         ReadTransaction readTransaction = dataProvider.newReadOnlyTransaction();
553
554         Optional<AddressEndpoint> addressEndpointOptional = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
555                 IidFactory.addressEndpointIid(new AddressEndpointKey(ae.getAddress(), ae.getAddressType(),
556                         ae.getContextId(), ae.getContextType())),
557                 readTransaction);
558
559         if (addressEndpointOptional.isPresent()) {
560             AddressEndpoint endpoint = addressEndpointOptional.get();
561             List<ChildEndpoint> childEndpoints = endpoint.getChildEndpoint();
562
563             for (ChildEndpoint childEndpoint : nullToEmpty(childEndpoints)) {
564                 Optional<AddressEndpoint> childAddressEndpointOptional =
565                         DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
566                                 IidFactory.addressEndpointIid(new AddressEndpointKey(childEndpoint.getAddress(),
567                                         childEndpoint.getAddressType(), childEndpoint.getContextId(),
568                                         childEndpoint.getContextType())),
569                                 readTransaction);
570
571                 AddressEndpoint child =
572                         childAddressEndpointOptional.isPresent() ? childAddressEndpointOptional.get() : null;
573                 ParentEndpointCase parentEndpointCase =
574                         (child != null) ? (ParentEndpointCase) child.getParentEndpointChoice() : null;
575                 List<ParentEndpoint> parentEndpoints;
576
577                 parentEndpoints = getParentEndpoints(parentEndpointCase);
578
579                 ParentEndpoint endpointToRemove = new ParentEndpointBuilder(endpoint).build();
580
581                 if (child != null && nullToEmpty(parentEndpoints).contains(endpointToRemove)) {
582                     parentEndpoints.remove(endpointToRemove);
583                     AddressEndpoint newChild =
584                             new AddressEndpointBuilder(child)
585                                 .setParentEndpointChoice(
586                                         new ParentEndpointCaseBuilder().setParentEndpoint(parentEndpoints).build())
587                                 .build();
588
589                     t.put(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(newChild.getKey()), newChild);
590                 }
591             }
592         }
593     }
594
595     private void updateContainmentEndpointUnregChilds(WriteTransaction t,
596             ContainmentEndpointUnreg containmentEndpointUnreg) {
597         ReadOnlyTransaction readTransaction = dataProvider.newReadOnlyTransaction();
598
599         ContainmentEndpointKey key = new ContainmentEndpointKey(containmentEndpointUnreg.getContextId(),
600                 containmentEndpointUnreg.getContextType());
601         Optional<ContainmentEndpoint> containmentEndpointOptional = DataStoreHelper
602             .readFromDs(LogicalDatastoreType.OPERATIONAL, IidFactory.containmentEndpointIid(key), readTransaction);
603
604         if (!containmentEndpointOptional.isPresent()) {
605             return;
606         }
607
608         for (ChildEndpoint child : nullToEmpty(containmentEndpointOptional.get().getChildEndpoint())) {
609             AddressEndpointKey aeKey = new AddressEndpointKey(child.getAddress(), child.getAddressType(),
610                     child.getContextId(), child.getContextType());
611             Optional<AddressEndpoint> addressEndpointOptional = DataStoreHelper
612                 .readFromDs(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(aeKey), readTransaction);
613
614             if (addressEndpointOptional.isPresent()) {
615                 ParentEndpointChoice parentEndpointChoice = addressEndpointOptional.get().getParentEndpointChoice();
616                 List<ParentContainmentEndpoint> parentContainmentEndpoints;
617                 parentContainmentEndpoints = getParentContainmentEndpoints(parentEndpointChoice);
618
619                 ParentContainmentEndpoint parentContainmentEndpoint =
620                         new ParentContainmentEndpointBuilder().setContextId(containmentEndpointUnreg.getContextId())
621                             .setContextType(containmentEndpointUnreg.getContextType())
622                             .build();
623                 if (nullToEmpty(parentContainmentEndpoints).contains(parentContainmentEndpoint)) {
624                     t.delete(LogicalDatastoreType.OPERATIONAL,
625                             IidFactory.parentContainmentEndpointIid(aeKey, parentContainmentEndpoint.getKey()));
626                 }
627             }
628         }
629     }
630
631     private List<ParentContainmentEndpoint> getParentContainmentEndpoints(ParentEndpointChoice parentEndpointChoice) {
632         return (parentEndpointChoice instanceof ParentContainmentEndpointCase) ? ((ParentContainmentEndpointCase) parentEndpointChoice)
633             .getParentContainmentEndpoint() : new ArrayList<>();
634     }
635
636     private List<ParentEndpoint> getParentEndpoints(ParentEndpointCase parentEndpointCase) {
637         return (parentEndpointCase == null
638                 || parentEndpointCase.getParentEndpoint() == null) ? new ArrayList<>() : parentEndpointCase
639                     .getParentEndpoint();
640     }
641
642     private ListenableFuture<RpcResult<Void>> buildFailFeature(String message) {
643         return Futures
644             .immediateFuture(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.PROTOCOL, message).build());
645     }
646
647     @Override
648     public void close() throws Exception {
649         if (rpcRegistration != null) {
650             rpcRegistration.close();
651         }
652     }
653
654     private <T> List<T> nullToEmpty(@Nullable List<T> list) {
655         return list == null ? Collections.emptyList() : list;
656     }
657
658 }