org.opendaylight.netvirt.neutronvpn.ChangeUtils Maven / Gradle / Ivy
/*
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.netvirt.neutronvpn;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import javax.annotation.Nullable;
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
import org.opendaylight.yangtools.yang.binding.ChildOf;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.Identifiable;
import org.opendaylight.yangtools.yang.binding.Identifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
public class ChangeUtils {
private ChangeUtils() { }
private static Predicate> hasDataBefore() {
return new Predicate>() {
@Override
public boolean apply(@Nullable DataObjectModification input) {
return input != null && input.getDataBefore() != null;
}
};
}
private static Predicate> hasDataBeforeAndDataAfter() {
return new Predicate>() {
@Override
public boolean apply(@Nullable DataObjectModification input) {
return input != null && input.getDataBefore() != null && input.getDataAfter() != null;
}
};
}
private static Predicate> hasNoDataBefore() {
return new Predicate>() {
@Override
public boolean apply(@Nullable DataObjectModification input) {
return input != null && input.getDataBefore() == null;
}
};
}
private static Predicate> hasDataAfterAndMatchesFilter(
final Predicate> filter) {
return new Predicate>() {
@Override
public boolean apply(@Nullable DataObjectModification input) {
return input != null && input.getDataAfter() != null && filter.apply(input);
}
};
}
private static Predicate> matchesEverything() {
return new Predicate>() {
@Override
public boolean apply(@Nullable DataObjectModification input) {
return true;
}
};
}
private static Predicate> modificationIsDeletion() {
return new Predicate>() {
@Override
public boolean apply(@Nullable DataObjectModification input) {
return input != null && input.getModificationType() == DataObjectModification
.ModificationType.DELETE;
}
};
}
private static Predicate>
modificationIsDeletionAndHasDataBefore() {
return new Predicate>() {
@Override
public boolean apply(@Nullable DataObjectModification input) {
return input != null && input.getModificationType() == DataObjectModification
.ModificationType.DELETE && input.getDataBefore() != null;
}
};
}
public static Map,T> extractCreated(
AsyncDataChangeEvent, DataObject> changes,Class klazz) {
return extract(changes.getCreatedData(),klazz);
}
/**
* Extract all the instances of {@code clazz} which were created in the given set of modifications.
*
* @param changes The changes to process.
* @param clazz The class we're interested in.
* @param The type of changes we're interested in.
* @param The type of changes to process.
* @return The created instances, mapped by instance identifier.
*/
public static Map, T> extractCreated(
Collection> changes, Class clazz) {
return extractCreatedOrUpdated(changes, clazz, hasNoDataBefore());
}
public static Map,T> extractUpdated(
AsyncDataChangeEvent,DataObject> changes,Class klazz) {
return extract(changes.getUpdatedData(),klazz);
}
/**
* Extract all the instances of {@code clazz} which were updated in the given set of modifications.
*
* @param changes The changes to process.
* @param clazz The class we're interested in.
* @param The type of changes we're interested in.
* @param The type of changes to process.
* @return The updated instances, mapped by instance identifier.
*/
public static Map, T> extractUpdated(
Collection> changes, Class clazz) {
return extractCreatedOrUpdated(changes, clazz, hasDataBeforeAndDataAfter());
}
/**
* Extract all the instance of {@code clazz} which were created or updated in the given set of modifications, and
* which satisfy the given filter.
*
* @param changes The changes to process.
* @param clazz The class we're interested in.
* @param filter The filter the changes must satisfy.
* @param The type of changes we're interested in.
* @param The type of changes to process.
* @return The created or updated instances which satisfy the filter, mapped by instance identifier.
*/
public static Map, T> extractCreatedOrUpdated(
Collection> changes, Class clazz,
Predicate> filter) {
Map, T> result = new HashMap<>();
for (Map.Entry, DataObjectModification> entry : extractDataObjectModifications(changes,
clazz, hasDataAfterAndMatchesFilter(filter)).entrySet()) {
result.put(entry.getKey(), entry.getValue().getDataAfter());
}
return result;
}
public static Map,T> extractCreatedOrUpdated(
AsyncDataChangeEvent,DataObject> changes,Class klazz) {
Map,T> result = extractUpdated(changes,klazz);
result.putAll(extractCreated(changes,klazz));
return result;
}
/**
* Extract all the instances of {@code clazz} which were created or updated in the given set of modifications.
*
* @param changes The changes to process.
* @param clazz The class we're interested in.
* @param The type of changes we're interested in.
* @param The type of changes to process.
* @return The created or updated instances, mapped by instance identifier.
*/
public static Map, T> extractCreatedOrUpdated(
Collection> changes, Class clazz) {
return extractCreatedOrUpdated(changes, clazz, matchesEverything());
}
public static Map, T> extractCreatedOrUpdatedOrRemoved(
AsyncDataChangeEvent, DataObject> changes,
Class klazz) {
Map,T> result = extractCreatedOrUpdated(changes,klazz);
result.putAll(extractRemovedObjects(changes, klazz));
return result;
}
/**
* Extract all the instances of {@code clazz} which were created, updated, or removed in the given set of
* modifications. For instances which were created or updated, the new instances are returned; for instances
* which were removed, the old instances are returned.
*
* @param changes The changes to process.
* @param clazz The class we're interested in.
* @param The type of changes we're interested in.
* @param The type of changes to process.
* @return The created, updated or removed instances, mapped by instance identifier.
*/
public static Map, T>
extractCreatedOrUpdatedOrRemoved(
Collection> changes, Class clazz) {
Map, T> result = extractCreatedOrUpdated(changes, clazz);
result.putAll(extractRemovedObjects(changes, clazz));
return result;
}
public static Map,T> extractOriginal(
AsyncDataChangeEvent,DataObject> changes,Class klazz) {
return extract(changes.getOriginalData(),klazz);
}
/**
* Extract the original instances of class {@code clazz} in the given set of modifications.
*
* @param changes The changes to process.
* @param clazz The class we're interested in.
* @param The type of changes we're interested in.
* @param The type of changes to process.
* @return The original instances, mapped by instance identifier.
*/
public static Map, T> extractOriginal(
Collection> changes, Class clazz) {
Map, T> result = new HashMap<>();
for (Map.Entry, DataObjectModification> entry :
extractDataObjectModifications(changes, clazz, hasDataBefore()).entrySet()) {
result.put(entry.getKey(), entry.getValue().getDataBefore());
}
return result;
}
public static Set> extractRemoved(
AsyncDataChangeEvent,DataObject> changes,Class klazz) {
Set> result = new HashSet<>();
if (changes != null && changes.getRemovedPaths() != null) {
for (InstanceIdentifier> iid : changes.getRemovedPaths()) {
if (iid.getTargetType().equals(klazz)) {
// Actually checked above
@SuppressWarnings("unchecked")
InstanceIdentifier iidn = (InstanceIdentifier)iid;
result.add(iidn);
}
}
}
return result;
}
/**
* Extract the instance identifier of removed instances of {@code clazz} from the given set of modifications.
*
* @param changes The changes to process.
* @param clazz The class we're interested in.
* @param The type of changes we're interested in.
* @param The type of changes to process.
* @return The instance identifiers of removed instances.
*/
public static Set> extractRemoved(
Collection> changes, Class clazz) {
return extractDataObjectModifications(changes, clazz, modificationIsDeletion()).keySet();
}
/**
* Extract all the modifications affecting instances of {@code clazz} which are present in the given set of
* modifications and satisfy the given filter.
*
* @param changes The changes to process.
* @param clazz The class we're interested in.
* @param filter The filter the changes must satisfy.
* @param The type of changes we're interested in.
* @param The type of changes to process.
* @return The modifications, mapped by instance identifier.
*/
private static Map, DataObjectModification>
extractDataObjectModifications(Collection> changes, Class clazz,
Predicate> filter) {
List> dataObjectModifications = new ArrayList<>();
List> paths = new ArrayList<>();
if (changes != null) {
for (DataTreeModification extends DataObject> change : changes) {
dataObjectModifications.add(change.getRootNode());
paths.add(change.getRootPath().getRootIdentifier());
}
}
return extractDataObjectModifications(dataObjectModifications, paths, clazz, filter);
}
/**
* Extract all the modifications affecting instances of {@code clazz} which are present in the given set of
* modifications and satisfy the given filter.
*
* @param changes The changes to process.
* @param paths The paths of the changes.
* @param clazz The class we're interested in.
* @param filter The filter the changes must satisfy.
* @param The type of changes we're interested in.
* @return The modifications, mapped by instance identifier.
*/
private static Map, DataObjectModification>
extractDataObjectModifications(
Collection> changes,
Collection> paths, Class clazz,
Predicate> filter) {
Map, DataObjectModification> result = new HashMap<>();
Queue> remainingChanges = new LinkedList<>(changes);
Queue> remainingPaths = new LinkedList<>(paths);
while (!remainingChanges.isEmpty()) {
DataObjectModification extends DataObject> change = remainingChanges.remove();
InstanceIdentifier extends DataObject> path = remainingPaths.remove();
// Is the change relevant?
if (clazz.isAssignableFrom(change.getDataType()) && filter.apply((DataObjectModification) change)) {
result.put((InstanceIdentifier) path, (DataObjectModification) change);
}
// Add any children to the queue
for (DataObjectModification extends DataObject> child : change.getModifiedChildren()) {
remainingChanges.add(child);
remainingPaths.add(extendPath(path, child));
}
}
return result;
}
/**
* Extends the given instance identifier path to include the given child. Augmentations are treated in the same way
* as children; keyed children are handled correctly.
*
* @param path The current path.
* @param child The child modification to include.
* @return The extended path.
*/
private static & ChildOf super T>, K extends Identifier, T extends DataObject>
InstanceIdentifier extends DataObject> extendPath(
InstanceIdentifier path,
DataObjectModification child) {
Class item = (Class) child.getDataType();
if (child.getIdentifier() instanceof InstanceIdentifier.IdentifiableItem) {
K key = (K) ((InstanceIdentifier.IdentifiableItem) child.getIdentifier()).getKey();
KeyedInstanceIdentifier extendedPath = path.child(item, key);
return extendedPath;
} else {
InstanceIdentifier extendedPath = path.child(item);
return extendedPath;
}
}
public static Map, T> extractRemovedObjects(
AsyncDataChangeEvent, DataObject> changes,
Class klazz) {
Set> iids = extractRemoved(changes, klazz);
return Maps.filterKeys(extractOriginal(changes, klazz),Predicates.in(iids));
}
/**
* Extract the removed instances of {@code clazz} from the given set of modifications.
*
* @param changes The changes to process.
* @param clazz The class we're interested in.
* @param The type of changes we're interested in.
* @param The type of changes to process.
* @return The removed instances, keyed by instance identifier.
*/
public static Map, T> extractRemovedObjects(
Collection> changes, Class clazz) {
Map, T> result = new HashMap<>();
for (Map.Entry, DataObjectModification> entry :
extractDataObjectModifications(changes, clazz, modificationIsDeletionAndHasDataBefore()).entrySet()) {
result.put(entry.getKey(), entry.getValue().getDataBefore());
}
return result;
}
public static Map,T> extract(
Map, DataObject> changes, Class klazz) {
Map,T> result = new HashMap<>();
if (changes != null) {
for (Entry, DataObject> created : changes.entrySet()) {
if (klazz.isInstance(created.getValue())) {
@SuppressWarnings("unchecked")
T value = (T) created.getValue();
Class> type = created.getKey().getTargetType();
if (type.equals(klazz)) {
// Actually checked above
@SuppressWarnings("unchecked")
InstanceIdentifier iid = (InstanceIdentifier) created.getKey();
result.put(iid, value);
}
}
}
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy