Example usage for java.util.concurrent.atomic AtomicBoolean set

List of usage examples for java.util.concurrent.atomic AtomicBoolean set

Introduction

In this page you can find the example usage for java.util.concurrent.atomic AtomicBoolean set.

Prototype

public final void set(boolean newValue) 

Source Link

Document

Sets the value to newValue , with memory effects as specified by VarHandle#setVolatile .

Usage

From source file:com.dragoniade.deviantart.favorites.FavoritesDownloader.java

private String getDocumentUrl(Deviation da, AtomicBoolean download) {
    String downloadUrl = da.getDocumentDownloadUrl();
    GetMethod method = new GetMethod(downloadUrl);

    try {//w  w  w  .  ja v  a 2  s .  co m
        int sc = -1;
        do {
            method.setFollowRedirects(false);
            sc = client.executeMethod(method);
            requestCount++;

            if (sc >= 300 && sc <= 399) {
                String location = method.getResponseHeader("Location").getValue();
                method.releaseConnection();
                return location;
            } else {
                LoggableException ex = new LoggableException(method.getResponseBodyAsString());
                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), ex);

                int res = showConfirmDialog(owner,
                        "An error has occured when contacting deviantART : error " + sc + ". Try again?",
                        "Continue?", JOptionPane.YES_NO_CANCEL_OPTION);
                if (res == JOptionPane.NO_OPTION) {
                    String text = "<br/><a style=\"color:red;\" href=\"" + da.getUrl() + "\">" + downloadUrl
                            + " has an error" + "</a>";
                    setPaneText(text);
                    method.releaseConnection();
                    progress.incremTotal();
                    download.set(false);
                    return null;
                }
                if (res == JOptionPane.CANCEL_OPTION) {
                    return null;
                }
            }
        } while (true);
    } catch (HttpException e) {
        showMessageDialog(owner, "Error contacting deviantART: " + e.getMessage(), "Error",
                JOptionPane.ERROR_MESSAGE);
        return null;
    } catch (IOException e) {
        showMessageDialog(owner, "Error contacting deviantART: " + e.getMessage(), "Error",
                JOptionPane.ERROR_MESSAGE);
        return null;
    }
}

From source file:org.apache.pulsar.broker.service.persistent.PersistentTopic.java

private boolean hasLocalProducers() {
    AtomicBoolean foundLocal = new AtomicBoolean(false);
    producers.forEach(producer -> {/*  ww w  .  j  a  va  2  s . c  o m*/
        if (!producer.isRemote()) {
            foundLocal.set(true);
        }
    });

    return foundLocal.get();
}

From source file:org.apache.pulsar.broker.service.persistent.PersistentTopic.java

private boolean hasRemoteProducers() {
    AtomicBoolean foundRemote = new AtomicBoolean(false);
    producers.forEach(producer -> {//from w  w w .  jav  a 2s  . c  o m
        if (producer.isRemote()) {
            foundRemote.set(true);
        }
    });

    return foundRemote.get();
}

From source file:com.indeed.lsmtree.recordcache.PersistentRecordCache.java

/**
 * Performs lookup for multiple keys and returns a streaming iterator to results.
 * Each element in the iterator is one of
 *  (1) an exception associated with a single lookup
 *  (2) a key value tuple//from  w w  w  .  jav a 2s . com
 *
 * @param keys      lookup keys
 * @param progress  (optional) an AtomicInteger for tracking progress
 * @param skipped   (optional) an AtomicInteger for tracking missing keys
 * @return          iterator of lookup results
 */
