2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.netconf.topology;
11 import static com.jayway.awaitility.Awaitility.await;
12 import static org.mockito.Matchers.any;
13 import static org.mockito.Mockito.when;
15 import akka.actor.ActorRef;
16 import akka.actor.ActorSystem;
17 import akka.actor.TypedActor;
18 import akka.actor.TypedActorExtension;
19 import akka.actor.TypedProps;
20 import akka.japi.Creator;
21 import com.google.common.base.Optional;
22 import com.google.common.base.Preconditions;
23 import com.google.common.collect.Lists;
24 import com.google.common.util.concurrent.FutureCallback;
25 import com.google.common.util.concurrent.Futures;
26 import com.google.common.util.concurrent.ListenableFuture;
27 import com.google.common.util.concurrent.SettableFuture;
28 import com.typesafe.config.ConfigFactory;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.List;
32 import java.util.concurrent.Callable;
33 import java.util.concurrent.ExecutorService;
34 import java.util.concurrent.Executors;
35 import java.util.concurrent.TimeUnit;
36 import javassist.ClassPool;
37 import javax.annotation.Nonnull;
38 import org.junit.Before;
39 import org.junit.Ignore;
40 import org.junit.Test;
41 import org.mockito.Mock;
42 import org.mockito.MockitoAnnotations;
43 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
44 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
45 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
46 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
47 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
48 import org.opendaylight.netconf.topology.NodeManagerCallback.NodeManagerCallbackFactory;
49 import org.opendaylight.netconf.topology.TopologyManagerCallback.TopologyManagerCallbackFactory;
50 import org.opendaylight.netconf.topology.example.ExampleNodeManagerCallback;
51 import org.opendaylight.netconf.topology.example.ExampleTopologyManagerCallback;
52 import org.opendaylight.netconf.topology.example.LoggingSalNodeWriter;
53 import org.opendaylight.netconf.topology.impl.NetconfNodeOperationalDataAggregator;
54 import org.opendaylight.netconf.topology.util.BaseTopologyManager;
55 import org.opendaylight.netconf.topology.util.NoopRoleChangeStrategy;
56 import org.opendaylight.netconf.topology.util.TopologyRoleChangeStrategy;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.$YangModuleInfoImpl;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.ClusteredConnectionStatusBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.clustered.connection.status.NodeStatus.Status;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.clustered.connection.status.NodeStatusBuilder;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
71 import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
72 import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
73 import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
74 import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
75 import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
77 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
81 public class ActorTest {
83 private static final Logger LOG = LoggerFactory.getLogger(ActorTest.class);
85 private static final String TOPOLOGY_NETCONF = "TopologyNetconf";
88 private EntityOwnershipService entityOwnershipService;
91 private DataBroker dataBroker;
93 private static final BindingNormalizedNodeCodecRegistry CODEC_REGISTRY;
96 final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
97 moduleInfoBackedContext.addModuleInfos(Collections.singletonList($YangModuleInfoImpl.getInstance()));
98 final Optional<SchemaContext> schemaContextOptional = moduleInfoBackedContext.tryToCreateSchemaContext();
99 Preconditions.checkState(schemaContextOptional.isPresent());
100 final SchemaContext topologySchemaCtx = schemaContextOptional.get();
102 final JavassistUtils javassist = JavassistUtils.forClassPool(ClassPool.getDefault());
103 CODEC_REGISTRY = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(javassist));
104 CODEC_REGISTRY.onBindingRuntimeContextUpdated(BindingRuntimeContext.create(moduleInfoBackedContext, topologySchemaCtx));
107 private static final String PATH_MASTER = "akka.tcp://NetconfNode@127.0.0.1:2552/user/TopologyNetconf";
108 private static final String PATH_SLAVE1 = "akka.tcp://NetconfNode@127.0.0.1:2553/user/TopologyNetconf";
109 private static final String PATH_SLAVE2 = "akka.tcp://NetconfNode@127.0.0.1:2554/user/TopologyNetconf";
111 private static final List<String> PATHS_MASTER = Lists.newArrayList(PATH_SLAVE1, PATH_SLAVE2);
112 private static final List<String> PATHS_SLAVE1 = Lists.newArrayList(PATH_MASTER, PATH_SLAVE2);
113 private static final List<String> PATHS_SLAVE2 = Lists.newArrayList(PATH_MASTER, PATH_SLAVE1);
115 private static final ActorSystem ACTOR_SYSTEM = ActorSystem.create("NetconfNode", ConfigFactory.load("netconf-node1"));
116 private static final ActorSystem ACTOR_SYSTEM_SLAVE1 = ActorSystem.create("NetconfNode", ConfigFactory.load("netconf-node2"));
117 private static final ActorSystem ACTOR_SYSTEM_SLAVE2 = ActorSystem.create("NetconfNode", ConfigFactory.load("netconf-node3"));
119 private static final ExecutorService callbackExecutor = Executors.newFixedThreadPool(8);
121 private TopologyManager master = null;
124 public void setup() {
125 MockitoAnnotations.initMocks(this);
126 when(dataBroker.registerDataChangeListener(
127 any(LogicalDatastoreType.class),
128 any(InstanceIdentifier.class),
129 any(DataChangeListener.class),
130 any(DataChangeScope.class))).thenReturn(null);
133 private void setMaster(final TopologyManager manager) {
138 public void testRealActors() throws Exception {
140 EntityOwnershipService topoOwnership = new TestingEntityOwnershipService();
142 final TopologyManager master = createManagerWithOwnership(ACTOR_SYSTEM, TOPOLOGY_NETCONF, true, createRealTopoTestingNodeCallbackFactory(), new TopologyRoleChangeStrategy(dataBroker, topoOwnership, TOPOLOGY_NETCONF, "topology-manager"));
144 final TopologyManager slave1 = createManagerWithOwnership(ACTOR_SYSTEM_SLAVE1, TOPOLOGY_NETCONF, false, createRealTopoTestingNodeCallbackFactory(), new TopologyRoleChangeStrategy(dataBroker, topoOwnership, TOPOLOGY_NETCONF, "topology-manager"));
145 final TopologyManager slave2 = createManagerWithOwnership(ACTOR_SYSTEM_SLAVE2, TOPOLOGY_NETCONF, false, createRealTopoTestingNodeCallbackFactory(), new TopologyRoleChangeStrategy(dataBroker, topoOwnership, TOPOLOGY_NETCONF, "topology-manager"));
147 await().atMost(30L, TimeUnit.SECONDS).until(new Callable<Boolean>() {
149 public Boolean call() throws Exception {
150 return master.hasAllPeersUp();
154 final List<ListenableFuture<Node>> futures = new ArrayList<>();
155 for (int i = 0; i <= 1; i++) {
156 final String nodeid = "testing-node" + i;
157 final Node testingNode = new NodeBuilder()
158 .setNodeId(new NodeId(nodeid))
159 .addAugmentation(NetconfNode.class,
160 new NetconfNodeBuilder()
161 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
162 .setPort(new PortNumber(10000 + i))
165 final ListenableFuture<Node> nodeListenableFuture = master.onNodeCreated(new NodeId(nodeid), testingNode);
166 futures.add(nodeListenableFuture);
167 Futures.addCallback(nodeListenableFuture, new FutureCallback<Node>() {
169 public void onSuccess(Node result) {
170 LOG.warn("Node {} created succesfully on all nodes", result.getNodeId().getValue());
174 public void onFailure(Throwable t) {
175 LOG.warn("Node creation failed. ", t);
180 for (int i = 0; i <= 1; i++) {
181 final String nodeid = "testing-node" + i;
182 final Node testingNode = new NodeBuilder()
183 .setNodeId(new NodeId(nodeid))
184 .addAugmentation(NetconfNode.class,
185 new NetconfNodeBuilder()
186 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
187 .setPort(new PortNumber(10000 + i))
190 final ListenableFuture<Node> nodeListenableFuture = master.onNodeUpdated(new NodeId(nodeid), testingNode);
191 futures.add(nodeListenableFuture);
192 Futures.addCallback(nodeListenableFuture, new FutureCallback<Node>() {
194 public void onSuccess(Node result) {
195 LOG.warn("Node {} updated succesfully on all nodes", result.getNodeId().getValue());
199 public void onFailure(Throwable t) {
200 LOG.warn("Node update failed. ", t);
206 final List<ListenableFuture<Void>> deleteFutures = new ArrayList<>();
207 for (int i = 0; i <= 1; i++) {
208 final String nodeid = "testing-node" + i;
209 final ListenableFuture<Void> nodeListenableFuture = master.onNodeDeleted(new NodeId(nodeid));
210 deleteFutures.add(nodeListenableFuture);
211 Futures.addCallback(nodeListenableFuture, new FutureCallback<Void>() {
213 public void onSuccess(Void result) {
214 LOG.warn("Node {} succesfully deleted on all nodes", nodeid);
218 public void onFailure(Throwable t) {
219 LOG.warn("Node delete failed. ", t);
224 LOG.warn("All tasks submitted");
225 Futures.allAsList(futures).get();
226 Futures.allAsList(deleteFutures).get();
228 TypedActor.get(ACTOR_SYSTEM).stop(master);
229 TypedActor.get(ACTOR_SYSTEM_SLAVE1).stop(slave1);
230 TypedActor.get(ACTOR_SYSTEM_SLAVE2).stop(slave2);
234 // TODO seems like stopping actors is not enough to create an actor with same name, split this into multiple classes?
237 public void testWithDummyOwnershipService() throws Exception {
239 final TestingEntityOwnershipService ownershipService = new TestingEntityOwnershipService();
241 final TopologyManager master = createNoopRoleChangeNode(ACTOR_SYSTEM, TOPOLOGY_NETCONF, true, createRealTopoCallbackFactory(ownershipService));
242 final TopologyManager slave1 = createNoopRoleChangeNode(ACTOR_SYSTEM_SLAVE1, TOPOLOGY_NETCONF, false, createRealTopoCallbackFactory(ownershipService));
243 final TopologyManager slave2 = createNoopRoleChangeNode(ACTOR_SYSTEM_SLAVE2, TOPOLOGY_NETCONF, false, createRealTopoCallbackFactory(ownershipService));
245 await().atMost(10L, TimeUnit.SECONDS).until(new Callable<Boolean>() {
247 public Boolean call() throws Exception {
248 return master.hasAllPeersUp();
252 final List<ListenableFuture<Node>> futures = new ArrayList<>();
253 for (int i = 0; i <= 0; i++) {
254 final String nodeid = "testing-node" + i;
255 final Node testingNode = new NodeBuilder()
256 .setNodeId(new NodeId(nodeid))
257 .addAugmentation(NetconfNode.class,
258 new NetconfNodeBuilder()
259 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
260 .setPort(new PortNumber(10000 + i))
263 final ListenableFuture<Node> nodeListenableFuture = master.onNodeCreated(new NodeId(nodeid), testingNode);
264 futures.add(nodeListenableFuture);
265 Futures.addCallback(nodeListenableFuture, new FutureCallback<Node>() {
267 public void onSuccess(Node result) {
268 LOG.warn("Node {} created succesfully on all nodes", result.getNodeId().getValue());
272 public void onFailure(Throwable t) {
273 LOG.warn("Node creation failed. ", t);
278 Futures.allAsList(futures).get();
279 ownershipService.distributeOwnership();
282 TypedActor.get(ACTOR_SYSTEM).stop(master);
283 TypedActor.get(ACTOR_SYSTEM_SLAVE1).stop(slave1);
284 TypedActor.get(ACTOR_SYSTEM_SLAVE2).stop(slave2);
287 private TopologyManager createNoopRoleChangeNode(final ActorSystem actorSystem, final String topologyId, final boolean isMaster,
288 final TopologyManagerCallbackFactory topologyManagerCallbackFactory) {
290 final TypedActorExtension typedActorExtension = TypedActor.get(actorSystem);
291 return typedActorExtension.typedActorOf(new TypedProps<>(TopologyManager.class, new Creator<BaseTopologyManager>() {
293 public BaseTopologyManager create() throws Exception {
294 return new BaseTopologyManager(actorSystem,
298 topologyManagerCallbackFactory,
299 new TestingSuccesfulStateAggregator(),
300 new LoggingSalNodeWriter(),
301 new NoopRoleChangeStrategy(),
304 }), TOPOLOGY_NETCONF);
307 private TopologyManager createManagerWithOwnership(final ActorSystem actorSystem, final String topologyId, final boolean isMaster,
308 final TopologyManagerCallbackFactory topologyManagerCallbackFactory, final RoleChangeStrategy roleChangeStrategy) {
309 final TypedActorExtension typedActorExtension = TypedActor.get(actorSystem);
310 return typedActorExtension.typedActorOf(new TypedProps<>(TopologyManager.class, new Creator<BaseTopologyManager>() {
312 public BaseTopologyManager create() throws Exception {
313 return new BaseTopologyManager(actorSystem,
317 topologyManagerCallbackFactory,
318 new NetconfNodeOperationalDataAggregator(),
319 new LoggingSalNodeWriter(),
323 }), TOPOLOGY_NETCONF);
326 private TopologyManagerCallbackFactory createRealTopoTestingNodeCallbackFactory() {
327 final NodeManagerCallbackFactory nodeManagerCallbackFactory = new NodeManagerCallbackFactory() {
329 public NodeManagerCallback create(String nodeId, String topologyId, ActorSystem actorSystem) {
330 return new LoggingNodeManagerCallback();
334 return new TopologyManagerCallbackFactory() {
336 public TopologyManagerCallback create(ActorSystem actorSystem, String topologyId) {
337 return new ExampleTopologyManagerCallback(actorSystem, dataBroker, topologyId, nodeManagerCallbackFactory, new LoggingSalNodeWriter());
342 private TopologyManagerCallbackFactory createRealTopoCallbackFactory(final EntityOwnershipService entityOwnershipService) {
343 final NodeManagerCallbackFactory nodeManagerCallbackFactory = new NodeManagerCallbackFactory() {
345 public NodeManagerCallback create(String nodeId, String topologyId, ActorSystem actorSystem) {
346 return new ExampleNodeManagerCallback();
350 return new TopologyManagerCallbackFactory() {
352 public TopologyManagerCallback create(ActorSystem actorSystem, String topologyId) {
353 return new ExampleTopologyManagerCallback(actorSystem, dataBroker, topologyId, nodeManagerCallbackFactory);
358 private TopologyManagerCallbackFactory createTestingTopoCallbackFactory() {
359 return new TopologyManagerCallbackFactory() {
361 public TopologyManagerCallback create(ActorSystem actorSystem, String topologyId) {
362 return new TestingTopologyManagerCallback();
367 public static class LoggingNodeManagerCallback implements NodeManagerCallback {
371 public Node getInitialState(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
372 final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class);
373 return new NodeBuilder()
375 .addAugmentation(NetconfNode.class,
376 new NetconfNodeBuilder()
377 .setHost(netconfNode.getHost())
378 .setPort(netconfNode.getPort())
379 .setConnectionStatus(ConnectionStatus.Connecting)
380 .setClusteredConnectionStatus(
381 new ClusteredConnectionStatusBuilder()
384 new NodeStatusBuilder()
385 .setNode("testing-node")
386 .setStatus(Status.Unavailable)
395 public Node getFailedState(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
396 final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class);
397 return new NodeBuilder()
399 .addAugmentation(NetconfNode.class,
400 new NetconfNodeBuilder()
401 .setHost(netconfNode.getHost())
402 .setPort(netconfNode.getPort())
403 .setConnectionStatus(ConnectionStatus.UnableToConnect)
404 .setClusteredConnectionStatus(
405 new ClusteredConnectionStatusBuilder()
407 Collections.singletonList(
408 new NodeStatusBuilder()
409 .setNode("testing-node")
410 .setStatus(Status.Failed)
419 public ListenableFuture<Node> onNodeCreated(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
420 LOG.debug("Creating node {} with config {}", nodeId, configNode);
421 final NetconfNode augmentation = configNode.getAugmentation(NetconfNode.class);
422 return Futures.immediateFuture(new NodeBuilder()
424 .addAugmentation(NetconfNode.class,
425 new NetconfNodeBuilder()
426 .setConnectionStatus(ConnectionStatus.Connected)
427 .setHost(augmentation.getHost())
428 .setPort(augmentation.getPort())
429 .setClusteredConnectionStatus(
430 new ClusteredConnectionStatusBuilder()
432 Collections.singletonList(
433 new NodeStatusBuilder()
434 .setNode("testing-node")
435 .setStatus(Status.Connected)
444 public ListenableFuture<Node> onNodeUpdated(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
445 LOG.debug("Updating node {} with config {}", nodeId, configNode);
446 final NetconfNode augmentation = configNode.getAugmentation(NetconfNode.class);
447 return Futures.immediateFuture(new NodeBuilder()
449 .addAugmentation(NetconfNode.class,
450 new NetconfNodeBuilder()
451 .setConnectionStatus(ConnectionStatus.Connected)
452 .setHost(augmentation.getHost())
453 .setPort(augmentation.getPort())
454 .setClusteredConnectionStatus(
455 new ClusteredConnectionStatusBuilder()
457 Collections.singletonList(
458 new NodeStatusBuilder()
459 .setNode("testing-node")
460 .setStatus(Status.Connected)
469 public ListenableFuture<Void> onNodeDeleted(@Nonnull NodeId nodeId) {
470 LOG.debug("Deleting node {}", nodeId);
471 return Futures.immediateFuture(null);
476 public ListenableFuture<Node> getCurrentStatusForNode(@Nonnull NodeId nodeId) {
481 public void onRoleChanged(RoleChangeDTO roleChangeDTO) {
486 public void onReceive(Object o, ActorRef actorRef) {
491 public static class TestingTopologyManagerCallback implements TopologyManagerCallback {
493 public TestingTopologyManagerCallback() {
498 public ListenableFuture<Node> onNodeCreated(NodeId nodeId, Node node) {
499 LOG.warn("Actor system that called this: {}", TypedActor.context().system().settings().toString());
500 return Futures.immediateFuture(new NodeBuilder()
502 .addAugmentation(NetconfNode.class,
503 new NetconfNodeBuilder()
504 .setConnectionStatus(ConnectionStatus.Connected)
505 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
506 .setPort(new PortNumber(2555))
512 public ListenableFuture<Node> onNodeUpdated(NodeId nodeId, Node node) {
513 LOG.warn("Actor system that called this: {}", TypedActor.context().system().settings().toString());
514 LOG.debug("Update called on node {}, with config {}", nodeId.getValue(), node);
515 return Futures.immediateFuture(new NodeBuilder()
517 .addAugmentation(NetconfNode.class,
518 new NetconfNodeBuilder()
519 .setConnectionStatus(ConnectionStatus.Connected)
520 .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
521 .setPort(new PortNumber(65535))
527 public ListenableFuture<Void> onNodeDeleted(NodeId nodeId) {
528 LOG.debug("Delete called on node {}", nodeId.getValue());
529 return Futures.immediateFuture(null);
534 public ListenableFuture<Node> getCurrentStatusForNode(@Nonnull NodeId nodeId) {
539 public void onRoleChanged(RoleChangeDTO roleChangeDTO) {
544 public void onReceive(Object o, ActorRef actorRef) {
549 public class TestingSuccesfulStateAggregator implements StateAggregator {
552 public ListenableFuture<Node> combineCreateAttempts(List<ListenableFuture<Node>> stateFutures) {
553 final SettableFuture<Node> future = SettableFuture.create();
554 final ListenableFuture<List<Node>> allAsList = Futures.allAsList(stateFutures);
555 Futures.addCallback(allAsList, new FutureCallback<List<Node>>() {
557 public void onSuccess(List<Node> result) {
558 for (int i = 0; i < result.size() - 1; i++) {
559 if (!result.get(i).equals(result.get(i + 1))) {
560 LOG.warn("Node 1 {}: {}", result.get(i).getClass(), result.get(i));
561 LOG.warn("Node 2 {}: {}", result.get(i + 1).getClass(), result.get(i + 1));
562 future.setException(new IllegalStateException("Create futures have different result"));
563 LOG.warn("Future1 : {} Future2 : {}", result.get(i), result.get(i+1));
566 future.set(result.get(0));
570 public void onFailure(Throwable t) {
571 LOG.error("One of the combined create attempts failed {}", t);
572 future.setException(t);
574 }, TypedActor.context().dispatcher());
580 public ListenableFuture<Node> combineUpdateAttempts(List<ListenableFuture<Node>> stateFutures) {
581 final SettableFuture<Node> future = SettableFuture.create();
582 final ListenableFuture<List<Node>> allAsList = Futures.allAsList(stateFutures);
583 Futures.addCallback(allAsList, new FutureCallback<List<Node>>() {
585 public void onSuccess(List<Node> result) {
586 for (int i = 0; i < result.size() - 1; i++) {
587 if (!result.get(i).equals(result.get(i + 1))) {
588 future.setException(new IllegalStateException("Update futures have different result"));
591 future.set(result.get(0));
595 public void onFailure(Throwable t) {
596 LOG.error("One of the combined update attempts failed {}", t);
597 future.setException(t);
604 public ListenableFuture<Void> combineDeleteAttempts(List<ListenableFuture<Void>> stateFutures) {
605 final SettableFuture<Void> future = SettableFuture.create();
606 final ListenableFuture<List<Void>> allAsList = Futures.allAsList(stateFutures);
607 Futures.addCallback(allAsList, new FutureCallback<List<Void>>() {
609 public void onSuccess(List<Void> result) {
614 public void onFailure(Throwable t) {
615 LOG.error("One of the combined delete attempts failed {}", t);
616 future.setException(t);