X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsamples%2Fclustering-test-app%2Fprovider%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fclustering%2Fit%2Fprovider%2Fimpl%2FIdIntsListener.java;h=14e728d286bdfb4b2fdcdf4e106a1828fb053a54;hb=5f587c3e2bfabc09fec49463d04a6fbeba414e9c;hp=c5c4eb95308ce2cdd94dc95cecf634b9d52b46df;hpb=5997e14efab9c12e7be2b7fb83f7efe16c2bfe7c;p=controller.git diff --git a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/IdIntsListener.java b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/IdIntsListener.java index c5c4eb9530..14e728d286 100644 --- a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/IdIntsListener.java +++ b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/IdIntsListener.java @@ -5,48 +5,61 @@ * 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.controller.clustering.it.provider.impl; -import com.google.common.base.Preconditions; +import static com.google.common.base.Preconditions.checkState; +import static org.opendaylight.controller.clustering.it.provider.impl.AbstractTransactionHandler.ITEM; + +import com.google.common.util.concurrent.SettableFuture; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Collection; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import org.opendaylight.mdsal.dom.api.ClusteredDOMDataTreeChangeListener; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; -import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; -import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class IdIntsListener implements DOMDataTreeChangeListener { +public class IdIntsListener implements ClusteredDOMDataTreeChangeListener { private static final Logger LOG = LoggerFactory.getLogger(IdIntsListener.class); + private static final long SECOND_AS_NANO = 1000000000; - private NormalizedNode localCopy = null; + private volatile NormalizedNode localCopy; + private final AtomicLong lastNotifTimestamp = new AtomicLong(0); + private ScheduledExecutorService executorService; + private ScheduledFuture scheduledFuture; @Override - public void onDataTreeChanged(@Nonnull final Collection changes) { + public void onDataTreeChanged(final Collection changes) { // There should only be one candidate reported - Preconditions.checkState(changes.size() == 1); + checkState(changes.size() == 1); + + lastNotifTimestamp.set(System.nanoTime()); // do not log the change into debug, only use trace since it will lead to OOM on default heap settings LOG.debug("Received data tree changed"); changes.forEach(change -> { if (change.getRootNode().getDataAfter().isPresent()) { - LOG.trace("Received change, data before: {}, data after: ", + LOG.trace("Received change, data before: {}, data after: {}", change.getRootNode().getDataBefore().isPresent() ? change.getRootNode().getDataBefore().get() : "", change.getRootNode().getDataAfter().get()); - if (localCopy == null || checkEqual(change.getRootNode().getDataBefore().get())) { - localCopy = change.getRootNode().getDataAfter().get(); - } else { - LOG.debug("Ignoring notification: {}", change); - } + localCopy = change.getRootNode().getDataAfter().get(); } else { LOG.warn("getDataAfter() is missing from notification. change: {}", change); } @@ -60,4 +73,75 @@ public class IdIntsListener implements DOMDataTreeChangeListener { public boolean checkEqual(final NormalizedNode expected) { return localCopy.equals(expected); } + + @SuppressFBWarnings("BC_UNCONFIRMED_CAST") + public String diffWithLocalCopy(final NormalizedNode expected) { + return diffNodes((MapNode)expected, (MapNode)localCopy); + } + + public Future tryFinishProcessing() { + executorService = Executors.newSingleThreadScheduledExecutor(); + final SettableFuture settableFuture = SettableFuture.create(); + + scheduledFuture = executorService.scheduleAtFixedRate(new CheckFinishedTask(settableFuture), + 0, 1, TimeUnit.SECONDS); + return settableFuture; + } + + public static String diffNodes(final MapNode expected, final MapNode actual) { + StringBuilder builder = new StringBuilder("MapNodes diff:"); + + final YangInstanceIdentifier.NodeIdentifier itemNodeId = new YangInstanceIdentifier.NodeIdentifier(ITEM); + + Map expIdIntMap = new HashMap<>(); + expected.getValue().forEach(node -> expIdIntMap.put(node.getIdentifier(), node)); + + actual.getValue().forEach(actIdInt -> { + final MapEntryNode expIdInt = expIdIntMap.remove(actIdInt.getIdentifier()); + if (expIdInt == null) { + builder.append('\n').append(" Unexpected id-int entry for ").append(actIdInt.getIdentifier()); + return; + } + + Map expItemMap = new HashMap<>(); + ((MapNode)expIdInt.getChild(itemNodeId).get()).getValue() + .forEach(node -> expItemMap.put(node.getIdentifier(), node)); + + ((MapNode)actIdInt.getChild(itemNodeId).get()).getValue().forEach(actItem -> { + final MapEntryNode expItem = expItemMap.remove(actItem.getIdentifier()); + if (expItem == null) { + builder.append('\n').append(" Unexpected item entry ").append(actItem.getIdentifier()) + .append(" for id-int entry ").append(actIdInt.getIdentifier()); + } + }); + + expItemMap.values().forEach(node -> builder.append('\n') + .append(" Actual is missing item entry ").append(node.getIdentifier()) + .append(" for id-int entry ").append(actIdInt.getIdentifier())); + }); + + expIdIntMap.values().forEach(node -> builder.append('\n') + .append(" Actual is missing id-int entry for ").append(node.getIdentifier())); + + return builder.toString(); + } + + private class CheckFinishedTask implements Runnable { + + private final SettableFuture future; + + CheckFinishedTask(final SettableFuture future) { + this.future = future; + } + + @Override + public void run() { + if (System.nanoTime() - lastNotifTimestamp.get() > SECOND_AS_NANO * 4) { + scheduledFuture.cancel(false); + future.set(null); + + executorService.shutdown(); + } + } + } }