public Iterator<Either<Exception, P2<K, V>>> getStreaming(final @Nonnull Iterator<K> keys,
        final @Nullable AtomicInteger progress, final @Nullable AtomicInteger skipped) {
    log.info("starting store lookups");
    LongArrayList addressList = new LongArrayList();
    int notFound = 0;
    while (keys.hasNext()) {
        final K key = keys.next();
        final Long address;
        try {
            address = index.get(key);
        } catch (IOException e) {
            log.error("error", e);
            return Iterators.singletonIterator(Left.<Exception, P2<K, V>>of(new IndexReadException(e)));
        }
        if (address != null) {
            addressList.add(address);
        } else {
            notFound++;
        }
    }
    if (progress != null)
        progress.addAndGet(notFound);
    if (skipped != null)
        skipped.addAndGet(notFound);
    log.info("store lookups complete, sorting addresses");

    final long[] addresses = addressList.elements();
    Arrays.sort(addresses, 0, addressList.size());

    log.info("initializing store lookup iterator");
    final BlockingQueue<Runnable> taskQueue = new ArrayBlockingQueue<Runnable>(100);
    final Iterator<List<Long>> iterable = Iterators.partition(addressList.iterator(), 1000);
    final ExecutorService primerThreads = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, taskQueue,
            new NamedThreadFactory("store priming thread", true, log), new RejectedExecutionHandler() {
                @Override
                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                    try {
                        taskQueue.put(r);
                    } catch (InterruptedException e) {
                        log.error("error", e);
                        throw new RuntimeException(e);
                    }
                }
            });
    final BlockingQueue<List<Either<Exception, P2<K, V>>>> completionQueue = new ArrayBlockingQueue<List<Either<Exception, P2<K, V>>>>(
            10);
    final AtomicLong runningTasks = new AtomicLong(0);
    final AtomicBoolean taskSubmitterRunning = new AtomicBoolean(true);

    new Thread(new Runnable() {
        @Override
        public void run() {
            while (iterable.hasNext()) {
                runningTasks.incrementAndGet();
                final List<Long> addressesSublist = iterable.next();
                primerThreads.submit(new FutureTask<List<Either<Exception, P2<K, V>>>>(
                        new RecordLookupTask(addressesSublist)) {
                    @Override
                    protected void done() {
                        try {
                            final List<Either<Exception, P2<K, V>>> results = get();
                            if (progress != null) {
                                progress.addAndGet(results.size());
                            }
                            completionQueue.put(results);
                        } catch (InterruptedException e) {
                            log.error("error", e);
                            throw new RuntimeException(e);
                        } catch (ExecutionException e) {
                            log.error("error", e);
                            throw new RuntimeException(e);
                        }
                    }
                });
            }
            taskSubmitterRunning.set(false);
        }
    }, "RecordLookupTaskSubmitterThread").start();

    return new Iterator<Either<Exception, P2<K, V>>>() {

        Iterator<Either<Exception, P2<K, V>>> currentIterator;

        @Override
        public boolean hasNext() {
            if (currentIterator != null && currentIterator.hasNext())
                return true;
            while (taskSubmitterRunning.get() || runningTasks.get() > 0) {
                try {
                    final List<Either<Exception, P2<K, V>>> list = completionQueue.poll(1, TimeUnit.SECONDS);
                    if (list != null) {
                        log.debug("remaining: " + runningTasks.decrementAndGet());
                        currentIterator = list.iterator();
                        if (currentIterator.hasNext())
                            return true;
                    }
                } catch (InterruptedException e) {
                    log.error("error", e);
                    throw new RuntimeException(e);
                }
            }
            primerThreads.shutdown();
            return false;
        }

        @Override
        public Either<Exception, P2<K, V>> next() {
            return currentIterator.next();
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    };
}

From source file:de.hybris.platform.jdbcwrapper.ConnectionPoolTest.java

private void doTestMultithreadedAccess(final int RUN_SECONDS, final int THREADS, final int PERCENT_NO_TX,
        final int PERCENT_TX_ROLLBACK, final boolean useInterrupt, final boolean sendDummyStatement) {
    HybrisDataSource dataSource = null;/*www .j  a  va  2s. com*/

    LOG.info("--- test multithreaded access to connection pool duration:" + RUN_SECONDS + "s threads:" + THREADS
            + " nonTx:" + PERCENT_NO_TX + "% rollback:" + PERCENT_TX_ROLLBACK + "% interrupt:" + useInterrupt
            + "-----------------------------------");
    try {
        final Collection<TestConnectionImpl> allConnections = new ConcurrentLinkedQueue<TestConnectionImpl>();

        final AtomicLong rollbackCounter = new AtomicLong(0);
        final AtomicLong connectionCounter = new AtomicLong(0);
        final AtomicBoolean finished = new AtomicBoolean(false);

        dataSource = createDataSource(Registry.getCurrentTenantNoFallback(), allConnections, connectionCounter,
                false, false);

        assertEquals(0, dataSource.getNumInUse());
        assertEquals(1, dataSource.getNumPhysicalOpen());
        assertEquals(1, dataSource.getMaxInUse());
        assertEquals(1, dataSource.getMaxPhysicalOpen());

        final int maxConnections = dataSource.getMaxAllowedPhysicalOpen();

        final String runId = "[" + RUN_SECONDS + "|" + THREADS + "|" + PERCENT_NO_TX + "|" + PERCENT_TX_ROLLBACK
                + "|" + useInterrupt + "]";

        final Runnable runnable = new ContinuousAccessRunnable(dataSource, PERCENT_NO_TX, PERCENT_TX_ROLLBACK,
                rollbackCounter, finished, runId, sendDummyStatement);

        final TestThreadsHolder threadsHolder = new TestThreadsHolder(THREADS, runnable) {
            @Override
            public void stopAll() {
                if (useInterrupt) {
                    super.stopAll();
                } else {
                    finished.set(true);
                }
            }
        };

        threadsHolder.startAll();

        waitDuration(RUN_SECONDS, maxConnections, dataSource, allConnections);

        threadsHolder.stopAll();
        final boolean allStoppedNormal = threadsHolder.waitForAll(30, TimeUnit.SECONDS);

        if (!allStoppedNormal) {
            // try fallback method
            finished.set(true);
            final boolean allStoppedFallback = threadsHolder.waitForAll(10, TimeUnit.SECONDS);
            if (allStoppedFallback) {
                LOG.error("Threads did not stop normally but only after using boolean flag!");
            } else {
                fail("db connection test threads did not stop correctly even after fallback method");
            }
        }

        // kill data source
        dataSource.destroy();
        assertTrue(dataSource.getConnectionPool().isPoolClosed());
        assertTrue(waitForAllInactive(dataSource.getConnectionPool(), 10, TimeUnit.SECONDS));

        if (PERCENT_TX_ROLLBACK > 0) {
            assertTrue(rollbackCounter.get() > 0);
        }

        final long maxAllowedConnections = maxConnections + rollbackCounter.get();

        final Stats stats = getStats(allConnections);

        LOG.info(//
                "max connections :" + maxConnections + "\n" + //
                        "rollbacks :" + rollbackCounter.get() + "\n" + //
                        "real connections :" + connectionCounter.get() + "\n" + //
                        "closed:" + stats.closed + "\n" + //
                        "open:" + stats.open + "\n" + //
                        "borrowed :" + stats.borrowed + "\n" + //
                        "returned :" + stats.returned + "\n" + //
                        "invalidated :" + stats.invalidated + "\n");

        // we cannot be sure since not each rollbacked connections *must* be re-created
        assertTrue(
                "handed out more than max connections (got:" + connectionCounter.get() + " > max:"
                        + maxAllowedConnections + ")", //
                connectionCounter.get() <= maxAllowedConnections);
        assertEquals("still got " + stats.borrowed + "borrowed connections", 0, stats.borrowed);
        assertEquals(
                "connection count mismatch - total:" + connectionCounter.get() + " <> "
                        + (stats.returned + stats.invalidated) + " (returned:" + stats.returned
                        + " + invalidated:" + stats.invalidated + ")", //
                connectionCounter.get(), stats.returned + stats.invalidated);

        // make sure all connections have been finally closed

        assertEquals(
                "data source " + dataSource + "still got " + dataSource.getNumInUse() + " connections in use", //
                0, dataSource.getNumInUse());
        assertEquals(
                "data source " + dataSource + "still got " + dataSource.getNumPhysicalOpen()
                        + " physical connections open (despite none are in use)", //
                0, dataSource.getNumPhysicalOpen());
        assertTrue(
                "data source " + dataSource + " had more than max allowed connections (max:" + maxConnections
                        + ", max in use:" + dataSource.getMaxInUse() + ")", //
                maxConnections >= dataSource.getMaxInUse());
        assertTrue(
                "data source " + dataSource + " had more than max allowed physical connections (max:"
                        + maxConnections + ", max physical in use:" + dataSource.getMaxPhysicalOpen() + ")", //
                maxConnections >= dataSource.getMaxPhysicalOpen());
    } finally {
        destroyDataSource(dataSource);
    }

}

From source file:interactivespaces.util.web.WebSocketTest.java

