@Test
  public void testApply() throws Exception {
    // Write something into the datastore
    DOMStoreReadWriteTransaction writeTransaction = store.newReadWriteTransaction();
    WriteModification writeModification =
        new WriteModification(
            TestModel.TEST_PATH,
            ImmutableNodes.containerNode(TestModel.TEST_QNAME),
            TestModel.createTestContext());
    writeModification.apply(writeTransaction);
    commitTransaction(writeTransaction);

    // Check if it's in the datastore
    Optional<NormalizedNode<?, ?>> data = readData(TestModel.TEST_PATH);
    Assert.assertTrue(data.isPresent());

    // Delete stuff from the datastore
    DOMStoreWriteTransaction deleteTransaction = store.newWriteOnlyTransaction();
    DeleteModification deleteModification = new DeleteModification(TestModel.TEST_PATH);
    deleteModification.apply(deleteTransaction);
    commitTransaction(deleteTransaction);

    data = readData(TestModel.TEST_PATH);
    Assert.assertFalse(data.isPresent());
  }
Example #2
0
  private void ensureParentsByMerge(
      final LogicalDatastoreType store,
      final YangInstanceIdentifier normalizedPath,
      final DOMDataReadWriteTransaction rwTx,
      final SchemaContext schemaContext) {
    final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
    YangInstanceIdentifier rootNormalizedPath = null;

    final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();

    while (it.hasNext()) {
      final PathArgument pathArgument = it.next();
      if (rootNormalizedPath == null) {
        rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
      }

      // Skip last element, its not a parent
      if (it.hasNext()) {
        normalizedPathWithoutChildArgs.add(pathArgument);
      }
    }

    // No parent structure involved, no need to ensure parents
    if (normalizedPathWithoutChildArgs.isEmpty()) {
      return;
    }

    Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");

    final NormalizedNode<?, ?> parentStructure =
        ImmutableNodes.fromInstanceId(
            schemaContext, YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
    rwTx.merge(store, rootNormalizedPath, parentStructure);
  }
Example #3
0
 private void postDataWithinTransaction(
     final DOMDataReadWriteTransaction rWTransaction,
     final LogicalDatastoreType datastore,
     final YangInstanceIdentifier path,
     final NormalizedNode<?, ?> payload,
     final SchemaContext schemaContext) {
   // FIXME: This is doing correct post for container and list children
   //        not sure if this will work for choice case
   if (payload instanceof MapNode) {
     LOG.trace(
         "POST {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
     final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
     rWTransaction.merge(
         datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
     ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
     for (final MapEntryNode child : ((MapNode) payload).getValue()) {
       final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
       checkItemDoesNotExists(rWTransaction, datastore, childPath);
       rWTransaction.put(datastore, childPath, child);
     }
   } else {
     checkItemDoesNotExists(rWTransaction, datastore, path);
     ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
     rWTransaction.put(datastore, path, payload);
   }
 }
  /**
   * This method stores the pushUpdate Notification data to MD-SAL
   *
   * @param sub_id
   * @param timeofeventupdate
   * @param domSource
   * @param data
   */
  private void storeToMdSal(
      String sub_id, String timeofeventupdate, DOMSource domSource, String data) {
    NodeIdentifier subscriptionid =
        NodeIdentifier.create(QName.create(PushUpdates.QNAME, "subscription-id"));
    NodeIdentifier timeofupdate =
        NodeIdentifier.create(QName.create(PushUpdates.QNAME, "time-of-update"));
    NodeIdentifier datanode = NodeIdentifier.create(QName.create(PushUpdates.QNAME, "data"));
    YangInstanceIdentifier pid =
        YangInstanceIdentifier.builder()
            .node(PushUpdates.QNAME)
            .node(
                org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangpush.rev150105
                    .push.updates.PushUpdate.QNAME)
            .build();

    NodeIdentifierWithPredicates p =
        new NodeIdentifierWithPredicates(
            QName.create(PushUpdates.QNAME, "push-update"),
            QName.create(PushUpdates.QNAME, "subscription-id"),
            sub_id);

    MapEntryNode men =
        ImmutableNodes.mapEntryBuilder()
            .withNodeIdentifier(p)
            .withChild(ImmutableNodes.leafNode(subscriptionid, sub_id))
            .withChild(ImmutableNodes.leafNode(timeofupdate, timeofeventupdate))
            .withChild(ImmutableNodes.leafNode(datanode, data))
            .build();

    DOMDataWriteTransaction tx = this.globalDomDataBroker.newWriteOnlyTransaction();
    YangInstanceIdentifier yid =
        pid.node(
            new NodeIdentifierWithPredicates(
                org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangpush.rev150105
                    .push.updates.PushUpdate.QNAME,
                men.getIdentifier().getKeyValues()));
    tx.merge(LogicalDatastoreType.CONFIGURATION, yid, men);
    LOG.info("--DATA PATh: {}\n--DATA\n{}", yid, men);
    try {
      tx.submit().checkedGet();
    } catch (TransactionCommitFailedException e) {
      e.printStackTrace();
    }
  }
  @Override
  public MapEntryNode build() {
    for (final Entry<QName, Object> key : getNodeIdentifier().getKeyValues().entrySet()) {
      final DataContainerChild<?, ?> childNode = getChild(childrenQNamesToPaths.get(key.getKey()));

      // We have enough information to fill-in missing leaf nodes, so let's do that
      if (childNode == null) {
        LeafNode<Object> leaf = ImmutableNodes.leafNode(key.getKey(), key.getValue());
        LOG.debug("Adding leaf {} implied by key {}", leaf, key);
        withChild(leaf);
      } else {
        DataValidationException.checkListKey(
            getNodeIdentifier(), key.getKey(), key.getValue(), childNode.getValue());
      }
    }

    return new ImmutableMapEntryNode(getNodeIdentifier(), buildValue(), getAttributes());
  }
  /**
   * Tests backwards compatible serialization/deserialization of a MergeData message with the base
   * and R1 Helium versions, which used the protobuff MergeData message.
   */
  @Test
  public void testSerializationWithHeliumR1Version() throws Exception {
    YangInstanceIdentifier path = TestModel.TEST_PATH;
    NormalizedNode<?, ?> data =
        ImmutableContainerNodeBuilder.create()
            .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
            .withChild(ImmutableNodes.leafNode(TestModel.DESC_QNAME, "foo"))
            .build();

    MergeData expected = new MergeData(path, data, DataStoreVersions.HELIUM_1_VERSION);

    Object serialized = expected.toSerializable();
    assertEquals(
        "Serialized type", ShardTransactionMessages.MergeData.class, serialized.getClass());

    MergeData actual =
        MergeData.fromSerializable(SerializationUtils.clone((Serializable) serialized));
    assertEquals("getPath", expected.getPath(), actual.getPath());
    assertEquals("getData", expected.getData(), actual.getData());
  }
  @Test
  public void testSerialization() {
    YangInstanceIdentifier path = TestModel.TEST_PATH;
    NormalizedNode<?, ?> data =
        ImmutableContainerNodeBuilder.create()
            .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
            .withChild(ImmutableNodes.leafNode(TestModel.DESC_QNAME, "foo"))
            .build();

    MergeData expected = new MergeData(path, data, DataStoreVersions.CURRENT_VERSION);

    Object serialized = expected.toSerializable();
    assertEquals("Serialized type", MergeData.class, serialized.getClass());
    assertEquals(
        "Version", DataStoreVersions.CURRENT_VERSION, ((MergeData) serialized).getVersion());

    Object clone = SerializationUtils.clone((Serializable) serialized);
    MergeData actual = MergeData.fromSerializable(clone);
    assertEquals("Version", DataStoreVersions.CURRENT_VERSION, actual.getVersion());
    assertEquals("getPath", expected.getPath(), actual.getPath());
    assertEquals("getData", expected.getData(), actual.getData());
  }
public class DOMDataTreeListenerTest {

  private SchemaContext schemaContext;
  private AbstractDOMDataBroker domBroker;
  private ListeningExecutorService executor;
  private ExecutorService futureExecutor;
  private CommitExecutorService commitExecutor;

  private static final DataContainerChild<?, ?> OUTER_LIST =
      ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
          .withChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1))
          .build();

  private static final DataContainerChild<?, ?> OUTER_LIST_2 =
      ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
          .withChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2))
          .build();

  private static final NormalizedNode<?, ?> TEST_CONTAINER =
      Builders.containerBuilder()
          .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
          .withChild(OUTER_LIST)
          .build();

  private static final NormalizedNode<?, ?> TEST_CONTAINER_2 =
      Builders.containerBuilder()
          .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
          .withChild(OUTER_LIST_2)
          .build();

  private static DOMDataTreeIdentifier ROOT_DATA_TREE_ID =
      new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);

  private static DOMDataTreeIdentifier OUTER_LIST_DATA_TREE_ID =
      new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, TestModel.OUTER_LIST_PATH);

  @Before
  public void setupStore() {
    InMemoryDOMDataStore operStore =
        new InMemoryDOMDataStore("OPER", MoreExecutors.newDirectExecutorService());
    InMemoryDOMDataStore configStore =
        new InMemoryDOMDataStore("CFG", MoreExecutors.newDirectExecutorService());
    schemaContext = TestModel.createTestContext();

    operStore.onGlobalContextUpdated(schemaContext);
    configStore.onGlobalContextUpdated(schemaContext);

    ImmutableMap<LogicalDatastoreType, DOMStore> stores =
        ImmutableMap.<LogicalDatastoreType, DOMStore>builder() //
            .put(CONFIGURATION, configStore) //
            .put(OPERATIONAL, operStore) //
            .build();

    commitExecutor = new CommitExecutorService(Executors.newSingleThreadExecutor());
    futureExecutor = SpecialExecutors.newBlockingBoundedCachedThreadPool(1, 5, "FCB");
    executor =
        new DeadlockDetectingListeningExecutorService(
            commitExecutor,
            TransactionCommitDeadlockException.DEADLOCK_EXCEPTION_SUPPLIER,
            futureExecutor);
    domBroker = new SerializedDOMDataBroker(stores, executor);
  }

  @After
  public void tearDown() {
    if (executor != null) {
      executor.shutdownNow();
    }

    if (futureExecutor != null) {
      futureExecutor.shutdownNow();
    }
  }

  @Test
  public void writeContainerEmptyTreeTest() throws InterruptedException {
    CountDownLatch latch = new CountDownLatch(1);

    DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
    assertNotNull(
        "DOMDataTreeChangeService not found, cannot continue with test!", dataTreeChangeService);

    final TestDataTreeListener listener = new TestDataTreeListener(latch);
    final ListenerRegistration<TestDataTreeListener> listenerReg =
        dataTreeChangeService.registerDataTreeChangeListener(ROOT_DATA_TREE_ID, listener);

    final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
    writeTx.submit();

    latch.await(5, TimeUnit.SECONDS);

    assertEquals(1, listener.getReceivedChanges().size());
    final Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
    assertEquals(1, changes.size());

    DataTreeCandidate candidate = changes.iterator().next();
    assertNotNull(candidate);
    DataTreeCandidateNode candidateRoot = candidate.getRootNode();
    checkChange(null, TEST_CONTAINER, ModificationType.WRITE, candidateRoot);
    listenerReg.close();
  }

  @Test
  public void replaceContainerContainerInTreeTest()
      throws InterruptedException, TransactionCommitFailedException {
    CountDownLatch latch = new CountDownLatch(2);

    DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
    assertNotNull(
        "DOMDataTreeChangeService not found, cannot continue with test!", dataTreeChangeService);

    DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
    writeTx.submit().checkedGet();

    final TestDataTreeListener listener = new TestDataTreeListener(latch);
    final ListenerRegistration<TestDataTreeListener> listenerReg =
        dataTreeChangeService.registerDataTreeChangeListener(ROOT_DATA_TREE_ID, listener);
    writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER_2);
    writeTx.submit();

    latch.await(5, TimeUnit.SECONDS);

    assertEquals(2, listener.getReceivedChanges().size());
    Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
    assertEquals(1, changes.size());

    DataTreeCandidate candidate = changes.iterator().next();
    assertNotNull(candidate);
    DataTreeCandidateNode candidateRoot = candidate.getRootNode();
    checkChange(null, TEST_CONTAINER, ModificationType.WRITE, candidateRoot);

    changes = listener.getReceivedChanges().get(1);
    assertEquals(1, changes.size());

    candidate = changes.iterator().next();
    assertNotNull(candidate);
    candidateRoot = candidate.getRootNode();
    checkChange(TEST_CONTAINER, TEST_CONTAINER_2, ModificationType.WRITE, candidateRoot);
    listenerReg.close();
  }

  @Test
  public void deleteContainerContainerInTreeTest()
      throws InterruptedException, TransactionCommitFailedException {
    CountDownLatch latch = new CountDownLatch(2);

    DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
    assertNotNull(
        "DOMDataTreeChangeService not found, cannot continue with test!", dataTreeChangeService);

    DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
    writeTx.submit().checkedGet();

    final TestDataTreeListener listener = new TestDataTreeListener(latch);
    final ListenerRegistration<TestDataTreeListener> listenerReg =
        dataTreeChangeService.registerDataTreeChangeListener(ROOT_DATA_TREE_ID, listener);

    writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.delete(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
    writeTx.submit();

    latch.await(5, TimeUnit.SECONDS);

    assertEquals(2, listener.getReceivedChanges().size());
    Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
    assertEquals(1, changes.size());

    DataTreeCandidate candidate = changes.iterator().next();
    assertNotNull(candidate);
    DataTreeCandidateNode candidateRoot = candidate.getRootNode();
    checkChange(null, TEST_CONTAINER, ModificationType.WRITE, candidateRoot);

    changes = listener.getReceivedChanges().get(1);
    assertEquals(1, changes.size());

    candidate = changes.iterator().next();
    assertNotNull(candidate);
    candidateRoot = candidate.getRootNode();
    checkChange(TEST_CONTAINER, null, ModificationType.DELETE, candidateRoot);
    listenerReg.close();
  }

  @Test
  public void replaceChildListContainerInTreeTest()
      throws InterruptedException, TransactionCommitFailedException {
    CountDownLatch latch = new CountDownLatch(2);

    DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
    assertNotNull(
        "DOMDataTreeChangeService not found, cannot continue with test!", dataTreeChangeService);

    DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
    writeTx.submit().checkedGet();

    final TestDataTreeListener listener = new TestDataTreeListener(latch);
    final ListenerRegistration<TestDataTreeListener> listenerReg =
        dataTreeChangeService.registerDataTreeChangeListener(ROOT_DATA_TREE_ID, listener);

    writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.OUTER_LIST_PATH, OUTER_LIST_2);
    writeTx.submit();

    latch.await(5, TimeUnit.SECONDS);

    assertEquals(2, listener.getReceivedChanges().size());
    Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
    assertEquals(1, changes.size());

    DataTreeCandidate candidate = changes.iterator().next();
    assertNotNull(candidate);
    DataTreeCandidateNode candidateRoot = candidate.getRootNode();
    checkChange(null, TEST_CONTAINER, ModificationType.WRITE, candidateRoot);

    changes = listener.getReceivedChanges().get(1);
    assertEquals(1, changes.size());

    candidate = changes.iterator().next();
    assertNotNull(candidate);
    candidateRoot = candidate.getRootNode();
    checkChange(TEST_CONTAINER, TEST_CONTAINER_2, ModificationType.SUBTREE_MODIFIED, candidateRoot);
    final DataTreeCandidateNode modifiedChild =
        candidateRoot.getModifiedChild(
            new YangInstanceIdentifier.NodeIdentifier(TestModel.OUTER_LIST_QNAME));
    assertNotNull(modifiedChild);
    checkChange(OUTER_LIST, OUTER_LIST_2, ModificationType.WRITE, modifiedChild);
    listenerReg.close();
  }

  @Test
  public void rootModificationChildListenerTest()
      throws InterruptedException, TransactionCommitFailedException {
    CountDownLatch latch = new CountDownLatch(2);

    DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
    assertNotNull(
        "DOMDataTreeChangeService not found, cannot continue with test!", dataTreeChangeService);

    DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
    writeTx.submit().checkedGet();

    final TestDataTreeListener listener = new TestDataTreeListener(latch);
    final ListenerRegistration<TestDataTreeListener> listenerReg =
        dataTreeChangeService.registerDataTreeChangeListener(OUTER_LIST_DATA_TREE_ID, listener);

    writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER_2);
    writeTx.submit().checkedGet();

    latch.await(1, TimeUnit.SECONDS);

    assertEquals(2, listener.getReceivedChanges().size());
    Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
    assertEquals(1, changes.size());

    DataTreeCandidate candidate = changes.iterator().next();
    assertNotNull(candidate);
    DataTreeCandidateNode candidateRoot = candidate.getRootNode();
    checkChange(null, OUTER_LIST, ModificationType.WRITE, candidateRoot);

    changes = listener.getReceivedChanges().get(1);
    assertEquals(1, changes.size());

    candidate = changes.iterator().next();
    assertNotNull(candidate);
    candidateRoot = candidate.getRootNode();
    checkChange(OUTER_LIST, OUTER_LIST_2, ModificationType.WRITE, candidateRoot);
    listenerReg.close();
  }

  @Test
  public void listEntryChangeNonRootRegistrationTest()
      throws InterruptedException, TransactionCommitFailedException {
    CountDownLatch latch = new CountDownLatch(2);

    DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
    assertNotNull(
        "DOMDataTreeChangeService not found, cannot continue with test!", dataTreeChangeService);

    DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
    writeTx.submit().checkedGet();

    final TestDataTreeListener listener = new TestDataTreeListener(latch);
    final ListenerRegistration<TestDataTreeListener> listenerReg =
        dataTreeChangeService.registerDataTreeChangeListener(OUTER_LIST_DATA_TREE_ID, listener);

    final YangInstanceIdentifier.NodeIdentifierWithPredicates outerListEntryId1 =
        new YangInstanceIdentifier.NodeIdentifierWithPredicates(
            TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1);
    final YangInstanceIdentifier.NodeIdentifierWithPredicates outerListEntryId2 =
        new YangInstanceIdentifier.NodeIdentifierWithPredicates(
            TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2);
    final YangInstanceIdentifier.NodeIdentifierWithPredicates outerListEntryId3 =
        new YangInstanceIdentifier.NodeIdentifierWithPredicates(
            TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3);

    final MapEntryNode outerListEntry1 =
        ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1);
    final MapEntryNode outerListEntry2 =
        ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2);
    final MapEntryNode outerListEntry3 =
        ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3);

    final MapNode listAfter =
        ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
            .withChild(outerListEntry2)
            .withChild(outerListEntry3)
            .build();

    writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.delete(
        LogicalDatastoreType.CONFIGURATION, TestModel.OUTER_LIST_PATH.node(outerListEntryId1));
    writeTx.put(
        LogicalDatastoreType.CONFIGURATION,
        TestModel.OUTER_LIST_PATH.node(outerListEntryId2),
        outerListEntry2);
    writeTx.put(
        LogicalDatastoreType.CONFIGURATION,
        TestModel.OUTER_LIST_PATH.node(outerListEntryId3),
        outerListEntry3);
    writeTx.submit();

    latch.await(5, TimeUnit.SECONDS);

    assertEquals(2, listener.getReceivedChanges().size());
    Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
    assertEquals(1, changes.size());

    DataTreeCandidate candidate = changes.iterator().next();
    assertNotNull(candidate);
    DataTreeCandidateNode candidateRoot = candidate.getRootNode();
    checkChange(null, OUTER_LIST, ModificationType.WRITE, candidateRoot);

    changes = listener.getReceivedChanges().get(1);
    assertEquals(1, changes.size());

    candidate = changes.iterator().next();
    assertNotNull(candidate);
    candidateRoot = candidate.getRootNode();
    checkChange(OUTER_LIST, listAfter, ModificationType.SUBTREE_MODIFIED, candidateRoot);
    final DataTreeCandidateNode entry1Canditate = candidateRoot.getModifiedChild(outerListEntryId1);
    checkChange(outerListEntry1, null, ModificationType.DELETE, entry1Canditate);
    final DataTreeCandidateNode entry2Canditate = candidateRoot.getModifiedChild(outerListEntryId2);
    checkChange(null, outerListEntry2, ModificationType.WRITE, entry2Canditate);
    final DataTreeCandidateNode entry3Canditate = candidateRoot.getModifiedChild(outerListEntryId3);
    checkChange(null, outerListEntry3, ModificationType.WRITE, entry3Canditate);
    listenerReg.close();
  }

  private static void checkChange(
      final NormalizedNode<?, ?> expectedBefore,
      final NormalizedNode<?, ?> expectedAfter,
      final ModificationType expectedMod,
      final DataTreeCandidateNode candidateNode) {
    if (expectedBefore != null) {
      assertTrue(candidateNode.getDataBefore().isPresent());
      assertEquals(expectedBefore, candidateNode.getDataBefore().get());
    } else {
      assertFalse(candidateNode.getDataBefore().isPresent());
    }

    if (expectedAfter != null) {
      assertTrue(candidateNode.getDataAfter().isPresent());
      assertEquals(expectedAfter, candidateNode.getDataAfter().get());
    } else {
      assertFalse(candidateNode.getDataAfter().isPresent());
    }

    assertEquals(expectedMod, candidateNode.getModificationType());
  }

  private DOMDataTreeChangeService getDOMDataTreeChangeService() {
    final DOMDataBrokerExtension extension =
        domBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
    if (extension == null) {
      return null;
    }
    DOMDataTreeChangeService dataTreeChangeService = null;
    if (extension instanceof DOMDataTreeChangeService) {
      dataTreeChangeService = (DOMDataTreeChangeService) extension;
    }
    return dataTreeChangeService;
  }

  static class CommitExecutorService extends ForwardingExecutorService {

    ExecutorService delegate;

    public CommitExecutorService(final ExecutorService delegate) {
      this.delegate = delegate;
    }

    @Override
    protected ExecutorService delegate() {
      return delegate;
    }
  }

  static class TestDataTreeListener implements DOMDataTreeChangeListener {

    private final List<Collection<DataTreeCandidate>> receivedChanges = new ArrayList<>();
    private final CountDownLatch latch;

    public TestDataTreeListener(final CountDownLatch latch) {
      this.latch = latch;
    }

    @Override
    public void onDataTreeChanged(@Nonnull final Collection<DataTreeCandidate> changes) {
      receivedChanges.add(changes);
      latch.countDown();
    }

    public List<Collection<DataTreeCandidate>> getReceivedChanges() {
      return receivedChanges;
    }
  }
}
  @Test
  public void listEntryChangeNonRootRegistrationTest()
      throws InterruptedException, TransactionCommitFailedException {
    CountDownLatch latch = new CountDownLatch(2);

    DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
    assertNotNull(
        "DOMDataTreeChangeService not found, cannot continue with test!", dataTreeChangeService);

    DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
    writeTx.submit().checkedGet();

    final TestDataTreeListener listener = new TestDataTreeListener(latch);
    final ListenerRegistration<TestDataTreeListener> listenerReg =
        dataTreeChangeService.registerDataTreeChangeListener(OUTER_LIST_DATA_TREE_ID, listener);

    final YangInstanceIdentifier.NodeIdentifierWithPredicates outerListEntryId1 =
        new YangInstanceIdentifier.NodeIdentifierWithPredicates(
            TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1);
    final YangInstanceIdentifier.NodeIdentifierWithPredicates outerListEntryId2 =
        new YangInstanceIdentifier.NodeIdentifierWithPredicates(
            TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2);
    final YangInstanceIdentifier.NodeIdentifierWithPredicates outerListEntryId3 =
        new YangInstanceIdentifier.NodeIdentifierWithPredicates(
            TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3);

    final MapEntryNode outerListEntry1 =
        ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1);
    final MapEntryNode outerListEntry2 =
        ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2);
    final MapEntryNode outerListEntry3 =
        ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3);

    final MapNode listAfter =
        ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
            .withChild(outerListEntry2)
            .withChild(outerListEntry3)
            .build();

    writeTx = domBroker.newWriteOnlyTransaction();
    writeTx.delete(
        LogicalDatastoreType.CONFIGURATION, TestModel.OUTER_LIST_PATH.node(outerListEntryId1));
    writeTx.put(
        LogicalDatastoreType.CONFIGURATION,
        TestModel.OUTER_LIST_PATH.node(outerListEntryId2),
        outerListEntry2);
    writeTx.put(
        LogicalDatastoreType.CONFIGURATION,
        TestModel.OUTER_LIST_PATH.node(outerListEntryId3),
        outerListEntry3);
    writeTx.submit();

    latch.await(5, TimeUnit.SECONDS);

    assertEquals(2, listener.getReceivedChanges().size());
    Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
    assertEquals(1, changes.size());

    DataTreeCandidate candidate = changes.iterator().next();
    assertNotNull(candidate);
    DataTreeCandidateNode candidateRoot = candidate.getRootNode();
    checkChange(null, OUTER_LIST, ModificationType.WRITE, candidateRoot);

    changes = listener.getReceivedChanges().get(1);
    assertEquals(1, changes.size());

    candidate = changes.iterator().next();
    assertNotNull(candidate);
    candidateRoot = candidate.getRootNode();
    checkChange(OUTER_LIST, listAfter, ModificationType.SUBTREE_MODIFIED, candidateRoot);
    final DataTreeCandidateNode entry1Canditate = candidateRoot.getModifiedChild(outerListEntryId1);
    checkChange(outerListEntry1, null, ModificationType.DELETE, entry1Canditate);
    final DataTreeCandidateNode entry2Canditate = candidateRoot.getModifiedChild(outerListEntryId2);
    checkChange(null, outerListEntry2, ModificationType.WRITE, entry2Canditate);
    final DataTreeCandidateNode entry3Canditate = candidateRoot.getModifiedChild(outerListEntryId3);
    checkChange(null, outerListEntry3, ModificationType.WRITE, entry3Canditate);
    listenerReg.close();
  }
 public static DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> nestedList(
     final String key) {
   return ImmutableNodes.mapEntryBuilder(NestedList.QNAME, NAME_QNAME, key);
 }
 protected static CollectionNodeBuilder<MapEntryNode, MapNode> topLevelMap() {
   return ImmutableNodes.mapNodeBuilder(TopLevelList.QNAME);
 }
  /** Test case: TerminationPoint translation */
  @Test
  public void testTerminationPoint() {
    String logicalName = "node:1";

    final String tpId1 = "tpId:1";
    String tpRef1 = "tpRef:1";
    String tpId2 = "tpId:2";
    String tpRef2 = "tpRef:2";
    String tpId3 = "tpId:3";
    String tpRef3 = "tpRef:3";
    String tpId4 = "tpId:4";
    String tpRef4 = "tpRef:4";

    final String physicalName1 = "node:1";
    MapNode terminationPoints1 =
        ImmutableNodes.mapNodeBuilder(TerminationPoint.QNAME)
            .withChild(
                ImmutableNodes.mapEntryBuilder(
                        TerminationPoint.QNAME, TopologyQNames.NETWORK_TP_ID_QNAME, tpId1)
                    .withChild(ImmutableNodes.leafNode(TopologyQNames.NETWORK_TP_ID_QNAME, tpId1))
                    .withChild(ImmutableNodes.leafNode(TopologyQNames.TP_REF, tpRef1))
                    .build())
            .withChild(
                ImmutableNodes.mapEntryBuilder(
                        TerminationPoint.QNAME, TopologyQNames.NETWORK_TP_ID_QNAME, tpId2)
                    .withChild(ImmutableNodes.leafNode(TopologyQNames.NETWORK_TP_ID_QNAME, tpId2))
                    .withChild(ImmutableNodes.leafNode(TopologyQNames.TP_REF, tpRef2))
                    .build())
            .build();
    final MapEntryNode node1 =
        ImmutableNodes.mapEntryBuilder(
                Node.QNAME, TopologyQNames.NETWORK_NODE_ID_QNAME, physicalName1)
            .withChild(terminationPoints1)
            .build();

    final String physicalName2 = "node:2";
    MapNode terminationPoints2 =
        ImmutableNodes.mapNodeBuilder(TerminationPoint.QNAME)
            .withChild(
                ImmutableNodes.mapEntryBuilder(
                        TerminationPoint.QNAME, TopologyQNames.NETWORK_TP_ID_QNAME, tpId1)
                    .withChild(ImmutableNodes.leafNode(TopologyQNames.NETWORK_TP_ID_QNAME, tpId1))
                    .withChild(ImmutableNodes.leafNode(TopologyQNames.TP_REF, tpRef1))
                    .build())
            .withChild(
                ImmutableNodes.mapEntryBuilder(
                        TerminationPoint.QNAME, TopologyQNames.NETWORK_TP_ID_QNAME, tpId3)
                    .withChild(ImmutableNodes.leafNode(TopologyQNames.NETWORK_TP_ID_QNAME, tpId3))
                    .withChild(ImmutableNodes.leafNode(TopologyQNames.TP_REF, tpRef3))
                    .build())
            .build();
    final MapEntryNode node2 =
        ImmutableNodes.mapEntryBuilder(
                Node.QNAME, TopologyQNames.NETWORK_NODE_ID_QNAME, physicalName2)
            .withChild(terminationPoints2)
            .build();

    final String physicalName3 = "node:3";
    MapNode terminationPoints3 =
        ImmutableNodes.mapNodeBuilder(TerminationPoint.QNAME)
            .withChild(
                ImmutableNodes.mapEntryBuilder(
                        TerminationPoint.QNAME, TopologyQNames.NETWORK_TP_ID_QNAME, tpId2)
                    .withChild(ImmutableNodes.leafNode(TopologyQNames.NETWORK_TP_ID_QNAME, tpId2))
                    .withChild(ImmutableNodes.leafNode(TopologyQNames.TP_REF, tpRef2))
                    .build())
            .withChild(
                ImmutableNodes.mapEntryBuilder(
                        TerminationPoint.QNAME, TopologyQNames.NETWORK_TP_ID_QNAME, tpId4)
                    .withChild(ImmutableNodes.leafNode(TopologyQNames.NETWORK_TP_ID_QNAME, tpId4))
                    .withChild(ImmutableNodes.leafNode(TopologyQNames.TP_REF, tpRef4))
                    .build())
            .build();
    final MapEntryNode node3 =
        ImmutableNodes.mapEntryBuilder(
                Node.QNAME, TopologyQNames.NETWORK_NODE_ID_QNAME, physicalName3)
            .withChild(terminationPoints3)
            .build();

    final Map<Integer, NormalizedNode<?, ?>> targetFields = new HashMap<>(1);
    targetFields.put(0, mockNormalizedNode);
    OverlayItem logicalNode1 =
        new OverlayItem(
            new ArrayList<UnderlayItem>() {
              {
                add(
                    new UnderlayItem(
                        node1,
                        targetFields,
                        TOPOLOGY_NAME,
                        physicalName1,
                        CorrelationItemEnum.Node));
                add(
                    new UnderlayItem(
                        node2,
                        targetFields,
                        TOPOLOGY_NAME,
                        physicalName2,
                        CorrelationItemEnum.Node));
              }
            },
            CorrelationItemEnum.Node);
    OverlayItem logicalNode2 =
        new OverlayItem(
            Collections.singletonList(
                new UnderlayItem(
                    node3, targetFields, TOPOLOGY_NAME, physicalName3, CorrelationItemEnum.Node)),
            CorrelationItemEnum.Node);
    OverlayItemWrapper wrapper = new OverlayItemWrapper(logicalName, logicalNode1);
    wrapper.addOverlayItem(logicalNode2);
    NormalizedNode<?, ?> normalizedNode = translator.translate(wrapper);

    Collection value =
        (Collection)
            ((MapEntryNode) normalizedNode)
                .getChild(new NodeIdentifier(TerminationPoint.QNAME))
                .get()
                .getValue();
    Assert.assertEquals("OverlayNode contains wrong amount of TerminationPoints", 6, value.size());
  }