X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=southbound%2Fsouthbound-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fovsdb%2Fsouthbound%2Fovsdb%2Ftransact%2FTransactUtils.java;h=c5e565a2d53add51b093741c64ca96342dd92ef4;hb=55ce82cbd9fdcb0edf9e629bd2d626b193c6ab26;hp=9af3750a7b2e8dd2057031b5bb420ed6350f9f10;hpb=1fbc1aa3836a2a1596ca91715bc2c087c626f0e2;p=ovsdb.git diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TransactUtils.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TransactUtils.java index 9af3750a7..c5e565a2d 100644 --- a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TransactUtils.java +++ b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TransactUtils.java @@ -10,13 +10,21 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact; import static org.opendaylight.ovsdb.lib.operations.Operations.op; 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 com.google.common.base.Predicate; +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.ovsdb.lib.notation.Mutation; import org.opendaylight.ovsdb.lib.notation.Mutator; @@ -33,10 +41,13 @@ import org.opendaylight.ovsdb.southbound.SouthboundConstants; import org.opendaylight.ovsdb.southbound.SouthboundMapper; import org.opendaylight.ovsdb.southbound.SouthboundUtil; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; + +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.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableMap; @@ -45,13 +56,78 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; public class TransactUtils { - private static final Logger LOG = LoggerFactory.getLogger(TransactUtils.class); + 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,Node> extractNode( Map, DataObject> changes) { Map,Node> result = new HashMap<>(); - if (changes != null && changes.entrySet() != null) { + if (changes != null) { for (Entry, DataObject> created : changes.entrySet()) { if (created.getValue() instanceof Node) { Node value = (Node) created.getValue(); @@ -72,11 +148,61 @@ public class TransactUtils { 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()); + } + + /** + * 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> 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()); + } + public static Map,T> extractCreatedOrUpdated( AsyncDataChangeEvent,DataObject> changes,Class klazz) { Map,T> result = extractUpdated(changes,klazz); @@ -84,6 +210,20 @@ public class TransactUtils { 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) { @@ -92,11 +232,49 @@ public class TransactUtils { 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<>(); @@ -112,6 +290,104 @@ public class TransactUtils { 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 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 change = remainingChanges.remove(); + InstanceIdentifier 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 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, K extends Identifier, T extends DataObject> + InstanceIdentifier 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) { @@ -119,10 +395,29 @@ public class TransactUtils { 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 && changes.entrySet() != null) { + if (changes != null) { for (Entry, DataObject> created : changes.entrySet()) { if (klazz.isInstance(created.getValue())) { @SuppressWarnings("unchecked") @@ -142,11 +437,9 @@ public class TransactUtils { public static List extractInsert(TransactionBuilder transaction, GenericTableSchema schema) { List operations = transaction.getOperations(); List inserts = new ArrayList<>(); - for (int count = 0;count < operations.size();count++) { - Operation operation = operations.get(count); + for (Operation operation : operations) { if (operation instanceof Insert && operation.getTableSchema().equals(schema)) { - Insert insert = (Insert)operation; - inserts.add(insert); + inserts.add((Insert) operation); } } return inserts; @@ -164,8 +457,7 @@ public class TransactUtils { String uuidString = insert.getUuidName() != null ? insert.getUuidName() : SouthboundMapper.getRandomUUID(); insert.setUuidName(uuidString); - UUID uuid = new UUID(uuidString); - return uuid; + return new UUID(uuidString); } public static > void stampInstanceIdentifier(TransactionBuilder transaction, @@ -192,4 +484,41 @@ public class TransactUtils { mutate.setMutations(mutations); return mutate; } + + /** + * This method builds a string by concatenating the 2 character + * hexadecimal representation of each byte from the input byte array. + * + * For example: an input byte array containing: + * bytes[0] = 'a' + * bytes[1] = 'b' + * bytes[2] = 'c' + * bytes[3] = '-' + * bytes[4] = '1' + * bytes[5] = '2' + * bytes[6] = '3' + * returns the string "6162632d313233" + * + * @param bytes + * The byte array to convert to string + * @return The hexadecimal representation of the byte array. If bytes is + * null, the string "" is returned + */ + public static String bytesToHexString(byte[] bytes) { + + if (bytes == null) { + return ""; + } + + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + short u8byte = (short) (bytes[i] & 0xff); + String tmp = Integer.toHexString(u8byte); + if (tmp.length() == 1) { + buf.append("0"); + } + buf.append(tmp); + } + return buf.toString(); + } }