@Test
public void testWebSocketCommunication() throws Exception {
    final String dataKey = "message";

    final CountDownLatch clientOpenning = new CountDownLatch(1);
    final CountDownLatch clientClosing = new CountDownLatch(1);

    final AtomicBoolean onConnectCalledServer = new AtomicBoolean(false);
    final AtomicBoolean onCloseCalledServer = new AtomicBoolean(false);

    final AtomicReference<WebServerWebSocketHandler> serverHandler = new AtomicReference<WebServerWebSocketHandler>();

    int port = 8082;
    String webSocketUriPrefix = "websockettest";

    URI uri = new URI(String.format("ws://127.0.0.1:%d/%s", port, webSocketUriPrefix));

    final List<Integer> serverReceivedList = Lists.newArrayList();
    final List<Integer> clientReceivedList = Lists.newArrayList();
    List<Integer> serverSentList = Lists.newArrayList();
    List<Integer> clientSentList = Lists.newArrayList();
    Random random = new Random(System.currentTimeMillis());

    for (int i = 0; i < 100; i++) {
        clientSentList.add(random.nextInt());
        serverSentList.add(random.nextInt());
    }//from w  ww.  j a  va2s .  c om

    NettyWebServer server = new NettyWebServer(threadPool, log);
    server.setServerName("test-server");
    server.setPort(port);
    server.setWebSocketHandlerFactory(webSocketUriPrefix, new WebServerWebSocketHandlerFactory() {

        @Override
        public WebServerWebSocketHandler newWebSocketHandler(WebSocketConnection connection) {
            WebServerWebSocketHandler handler = new WebServerWebSocketHandlerSupport(connection) {

                @Override
                public void onReceive(Object data) {
                    @SuppressWarnings("unchecked")
                    Map<String, Object> d = (Map<String, Object>) data;

                    serverReceivedList.add((Integer) d.get(dataKey));
                }

                @Override
                public void onConnect() {
                    onConnectCalledServer.set(true);
                }

                @Override
                public void onClose() {
                    onCloseCalledServer.set(true);
                }
            };

            serverHandler.set(handler);

            return handler;
        }
    });
    server.startup();

    Thread.sleep(2000);

    WebSocketHandler clientHandler = new WebSocketHandler() {

        @Override
        public void onConnect() {
            clientOpenning.countDown();
        }

        @Override
        public void onClose() {
            clientClosing.countDown();
        }

        @Override
        public void onReceive(Object data) {
            @SuppressWarnings("unchecked")
            Map<String, Object> d = (Map<String, Object>) data;

            clientReceivedList.add((Integer) d.get(dataKey));
        }
    };

    NettyWebSocketClient client = new NettyWebSocketClient(uri, clientHandler, threadPool, log);
    client.startup();

    Assert.assertTrue(clientOpenning.await(10, TimeUnit.SECONDS));

    Assert.assertTrue(client.isOpen());

    Map<String, Object> data = Maps.newHashMap();
    for (Integer i : clientSentList) {
        data.put("message", i);
        client.writeDataAsJson(data);
    }

    for (Integer i : serverSentList) {
        data.put("message", i);
        serverHandler.get().sendJson(data);
    }

    client.ping();

    client.shutdown();

    Assert.assertTrue(clientClosing.await(10, TimeUnit.SECONDS));

    server.shutdown();

    Assert.assertEquals(clientSentList, serverReceivedList);
    Assert.assertEquals(serverSentList, clientReceivedList);
    Assert.assertTrue(onConnectCalledServer.get());
    Assert.assertTrue(onCloseCalledServer.get());
}

From source file:de.hybris.platform.test.TransactionTest.java

