From: Tony Tkacik Date: Wed, 1 Apr 2015 10:50:57 +0000 (+0200) Subject: Bug 2933: Make DataTreeModification and Listeners type-safe X-Git-Tag: release/lithium~303^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=98b2fe4c9d3c3f2a6d4fa2d0c3f17e237d15082e Bug 2933: Make DataTreeModification and Listeners type-safe Introduced generic to DataTreeModification, DataTreeChangeListener and DataTreeIdentifier which captures target type from InstanceIdentifier so users does not have to deal with casts by themselves. Added utility walker methods to DataObjectModification, which are possible thanks to DataTreeModification capturing target type. Change-Id: Ia3566ae3dbe98fb118b49cc8ac8e1925fc111d8b Signed-off-by: Tony Tkacik --- diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataObjectModification.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataObjectModification.java index 2eee0e8099..678ac34e39 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataObjectModification.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataObjectModification.java @@ -10,8 +10,11 @@ package org.opendaylight.controller.md.sal.binding.api; import java.util.Collection; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.yang.binding.Augmentation; +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.PathArgument; /** @@ -20,7 +23,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; * Represents modification of Data Object. * */ -public interface DataObjectModification extends Identifiable { +public interface DataObjectModification extends org.opendaylight.yangtools.concepts.Identifiable { enum ModificationType { /** @@ -76,5 +79,56 @@ public interface DataObjectModification extends Identifiab */ @Nonnull Collection> getModifiedChildren(); + /** + * Returns container child modification if {@code child} was modified by this + * modification. + * + * For accessing all modified list items consider iterating over {@link #getModifiedChildren()}. + * + * @param child Type of child - must be only container + * @return Modification of {@code child} if {@code child} was modified, null otherwise. + * @throws IllegalArgumentException If supplied {@code child} class is not valid child according + * to generated model. + */ + @Nullable > DataObjectModification getModifiedChildContainer(@Nonnull Class child); + + /** + * Returns augmentation child modification if {@code augmentation} was modified by this + * modification. + * + * For accessing all modified list items consider iterating over {@link #getModifiedChildren()}. + * + * @param augmentation Type of augmentation - must be only container + * @return Modification of {@code augmentation} if {@code augmentation} was modified, null otherwise. + * @throws IllegalArgumentException If supplied {@code augmentation} class is not valid augmentation + * according to generated model. + */ + @Nullable & DataObject> DataObjectModification getModifiedAugmentation(@Nonnull Class augmentation); + + + /** + * Returns child list item modification if {@code child} was modified by this modification. + * + * @param listItem Type of list item - must be list item with key + * @param listKey List item key + * @return Modification of {@code child} if {@code child} was modified, null otherwise. + * @throws IllegalArgumentException If supplied {@code listItem} class is not valid child according + * to generated model. + */ + & ChildOf, K extends Identifier> DataObjectModification getModifiedChildListItem( + @Nonnull Class listItem,@Nonnull K listKey); + + /** + * Returns a child modification if a node identified by {@code childArgument} was modified by + * this modification. + * + * @param childArgument Path Argument of child node + * @return Modification of child identified by {@code childArgument} if {@code childArgument} + * was modified, null otherwise. + * @throws IllegalArgumentException If supplied path argument is not valid child according to + * generated model. + * + */ + @Nullable DataObjectModification getModifiedChild(PathArgument childArgument); } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeListener.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeListener.java index 6b1df719ac..93ab968451 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeListener.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeListener.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.md.sal.binding.api; import java.util.Collection; import java.util.EventListener; import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; /** * Interface implemented by classes interested in receiving notifications about @@ -17,7 +18,7 @@ import javax.annotation.Nonnull; * in that it provides a cursor-based view of the change, which has potentially * lower overhead and allow more flexible consumption of change event. */ -public interface DataTreeChangeListener extends EventListener { +public interface DataTreeChangeListener extends EventListener { /** * Invoked when there was data change for the supplied path, which was used * to register this listener. @@ -39,5 +40,5 @@ public interface DataTreeChangeListener extends EventListener { * * @param changes Collection of change events, may not be null or empty. */ - void onDataTreeChanged(@Nonnull Collection changes); + void onDataTreeChanged(@Nonnull Collection> changes); } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeService.java index ae4e36f14a..9d12e44916 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeService.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeService.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.md.sal.binding.api; import javax.annotation.Nonnull; import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; /** * A {@link DOMService} which allows users to register for changes to a @@ -50,5 +51,5 @@ public interface DataTreeChangeService extends BindingService { * your listener using {@link ListenerRegistration#close()} to stop * delivery of change events. */ - @Nonnull ListenerRegistration registerDataTreeChangeListener(@Nonnull DataTreeIdentifier treeId, @Nonnull L listener); + @Nonnull > ListenerRegistration registerDataTreeChangeListener(@Nonnull DataTreeIdentifier treeId, @Nonnull L listener); } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeIdentifier.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeIdentifier.java index 428957e988..c1c23d5e6f 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeIdentifier.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeIdentifier.java @@ -13,18 +13,19 @@ import javax.annotation.Nonnull; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** * A unique identifier for a particular subtree. It is composed of the logical * data store type and the instance identifier of the root node. */ -public final class DataTreeIdentifier implements Immutable, Path, Serializable { +public final class DataTreeIdentifier implements Immutable, Path>, Serializable { private static final long serialVersionUID = 1L; - private final InstanceIdentifier rootIdentifier; + private final InstanceIdentifier rootIdentifier; private final LogicalDatastoreType datastoreType; - public DataTreeIdentifier(final LogicalDatastoreType datastoreType, final InstanceIdentifier rootIdentifier) { + public DataTreeIdentifier(final LogicalDatastoreType datastoreType, final InstanceIdentifier rootIdentifier) { this.datastoreType = Preconditions.checkNotNull(datastoreType); this.rootIdentifier = Preconditions.checkNotNull(rootIdentifier); } @@ -48,7 +49,7 @@ public final class DataTreeIdentifier implements Immutable, Path other) { return datastoreType == other.datastoreType && rootIdentifier.contains(other.rootIdentifier); } @@ -69,7 +70,7 @@ public final class DataTreeIdentifier implements Immutable, Path other = (DataTreeIdentifier) obj; if (datastoreType != other.datastoreType) { return false; } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeModification.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeModification.java index aac51a6a4c..8163baceac 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeModification.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeModification.java @@ -17,7 +17,7 @@ import org.opendaylight.yangtools.yang.binding.DataObject; * @author Tony Tkacik <ttkacik@cisco.com> * */ -public interface DataTreeModification { +public interface DataTreeModification { /** * Get the modification root path. This is the path of the root node @@ -25,13 +25,13 @@ public interface DataTreeModification { * * @return absolute path of the root node */ - @Nonnull DataTreeIdentifier getRootPath(); + @Nonnull DataTreeIdentifier getRootPath(); /** * Get the modification root node. * * @return modification root node */ - @Nonnull DataObjectModification getRootNode(); + @Nonnull DataObjectModification getRootNode(); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMDataTreeChangeListenerAdapter.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMDataTreeChangeListenerAdapter.java index bc60bdcba2..35b2ce42b6 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMDataTreeChangeListenerAdapter.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMDataTreeChangeListenerAdapter.java @@ -13,6 +13,7 @@ import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener; +import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; /** @@ -21,10 +22,10 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; * to their Binding equivalent. * */ -final class BindingDOMDataTreeChangeListenerAdapter implements DOMDataTreeChangeListener { +final class BindingDOMDataTreeChangeListenerAdapter implements DOMDataTreeChangeListener { private final BindingToNormalizedNodeCodec codec; - private final DataTreeChangeListener listener; + private final DataTreeChangeListener listener; private final LogicalDatastoreType store; BindingDOMDataTreeChangeListenerAdapter(final BindingToNormalizedNodeCodec codec, final DataTreeChangeListener listener, @@ -36,7 +37,7 @@ final class BindingDOMDataTreeChangeListenerAdapter implements DOMDataTreeChange @Override public void onDataTreeChanged(final Collection domChanges) { - final Collection bindingChanges = LazyDataTreeModification.from(codec, domChanges, store); + final Collection> bindingChanges = LazyDataTreeModification.from(codec, domChanges, store); listener.onDataTreeChanged(bindingChanges); } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMDataTreeChangeServiceAdapter.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMDataTreeChangeServiceAdapter.java index 04c6ad5702..ad0ab54e9f 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMDataTreeChangeServiceAdapter.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMDataTreeChangeServiceAdapter.java @@ -14,6 +14,7 @@ import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService; import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier; import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -44,15 +45,15 @@ final class BindingDOMDataTreeChangeServiceAdapter implements DataTreeChangeServ } @Override - public ListenerRegistration registerDataTreeChangeListener( - final DataTreeIdentifier treeId, final L listener) { + public > ListenerRegistration registerDataTreeChangeListener( + final DataTreeIdentifier treeId, final L listener) { final DOMDataTreeIdentifier domIdentifier = toDomTreeIdentifier(treeId); - final BindingDOMDataTreeChangeListenerAdapter domListener = new BindingDOMDataTreeChangeListenerAdapter(codec,listener, treeId.getDatastoreType()); - final ListenerRegistration domReg = dataTreeChangeService.registerDataTreeChangeListener(domIdentifier, domListener); + final BindingDOMDataTreeChangeListenerAdapter domListener = new BindingDOMDataTreeChangeListenerAdapter<>(codec,listener, treeId.getDatastoreType()); + final ListenerRegistration> domReg = dataTreeChangeService.registerDataTreeChangeListener(domIdentifier, domListener); return new BindingDataTreeChangeListenerRegistration<>(listener,domReg); } - private DOMDataTreeIdentifier toDomTreeIdentifier(final DataTreeIdentifier treeId) { + private DOMDataTreeIdentifier toDomTreeIdentifier(final DataTreeIdentifier treeId) { final YangInstanceIdentifier domPath = codec.toYangInstanceIdentifier(treeId.getRootIdentifier()); return new DOMDataTreeIdentifier(treeId.getDatastoreType(), domPath); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataTreeChangeListenerRegistration.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataTreeChangeListenerRegistration.java index 524d97c497..8a92e5fc80 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataTreeChangeListenerRegistration.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataTreeChangeListenerRegistration.java @@ -12,12 +12,11 @@ import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; import org.opendaylight.yangtools.concepts.AbstractListenerRegistration; import org.opendaylight.yangtools.concepts.ListenerRegistration; -class BindingDataTreeChangeListenerRegistration extends AbstractListenerRegistration { +class BindingDataTreeChangeListenerRegistration> extends AbstractListenerRegistration { - private final ListenerRegistration domReg; + private final ListenerRegistration domReg; - BindingDataTreeChangeListenerRegistration(final L listener, - final ListenerRegistration domReg) { + BindingDataTreeChangeListenerRegistration(final L listener, final ListenerRegistration domReg) { super(listener); this.domReg = Preconditions.checkNotNull(domReg); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/LazyDataObjectModification.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/LazyDataObjectModification.java index b29ed3849b..a165242b30 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/LazyDataObjectModification.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/LazyDataObjectModification.java @@ -15,8 +15,11 @@ import java.util.Iterator; import java.util.List; import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeNode; +import org.opendaylight.yangtools.yang.binding.Augmentation; 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.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -49,7 +52,7 @@ class LazyDataObjectModification implements DataObjectModi this.identifier = codec.deserializePathArgument(domData.getIdentifier()); } - static DataObjectModification create(final BindingCodecTreeNode codec, + static DataObjectModification create(final BindingCodecTreeNode codec, final DataTreeCandidateNode domData) { return new LazyDataObjectModification<>(codec,domData); } @@ -152,6 +155,7 @@ class LazyDataObjectModification implements DataObjectModi return childNodesCache; } + @Override public DataObjectModification getModifiedChild(final PathArgument arg) { final List domArgumentList = new ArrayList<>(); final BindingCodecTreeNode childCodec = codec.bindingPathArgumentChild(arg, domArgumentList); @@ -166,11 +170,26 @@ class LazyDataObjectModification implements DataObjectModi return null; } + @Override + @SuppressWarnings("unchecked") + public & ChildOf, K extends Identifier> DataObjectModification getModifiedChildListItem( + final Class listItem, final K listKey) { + return (DataObjectModification) getModifiedChild(new InstanceIdentifier.IdentifiableItem<>(listItem, listKey)); + } + + @Override @SuppressWarnings("unchecked") - public > DataObjectModification getModifiedChild(final Class arg) { + public > DataObjectModification getModifiedChildContainer(final Class arg) { return (DataObjectModification) getModifiedChild(new InstanceIdentifier.Item<>(arg)); } + @Override + @SuppressWarnings("unchecked") + public & DataObject> DataObjectModification getModifiedAugmentation( + final Class augmentation) { + return (DataObjectModification) getModifiedChild(new InstanceIdentifier.Item<>(augmentation)); + } + private T deserialize(final Optional> dataAfter) { if(dataAfter.isPresent()) { return codec.deserialize(dataAfter.get()); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/LazyDataTreeModification.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/LazyDataTreeModification.java index 26fd420c0e..2a90f96646 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/LazyDataTreeModification.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/LazyDataTreeModification.java @@ -28,38 +28,39 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; * which are directly accessed by user of data object modification. * */ -class LazyDataTreeModification implements DataTreeModification { +class LazyDataTreeModification implements DataTreeModification { - private final DataTreeIdentifier path; - private final DataObjectModification rootNode; + private final DataTreeIdentifier path; + private final DataObjectModification rootNode; - LazyDataTreeModification(final LogicalDatastoreType datastoreType, final InstanceIdentifier path, final BindingCodecTreeNode codec, final DataTreeCandidate domChange) { - this.path = new DataTreeIdentifier(datastoreType, path); + LazyDataTreeModification(final LogicalDatastoreType datastoreType, final InstanceIdentifier path, final BindingCodecTreeNode codec, final DataTreeCandidate domChange) { + this.path = new DataTreeIdentifier<>(datastoreType, path); this.rootNode = LazyDataObjectModification.create(codec, domChange.getRootNode()); } @Override - public DataObjectModification getRootNode() { + public DataObjectModification getRootNode() { return rootNode; } @Override - public DataTreeIdentifier getRootPath() { + public DataTreeIdentifier getRootPath() { return path; } - static DataTreeModification create(final BindingToNormalizedNodeCodec codec, final DataTreeCandidate domChange, + @SuppressWarnings({"unchecked", "rawtypes"}) + static DataTreeModification create(final BindingToNormalizedNodeCodec codec, final DataTreeCandidate domChange, final LogicalDatastoreType datastoreType) { final Entry, BindingCodecTreeNode> codecCtx = codec.getSubtreeCodec(domChange.getRootPath()); - return new LazyDataTreeModification(datastoreType, codecCtx.getKey(), codecCtx.getValue(), domChange); + return (DataTreeModification) new LazyDataTreeModification(datastoreType, codecCtx.getKey(), codecCtx.getValue(), domChange); } - static Collection from(final BindingToNormalizedNodeCodec codec, + static Collection> from(final BindingToNormalizedNodeCodec codec, final Collection domChanges, final LogicalDatastoreType datastoreType) { - final List result = new ArrayList<>(domChanges.size()); + final List> result = new ArrayList<>(domChanges.size()); for (final DataTreeCandidate domChange : domChanges) { - result.add(create(codec, domChange, datastoreType)); + result.add(LazyDataTreeModification.create(codec, domChange, datastoreType)); } return result; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/DataTreeChangeListenerTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/DataTreeChangeListenerTest.java index 218233e8f1..888a628133 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/DataTreeChangeListenerTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/DataTreeChangeListenerTest.java @@ -2,6 +2,7 @@ package org.opendaylight.controller.md.sal.binding.impl.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.TOP_BAR_KEY; import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.TOP_FOO_KEY; import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.USES_ONE_KEY; @@ -39,31 +40,32 @@ import org.opendaylight.yangtools.yang.binding.util.BindingReflections; public class DataTreeChangeListenerTest extends AbstractDataBrokerTest { private static final InstanceIdentifier TOP_PATH = InstanceIdentifier.create(Top.class); + private static final PathArgument TOP_ARGUMENT= TOP_PATH.getPathArguments().iterator().next(); private static final InstanceIdentifier FOO_PATH = path(TOP_FOO_KEY); private static final PathArgument FOO_ARGUMENT = Iterables.getLast(FOO_PATH.getPathArguments()); private static final TopLevelList FOO_DATA = topLevelList(TOP_FOO_KEY, complexUsesAugment(USES_ONE_KEY)); private static final InstanceIdentifier BAR_PATH = path(TOP_BAR_KEY); private static final PathArgument BAR_ARGUMENT = Iterables.getLast(BAR_PATH.getPathArguments()); private static final TopLevelList BAR_DATA = topLevelList(TOP_BAR_KEY); - private static final DataTreeIdentifier TOP_IDENTIFIER = new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, +private static final DataTreeIdentifier TOP_IDENTIFIER = new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, TOP_PATH); private static final Top TOP_INITIAL_DATA = top(FOO_DATA); private BindingDOMDataBrokerAdapter dataBrokerImpl; - private static final class EventCapturingListener implements DataTreeChangeListener { + private static final class EventCapturingListener implements DataTreeChangeListener { - private SettableFuture> changes = SettableFuture.create(); + private SettableFuture>> changes = SettableFuture.create(); @Override - public void onDataTreeChanged(final Collection changes) { + public void onDataTreeChanged(final Collection> changes) { this.changes.set(changes); } - Collection nextEvent() throws Exception { - final Collection result = changes.get(200,TimeUnit.MILLISECONDS); + Collection> nextEvent() throws Exception { + final Collection> result = changes.get(200,TimeUnit.MILLISECONDS); changes = SettableFuture.create(); return result; } @@ -85,67 +87,61 @@ public class DataTreeChangeListenerTest extends AbstractDataBrokerTest { @Test public void testTopLevelListener() throws Exception { - final EventCapturingListener listener = new EventCapturingListener(); + final EventCapturingListener listener = new EventCapturingListener<>(); dataBrokerImpl.registerDataTreeChangeListener(TOP_IDENTIFIER, listener); createAndVerifyTop(listener); putTx(BAR_PATH, BAR_DATA).submit().checkedGet(); - final DataTreeModification afterBarPutEvent = Iterables.getOnlyElement(listener.nextEvent()); - final DataObjectModification barPutMod = - getOnlyChildModification(afterBarPutEvent.getRootNode(), ModificationType.SUBTREE_MODIFIED); + final DataObjectModification afterBarPutEvent = Iterables.getOnlyElement(listener.nextEvent()).getRootNode(); + verifyModification(afterBarPutEvent, TOP_ARGUMENT, ModificationType.SUBTREE_MODIFIED); + final DataObjectModification barPutMod = afterBarPutEvent.getModifiedChildListItem(TopLevelList.class, TOP_BAR_KEY); + assertNotNull(barPutMod); verifyModification(barPutMod, BAR_ARGUMENT, ModificationType.WRITE); deleteTx(BAR_PATH).submit().checkedGet(); - final DataTreeModification afterBarDeleteEvent = Iterables.getOnlyElement(listener.nextEvent()); - final DataObjectModification barDeleteMod = - getOnlyChildModification(afterBarDeleteEvent.getRootNode(), ModificationType.SUBTREE_MODIFIED); + final DataObjectModification afterBarDeleteEvent = Iterables.getOnlyElement(listener.nextEvent()).getRootNode(); + verifyModification(afterBarDeleteEvent, TOP_ARGUMENT, ModificationType.SUBTREE_MODIFIED); + final DataObjectModification barDeleteMod = afterBarDeleteEvent.getModifiedChildListItem(TopLevelList.class, TOP_BAR_KEY); verifyModification(barDeleteMod, BAR_ARGUMENT, ModificationType.DELETE); } @Test public void testWildcardedListListener() throws Exception { - final EventCapturingListener listener = new EventCapturingListener(); - final DataTreeIdentifier wildcard = new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, TOP_PATH.child(TopLevelList.class)); + final EventCapturingListener listener = new EventCapturingListener<>(); + final DataTreeIdentifier wildcard = new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, TOP_PATH.child(TopLevelList.class)); dataBrokerImpl.registerDataTreeChangeListener(wildcard, listener); putTx(TOP_PATH, TOP_INITIAL_DATA).submit().checkedGet(); - final DataTreeModification fooWriteEvent = Iterables.getOnlyElement(listener.nextEvent()); + final DataTreeModification fooWriteEvent = Iterables.getOnlyElement(listener.nextEvent()); assertEquals(FOO_PATH, fooWriteEvent.getRootPath().getRootIdentifier()); verifyModification(fooWriteEvent.getRootNode(), FOO_ARGUMENT, ModificationType.WRITE); putTx(BAR_PATH, BAR_DATA).submit().checkedGet(); - final DataTreeModification barWriteEvent = Iterables.getOnlyElement(listener.nextEvent()); + final DataTreeModification barWriteEvent = Iterables.getOnlyElement(listener.nextEvent()); assertEquals(BAR_PATH, barWriteEvent.getRootPath().getRootIdentifier()); verifyModification(barWriteEvent.getRootNode(), BAR_ARGUMENT, ModificationType.WRITE); deleteTx(BAR_PATH).submit().checkedGet(); - final DataTreeModification barDeleteEvent = Iterables.getOnlyElement(listener.nextEvent()); + final DataTreeModification barDeleteEvent = Iterables.getOnlyElement(listener.nextEvent()); assertEquals(BAR_PATH, barDeleteEvent.getRootPath().getRootIdentifier()); verifyModification(barDeleteEvent.getRootNode(), BAR_ARGUMENT, ModificationType.DELETE); } - private void createAndVerifyTop(final EventCapturingListener listener) throws Exception { + private void createAndVerifyTop(final EventCapturingListener listener) throws Exception { putTx(TOP_PATH,TOP_INITIAL_DATA).submit().checkedGet(); - final Collection events = listener.nextEvent(); + final Collection> events = listener.nextEvent(); assertFalse("Non empty collection should be received.",events.isEmpty()); - final DataTreeModification initialWrite = Iterables.getOnlyElement(events); + final DataTreeModification initialWrite = Iterables.getOnlyElement(events); final DataObjectModification initialNode = initialWrite.getRootNode(); verifyModification(initialNode,TOP_PATH.getPathArguments().iterator().next(),ModificationType.WRITE); assertEquals(TOP_INITIAL_DATA, initialNode.getDataAfter()); } - private DataObjectModification getOnlyChildModification(final DataObjectModification parentMod,final DataObjectModification.ModificationType eventType) throws Exception { - assertEquals(eventType,parentMod.getModificationType()); - final Collection> childMod = parentMod.getModifiedChildren(); - assertFalse("Non empty children modification",childMod.isEmpty()); - return Iterables.getOnlyElement(childMod); - } - private void verifyModification(final DataObjectModification barWrite, final PathArgument pathArg, final ModificationType eventType) { assertEquals(pathArg.getType(), barWrite.getDataType());