Bug 8228 - metadata service fix made cleaner
[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             if (realLocations.get(epKey) != null) {
109                 realLocations.get(epKey).remove(priority);
110             }
111             AbsoluteLocation newAbsoluteLocation = getBestAbsoluteLocation(epKey);
112             if (newAbsoluteLocation == null) {
113                 InstanceIdentifier<AbsoluteLocation> iid = IidFactory.absoluteLocationIid(epKey);
114                 wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
115             } else {
116                 AddressEndpointLocationBuilder newEP =
117                         new AddressEndpointLocationBuilder().setKey(epKey).setAbsoluteLocation(newAbsoluteLocation);
118                 InstanceIdentifier<AddressEndpointLocation> iid = IidFactory.addressEndpointLocationIid(newEP.getKey());
119                 wtx.merge(LogicalDatastoreType.OPERATIONAL, iid, newEP.build(), true);
120             }
121             if (addressEndpointLocation.getRelativeLocations() != null) {
122                 for (InternalLocation location : nullToEmpty(
123                         addressEndpointLocation.getRelativeLocations().getInternalLocation())) {
124                     InstanceIdentifier<InternalLocation> iid = IidFactory.internalLocationIid(epKey, location.getKey());
125                     wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
126                 }
127                 for (ExternalLocation location : nullToEmpty(
128                         addressEndpointLocation.getRelativeLocations().getExternalLocation())) {
129                     InstanceIdentifier<ExternalLocation> iid = IidFactory.externalLocationIid(epKey, location.getKey());
130                     wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
131                 }
132             }
133             if (newAbsoluteLocation == null && addressEndpointLocation.getRelativeLocations() == null) {
134                 InstanceIdentifier<AddressEndpointLocation> iid = IidFactory.addressEndpointLocationIid(epKey);
135                 wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
136             }
137         }
138         for (ProviderContainmentEndpointLocation containmentEndpoint : nullToEmpty(
139                 provider.getProviderContainmentEndpointLocation())) {
140             ContainmentEndpointLocationKey epKey = createContainmentEndpointLocationKey(containmentEndpoint.getKey());
141             if (containmentEndpoint.getRelativeLocations() != null) {
142                 for (InternalLocation location : nullToEmpty(
143                         containmentEndpoint.getRelativeLocations().getInternalLocation())) {
144                     InstanceIdentifier<InternalLocation> iid = IidFactory.internalLocationIid(epKey, location.getKey());
145                     wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
146                 }
147                 for (ExternalLocation location : nullToEmpty(
148                         containmentEndpoint.getRelativeLocations().getExternalLocation())) {
149                     InstanceIdentifier<ExternalLocation> iid = IidFactory.externalLocationIid(epKey, location.getKey());
150                     wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
151                 }
152             }
153         }
154     }
155
156     private void processCreatedLocationProviderData(LocationProvider provider, WriteTransaction wtx) {
157         for (ProviderAddressEndpointLocation addressEndpointLocation : nullToEmpty(
158                 provider.getProviderAddressEndpointLocation())) {
159             AddressEndpointLocationKey epKey = createAddressEndpointLocationKey(addressEndpointLocation.getKey());
160             AddressEndpointLocationBuilder newEP = new AddressEndpointLocationBuilder().setKey(epKey);
161             if (addressEndpointLocation.getAbsoluteLocation() != null) {
162                 if (realLocations.get(epKey) == null) {
163                     realLocations.put(epKey, new HashMap<>());
164                 }
165                 long priority;
166                 if (provider.getPriority() == null) {
167                     priority = 0;
168                     LOG.debug("{} provider doesnt provide priority. Using 0 as priority instead.",
169                             provider.getProvider().getValue());
170                 } else {
171                     priority = provider.getPriority();
172                 }
173                 realLocations.get(epKey).put(priority, addressEndpointLocation.getAbsoluteLocation());
174             }
175             AbsoluteLocation bestLocation = getBestAbsoluteLocation(epKey);
176             if (bestLocation != null) {
177                 newEP.setAbsoluteLocation(bestLocation);
178             }
179             if (addressEndpointLocation.getRelativeLocations() != null) {
180                 newEP.setRelativeLocations(addressEndpointLocation.getRelativeLocations());
181             }
182             InstanceIdentifier<AddressEndpointLocation> iid = IidFactory.addressEndpointLocationIid(newEP.getKey());
183             wtx.merge(LogicalDatastoreType.OPERATIONAL, iid, newEP.build(), true);
184         }
185         for (ProviderContainmentEndpointLocation containmentEndpointLocation : nullToEmpty(
186                 provider.getProviderContainmentEndpointLocation())) {
187             if (containmentEndpointLocation.getRelativeLocations() != null) {
188                 ContainmentEndpointLocationKey key =
189                         createContainmentEndpointLocationKey(containmentEndpointLocation.getKey());
190                 ContainmentEndpointLocationBuilder newEP = new ContainmentEndpointLocationBuilder().setKey(key);
191                 newEP.setRelativeLocations(containmentEndpointLocation.getRelativeLocations());
192                 InstanceIdentifier<ContainmentEndpointLocation> iid =
193                         IidFactory.containmentEndpointLocationIid(newEP.getKey());
194                 wtx.merge(LogicalDatastoreType.OPERATIONAL, iid, newEP.build(), true);
195             }
196         }
197     }
198
199     private AbsoluteLocation getBestAbsoluteLocation(AddressEndpointLocationKey epKey) {
200         if (realLocations.get(epKey) == null) {
201             return null;
202         }
203         long bestPriority = -1;
204         for (long priority : realLocations.get(epKey).keySet()) {
205             bestPriority = bestPriority > priority ? bestPriority : priority;
206         };
207         if (bestPriority == -1) {
208             return null;
209         }
210         return (realLocations.get(epKey).get(new Long(bestPriority)));
211     }
212
213     private AddressEndpointLocationKey createAddressEndpointLocationKey(ProviderAddressEndpointLocationKey key) {
214         return new AddressEndpointLocationKey(key.getAddress(), key.getAddressType(), key.getContextId(),
215                 key.getContextType());
216     }
217
218     private ContainmentEndpointLocationKey createContainmentEndpointLocationKey(
219             ProviderContainmentEndpointLocationKey key) {
220         return new ContainmentEndpointLocationKey(key.getContextId(), key.getContextType());
221     }
222
223     private <T> List<T> nullToEmpty(@Nullable List<T> list) {
224         return list == null ? Collections.emptyList() : list;
225     }
226
227     @Override
228     public void close() {
229         listenerRegistation.close();
230     }
231 }