@Test
public void testNestedTAError() throws Exception {

    final AtomicBoolean storeCalled = new AtomicBoolean();
    final AtomicBoolean commitCalled = new AtomicBoolean();
    final AtomicBoolean rollbackCalled = new AtomicBoolean();

    final Transaction transaction = new DefaultTransaction() {
        @Override/*  w  w w  .jav a  2 s. c o  m*/
        public void rollback() throws TransactionException {
            rollbackCalled.set(true);
            super.rollback();
        }

        @Override
        public void commit() throws TransactionException {
            commitCalled.set(true);
            super.commit();
        }
    };
    transaction.enableDelayedStore(true);

    final EntityInstanceContext eCtx = new EntityInstanceContext() {

        @Override
        public ItemDeployment getItemDeployment() {
            return null;
        }

        @Override
        public PK getPK() {
            return PK.NULL_PK;
        }

        @Override
        public PersistencePool getPersistencePool() {
            return null;
        }

        @Override
        public void setPK(final PK pk) {
            // mock
        }
    };

    final EntityInstance mockEntity = new EntityInstance() {
        final EntityInstanceContext ctx = eCtx;

        @Override
        public PK ejbFindByPrimaryKey(final PK pkValue) throws YObjectNotFoundException {
            return null;
        }

        @Override
        public void ejbLoad() {
            // mock
        }

        @Override
        public void ejbRemove() {
            // mock
        }

        @Override
        public void ejbStore() {
            storeCalled.set(true);
            throw new IllegalArgumentException("let's rollback ;)");
        }

        @Override
        public EntityInstanceContext getEntityContext() {
            return ctx;
        }

        @Override
        public boolean needsStoring() {
            return true;
        }

        @Override
        public void setEntityContext(final EntityInstanceContext ctx) {
            // mock
        }

        @Override
        public void setNeedsStoring(final boolean needs) {
            // mock
        }

    };

    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
    final PrintStream printstream = new PrintStream(bos);

    final PrintStream err = System.err;

    final AtomicReference<Title> itemRef = new AtomicReference<Title>();

    try {
        System.setErr(printstream);

        // outer TA
        transaction.execute(new TransactionBody() {
            @Override
            public Object execute() throws Exception {
                // inner TA
                transaction.execute(new TransactionBody() {
                    @Override
                    public Object execute() throws Exception {
                        itemRef.set(UserManager.getInstance().createTitle("T" + System.currentTimeMillis()));

                        // inject mock entity to call ejbStore upon -> throws exception
                        transaction.registerEntityInstance(mockEntity);

                        return null;
                    }

                });
                return null;
            }

        });
        fail("IllegalArgumentException expected");
    } catch (final IllegalArgumentException ex) {
        assertTrue(storeCalled.get());
        assertEquals("let's rollback ;)", ex.getMessage());

        assertFalse(transaction.isRunning());
        assertEquals(0, transaction.getOpenTransactionCount());
        assertNotNull(itemRef.get());
        assertFalse(itemRef.get().isAlive());

        final String errorLog = new String(bos.toByteArray());

        assertFalse(errorLog.contains("no transaction running"));
    } catch (final Exception e) {
        fail("unexpected error " + e.getMessage());
    } finally {
        System.setErr(err);
    }
}

From source file:org.apache.hadoop.hbase.regionserver.TestRegionReplicaFailover.java

/**
 * Tests the case where there are 3 region replicas and the primary is continuously accepting
 * new writes while one of the secondaries is killed. Verification is done for both of the
 * secondary replicas./*from  ww w.j  a  va 2 s.  c  om*/
 */
@Test(timeout = 120000)
public void testSecondaryRegionKillWhilePrimaryIsAcceptingWrites() throws Exception {
    try (Connection connection = ConnectionFactory.createConnection(HTU.getConfiguration());
            Table table = connection.getTable(htd.getTableName());
            Admin admin = connection.getAdmin()) {
        // start a thread to do the loading of primary
        HTU.loadNumericRows(table, fam, 0, 1000); // start with some base
        admin.flush(table.getName());
        HTU.loadNumericRows(table, fam, 1000, 2000);

        final AtomicReference<Throwable> ex = new AtomicReference<Throwable>(null);
        final AtomicBoolean done = new AtomicBoolean(false);
        final AtomicInteger key = new AtomicInteger(2000);

        Thread loader = new Thread() {
            @Override
            public void run() {
                while (!done.get()) {
                    try {
                        HTU.loadNumericRows(table, fam, key.get(), key.get() + 1000);
                        key.addAndGet(1000);
                    } catch (Throwable e) {
                        ex.compareAndSet(null, e);
                    }
                }
            }
        };
        loader.start();

        Thread aborter = new Thread() {
            @Override
            public void run() {
                try {
                    boolean aborted = false;
                    for (RegionServerThread rs : HTU.getMiniHBaseCluster().getRegionServerThreads()) {
                        for (Region r : rs.getRegionServer().getOnlineRegions(htd.getTableName())) {
                            if (r.getRegionInfo().getReplicaId() == 1) {
                                LOG.info("Aborting region server hosting secondary region replica");
                                rs.getRegionServer().abort("for test");
                                aborted = true;
                            }
                        }
                    }
                    assertTrue(aborted);
                } catch (Throwable e) {
                    ex.compareAndSet(null, e);
                }
            };
        };

        aborter.start();
        aborter.join();
        done.set(true);
        loader.join();

        assertNull(ex.get());

        assertTrue(key.get() > 1000); // assert that the test is working as designed
        LOG.info("Loaded up to key :" + key.get());
        verifyNumericRowsWithTimeout(table, fam, 0, key.get(), 0, 30000);
        verifyNumericRowsWithTimeout(table, fam, 0, key.get(), 1, 30000);
        verifyNumericRowsWithTimeout(table, fam, 0, key.get(), 2, 30000);
    }

    // restart the region server
    HTU.getMiniHBaseCluster().startRegionServer();
}

