All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glowroot.central.util.MoreFutures Maven / Gradle / Ivy

/*
 * Copyright 2016-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.glowroot.central.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;

import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.exceptions.DriverException;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MoreFutures {

    private static final Logger logger = LoggerFactory.getLogger(MoreFutures.class);

    private MoreFutures() {}

    public static void waitForAll(Collection> futures) throws Exception {
        Exception exception = null;
        for (Future future : futures) {
            if (exception != null) {
                future.cancel(true);
            } else {
                try {
                    future.get();
                } catch (InterruptedException | ExecutionException e) {
                    logger.debug(e.getMessage(), e);
                    exception = e;
                }
            }
        }
        if (exception == null) {
            return;
        }
        if (exception instanceof ExecutionException) {
            throw unwrapDriverException((ExecutionException) exception);
        }
        throw exception;
    }

    public static  ListenableFuture onFailure(ListenableFuture future,
            Runnable onFailure) {
        SettableFuture outerFuture = SettableFuture.create();
        Futures.addCallback(future, new FutureCallback() {
            @Override
            public void onSuccess(V result) {
                outerFuture.set(result);
            }
            @Override
            public void onFailure(Throwable t) {
                logger.debug(t.getMessage(), t);
                onFailure.run();
                outerFuture.setException(t);
            }
        }, MoreExecutors.directExecutor());
        return outerFuture;
    }

    public static  ListenableFuture onSuccessAndFailure(ListenableFuture future,
            Runnable onSuccess, Runnable onFailure) {
        SettableFuture outerFuture = SettableFuture.create();
        Futures.addCallback(future, new FutureCallback() {
            @Override
            public void onSuccess(V result) {
                onSuccess.run();
                outerFuture.set(result);
            }
            @Override
            public void onFailure(Throwable t) {
                logger.debug(t.getMessage(), t);
                onFailure.run();
                outerFuture.setException(t);
            }
        }, MoreExecutors.directExecutor());
        return outerFuture;
    }

    public static ListenableFuture rollupAsync(ListenableFuture input,
            Executor asyncExecutor, DoRollup function) {
        return transformAsync(input, asyncExecutor,
                new AsyncFunction() {
                    @Override
                    @SuppressWarnings("unchecked")
                    public ListenableFuture apply(ResultSet results)
                            throws Exception {
                        if (results.isExhausted()) {
                            return Futures.immediateFuture(null);
                        }
                        return (ListenableFuture) function.execute(results);
                    }
                });
    }

    public static ListenableFuture rollupAsync(Collection> futures,
            Executor asyncExecutor, DoRollup function) {
        return transformAsync(Futures.allAsList(futures), asyncExecutor,
                new AsyncFunction, /*@Nullable*/ Object>() {
                    @Override
                    @SuppressWarnings("unchecked")
                    public ListenableFuture apply(List list)
                            throws Exception {
                        List rows = new ArrayList<>();
                        for (ResultSet results : list) {
                            rows.addAll(results.all());
                        }
                        if (rows.isEmpty()) {
                            return Futures.immediateFuture(null);
                        }
                        return (ListenableFuture) function.execute(rows);
                    }
                });
    }

    public static ListenableFuture transformAsync(ListenableFuture input,
            Executor asyncExecutor, DoWithResults function) {
        return transformAsync(input, asyncExecutor,
                new AsyncFunction() {
                    @Override
                    @SuppressWarnings("unchecked")
                    public ListenableFuture apply(ResultSet results)
                            throws Exception {
                        return (ListenableFuture) function.execute(results);
                    }
                });
    }

    private static  ListenableFuture transformAsync(ListenableFuture future,
            Executor asyncExecutor, AsyncFunction function) {
        boolean inRollupThread = Session.isInRollupThread();
        return Futures.transformAsync(future,
                new AsyncFunction() {
                    @Override
                    public ListenableFuture apply(V input) throws Exception {
                        boolean priorInRollupThread = Session.isInRollupThread();
                        Session.setInRollupThread(inRollupThread);
                        try {
                            return function.apply(input);
                        } finally {
                            Session.setInRollupThread(priorInRollupThread);
                        }
                    }
                },
                // calls to Session.readAsync() inside of the function could block due to the
                // per-thread concurrent limit, so this needs to be executed in its own thread, not
                // in the cassandra driver thread that completes the last future which will block
                // the cassandra driver thread pool
                asyncExecutor);
    }

    public static Exception unwrapDriverException(ExecutionException e) {
        Throwable cause = e.getCause();
        if (cause instanceof DriverException) {
            // see com.datastax.driver.core.DriverThrowables.propagateCause()
            return ((DriverException) cause).copy();
        } else {
            return e;
        }
    }

    public interface DoWithResults {
        ListenableFuture execute(ResultSet results) throws Exception;
    }

    public interface DoRollup {
        ListenableFuture execute(Iterable rows) throws Exception;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy