zipkin2.storage.cassandra.internal.call.ResultSetFutureCall.java Source code

Java tutorial

Introduction

Here is the source code for zipkin2.storage.cassandra.internal.call.ResultSetFutureCall.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 zipkin2.storage.cassandra.internal.call;

import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.ResultSetFuture;
import com.datastax.driver.core.exceptions.DriverException;
import com.datastax.driver.core.exceptions.DriverInternalError;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.Uninterruptibles;
import java.util.concurrent.ExecutionException;
import zipkin2.Call;
import zipkin2.Callback;

/**
 * Future call pattern that takes advantage of special 'get' hooks on {@link
 * com.datastax.driver.core.ResultSetFuture}.
 */
// some copy/pasting is ok here as debugging is obscured when the type hierarchy gets deep.
public abstract class ResultSetFutureCall<V> extends Call.Base<V> implements Call.Mapper<ResultSet, V> {
    /** Defers I/O until {@link #enqueue(Callback)} or {@link #execute()} are called. */
    protected abstract ListenableFuture<ResultSet> newFuture();

    volatile ListenableFuture<ResultSet> future;

    @Override
    protected V doExecute() {
        return map(getUninterruptibly(future = newFuture()));
    }

    @Override
    protected void doEnqueue(Callback<V> callback) {
        // Similar to Futures.addCallback except doesn't double-wrap
        class CallbackListener implements Runnable {
            @Override
            public void run() {
                try {
                    callback.onSuccess(map(getUninterruptibly(future)));
                } catch (RuntimeException | Error e) {
                    propagateIfFatal(e);
                    callback.onError(e);
                }
            }
        }
        try {
            (future = newFuture()).addListener(new CallbackListener(), DirectExecutor.INSTANCE);
        } catch (RuntimeException | Error e) {
            callback.onError(e);
            throw e;
        }
    }

    @Override
    protected void doCancel() {
        ListenableFuture<ResultSet> maybeFuture = future;
        if (maybeFuture != null)
            maybeFuture.cancel(true);
    }

    @Override
    protected final boolean doIsCanceled() {
        ListenableFuture<ResultSet> maybeFuture = future;
        return maybeFuture != null && maybeFuture.isCancelled();
    }

    static ResultSet getUninterruptibly(ListenableFuture<ResultSet> future) {
        if (future instanceof ResultSetFuture) {
            return ((ResultSetFuture) future).getUninterruptibly();
        }
        try { // emulate ResultSetFuture.getUninterruptibly
            return Uninterruptibles.getUninterruptibly(future);
        } catch (ExecutionException e) {
            Throwable cause = e.getCause();
            if (cause instanceof Error)
                throw ((Error) cause);
            if (cause instanceof DriverException)
                throw ((DriverException) cause).copy();
            throw new DriverInternalError("Unexpected exception thrown", cause);
        }
    }
}