Use OFtunnels when configuring automatic tunnels
[netvirt.git] / vpnservice / neutronvpn / neutronvpn-impl / src / main / java / org / opendaylight / netvirt / neutronvpn / ChangeUtils.java
1 /*
2  * Copyright (c) 2014 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 package org.opendaylight.netvirt.neutronvpn;
9
10 import com.google.common.base.Predicates;
11 import com.google.common.collect.Maps;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.LinkedList;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.Queue;
21 import java.util.Set;
22 import java.util.function.Predicate;
23 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
24 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
25 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
26 import org.opendaylight.yangtools.yang.binding.ChildOf;
27 import org.opendaylight.yangtools.yang.binding.DataObject;
28 import org.opendaylight.yangtools.yang.binding.Identifiable;
29 import org.opendaylight.yangtools.yang.binding.Identifier;
30 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
31 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
32
33 public class ChangeUtils {
34
35     private ChangeUtils() { }
36
37     private static <T extends DataObject> Predicate<DataObjectModification<T>> hasDataBefore() {
38         return input -> input != null && input.getDataBefore() != null;
39     }
40
41     private static <T extends DataObject> Predicate<DataObjectModification<T>> hasDataBeforeAndDataAfter() {
42         return input -> input != null && input.getDataBefore() != null && input.getDataAfter() != null;
43     }
44
45     private static <T extends DataObject> Predicate<DataObjectModification<T>> hasNoDataBefore() {
46         return input -> input != null && input.getDataBefore() == null;
47     }
48
49     private static <T extends DataObject> Predicate<DataObjectModification<T>> hasDataAfterAndMatchesFilter(
50             final Predicate<DataObjectModification<T>> filter) {
51         return input -> input != null && input.getDataAfter() != null && filter.test(input);
52     }
53
54     private static <T extends DataObject> Predicate<DataObjectModification<T>> matchesEverything() {
55         return input -> true;
56     }
57
58     private static <T extends DataObject> Predicate<DataObjectModification<T>> modificationIsDeletion() {
59         return input -> input != null && input.getModificationType() == DataObjectModification
60                 .ModificationType.DELETE;
61     }
62
63     private static <T extends DataObject> Predicate<DataObjectModification<T>>
64         modificationIsDeletionAndHasDataBefore() {
65         return input -> input != null && input.getModificationType() == DataObjectModification
66                 .ModificationType.DELETE && input.getDataBefore() != null;
67     }
68
69     public static <T extends DataObject> Map<InstanceIdentifier<T>,T> extractCreated(
70             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,Class<T> klazz) {
71         return extract(changes.getCreatedData(),klazz);
72     }
73
74     /**
75      * Extract all the instances of {@code clazz} which were created in the given set of modifications.
76      *
77      * @param changes The changes to process.
78      * @param clazz The class we're interested in.
79      * @param <T> The type of changes we're interested in.
80      * @param <U> The type of changes to process.
81      * @return The created instances, mapped by instance identifier.
82      */
83     public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T> extractCreated(
84             Collection<DataTreeModification<U>> changes, Class<T> clazz) {
85         return extractCreatedOrUpdated(changes, clazz, hasNoDataBefore());
86     }
87
88     public static <T extends DataObject> Map<InstanceIdentifier<T>,T> extractUpdated(
89             AsyncDataChangeEvent<InstanceIdentifier<?>,DataObject> changes,Class<T> klazz) {
90         return extract(changes.getUpdatedData(),klazz);
91     }
92
93     /**
94      * Extract all the instances of {@code clazz} which were updated in the given set of modifications.
95      *
96      * @param changes The changes to process.
97      * @param clazz The class we're interested in.
98      * @param <T> The type of changes we're interested in.
99      * @param <U> The type of changes to process.
100      * @return The updated instances, mapped by instance identifier.
101      */
102     public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T> extractUpdated(
103             Collection<DataTreeModification<U>> changes, Class<T> clazz) {
104         return extractCreatedOrUpdated(changes, clazz, hasDataBeforeAndDataAfter());
105     }
106
107     /**
108      * Extract all the instance of {@code clazz} which were created or updated in the given set of modifications, and
109      * which satisfy the given filter.
110      *
111      * @param changes The changes to process.
112      * @param clazz The class we're interested in.
113      * @param filter The filter the changes must satisfy.
114      * @param <T> The type of changes we're interested in.
115      * @param <U> The type of changes to process.
116      * @return The created or updated instances which satisfy the filter, mapped by instance identifier.
117      */
118     public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T> extractCreatedOrUpdated(
119             Collection<DataTreeModification<U>> changes, Class<T> clazz,
120             Predicate<DataObjectModification<T>> filter) {
121         Map<InstanceIdentifier<T>, T> result = new HashMap<>();
122         for (Entry<InstanceIdentifier<T>, DataObjectModification<T>> entry : extractDataObjectModifications(changes,
123                 clazz, hasDataAfterAndMatchesFilter(filter)).entrySet()) {
124             result.put(entry.getKey(), entry.getValue().getDataAfter());
125         }
126         return result;
127     }
128
129     public static <T extends DataObject> Map<InstanceIdentifier<T>,T> extractCreatedOrUpdated(
130             AsyncDataChangeEvent<InstanceIdentifier<?>,DataObject> changes,Class<T> klazz) {
131         Map<InstanceIdentifier<T>,T> result = extractUpdated(changes,klazz);
132         result.putAll(extractCreated(changes,klazz));
133         return result;
134     }
135
136     /**
137      * Extract all the instances of {@code clazz} which were created or updated in the given set of modifications.
138      *
139      * @param changes The changes to process.
140      * @param clazz The class we're interested in.
141      * @param <T> The type of changes we're interested in.
142      * @param <U> The type of changes to process.
143      * @return The created or updated instances, mapped by instance identifier.
144      */
145     public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T> extractCreatedOrUpdated(
146             Collection<DataTreeModification<U>> changes, Class<T> clazz) {
147         return extractCreatedOrUpdated(changes, clazz, matchesEverything());
148     }
149
150     public static <T extends DataObject> Map<InstanceIdentifier<T>, T> extractCreatedOrUpdatedOrRemoved(
151             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
152             Class<T> klazz) {
153         Map<InstanceIdentifier<T>,T> result = extractCreatedOrUpdated(changes,klazz);
154         result.putAll(extractRemovedObjects(changes, klazz));
155         return result;
156     }
157
158     /**
159      * Extract all the instances of {@code clazz} which were created, updated, or removed in the given set of
160      * modifications. For instances which were created or updated, the new instances are returned; for instances
161      * which were removed, the old instances are returned.
162      *
163      * @param changes The changes to process.
164      * @param clazz The class we're interested in.
165      * @param <T> The type of changes we're interested in.
166      * @param <U> The type of changes to process.
167      * @return The created, updated or removed instances, mapped by instance identifier.
168      */
169     public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T>
170         extractCreatedOrUpdatedOrRemoved(
171             Collection<DataTreeModification<U>> changes, Class<T> clazz) {
172         Map<InstanceIdentifier<T>, T> result = extractCreatedOrUpdated(changes, clazz);
173         result.putAll(extractRemovedObjects(changes, clazz));
174         return result;
175     }
176
177     public static <T extends DataObject> Map<InstanceIdentifier<T>,T> extractOriginal(
178             AsyncDataChangeEvent<InstanceIdentifier<?>,DataObject> changes,Class<T> klazz) {
179         return extract(changes.getOriginalData(),klazz);
180     }
181
182     /**
183      * Extract the original instances of class {@code clazz} in the given set of modifications.
184      *
185      * @param changes The changes to process.
186      * @param clazz The class we're interested in.
187      * @param <T> The type of changes we're interested in.
188      * @param <U> The type of changes to process.
189      * @return The original instances, mapped by instance identifier.
190      */
191     public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T> extractOriginal(
192             Collection<DataTreeModification<U>> changes, Class<T> clazz) {
193         Map<InstanceIdentifier<T>, T> result = new HashMap<>();
194         for (Entry<InstanceIdentifier<T>, DataObjectModification<T>> entry :
195                 extractDataObjectModifications(changes, clazz, hasDataBefore()).entrySet()) {
196             result.put(entry.getKey(), entry.getValue().getDataBefore());
197         }
198         return result;
199     }
200
201     public static <T extends DataObject> Set<InstanceIdentifier<T>> extractRemoved(
202             AsyncDataChangeEvent<InstanceIdentifier<?>,DataObject> changes,Class<T> klazz) {
203         Set<InstanceIdentifier<T>> result = new HashSet<>();
204         if (changes != null && changes.getRemovedPaths() != null) {
205             for (InstanceIdentifier<?> iid : changes.getRemovedPaths()) {
206                 if (iid.getTargetType().equals(klazz)) {
207                     // Actually checked above
208                     @SuppressWarnings("unchecked")
209                     InstanceIdentifier<T> iidn = (InstanceIdentifier<T>)iid;
210                     result.add(iidn);
211                 }
212             }
213         }
214         return result;
215     }
216
217     /**
218      * Extract the instance identifier of removed instances of {@code clazz} from the given set of modifications.
219      *
220      * @param changes The changes to process.
221      * @param clazz The class we're interested in.
222      * @param <T> The type of changes we're interested in.
223      * @param <U> The type of changes to process.
224      * @return The instance identifiers of removed instances.
225      */
226     public static <T extends DataObject, U extends DataObject> Set<InstanceIdentifier<T>> extractRemoved(
227             Collection<DataTreeModification<U>> changes, Class<T> clazz) {
228         return extractDataObjectModifications(changes, clazz, modificationIsDeletion()).keySet();
229     }
230
231     /**
232      * Extract all the modifications affecting instances of {@code clazz} which are present in the given set of
233      * modifications and satisfy the given filter.
234      *
235      * @param changes The changes to process.
236      * @param clazz The class we're interested in.
237      * @param filter The filter the changes must satisfy.
238      * @param <T> The type of changes we're interested in.
239      * @param <U> The type of changes to process.
240      * @return The modifications, mapped by instance identifier.
241      */
242     private static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, DataObjectModification<T>>
243         extractDataObjectModifications(Collection<DataTreeModification<U>> changes, Class<T> clazz,
244                                        Predicate<DataObjectModification<T>> filter) {
245         List<DataObjectModification<? extends DataObject>> dataObjectModifications = new ArrayList<>();
246         List<InstanceIdentifier<? extends DataObject>> paths = new ArrayList<>();
247         if (changes != null) {
248             for (DataTreeModification<? extends DataObject> change : changes) {
249                 dataObjectModifications.add(change.getRootNode());
250                 paths.add(change.getRootPath().getRootIdentifier());
251             }
252         }
253         return extractDataObjectModifications(dataObjectModifications, paths, clazz, filter);
254     }
255
256     /**
257      * Extract all the modifications affecting instances of {@code clazz} which are present in the given set of
258      * modifications and satisfy the given filter.
259      *
260      * @param changes The changes to process.
261      * @param paths The paths of the changes.
262      * @param clazz The class we're interested in.
263      * @param filter The filter the changes must satisfy.
264      * @param <T> The type of changes we're interested in.
265      * @return The modifications, mapped by instance identifier.
266      */
267     private static <T extends DataObject> Map<InstanceIdentifier<T>, DataObjectModification<T>>
268         extractDataObjectModifications(
269             Collection<DataObjectModification<? extends DataObject>> changes,
270             Collection<InstanceIdentifier<? extends DataObject>> paths, Class<T> clazz,
271             Predicate<DataObjectModification<T>> filter) {
272         Map<InstanceIdentifier<T>, DataObjectModification<T>> result = new HashMap<>();
273         Queue<DataObjectModification<? extends DataObject>> remainingChanges = new LinkedList<>(changes);
274         Queue<InstanceIdentifier<? extends DataObject>> remainingPaths = new LinkedList<>(paths);
275         while (!remainingChanges.isEmpty()) {
276             DataObjectModification<? extends DataObject> change = remainingChanges.remove();
277             InstanceIdentifier<? extends DataObject> path = remainingPaths.remove();
278             // Is the change relevant?
279             if (clazz.isAssignableFrom(change.getDataType()) && filter.test((DataObjectModification<T>) change)) {
280                 result.put((InstanceIdentifier<T>) path, (DataObjectModification<T>) change);
281             }
282             // Add any children to the queue
283             for (DataObjectModification<? extends DataObject> child : change.getModifiedChildren()) {
284                 remainingChanges.add(child);
285                 remainingPaths.add(extendPath(path, child));
286             }
287         }
288         return result;
289     }
290
291     /**
292      * Extends the given instance identifier path to include the given child. Augmentations are treated in the same way
293      * as children; keyed children are handled correctly.
294      *
295      * @param path The current path.
296      * @param child The child modification to include.
297      * @return The extended path.
298      */
299     private static <N extends Identifiable<K> & ChildOf<? super T>, K extends Identifier<N>, T extends DataObject>
300         InstanceIdentifier<? extends DataObject> extendPath(
301             InstanceIdentifier path,
302             DataObjectModification child) {
303         Class<N> item = (Class<N>) child.getDataType();
304         if (child.getIdentifier() instanceof InstanceIdentifier.IdentifiableItem) {
305             K key = (K) ((InstanceIdentifier.IdentifiableItem) child.getIdentifier()).getKey();
306             KeyedInstanceIdentifier<N, K> extendedPath = path.child(item, key);
307             return extendedPath;
308         } else {
309             InstanceIdentifier<N> extendedPath = path.child(item);
310             return extendedPath;
311         }
312     }
313
314     public static <T extends DataObject> Map<InstanceIdentifier<T>, T> extractRemovedObjects(
315             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
316             Class<T> klazz) {
317         Set<InstanceIdentifier<T>> iids = extractRemoved(changes, klazz);
318         return Maps.filterKeys(extractOriginal(changes, klazz),Predicates.in(iids));
319     }
320
321     /**
322      * Extract the removed instances of {@code clazz} from the given set of modifications.
323      *
324      * @param changes The changes to process.
325      * @param clazz The class we're interested in.
326      * @param <T> The type of changes we're interested in.
327      * @param <U> The type of changes to process.
328      * @return The removed instances, keyed by instance identifier.
329      */
330     public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T> extractRemovedObjects(
331             Collection<DataTreeModification<U>> changes, Class<T> clazz) {
332         Map<InstanceIdentifier<T>, T> result = new HashMap<>();
333         for (Entry<InstanceIdentifier<T>, DataObjectModification<T>> entry :
334                 extractDataObjectModifications(changes, clazz, modificationIsDeletionAndHasDataBefore()).entrySet()) {
335             result.put(entry.getKey(), entry.getValue().getDataBefore());
336         }
337         return result;
338     }
339
340     public static <T extends DataObject> Map<InstanceIdentifier<T>,T> extract(
341             Map<InstanceIdentifier<?>, DataObject> changes, Class<T> klazz) {
342         Map<InstanceIdentifier<T>,T> result = new HashMap<>();
343         if (changes != null) {
344             for (Entry<InstanceIdentifier<?>, DataObject> created : changes.entrySet()) {
345                 if (klazz.isInstance(created.getValue())) {
346                     @SuppressWarnings("unchecked")
347                     T value = (T) created.getValue();
348                     Class<?> type = created.getKey().getTargetType();
349                     if (type.equals(klazz)) {
350                         // Actually checked above
351                         @SuppressWarnings("unchecked")
352                         InstanceIdentifier<T> iid = (InstanceIdentifier<T>) created.getKey();
353                         result.put(iid, value);
354                     }
355                 }
356             }
357         }
358         return result;
359     }
360 }