From source file:de.hybris.platform.test.TransactionTest.java

@Test
public void testItemUpdateDuringCommit_PLA10839() throws Exception {
    final Title title1 = UserManager.getInstance().createTitle("t1");
    final Title title2 = UserManager.getInstance().createTitle("t2");
    final Title title3 = UserManager.getInstance().createTitle("t3");
    final Title title4 = UserManager.getInstance().createTitle("t4");

    final AtomicBoolean listenerHasBeenCalled = new AtomicBoolean(false);

    final InvalidationListener listener = new InvalidationListener() {
        @Override/*ww  w.j  ava  2  s  .c  o  m*/
        public void keyInvalidated(final Object[] key, final int invalidationType,
                final InvalidationTarget target, final RemoteInvalidationSource remoteSrc) {
            listenerHasBeenCalled.set(true);
            // change t1 here
            title1.setName("newOne");
        }
    };
    final InvalidationTopic topic = InvalidationManager.getInstance()
            .getInvalidationTopic(new Object[] { Cache.CACHEKEY_HJMP, Cache.CACHEKEY_ENTITY });
    try {
        topic.addInvalidationListener(listener);

        final Transaction tx = Transaction.current();
        tx.execute(new TransactionBody() {

            @Override
            public Object execute() throws Exception {
                title2.setName("foo");
                title3.setName("foo");
                title4.setName("foo");
                return null;
            }
        });
        assertEquals("foo", title2.getName());
        assertEquals("foo", title3.getName());
        assertEquals("foo", title4.getName());
        assertEquals("newOne", title1.getName());
        assertTrue(listenerHasBeenCalled.get());
    } finally {
        topic.removeInvalidationListener(listener);
    }
}

From source file:de.hybris.platform.test.TransactionTest.java

@Test
public void testItemAccessDuringCommit_PLA10839() throws Exception {
    final Title title1 = UserManager.getInstance().createTitle("t1");
    final Title title2 = UserManager.getInstance().createTitle("t2");
    final Title title3 = UserManager.getInstance().createTitle("t3");
    final Title title4 = UserManager.getInstance().createTitle("t4");

    final AtomicBoolean listenerHasBeenCalled = new AtomicBoolean(false);

    final InvalidationListener listener = new InvalidationListener() {
        @Override/* ww  w .  j  a  va  2s  . c  o m*/
        public void keyInvalidated(final Object[] key, final int invalidationType,
                final InvalidationTarget target, final RemoteInvalidationSource remoteSrc) {
            listenerHasBeenCalled.set(true);
            // access t1 here
            if (StringUtils.isEmpty(title1.getName())) {
                System.err.println("title1 name is empty");
            }
        }
    };
    final InvalidationTopic topic = InvalidationManager.getInstance()
            .getInvalidationTopic(new Object[] { Cache.CACHEKEY_HJMP, Cache.CACHEKEY_ENTITY });
    try {
        topic.addInvalidationListener(listener);

        final Transaction tx = Transaction.current();
        tx.execute(new TransactionBody() {

            @Override
            public Object execute() throws Exception {
                title2.setName("foo");
                title3.setName("foo");
                title4.setName("foo");
                return null;
            }
        });
        assertEquals("foo", title2.getName());
        assertEquals("foo", title3.getName());
        assertEquals("foo", title4.getName());
        assertTrue(listenerHasBeenCalled.get());
    } finally {
        topic.removeInvalidationListener(listener);
    }
}