From: Tomas Cere Date: Mon, 27 Mar 2017 11:17:11 +0000 (+0200) Subject: Bug 7804: Implement agent RPCs for DOMDataTreeListener testing X-Git-Tag: release/carbon~116 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=1cc64603a97e49d153e16328b3b4a7d0926e086d Bug 7804: Implement agent RPCs for DOMDataTreeListener testing Change-Id: I9e57e169fc3151a12914b2f370e0c97f41395992 Signed-off-by: Tomas Cere --- diff --git a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/MdsalLowLevelTestProvider.java b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/MdsalLowLevelTestProvider.java index d653a2c30b..15c9d8ea60 100644 --- a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/MdsalLowLevelTestProvider.java +++ b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/MdsalLowLevelTestProvider.java @@ -8,16 +8,23 @@ package org.opendaylight.controller.clustering.it.provider; +import com.google.common.base.Preconditions; import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import javax.annotation.Nonnull; import org.opendaylight.controller.cluster.sharding.DistributedShardFactory; import org.opendaylight.controller.clustering.it.provider.impl.FlappingSingletonService; import org.opendaylight.controller.clustering.it.provider.impl.GetConstantService; +import org.opendaylight.controller.clustering.it.provider.impl.IdIntsDOMDataTreeLIstener; import org.opendaylight.controller.clustering.it.provider.impl.PrefixShardHandler; import org.opendaylight.controller.clustering.it.provider.impl.ProduceTransactionsHandler; import org.opendaylight.controller.clustering.it.provider.impl.PublishNotificationsTask; @@ -34,6 +41,11 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; +import org.opendaylight.mdsal.dom.api.DOMDataTreeListener; +import org.opendaylight.mdsal.dom.api.DOMDataTreeListeningException; +import org.opendaylight.mdsal.dom.api.DOMDataTreeLoopException; import org.opendaylight.mdsal.dom.api.DOMDataTreeService; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration; @@ -59,6 +71,7 @@ import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.l import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.UnregisterFlappingSingletonOutput; import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.UnregisterFlappingSingletonOutputBuilder; import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.UnsubscribeDdtlOutput; +import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.UnsubscribeDdtlOutputBuilder; import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.UnsubscribeDtclOutput; import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.UnsubscribeYnlInput; import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.UnsubscribeYnlOutput; @@ -70,6 +83,8 @@ import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -99,6 +114,8 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService private ClusterSingletonServiceRegistration getSingletonConstantRegistration; private FlappingSingletonService flappingSingletonService; private Map publishNotificationsTasks = new HashMap<>(); + private ListenerRegistration ddtlReg; + private IdIntsDOMDataTreeLIstener idIntsDdtl; public MdsalLowLevelTestProvider(final RpcProviderRegistry rpcRegistry, final DOMRpcProviderService domRpcService, @@ -307,7 +324,27 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService @Override public Future> subscribeDdtl() { - return null; + + if (ddtlReg != null) { + final RpcError error = RpcResultBuilder.newError(ErrorType.RPC, "Registration present.", + "There is already dataTreeChangeListener registered on id-ints list."); + return Futures.immediateFuture(RpcResultBuilder.failed().withRpcError(error).build()); + } + + idIntsDdtl = new IdIntsDOMDataTreeLIstener(); + + try { + ddtlReg = + domDataTreeService.registerListener(idIntsDdtl, + Collections.singleton(new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, + ProduceTransactionsHandler.ID_INTS_YID)) + , true, Collections.emptyList()); + } catch (DOMDataTreeLoopException e) { + LOG.error("Failed to register DOMDataTreeListener.", e); + + } + + return Futures.immediateFuture(RpcResultBuilder.success().build()); } @Override @@ -460,6 +497,79 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService @Override public Future> unsubscribeDdtl() { - return null; + LOG.debug("Received unsubscribe-ddtl."); + + if (idIntsDdtl == null || ddtlReg == null) { + final RpcError error = RpcResultBuilder.newError( + ErrorType.RPC, "Ddtl missing.", "No DOMDataTreeListener registered."); + return Futures.immediateFuture(RpcResultBuilder.failed().withRpcError(error).build()); + } + + ddtlReg.close(); + ddtlReg = null; + + final ReadListener readListener = new ReadListener(); + try { + final ListenerRegistration registration = domDataTreeService.registerListener(readListener, + Collections.singleton(new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, + ProduceTransactionsHandler.ID_INTS_YID)) + , true, Collections.emptyList()); + + final DataTreeCandidate dataTreeCandidate = readListener.getFirstNotif().get(); + registration.close(); + + if (!dataTreeCandidate.getRootNode().getDataAfter().isPresent()) { + final RpcError error = RpcResultBuilder.newError( + ErrorType.APPLICATION, "Final read empty.", "No data read from id-ints list."); + return Futures.immediateFuture(RpcResultBuilder.failed() + .withRpcError(error).build()); + } + + final NormalizedNode lastRead = dataTreeCandidate.getRootNode().getDataAfter().get(); + + return Futures.immediateFuture( + RpcResultBuilder.success(new UnsubscribeDdtlOutputBuilder() + .setCopyMatches(idIntsDdtl.checkEqual(lastRead))).build()); + + + } catch (final DOMDataTreeLoopException | InterruptedException | ExecutionException e) { + LOG.error("Unable to read data to verify ddtl data.", e); + final RpcError error = RpcResultBuilder.newError( + ErrorType.APPLICATION, "Read failed.", "Final read from id-ints failed."); + return Futures.immediateFuture(RpcResultBuilder.failed() + .withRpcError(error).build()); + } + } + + private static class ReadListener implements DOMDataTreeListener { + + private Collection changes = null; + private SettableFuture readFuture; + + @Override + public synchronized void onDataTreeChanged(@Nonnull final Collection changes, + @Nonnull final Map> subtrees) { + Preconditions.checkArgument(changes.size() == 1); + + if (this.changes == null) { + this.changes = changes; + + readFuture.set(changes.iterator().next()); + } + } + + @Override + public void onDataTreeFailed(@Nonnull final Collection causes) { + LOG.error("Read Listener failed. {}", causes); + } + + public synchronized ListenableFuture getFirstNotif() { + if (changes != null) { + return Futures.immediateFuture(changes.iterator().next()); + } + + readFuture = SettableFuture.create(); + return readFuture; + } } } diff --git a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/IdIntsDOMDataTreeLIstener.java b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/IdIntsDOMDataTreeLIstener.java new file mode 100644 index 0000000000..be46a0ee31 --- /dev/null +++ b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/IdIntsDOMDataTreeLIstener.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017 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.controller.clustering.it.provider.impl; + +import com.google.common.base.Preconditions; +import java.util.Collection; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; +import org.opendaylight.mdsal.dom.api.DOMDataTreeListener; +import org.opendaylight.mdsal.dom.api.DOMDataTreeListeningException; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class IdIntsDOMDataTreeLIstener implements DOMDataTreeListener { + + private static final Logger LOG = LoggerFactory.getLogger(IdIntsDOMDataTreeLIstener.class); + + private NormalizedNode localCopy = null; + + @Override + public void onDataTreeChanged(@Nonnull final Collection changes, + @Nonnull final Map> subtrees) { + + // There should only be one candidate reported + Preconditions.checkState(changes.size() == 1); + + // 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: ", 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); + } + } else { + LOG.warn("getDataAfter() is missing from notification. change: {}", change); + } + }); + } + + @Override + public void onDataTreeFailed(@Nonnull Collection causes) { + + } + + public boolean checkEqual(final NormalizedNode expected) { + return localCopy.equals(expected); + } +} diff --git a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/ProduceTransactionsHandler.java b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/ProduceTransactionsHandler.java index 49024ef283..ee46a74746 100644 --- a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/ProduceTransactionsHandler.java +++ b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/ProduceTransactionsHandler.java @@ -63,7 +63,7 @@ public class ProduceTransactionsHandler implements Runnable { private static final QName NUMBER = QName.create("tag:opendaylight.org,2017:controller:yang:lowlevel:target", "2017-02-15", "number"); - private final YangInstanceIdentifier ID_INTS_YID = + public static final YangInstanceIdentifier ID_INTS_YID = YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(ID_INTS)); private final DOMDataTreeService domDataTreeService;