/*
 * 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 com.datastax.driver.core;

import com.datastax.driver.core.exceptions.NoHostAvailableException;
import com.datastax.driver.core.exceptions.QueryExecutionException;
import com.datastax.driver.core.exceptions.QueryValidationException;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * A future on a {@link ResultSet}.
 *
 * <p>Note that this class implements <a href="http://github.com/google/guava/">Guava</a>'s {@code
 * ListenableFuture} and can so be used with Guava's future utilities.
 */
public interface ResultSetFuture extends ListenableFuture<ResultSet> {

  /**
   * Waits for the query to return and return its result.
   *
   * <p>This method is usually more convenient than {@link #get} because it:
   *
   * <ul>
   *   <li>Waits for the result uninterruptibly, and so doesn't throw {@link InterruptedException}.
   *   <li>Returns meaningful exceptions, instead of having to deal with ExecutionException.
   * </ul>
   *
   * As such, it is the preferred way to get the future result.
   *
   * @return the query result set.
   * @throws NoHostAvailableException if no host in the cluster can be contacted successfully to
   *     execute this query.
   * @throws QueryExecutionException if the query triggered an execution exception, that is an
   *     exception thrown by Cassandra when it cannot execute the query with the requested
   *     consistency level successfully.
   * @throws QueryValidationException if the query is invalid (syntax error, unauthorized or any
   *     other validation problem).
   */
  public ResultSet getUninterruptibly();

  /**
   * Waits for the provided time for the query to return and return its result if available.
   *
   * <p>This method is usually more convenient than {@link #get} because it:
   *
   * <ul>
   *   <li>Waits for the result uninterruptibly, and so doesn't throw {@link InterruptedException}.
   *   <li>Returns meaningful exceptions, instead of having to deal with ExecutionException.
   * </ul>
   *
   * As such, it is the preferred way to get the future result.
   *
   * @param timeout the time to wait for the query to return.
   * @param unit the unit for {@code timeout}.
   * @return the query result set.
   * @throws NoHostAvailableException if no host in the cluster can be contacted successfully to
   *     execute this query.
   * @throws QueryExecutionException if the query triggered an execution exception, that is an
   *     exception thrown by Cassandra when it cannot execute the query with the requested
   *     consistency level successfully.
   * @throws QueryValidationException if the query if invalid (syntax error, unauthorized or any
   *     other validation problem).
   * @throws TimeoutException if the wait timed out (Note that this is different from a Cassandra
   *     timeout, which is a {@code QueryExecutionException}).
   */
  public ResultSet getUninterruptibly(long timeout, TimeUnit unit) throws TimeoutException;

  /**
   * Attempts to cancel the execution of the request corresponding to this future. This attempt will
   * fail if the request has already returned.
   *
   * <p>Please note that this only cancel the request driver side, but nothing is done to interrupt
   * the execution of the request Cassandra side (and that even if {@code mayInterruptIfRunning} is
   * true) since Cassandra does not support such interruption.
   *
   * <p>This method can be used to ensure no more work is performed driver side (which, while it
   * doesn't include stopping a request already submitted to a Cassandra node, may include not
   * retrying another Cassandra host on failure/timeout) if the ResultSet is not going to be
   * retried. Typically, the code to wait for a request result for a maximum of 1 second could look
   * like:
   *
   * <pre>
   *   ResultSetFuture future = session.executeAsync(...some query...);
   *   try {
   *       ResultSet result = future.get(1, TimeUnit.SECONDS);
   *       ... process result ...
   *   } catch (TimeoutException e) {
   *       future.cancel(true); // Ensure any resource used by this query driver
   *                            // side is released immediately
   *       ... handle timeout ...
   *   }
   * </pre>
   *
   * @param mayInterruptIfRunning the value of this parameter is currently ignored.
   * @return {@code false} if the future could not be cancelled (it has already completed normally);
   *     {@code true} otherwise.
   */
  @Override
  public boolean cancel(boolean mayInterruptIfRunning);
}
