remove redundant parent data with last child
[groupbasedpolicy.git] / groupbasedpolicy / src / main / java / org / opendaylight / groupbasedpolicy / location / resolver / LocationResolver.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.location.resolver;
10
11 import java.util.Collection;
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16
17 import javax.annotation.Nullable;
18
19 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
22 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
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.endpoint.locations.AddressEndpointLocation;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoint.locations.AddressEndpointLocationBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoint.locations.AddressEndpointLocationKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoint.locations.ContainmentEndpointLocation;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoint.locations.ContainmentEndpointLocationBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoint.locations.ContainmentEndpointLocationKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.relative.locations.ExternalLocation;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.relative.locations.InternalLocation;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.LocationProviders;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProvider;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocation;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocationKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderContainmentEndpointLocation;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderContainmentEndpointLocationKey;
42 import org.opendaylight.yangtools.concepts.ListenerRegistration;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 public class LocationResolver implements ClusteredDataTreeChangeListener<LocationProvider>, AutoCloseable {
48
49     private static final Logger LOG = LoggerFactory.getLogger(LocationResolver.class);
50     private Map<AddressEndpointLocationKey, Map<Long, AbsoluteLocation>> realLocations;
51     private DataBroker dataBroker;
52     private ListenerRegistration<LocationResolver> listenerRegistation;
53
54     public LocationResolver(DataBroker dataBroker) {
55         this.dataBroker = dataBroker;
56         this.realLocations = new HashMap<>();
57         this.listenerRegistation = dataBroker.registerDataTreeChangeListener(
58                 new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
59                         InstanceIdentifier.builder(LocationProviders.class).child(LocationProvider.class).build()),
60                 this);
61     }
62
63     @Override
64     public synchronized void onDataTreeChanged(Collection<DataTreeModification<LocationProvider>> changes) {
65         for (DataTreeModification<LocationProvider> change : changes) {
66             WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
67             switch (change.getRootNode().getModificationType()) {
68                 case DELETE: {
69                     processRemovedLocationProviderData(change.getRootNode().getDataBefore(), wtx);
70                     LOG.debug("Data from location provider {} has been removed",
71                             change.getRootNode().getDataBefore().getProvider().getValue());
72                     break;
73                 }
74                 case WRITE: {
75                     if (change.getRootNode().getDataBefore() != null) {
76                         processRemovedLocationProviderData(change.getRootNode().getDataBefore(), wtx);
77                     }
78                     processCreatedLocationProviderData(change.getRootNode().getDataAfter(), wtx);
79                     LOG.debug("Data from location provider {} has been created",
80                             change.getRootNode().getDataAfter().getProvider().getValue());
81                     break;
82                 }
83                 case SUBTREE_MODIFIED: {
84                     processRemovedLocationProviderData(change.getRootNode().getDataBefore(), wtx);
85                     processCreatedLocationProviderData(change.getRootNode().getDataAfter(), wtx);
86                     LOG.debug("Data from location provider {} has been changed",
87                             change.getRootNode().getDataAfter().getProvider().getValue());
88                     break;
89                 }
90             }
91             LOG.debug("Writing endpoint location changes to DS");
92             DataStoreHelper.submitToDs(wtx);
93         }
94     }
95
96     private void processRemovedLocationProviderData(LocationProvider provider, WriteTransaction wtx) {
97         for (ProviderAddressEndpointLocation addressEndpointLocation : nullToEmpty(
98                 provider.getProviderAddressEndpointLocation())) {
99             AddressEndpointLocationKey epKey = createAddressEndpointLocationKey(addressEndpointLocation.getKey());
100             long priority;
101             if (provider.getPriority() == null) {
102                 priority = 0;
103                 LOG.debug("{} provider doesn't provide priority. Using 0 as priority instead.",
104                         provider.getProvider().getValue());
105             } else {
106                 priority = provider.getPriority();
107             }
108             realLocations.get(epKey).remove(priority);
109             AbsoluteLocation newAbsoluteLocation = getBestAbsoluteLocation(epKey);
110             if (newAbsoluteLocation == null) {
111                 InstanceIdentifier<AbsoluteLocation> iid = IidFactory.absoluteLocationIid(epKey);
112                 wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
113             } else {
114                 AddressEndpointLocationBuilder newEP =
115                         new AddressEndpointLocationBuilder().setKey(epKey).setAbsoluteLocation(newAbsoluteLocation);
116                 InstanceIdentifier<AddressEndpointLocation> iid = IidFactory.addressEndpointLocationIid(newEP.getKey());
117                 wtx.merge(LogicalDatastoreType.OPERATIONAL, iid, newEP.build(), true);
118             }
119             if (addressEndpointLocation.getRelativeLocations() != null) {
120                 for (InternalLocation location : nullToEmpty(
121                         addressEndpointLocation.getRelativeLocations().getInternalLocation())) {
122                     InstanceIdentifier<InternalLocation> iid = IidFactory.internalLocationIid(epKey, location.getKey());
123                     wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
124                 }
125                 for (ExternalLocation location : nullToEmpty(
126                         addressEndpointLocation.getRelativeLocations().getExternalLocation())) {
127                     InstanceIdentifier<ExternalLocation> iid = IidFactory.externalLocationIid(epKey, location.getKey());
128                     wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
129                 }
130             }
131             if (newAbsoluteLocation == null && addressEndpointLocation.getRelativeLocations() == null) {
132                 InstanceIdentifier<AddressEndpointLocation> iid = IidFactory.addressEndpointLocationIid(epKey);
133                 wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
134             }
135         }
136         for (ProviderContainmentEndpointLocation containmentEndpoint : nullToEmpty(
137                 provider.getProviderContainmentEndpointLocation())) {
138             ContainmentEndpointLocationKey epKey = createContainmentEndpointLocationKey(containmentEndpoint.getKey());
139             if (containmentEndpoint.getRelativeLocations() != null) {
140                 for (InternalLocation location : nullToEmpty(
141                         containmentEndpoint.getRelativeLocations().getInternalLocation())) {
142                     InstanceIdentifier<InternalLocation> iid = IidFactory.internalLocationIid(epKey, location.getKey());
143                     wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
144                 }
145                 for (ExternalLocation location : nullToEmpty(
146                         containmentEndpoint.getRelativeLocations().getExternalLocation())) {
147                     InstanceIdentifier<ExternalLocation> iid = IidFactory.externalLocationIid(epKey, location.getKey());
148                     wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
149                 }
150             }
151         }
152     }
153
154     private void processCreatedLocationProviderData(LocationProvider provider, WriteTransaction wtx) {
155         for (ProviderAddressEndpointLocation addressEndpointLocation : nullToEmpty(
156                 provider.getProviderAddressEndpointLocation())) {
157             AddressEndpointLocationKey epKey = createAddressEndpointLocationKey(addressEndpointLocation.getKey());
158             AddressEndpointLocationBuilder newEP = new AddressEndpointLocationBuilder().setKey(epKey);
159             if (addressEndpointLocation.getAbsoluteLocation() != null) {
160                 if (realLocations.get(epKey) == null) {
161                     realLocations.put(epKey, new HashMap<>());
162                 }
163                 long priority;
164                 if (provider.getPriority() == null) {
165                     priority = 0;
166                     LOG.debug("{} provider doesnt provide priority. Using 0 as priority instead.",
167                             provider.getProvider().getValue());
168                 } else {
169                     priority = provider.getPriority();
170                 }
171                 realLocations.get(epKey).put(priority, addressEndpointLocation.getAbsoluteLocation());
172             }
173             AbsoluteLocation bestLocation = getBestAbsoluteLocation(epKey);
174             if (bestLocation != null) {
175                 newEP.setAbsoluteLocation(bestLocation);
176             }
177             if (addressEndpointLocation.getRelativeLocations() != null) {
178                 newEP.setRelativeLocations(addressEndpointLocation.getRelativeLocations());
179             }
180             InstanceIdentifier<AddressEndpointLocation> iid = IidFactory.addressEndpointLocationIid(newEP.getKey());
181             wtx.merge(LogicalDatastoreType.OPERATIONAL, iid, newEP.build(), true);
182         }
183         for (ProviderContainmentEndpointLocation containmentEndpointLocation : nullToEmpty(
184                 provider.getProviderContainmentEndpointLocation())) {
185             if (containmentEndpointLocation.getRelativeLocations() != null) {
186                 ContainmentEndpointLocationKey key =
187                         createContainmentEndpointLocationKey(containmentEndpointLocation.getKey());
188                 ContainmentEndpointLocationBuilder newEP = new ContainmentEndpointLocationBuilder().setKey(key);
189                 newEP.setRelativeLocations(containmentEndpointLocation.getRelativeLocations());
190                 InstanceIdentifier<ContainmentEndpointLocation> iid =
191                         IidFactory.containmentEndpointLocationIid(newEP.getKey());
192                 wtx.merge(LogicalDatastoreType.OPERATIONAL, iid, newEP.build(), true);
193             }
194         }
195     }
196
197     private AbsoluteLocation getBestAbsoluteLocation(AddressEndpointLocationKey epKey) {
198         if (realLocations.get(epKey) == null) {
199             return null;
200         }
201         long bestPriority = -1;
202         for (long priority : realLocations.get(epKey).keySet()) {
203             bestPriority = bestPriority > priority ? bestPriority : priority;
204         };
205         if (bestPriority == -1) {
206             return null;
207         }
208         return (realLocations.get(epKey).get(new Long(bestPriority)));
209     }
210
211     private AddressEndpointLocationKey createAddressEndpointLocationKey(ProviderAddressEndpointLocationKey key) {
212         return new AddressEndpointLocationKey(key.getAddress(), key.getAddressType(), key.getContextId(),
213                 key.getContextType());
214     }
215
216     private ContainmentEndpointLocationKey createContainmentEndpointLocationKey(
217             ProviderContainmentEndpointLocationKey key) {
218         return new ContainmentEndpointLocationKey(key.getContextId(), key.getContextType());
219     }
220
221     private <T> List<T> nullToEmpty(@Nullable List<T> list) {
222         return list == null ? Collections.emptyList() : list;
223     }
224
225     @Override
226     public void close() {
227         listenerRegistation.close();
228     }
229 }