Example usage for com.google.common.util.concurrent ListenableFuture addListener

List of usage examples for com.google.common.util.concurrent ListenableFuture addListener

Introduction

In this page you can find the example usage for com.google.common.util.concurrent ListenableFuture addListener.

Prototype

void addListener(Runnable listener, Executor executor);

Source Link

Document

Registers a listener to be Executor#execute(Runnable) run on the given executor.

Usage

From source file:org.waveprotocol.box.server.waveserver.WaveletContainerImpl.java

/**
 * Constructs an empty WaveletContainer for a wavelet.
 * WaveletData is not set until a delta has been applied.
 *
 * @param notifiee the subscriber to notify of wavelet updates and commits.
 * @param waveletState the wavelet's delta history and current state.
 * @param waveDomain the wave server domain.
 * @param storageContinuationExecutor the executor used to perform post wavelet loading logic.
 *///from  w  ww  . j  a va 2 s.  c  o  m
public WaveletContainerImpl(WaveletName waveletName, WaveletNotificationSubscriber notifiee,
        final ListenableFuture<? extends WaveletState> waveletStateFuture, String waveDomain,
        Executor storageContinuationExecutor) {
    this.waveletName = waveletName;
    this.notifiee = notifiee;
    this.sharedDomainParticipantId = waveDomain != null
            ? ParticipantIdUtil.makeUnsafeSharedDomainParticipantId(waveDomain)
            : null;
    this.storageContinuationExecutor = storageContinuationExecutor;
    ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    this.readLock = readWriteLock.readLock();
    this.writeLock = readWriteLock.writeLock();

    waveletStateFuture.addListener(new Runnable() {
        @Override
        public void run() {
            acquireWriteLock();
            try {
                Preconditions.checkState(waveletState == null, "Repeat attempts to set wavelet state");
                Preconditions.checkState(state == State.LOADING, "Unexpected state %s", state);
                waveletState = FutureUtil.getResultOrPropagateException(waveletStateFuture,
                        PersistenceException.class);
                Preconditions.checkState(waveletState.getWaveletName().equals(getWaveletName()),
                        "Wrong wavelet state, named %s, expected %s", waveletState.getWaveletName(),
                        getWaveletName());
                state = State.OK;
            } catch (PersistenceException e) {
                LOG.warning("Failed to load wavelet " + getWaveletName(), e);
                state = State.CORRUPTED;
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                LOG.warning("Interrupted loading wavelet " + getWaveletName(), e);
                state = State.CORRUPTED;
            } catch (RuntimeException e) {
                // TODO(soren): would be better to terminate the process in this case
                LOG.severe("Unexpected exception loading wavelet " + getWaveletName(), e);
                state = State.CORRUPTED;
            } finally {
                releaseWriteLock();
            }
            loadLatch.countDown();
        }
    }, storageContinuationExecutor);
}

From source file:me.lucko.luckperms.commands.migration.subcommands.MigrationPowerfulPerms.java

private CommandResult run(LuckPermsPlugin plugin, List<String> args) {
    final Logger log = plugin.getLog();
    if (!plugin.isPluginLoaded("PowerfulPerms")) {
        log.severe("PowerfulPerms Migration: Error -> PowerfulPerms is not loaded.");
        return CommandResult.STATE_ERROR;
    }/*  ww w .  j  a  v a 2  s.co m*/

    final String address = args.get(0);
    final String database = args.get(1);
    final String username = args.get(2);
    final String password = args.get(3);
    final String dbTable = args.get(4);

    // Find a list of UUIDs
    log.info("PowerfulPerms Migration: Getting a list of UUIDs to migrate.");

    @Cleanup
    HikariDataSource hikari = new HikariDataSource();
    hikari.setMaximumPoolSize(2);
    hikari.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
    hikari.addDataSourceProperty("serverName", address.split(":")[0]);
    hikari.addDataSourceProperty("port", address.split(":")[1]);
    hikari.addDataSourceProperty("databaseName", database);
    hikari.addDataSourceProperty("user", username);
    hikari.addDataSourceProperty("password", password);

    Set<UUID> uuids = new HashSet<>();

    try {
        @Cleanup
        Connection connection = hikari.getConnection();
        DatabaseMetaData meta = connection.getMetaData();

        @Cleanup
        ResultSet tables = meta.getTables(null, null, dbTable, null);
        if (!tables.next()) {
            log.severe("PowerfulPerms Migration: Error - Couldn't find table.");
            return CommandResult.FAILURE;

        } else {
            @Cleanup
            PreparedStatement columnPs = connection.prepareStatement(
                    "SELECT COLUMN_NAME, COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=?");
            columnPs.setString(1, dbTable);
            @Cleanup
            ResultSet columnRs = columnPs.executeQuery();

            log.info("Found table: " + dbTable);
            while (columnRs.next()) {
                log.info("" + columnRs.getString("COLUMN_NAME") + " - " + columnRs.getString("COLUMN_TYPE"));
            }

            @Cleanup
            PreparedStatement preparedStatement = connection.prepareStatement("SELECT `uuid` FROM " + dbTable);
            @Cleanup
            ResultSet resultSet = preparedStatement.executeQuery();

            while (resultSet.next()) {
                uuids.add(UUID.fromString(resultSet.getString("uuid")));
            }
        }

    } catch (Exception e) {
        e.printStackTrace();
        return CommandResult.FAILURE;
    }

    if (uuids.isEmpty()) {
        log.severe("PowerfulPerms Migration: Error - Unable to find any UUIDs to migrate.");
        return CommandResult.FAILURE;
    }

    log.info("PowerfulPerms Migration: Found " + uuids.size() + " uuids. Starting migration.");

    PowerfulPermsPlugin ppPlugin = (PowerfulPermsPlugin) plugin.getPlugin("PowerfulPerms");
    PermissionManager pm = ppPlugin.getPermissionManager();

    // Groups first.
    log.info("PowerfulPerms Migration: Starting group migration.");
    Map<Integer, Group> groups = pm.getGroups(); // All versions
    for (Group g : groups.values()) {
        plugin.getDatastore().createAndLoadGroup(g.getName().toLowerCase());
        final me.lucko.luckperms.groups.Group group = plugin.getGroupManager().get(g.getName().toLowerCase());
        try {
            LogEntry.build().actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
                    .acted(group).action("create").build().submit(plugin);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        for (Permission p : g.getOwnPermissions()) { // All versions
            applyPerm(group, p, plugin);
        }

        for (Group parent : g.getParents()) { // All versions
            try {
                group.setPermission("group." + parent.getName().toLowerCase(), true);
                LogEntry.build().actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
                        .acted(group).action("setinherit " + parent.getName().toLowerCase()) // All versions
                        .build().submit(plugin);
            } catch (Exception ex) {
                if (!(ex instanceof ObjectAlreadyHasException)) {
                    ex.printStackTrace();
                }
            }
        }

        plugin.getDatastore().saveGroup(group);
    }
    log.info("PowerfulPerms Migration: Group migration complete.");

    // Now users.
    log.info("PowerfulPerms Migration: Starting user migration.");
    final Map<UUID, CountDownLatch> progress = new HashMap<>();

    // Migrate all users and their groups
    for (UUID uuid : uuids) {
        progress.put(uuid, new CountDownLatch(2));

        // Create a LuckPerms user for the UUID
        plugin.getDatastore().loadUser(uuid, "null");
        User user = plugin.getUserManager().get(uuid);

        // Get a list of Permissions held by the user from the PP API.
        getPlayerPermissions(pm, uuid, perms -> { // Changes each version
            perms.forEach(p -> applyPerm(user, p, plugin));

            // Update the progress so the user can be saved and unloaded.
            synchronized (progress) {
                progress.get(uuid).countDown();
                if (progress.get(uuid).getCount() == 0) {
                    plugin.getDatastore().saveUser(user);
                    plugin.getUserManager().cleanup(user);
                }
            }
        });

        // Migrate the user's groups to LuckPerms from PP.
        Callback<Map<String, List<CachedGroup>>> callback = groups1 -> {
            for (Map.Entry<String, List<CachedGroup>> e : groups1.entrySet()) {
                final String server;
                if (e.getKey() != null && (e.getKey().equals("") || e.getKey().equalsIgnoreCase("all"))) {
                    server = null;
                } else {
                    server = e.getKey();
                }

                if (superLegacy) {
                    e.getValue().stream().filter(cg -> !cg.isNegated()).map(cg -> {
                        try {
                            return (Group) getGroupMethod.invoke(cg);
                        } catch (IllegalAccessException | InvocationTargetException e1) {
                            e1.printStackTrace();
                            return null;
                        }
                    }).forEach(g -> {
                        if (g != null) {
                            if (server == null) {
                                try {
                                    user.setPermission("group." + g.getName().toLowerCase(), true);
                                    LogEntry.build().actor(Constants.getConsoleUUID())
                                            .actorName(Constants.getConsoleName()).acted(user)
                                            .action("addgroup " + g.getName().toLowerCase()).build()
                                            .submit(plugin);
                                } catch (Exception ex) {
                                    if (!(ex instanceof ObjectAlreadyHasException)) {
                                        ex.printStackTrace();
                                    }
                                }
                            } else {
                                try {
                                    user.setPermission("group." + g.getName().toLowerCase(), true, server);
                                    LogEntry.build().actor(Constants.getConsoleUUID())
                                            .actorName(Constants.getConsoleName()).acted(user)
                                            .action("addgroup " + g.getName().toLowerCase() + " " + server)
                                            .build().submit(plugin);
                                } catch (Exception ex) {
                                    if (!(ex instanceof ObjectAlreadyHasException)) {
                                        ex.printStackTrace();
                                    }
                                }
                            }
                        }
                    });
                } else {
                    e.getValue().stream().filter(g -> !g.hasExpired() && !g.isNegated()).forEach(g -> {
                        final Group group = pm.getGroup(g.getGroupId());
                        if (g.willExpire()) {
                            if (server == null) {
                                try {
                                    user.setPermission("group." + group.getName().toLowerCase(), true,
                                            g.getExpirationDate().getTime() / 1000L);
                                    LogEntry.build().actor(Constants.getConsoleUUID())
                                            .actorName(Constants.getConsoleName()).acted(user)
                                            .action("addtempgroup " + group.getName().toLowerCase() + " "
                                                    + g.getExpirationDate().getTime() / 1000L)
                                            .build().submit(plugin);
                                } catch (Exception ex) {
                                    if (!(ex instanceof ObjectAlreadyHasException)) {
                                        ex.printStackTrace();
                                    }
                                }
                            } else {
                                try {
                                    user.setPermission("group." + group.getName().toLowerCase(), true, server,
                                            g.getExpirationDate().getTime() / 1000L);
                                    LogEntry.build().actor(Constants.getConsoleUUID())
                                            .actorName(Constants.getConsoleName()).acted(user)
                                            .action("addtempgroup " + group.getName().toLowerCase() + " "
                                                    + g.getExpirationDate().getTime() / 1000L + " " + server)
                                            .build().submit(plugin);
                                } catch (Exception ex) {
                                    if (!(ex instanceof ObjectAlreadyHasException)) {
                                        ex.printStackTrace();
                                    }
                                }
                            }

                        } else {
                            if (server == null) {
                                try {
                                    user.setPermission("group." + group.getName().toLowerCase(), true);
                                    LogEntry.build().actor(Constants.getConsoleUUID())
                                            .actorName(Constants.getConsoleName()).acted(user)
                                            .action("addgroup " + group.getName().toLowerCase()).build()
                                            .submit(plugin);
                                } catch (Exception ex) {
                                    if (!(ex instanceof ObjectAlreadyHasException)) {
                                        ex.printStackTrace();
                                    }
                                }
                            } else {
                                try {
                                    user.setPermission("group." + group.getName().toLowerCase(), true, server);
                                    LogEntry.build().actor(Constants.getConsoleUUID())
                                            .actorName(Constants.getConsoleName()).acted(user)
                                            .action("addgroup " + group.getName().toLowerCase() + " " + server)
                                            .build().submit(plugin);
                                } catch (Exception ex) {
                                    if (!(ex instanceof ObjectAlreadyHasException)) {
                                        ex.printStackTrace();
                                    }
                                }
                            }
                        }
                    });
                }
            }

            // Update the progress so the user can be saved and unloaded.
            synchronized (progress) {
                progress.get(uuid).countDown();
                if (progress.get(uuid).getCount() == 0) {
                    plugin.getDatastore().saveUser(user);
                    plugin.getUserManager().cleanup(user);
                }
            }
        };

        if (!legacy) {
            try {
                ListenableFuture<LinkedHashMap<String, List<CachedGroup>>> future = (ListenableFuture<LinkedHashMap<String, List<CachedGroup>>>) getPlayerGroupsMethod
                        .invoke(pm, uuid);
                try {
                    if (future.isDone()) {
                        callback.onComplete(future.get());
                    } else {
                        future.addListener(() -> {
                            try {
                                callback.onComplete(future.get());
                            } catch (InterruptedException | ExecutionException e) {
                                e.printStackTrace();
                            }
                        }, Runnable::run);
                    }
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            } catch (IllegalAccessException | InvocationTargetException e) {
                log.info("PowerfulPerms Migration: Error");
                e.printStackTrace();
            }
        } else {
            try {
                getPlayerGroupsMethod.invoke(pm, uuid,
                        new LPResultRunnable<LinkedHashMap<String, List<CachedGroup>>>() {
                            @Override
                            public void run() {
                                callback.onComplete(getResult());
                            }
                        });
            } catch (IllegalAccessException | InvocationTargetException e) {
                log.info("PowerfulPerms Migration: Error");
                e.printStackTrace();
            }
        }
    }

    // All groups are migrated, but there may still be some users being migrated.
    // This block will wait for all users to be completed.
    log.info("PowerfulPerms Migration: Waiting for user migration to complete. This may take some time");
    boolean sleep = true;
    while (sleep) {
        sleep = false;

        for (Map.Entry<UUID, CountDownLatch> e : progress.entrySet()) {
            if (e.getValue().getCount() != 0) {
                sleep = true;
                break;
            }
        }

        if (sleep) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    // We done.
    log.info("PowerfulPerms Migration: Success! Completed without any errors.");
    return CommandResult.SUCCESS;
}

From source file:org.eclipse.che.plugin.internal.installer.PluginInstallerImpl.java

/**
 * Ask to install/uninstall step//from   ww w.j ava 2 s.com
 * @param pluginInstallerCallback an optional callback used to notify if install is success or failed
 * @return ID of the current install
 */
@Override
public IPluginInstall requireNewInstall(FutureCallback pluginInstallerCallback)
        throws PluginInstallerException {
    if (currentExecution.get() != null) {
        throw new PluginInstallerException(
                "There is already install in progress. Wait that this install is finished");
    }

    Long id = idGenerator.getAndIncrement();
    PluginInstallImpl pluginInstall = new PluginInstallImpl(id);
    final ListenableFuture<Integer> job = this.executor.submit(() -> {

        // run ext script
        ProcessBuilder pb = new ProcessBuilder(
                pluginConfiguration.getInstallScript().toAbsolutePath().toString());
        pb.directory(pluginConfiguration.getCheHome().toFile());
        pb = pb.redirectErrorStream(true);
        Process p = pb.start();

        // collect stream
        InputStream is = p.getInputStream();
        InputStreamReader isr = new InputStreamReader(is, Charset.defaultCharset());
        BufferedReader br = new BufferedReader(isr);
        String line;
        String fullLog = "";
        pluginInstall.setLog(fullLog);
        while ((line = br.readLine()) != null) {
            fullLog += (line + "\n");
            pluginInstall.setLog(fullLog);
        }

        return p.waitFor();
    });
    pluginInstall.setFuture(job);

    currentExecution.set(job);

    if (pluginInstallerCallback != null) {
        Futures.addCallback(job, pluginInstallerCallback);
    }

    Futures.addCallback(job, new IntegerFutureCallback(pluginInstall, pluginInstallerCallback));

    job.addListener(() -> {
        resetCurrentExecution();
    }, this.executor);

    this.executions.put(id, pluginInstall);

    // wait a little so empty script callbacks could be setup
    try {
        Thread.sleep(100L);
    } catch (InterruptedException e) {
        throw new PluginInstallerException("Unable to get install ID", e);
    }

    return pluginInstall;
}

From source file:net.floodlightcontroller.core.internal.OFSwitch.java

/**
 * Append a listener to receive an OFStatsReply and update the 
 * internal OFSwitch data structures.//  ww w .  j  a v a  2  s  .c om
 * 
 * This presently taps into the following stats request 
 * messages to listen for the corresponding reply:
 * -- OFTableFeaturesStatsRequest
 * 
 * Extend this to tap into and update other OFStatsType messages.
 * 
 * @param future
 * @param request
 * @return
 */
private <REPLY extends OFStatsReply> ListenableFuture<List<REPLY>> addInternalStatsReplyListener(
        final ListenableFuture<List<REPLY>> future, OFStatsRequest<REPLY> request) {
    switch (request.getStatsType()) {
    case TABLE_FEATURES:
        /* case YOUR_CASE_HERE */
        future.addListener(new Runnable() {
            /*
             * We know the reply will be a list of OFStatsReply.
             */
            @SuppressWarnings("unchecked")
            @Override
            public void run() {
                /*
                 * The OFConnection handles REPLY_MORE for us in the case there
                 * are multiple OFStatsReply messages with the same XID.
                 */
                try {
                    List<? extends OFStatsReply> replies = future.get();
                    if (!replies.isEmpty()) {
                        /*
                         * By checking only the 0th element, we assume all others are the same type.
                         * TODO If not, what then?
                         */
                        switch (replies.get(0).getStatsType()) {
                        case TABLE_FEATURES:
                            processOFTableFeatures((List<OFTableFeaturesStatsReply>) future.get());
                            break;
                        /* case YOUR_CASE_HERE */
                        default:
                            throw new Exception("Received an invalid OFStatsReply of "
                                    + replies.get(0).getStatsType().toString() + ". Expected TABLE_FEATURES.");
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, MoreExecutors.sameThreadExecutor()); /* No need for another thread. */
    default:
        break;
    }
    return future; /* either unmodified or with an additional listener */
}

From source file:bio.gcat.batch.Batch.java

public ListenableFuture<Result> execute(Collection<Tuple> tuples) {
    final Result result = new Result(tuples);
    Queue<Action> queue = new LinkedList<>(actions);
    if (queue.isEmpty())
        return new DefiniteListenableFuture<>(result);

    Action action;/*from  www.  j a v  a 2s. co m*/
    Future<Collection<Tuple>> future = new DefiniteFuture<>(tuples);
    ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
    while ((action = queue.poll()) != null)
        future = service.submit(InjectionLogger.injectLogger(result, action.new Task(future)));

    final ListenableFuture<Collection<Tuple>> lastFuture = (ListenableFuture<Collection<Tuple>>) future;
    return new ListenableFuture<Result>() {
        @Override
        public boolean isDone() {
            return lastFuture.isDone();
        }

        @Override
        public boolean isCancelled() {
            return lastFuture.isCancelled();
        }

        @Override
        public Result get(long timeout, TimeUnit unit)
                throws InterruptedException, ExecutionException, TimeoutException {
            result.setTuples(lastFuture.get(timeout, unit));
            return result;
        }

        @Override
        public Result get() throws InterruptedException, ExecutionException {
            result.setTuples(lastFuture.get());
            return result;
        }

        @Override
        public boolean cancel(boolean mayInterruptIfRunning) {
            return lastFuture.cancel(mayInterruptIfRunning);
        }

        @Override
        public void addListener(Runnable listener, Executor executor) {
            lastFuture.addListener(listener, executor);
        }
    };
}

From source file:com.google.digitalcoin.core.PeerGroup.java

/**
 * <p>Given a transaction, sends it un-announced to one peer and then waits for it to be received back from other
 * peers. Once all connected peers have announced the transaction, the future will be completed. If anything goes
 * wrong the exception will be thrown when get() is called, or you can receive it via a callback on the
 * {@link ListenableFuture}. This method returns immediately, so if you want it to block just call get() on the
 * result.</p>/*from   w w w . jav  a  2s  .co  m*/
 *
 * <p>Note that if the PeerGroup is limited to only one connection (discovery is not activated) then the future
 * will complete as soon as the transaction was successfully written to that peer.</p>
 *
 * <p>Other than for sending your own transactions, this method is useful if you have received a transaction from
 * someone and want to know that it's valid. It's a bit of a weird hack because the current version of the Digitalcoin
 * protocol does not inform you if you send an invalid transaction. Because sending bad transactions counts towards
 * your DoS limit, be careful with relaying lots of unknown transactions. Otherwise you might get kicked off the
 * network.</p>
 *
 * <p>The transaction won't be sent until there are at least minConnections active connections available.
 * A good choice for proportion would be between 0.5 and 0.8 but if you want faster transmission during initial
 * bringup of the peer group you can lower it.</p>
 */
public ListenableFuture<Transaction> broadcastTransaction(final Transaction tx, final int minConnections) {
    final SettableFuture<Transaction> future = SettableFuture.create();
    log.info("Waiting for {} peers required for broadcast ...", minConnections);
    ListenableFuture<PeerGroup> peerAvailabilityFuture = waitForPeers(minConnections);
    peerAvailabilityFuture.addListener(new Runnable() {
        public void run() {
            // We now have enough connected peers to send the transaction.
            // This can be called immediately if we already have enough. Otherwise it'll be called from a peer
            // thread.

            // Pick a peer to be the lucky recipient of our tx.
            final Peer somePeer = peers.get(0);
            log.info("broadcastTransaction: Enough peers, adding {} to the memory pool and sending to {}",
                    tx.getHashAsString(), somePeer);
            final Transaction pinnedTx = memoryPool.seen(tx, somePeer.getAddress());
            // Prepare to send the transaction by adding a listener that'll be called when confidence changes.
            // Only bother with this if we might actually hear back:
            if (minConnections > 1)
                tx.getConfidence().addEventListener(new TransactionConfidence.Listener() {
                    public void onConfidenceChanged(Transaction tx) {
                        // The number of peers that announced this tx has gone up.
                        // Thread safe - this can run in parallel.
                        final TransactionConfidence conf = tx.getConfidence();
                        int numSeenPeers = conf.numBroadcastPeers();
                        boolean mined = conf
                                .getConfidenceType() != TransactionConfidence.ConfidenceType.NOT_SEEN_IN_CHAIN;
                        log.info("broadcastTransaction: TX {} seen by {} peers{}", new Object[] {
                                pinnedTx.getHashAsString(), numSeenPeers, mined ? " and mined" : "" });
                        if (!(numSeenPeers >= minConnections || mined))
                            return;
                        // We've seen the min required number of peers announce the transaction, or it was included
                        // in a block. Normally we'd expect to see it fully propagate before it gets mined, but
                        // it can be that a block is solved very soon after broadcast, and it's also possible that
                        // due to version skew and changes in the relay rules our transaction is not going to
                        // fully propagate yet can get mined anyway.
                        //
                        // Note that we can't wait for the current number of connected peers right now because we
                        // could have added more peers after the broadcast took place, which means they won't
                        // have seen the transaction. In future when peers sync up their memory pools after they
                        // connect we could come back and change this.
                        //
                        // OK, now tell the wallet about the transaction. If the wallet created the transaction then
                        // it already knows and will ignore this. If it's a transaction we received from
                        // somebody else via a side channel and are now broadcasting, this will put it into the
                        // wallet now we know it's valid.
                        for (Wallet wallet : wallets) {
                            try {
                                // Assumption here is there are no dependencies of the created transaction.
                                //
                                // We may end up with two threads trying to do this in parallel - the wallet will
                                // ignore whichever one loses the race.
                                wallet.receivePending(pinnedTx, null);
                            } catch (Throwable t) {
                                future.setException(t); // RE-ENTRANCY POINT
                                return;
                            }
                        }
                        // We're done! It's important that the PeerGroup lock is not held (by this thread) at this
                        // point to avoid triggering inversions when the Future completes.
                        log.info("broadcastTransaction: {} complete", pinnedTx.getHashAsString());
                        tx.getConfidence().removeEventListener(this);
                        future.set(pinnedTx); // RE-ENTRANCY POINT
                    }
                });

            // Satoshis code sends an inv in this case and then lets the peer request the tx data. We just
            // blast out the TX here for a couple of reasons. Firstly it's simpler: in the case where we have
            // just a single connection we don't have to wait for getdata to be received and handled before
            // completing the future in the code immediately below. Secondly, it's faster. The reason the
            // Satoshi client sends an inv is privacy - it means you can't tell if the peer originated the
            // transaction or not. However, we are not a fully validating node and this is advertised in
            // our version message, as SPV nodes cannot relay it doesn't give away any additional information
            // to skip the inv here - we wouldn't send invs anyway.
            //
            // TODO: The peer we picked might be dead by now. If we can't write the message, pick again and retry.
            ChannelFuture sendComplete = somePeer.sendMessage(pinnedTx);
            // If we've been limited to talk to only one peer, we can't wait to hear back because the
            // remote peer won't tell us about transactions we just announced to it for obvious reasons.
            // So we just have to assume we're done, at that point. This happens when we're not given
            // any peer discovery source and the user just calls connectTo() once.
            if (minConnections == 1) {
                sendComplete.addListener(new ChannelFutureListener() {
                    public void operationComplete(ChannelFuture _) throws Exception {
                        for (Wallet wallet : wallets) {
                            try {
                                // Assumption here is there are no dependencies of the created transaction.
                                wallet.receivePending(pinnedTx, null);
                            } catch (Throwable t) {
                                future.setException(t);
                                return;
                            }
                        }
                        future.set(pinnedTx);
                    }
                });
            }
        }
    }, MoreExecutors.sameThreadExecutor());
    return future;
}

From source file:com.facebook.buck.util.concurrent.ResourcePool.java

/**
 * @param executorService where to perform the resource processing. Should really be a "real"
 *                        executor (not a directExecutor).
 * @return a {@link ListenableFuture} containing the result of the processing. The future will be
 *         cancelled if the {@link ResourcePool#close()} method is called.
 *///from ww w .ja  v  a 2s . c  o  m
public synchronized <T> ListenableFuture<T> scheduleOperationWithResource(ThrowingFunction<R, T> withResource,
        final ListeningExecutorService executorService) {
    Preconditions.checkState(!closing.get());

    final ListenableFuture<T> futureWork = Futures.transformAsync(initialSchedule(),
            new AsyncFunction<Void, T>() {
                @Override
                public ListenableFuture<T> apply(Void input) throws Exception {
                    Either<R, ListenableFuture<Void>> resourceRequest = requestResource();
                    if (resourceRequest.isLeft()) {
                        R resource = resourceRequest.getLeft();
                        boolean resourceIsDefunct = false;
                        try {
                            return Futures.immediateFuture(withResource.apply(resource));
                        } catch (Exception e) {
                            resourceIsDefunct = (resourceUsageErrorPolicy == ResourceUsageErrorPolicy.RETIRE);
                            throw e;
                        } finally {
                            returnResource(resource, resourceIsDefunct);
                        }
                    } else {
                        return Futures.transformAsync(resourceRequest.getRight(), this, executorService);
                    }
                }
            }, executorService);

    pendingWork.add(futureWork);
    futureWork.addListener(() -> {
        synchronized (ResourcePool.this) {
            pendingWork.remove(futureWork);
        }
    }, executorService);

    // If someone else calls cancel on `futureWork` it makes it impossible to wait for that future
    // to finish using the resource, which then makes shutdown code exit too early.
    return Futures.nonCancellationPropagating(futureWork);
}

From source file:com.google.NithPoints.core.PeerGroup.java

/**
 * <p>Given a transaction, sends it un-announced to one peer and then waits for it to be received back from other
 * peers. Once all connected peers have announced the transaction, the future will be completed. If anything goes
 * wrong the exception will be thrown when get() is called, or you can receive it via a callback on the
 * {@link ListenableFuture}. This method returns immediately, so if you want it to block just call get() on the
 * result.</p>//from  w  w  w  .j av a2s . c o  m
 *
 * <p>Note that if the PeerGroup is limited to only one connection (discovery is not activated) then the future
 * will complete as soon as the transaction was successfully written to that peer.</p>
 *
 * <p>Other than for sending your own transactions, this method is useful if you have received a transaction from
 * someone and want to know that it's valid. It's a bit of a weird hack because the current version of the NithPoints
 * protocol does not inform you if you send an invalid transaction. Because sending bad transactions counts towards
 * your DoS limit, be careful with relaying lots of unknown transactions. Otherwise you might get kicked off the
 * network.</p>
 *
 * <p>The transaction won't be sent until there are at least minConnections active connections available.
 * A good choice for proportion would be between 0.5 and 0.8 but if you want faster transmission during initial
 * bringup of the peer group you can lower it.</p>
 */
public ListenableFuture<Transaction> broadcastTransaction(final Transaction tx, final int minConnections) {
    final SettableFuture<Transaction> future = SettableFuture.create();
    log.info("Waiting for {} peers required for broadcast ...", minConnections);
    ListenableFuture<PeerGroup> peerAvailabilityFuture = waitForPeers(minConnections);
    peerAvailabilityFuture.addListener(new Runnable() {
        public void run() {
            // We now have enough connected peers to send the transaction.
            // This can be called immediately if we already have enough. Otherwise it'll be called from a peer
            // thread.

            // Pick a peer to be the lucky recipient of our tx. This can race if the peer we pick dies immediately.
            final Peer somePeer;
            lock.lock();
            try {
                somePeer = peers.get(0);
            } finally {
                lock.unlock();
            }
            log.info("broadcastTransaction: Enough peers, adding {} to the memory pool and sending to {}",
                    tx.getHashAsString(), somePeer);
            final Transaction pinnedTx = memoryPool.seen(tx, somePeer.getAddress());
            // Prepare to send the transaction by adding a listener that'll be called when confidence changes.
            // Only bother with this if we might actually hear back:
            if (minConnections > 1)
                tx.getConfidence().addEventListener(new TransactionConfidence.Listener() {
                    public void onConfidenceChanged(Transaction tx) {
                        // The number of peers that announced this tx has gone up.
                        // Thread safe - this can run in parallel.
                        final TransactionConfidence conf = tx.getConfidence();
                        int numSeenPeers = conf.numBroadcastPeers();
                        boolean mined = conf
                                .getConfidenceType() != TransactionConfidence.ConfidenceType.NOT_SEEN_IN_CHAIN;
                        log.info("broadcastTransaction: TX {} seen by {} peers{}", new Object[] {
                                pinnedTx.getHashAsString(), numSeenPeers, mined ? " and mined" : "" });
                        if (!(numSeenPeers >= minConnections || mined))
                            return;
                        // We've seen the min required number of peers announce the transaction, or it was included
                        // in a block. Normally we'd expect to see it fully propagate before it gets mined, but
                        // it can be that a block is solved very soon after broadcast, and it's also possible that
                        // due to version skew and changes in the relay rules our transaction is not going to
                        // fully propagate yet can get mined anyway.
                        //
                        // Note that we can't wait for the current number of connected peers right now because we
                        // could have added more peers after the broadcast took place, which means they won't
                        // have seen the transaction. In future when peers sync up their memory pools after they
                        // connect we could come back and change this.
                        //
                        // OK, now tell the wallet about the transaction. If the wallet created the transaction then
                        // it already knows and will ignore this. If it's a transaction we received from
                        // somebody else via a side channel and are now broadcasting, this will put it into the
                        // wallet now we know it's valid.
                        for (Wallet wallet : wallets) {
                            try {
                                // Assumption here is there are no dependencies of the created transaction.
                                //
                                // We may end up with two threads trying to do this in parallel - the wallet will
                                // ignore whichever one loses the race.
                                wallet.receivePending(pinnedTx, null);
                            } catch (Throwable t) {
                                future.setException(t); // RE-ENTRANCY POINT
                                return;
                            }
                        }
                        // We're done! It's important that the PeerGroup lock is not held (by this thread) at this
                        // point to avoid triggering inversions when the Future completes.
                        log.info("broadcastTransaction: {} complete", pinnedTx.getHashAsString());
                        tx.getConfidence().removeEventListener(this);
                        future.set(pinnedTx); // RE-ENTRANCY POINT
                    }
                });

            // Satoshis code sends an inv in this case and then lets the peer request the tx data. We just
            // blast out the TX here for a couple of reasons. Firstly it's simpler: in the case where we have
            // just a single connection we don't have to wait for getdata to be received and handled before
            // completing the future in the code immediately below. Secondly, it's faster. The reason the
            // Satoshi client sends an inv is privacy - it means you can't tell if the peer originated the
            // transaction or not. However, we are not a fully validating node and this is advertised in
            // our version message, as SPV nodes cannot relay it doesn't give away any additional information
            // to skip the inv here - we wouldn't send invs anyway.
            //
            // TODO: The peer we picked might be dead by now. If we can't write the message, pick again and retry.
            ChannelFuture sendComplete = somePeer.sendMessage(pinnedTx);
            // If we've been limited to talk to only one peer, we can't wait to hear back because the
            // remote peer won't tell us about transactions we just announced to it for obvious reasons.
            // So we just have to assume we're done, at that point. This happens when we're not given
            // any peer discovery source and the user just calls connectTo() once.
            if (minConnections == 1) {
                sendComplete.addListener(new ChannelFutureListener() {
                    public void operationComplete(ChannelFuture _) throws Exception {
                        for (Wallet wallet : wallets) {
                            try {
                                // Assumption here is there are no dependencies of the created transaction.
                                wallet.receivePending(pinnedTx, null);
                            } catch (Throwable t) {
                                future.setException(t);
                                return;
                            }
                        }
                        future.set(pinnedTx);
                    }
                });
            }
        }
    }, MoreExecutors.sameThreadExecutor());
    return future;
}

From source file:com.google.logicoin.core.PeerGroup.java

/**
 * <p>Given a transaction, sends it un-announced to one peer and then waits for it to be received back from other
 * peers. Once all connected peers have announced the transaction, the future will be completed. If anything goes
 * wrong the exception will be thrown when get() is called, or you can receive it via a callback on the
 * {@link ListenableFuture}. This method returns immediately, so if you want it to block just call get() on the
 * result.</p>//from w w w.  j a v a 2  s.  c o  m
 *
 * <p>Note that if the PeerGroup is limited to only one connection (discovery is not activated) then the future
 * will complete as soon as the transaction was successfully written to that peer.</p>
 *
 * <p>Other than for sending your own transactions, this method is useful if you have received a transaction from
 * someone and want to know that it's valid. It's a bit of a weird hack because the current version of the Bitcoin
 * protocol does not inform you if you send an invalid transaction. Because sending bad transactions counts towards
 * your DoS limit, be careful with relaying lots of unknown transactions. Otherwise you might get kicked off the
 * network.</p>
 *
 * <p>The transaction won't be sent until there are at least minConnections active connections available.
 * A good choice for proportion would be between 0.5 and 0.8 but if you want faster transmission during initial
 * bringup of the peer group you can lower it.</p>
 */
public ListenableFuture<Transaction> broadcastTransaction(final Transaction tx, final int minConnections) {
    final SettableFuture<Transaction> future = SettableFuture.create();
    log.info("Waiting for {} peers required for broadcast ...", minConnections);
    ListenableFuture<PeerGroup> peerAvailabilityFuture = waitForPeers(minConnections);
    peerAvailabilityFuture.addListener(new Runnable() {
        public void run() {
            // We now have enough connected peers to send the transaction.
            // This can be called immediately if we already have enough. Otherwise it'll be called from a peer
            // thread.

            // Pick a peer to be the lucky recipient of our tx. This can race if the peer we pick dies immediately.
            final Peer somePeer;
            lock.lock();
            try {
                somePeer = peers.get(0);
            } finally {
                lock.unlock();
            }
            log.info("broadcastTransaction: Enough peers, adding {} to the memory pool and sending to {}",
                    tx.getHashAsString(), somePeer);
            final Transaction pinnedTx = memoryPool.seen(tx, somePeer.getAddress());
            // Prepare to send the transaction by adding a listener that'll be called when confidence changes.
            // Only bother with this if we might actually hear back:
            if (minConnections > 1)
                tx.getConfidence().addEventListener(new TransactionConfidence.Listener() {
                    public void onConfidenceChanged(Transaction tx,
                            TransactionConfidence.Listener.ChangeReason reason) {
                        // The number of peers that announced this tx has gone up.
                        final TransactionConfidence conf = tx.getConfidence();
                        int numSeenPeers = conf.numBroadcastPeers();
                        boolean mined = tx.getAppearsInHashes() != null;
                        log.info("broadcastTransaction: TX {} seen by {} peers{}", new Object[] {
                                pinnedTx.getHashAsString(), numSeenPeers, mined ? " and mined" : "" });
                        if (!(numSeenPeers >= minConnections || mined))
                            return;
                        // We've seen the min required number of peers announce the transaction, or it was included
                        // in a block. Normally we'd expect to see it fully propagate before it gets mined, but
                        // it can be that a block is solved very soon after broadcast, and it's also possible that
                        // due to version skew and changes in the relay rules our transaction is not going to
                        // fully propagate yet can get mined anyway.
                        //
                        // Note that we can't wait for the current number of connected peers right now because we
                        // could have added more peers after the broadcast took place, which means they won't
                        // have seen the transaction. In future when peers sync up their memory pools after they
                        // connect we could come back and change this.
                        //
                        // OK, now tell the wallet about the transaction. If the wallet created the transaction then
                        // it already knows and will ignore this. If it's a transaction we received from
                        // somebody else via a side channel and are now broadcasting, this will put it into the
                        // wallet now we know it's valid.
                        for (Wallet wallet : wallets) {
                            try {
                                // Assumption here is there are no dependencies of the created transaction.
                                //
                                // We may end up with two threads trying to do this in parallel - the wallet will
                                // ignore whichever one loses the race.
                                wallet.receivePending(pinnedTx, null);
                            } catch (Throwable t) {
                                future.setException(t); // RE-ENTRANCY POINT
                                return;
                            }
                        }

                        // We're done! It's important that the PeerGroup lock is not held (by this thread) at this
                        // point to avoid triggering inversions when the Future completes.
                        log.info("broadcastTransaction: {} complete", pinnedTx.getHashAsString());
                        tx.getConfidence().removeEventListener(this);
                        future.set(pinnedTx); // RE-ENTRANCY POINT
                    }
                });

            // Satoshis code sends an inv in this case and then lets the peer request the tx data. We just
            // blast out the TX here for a couple of reasons. Firstly it's simpler: in the case where we have
            // just a single connection we don't have to wait for getdata to be received and handled before
            // completing the future in the code immediately below. Secondly, it's faster. The reason the
            // Satoshi client sends an inv is privacy - it means you can't tell if the peer originated the
            // transaction or not. However, we are not a fully validating node and this is advertised in
            // our version message, as SPV nodes cannot relay it doesn't give away any additional information
            // to skip the inv here - we wouldn't send invs anyway.
            //
            // TODO: The peer we picked might be dead by now. If we can't write the message, pick again and retry.
            ChannelFuture sendComplete = somePeer.sendMessage(pinnedTx);
            // If we've been limited to talk to only one peer, we can't wait to hear back because the
            // remote peer won't tell us about transactions we just announced to it for obvious reasons.
            // So we just have to assume we're done, at that point. This happens when we're not given
            // any peer discovery source and the user just calls connectTo() once.
            if (minConnections == 1) {
                sendComplete.addListener(new ChannelFutureListener() {
                    public void operationComplete(ChannelFuture _) throws Exception {
                        for (Wallet wallet : wallets) {
                            try {
                                // Assumption here is there are no dependencies of the created transaction.
                                wallet.receivePending(pinnedTx, null);
                            } catch (Throwable t) {
                                future.setException(t);
                                return;
                            }
                        }
                        future.set(pinnedTx);
                    }
                });
            }
        }
    }, Threading.SAME_THREAD);
    return future;
}

From source file:com.facebook.buck.distributed.build_slave.ThriftCoordinatorServer.java

public ThriftCoordinatorServer(OptionalInt port, ListenableFuture<BuildTargetsQueue> queue,
        StampedeId stampedeId, EventListener eventListener,
        CoordinatorBuildRuleEventsPublisher coordinatorBuildRuleEventsPublisher,
        MinionHealthTracker minionHealthTracker, DistBuildService distBuildService,
        MinionCountProvider minionCountProvider, Optional<String> coordinatorMinionId,
        boolean releasingMinionsEarlyEnabled) {
    this.eventListener = eventListener;
    this.stampedeId = stampedeId;
    this.coordinatorBuildRuleEventsPublisher = coordinatorBuildRuleEventsPublisher;
    this.minionHealthTracker = minionHealthTracker;
    this.distBuildService = distBuildService;
    this.minionCountProvider = minionCountProvider;
    this.coordinatorMinionId = coordinatorMinionId;
    this.releasingMinionsEarlyEnabled = releasingMinionsEarlyEnabled;
    this.lock = new Object();
    this.exitCodeFuture = new CompletableFuture<>();
    this.chromeTraceTracker = new DistBuildTraceTracker(stampedeId);
    this.port = port;
    this.handler = new IdleCoordinatorService();
    this.deadMinions = new HashSet<>();
    CoordinatorServiceHandler handlerWrapper = new CoordinatorServiceHandler();
    this.processor = new CoordinatorService.Processor<>(handlerWrapper);
    queue.addListener(() -> switchToActiveModeOrFail(queue), MoreExecutors.directExecutor());
}