Example usage for com.google.common.util.concurrent AsyncFunction AsyncFunction

List of usage examples for com.google.common.util.concurrent AsyncFunction AsyncFunction

Introduction

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

Prototype

AsyncFunction

Source Link

Usage

From source file:org.opendaylight.vpnservice.natservice.internal.VpnFloatingIpHandler.java

@Override
public void onRemoveFloatingIp(final BigInteger dpnId, String routerId, Uuid networkId, final String externalIp,
        String internalIp, final long label) {
    final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
    if (vpnName == null) {
        LOG.info("No VPN associated with ext nw {} to handle remove floating ip configuration {} in router {}",
                networkId, externalIp, routerId);
        return;//from   www  . ja va  2 s.c  o  m
    }
    //Remove Prefix from BGP
    String rd = NatUtil.getVpnRd(dataBroker, vpnName);
    removePrefixFromBGP(rd, externalIp + "/32");

    //Remove custom FIB routes
    //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
    RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId)
            .setIpAddress(externalIp + "/32").setServiceId(label).build();
    Future<RpcResult<Void>> future = fibService.removeFibEntry(input);

    ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(
            JdkFutureAdapters.listenInPoolThread(future),
            new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {

                @Override
                public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
                    //Release label
                    if (result.isSuccessful()) {
                        removeTunnelTableEntry(dpnId, label);
                        removeLFibTableEntry(dpnId, label);
                        RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName)
                                .setIpPrefix(externalIp).build();
                        Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
                        return JdkFutureAdapters.listenInPoolThread(labelFuture);
                    } else {
                        String errMsg = String.format(
                                "RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s",
                                dpnId, externalIp, result.getErrors());
                        LOG.error(errMsg);
                        return Futures.immediateFailedFuture(new RuntimeException(errMsg));
                    }
                }
            });

    Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {

        @Override
        public void onFailure(Throwable error) {
            LOG.error("Error in removing the label or custom fib entries", error);
        }

        @Override
        public void onSuccess(RpcResult<Void> result) {
            if (result.isSuccessful()) {
                LOG.debug("Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
            } else {
                LOG.error("Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName,
                        result.getErrors());
            }
        }
    });
}

From source file:com.spotify.futures.FuturesExtra.java

/**
 * Transform the input futures into a single future, using the provided
 * transform function. The transformation follows the same semantics as as
 * {@link Futures#transform(ListenableFuture, AsyncFunction)} and the input
 * futures are combined using {@link Futures#allAsList}.
 *
 * @param a a ListenableFuture to combine
 * @param b a ListenableFuture to combine
 * @param function the implementation of the transform
 * @return a ListenableFuture holding the result of function.apply()
 *//* w  w  w  .j  a  va2s  .c om*/
public static <Z, A, B> ListenableFuture<Z> asyncTransform2(ListenableFuture<A> a, ListenableFuture<B> b,
        final AsyncFunction2<Z, ? super A, ? super B> function) {
    return transform(Arrays.asList(a, b), new AsyncFunction<List<Object>, Z>() {
        @Override
        public ListenableFuture<Z> apply(List<Object> results) throws Exception {
            return function.apply((A) results.get(0), (B) results.get(1));
        }
    });
}

From source file:com.orangerhymelabs.helenus.cassandra.document.DocumentService.java

public ListenableFuture<Document> update(String database, String table, Document document) {
    ListenableFuture<AbstractDocumentRepository> docs = acquireRepositoryFor(database, table);
    return Futures.transformAsync(docs, new AsyncFunction<AbstractDocumentRepository, Document>() {
        @Override/*from   w  ww.  ja v  a2 s .  com*/
        public ListenableFuture<Document> apply(AbstractDocumentRepository input) throws Exception {
            try {
                ValidationEngine.validateAndThrow(document);
                return input.update(document);
            } catch (ValidationException e) {
                return Futures.immediateFailedFuture(e);
            }
        }
    }, MoreExecutors.directExecutor());
}

From source file:org.apache.cassandra.repair.RepairRunnable.java

protected void runMayThrow() throws Exception {
    final TraceState traceState;

    final String tag = "repair:" + cmd;

    final AtomicInteger progress = new AtomicInteger();
    final int totalProgress = 3 + options.getRanges().size(); // calculate neighbors, validation, prepare for repair + number of ranges to repair

    String[] columnFamilies = options.getColumnFamilies()
            .toArray(new String[options.getColumnFamilies().size()]);
    Iterable<ColumnFamilyStore> validColumnFamilies = storageService.getValidColumnFamilies(false, false,
            keyspace, columnFamilies);//  w w w  .  jav a  2 s  . c  o  m

    final long startTime = System.currentTimeMillis();
    String message = String.format("Starting repair command #%d, repairing keyspace %s with %s", cmd, keyspace,
            options);
    logger.info(message);
    fireProgressEvent(tag, new ProgressEvent(ProgressEventType.START, 0, 100, message));
    if (options.isTraced()) {
        StringBuilder cfsb = new StringBuilder();
        for (ColumnFamilyStore cfs : validColumnFamilies)
            cfsb.append(", ").append(cfs.keyspace.getName()).append(".").append(cfs.name);

        UUID sessionId = Tracing.instance.newSession(Tracing.TraceType.REPAIR);
        traceState = Tracing.instance.begin("repair",
                ImmutableMap.of("keyspace", keyspace, "columnFamilies", cfsb.substring(2)));
        Tracing.traceRepair(message);
        traceState.enableActivityNotification(tag);
        for (ProgressListener listener : listeners)
            traceState.addProgressListener(listener);
        Thread queryThread = createQueryThread(cmd, sessionId);
        queryThread.setName("RepairTracePolling");
        queryThread.start();
    } else {
        traceState = null;
    }

    final Set<InetAddress> allNeighbors = new HashSet<>();
    Map<Range, Set<InetAddress>> rangeToNeighbors = new HashMap<>();
    try {
        for (Range<Token> range : options.getRanges()) {
            Set<InetAddress> neighbors = ActiveRepairService.getNeighbors(keyspace, range,
                    options.getDataCenters(), options.getHosts());
            rangeToNeighbors.put(range, neighbors);
            allNeighbors.addAll(neighbors);
        }
        progress.incrementAndGet();
    } catch (IllegalArgumentException e) {
        logger.error("Repair failed:", e);
        fireErrorAndComplete(tag, progress.get(), totalProgress, e.getMessage());
        return;
    }

    // Validate columnfamilies
    List<ColumnFamilyStore> columnFamilyStores = new ArrayList<>();
    try {
        Iterables.addAll(columnFamilyStores, validColumnFamilies);
        progress.incrementAndGet();
    } catch (IllegalArgumentException e) {
        fireErrorAndComplete(tag, progress.get(), totalProgress, e.getMessage());
        return;
    }

    String[] cfnames = new String[columnFamilyStores.size()];
    for (int i = 0; i < columnFamilyStores.size(); i++) {
        cfnames[i] = columnFamilyStores.get(i).name;
    }

    final UUID parentSession = UUIDGen.getTimeUUID();
    SystemDistributedKeyspace.startParentRepair(parentSession, keyspace, cfnames, options.getRanges());
    long repairedAt;
    try {
        ActiveRepairService.instance.prepareForRepair(parentSession, allNeighbors, options, columnFamilyStores);
        repairedAt = ActiveRepairService.instance.getParentRepairSession(parentSession).getRepairedAt();
        progress.incrementAndGet();
    } catch (Throwable t) {
        SystemDistributedKeyspace.failParentRepair(parentSession, t);
        fireErrorAndComplete(tag, progress.get(), totalProgress, t.getMessage());
        return;
    }

    // Set up RepairJob executor for this repair command.
    final ListeningExecutorService executor = MoreExecutors.listeningDecorator(
            new JMXConfigurableThreadPoolExecutor(options.getJobThreads(), Integer.MAX_VALUE, TimeUnit.SECONDS,
                    new LinkedBlockingQueue<Runnable>(), new NamedThreadFactory("Repair#" + cmd), "internal"));

    List<ListenableFuture<RepairSessionResult>> futures = new ArrayList<>(options.getRanges().size());
    for (Range<Token> range : options.getRanges()) {
        final RepairSession session = ActiveRepairService.instance.submitRepairSession(parentSession, range,
                keyspace, options.getParallelism(), rangeToNeighbors.get(range), repairedAt, executor, cfnames);
        if (session == null)
            continue;
        // After repair session completes, notify client its result
        Futures.addCallback(session, new FutureCallback<RepairSessionResult>() {
            public void onSuccess(RepairSessionResult result) {
                String message = String.format("Repair session %s for range %s finished", session.getId(),
                        session.getRange().toString());
                logger.info(message);
                fireProgressEvent(tag, new ProgressEvent(ProgressEventType.PROGRESS, progress.incrementAndGet(),
                        totalProgress, message));
            }

            public void onFailure(Throwable t) {
                String message = String.format("Repair session %s for range %s failed with error %s",
                        session.getId(), session.getRange().toString(), t.getMessage());
                logger.error(message, t);
                fireProgressEvent(tag, new ProgressEvent(ProgressEventType.PROGRESS, progress.incrementAndGet(),
                        totalProgress, message));
            }
        });
        futures.add(session);
    }

    // After all repair sessions completes(successful or not),
    // run anticompaction if necessary and send finish notice back to client
    final Collection<Range<Token>> successfulRanges = new ArrayList<>();
    final AtomicBoolean hasFailure = new AtomicBoolean();
    final ListenableFuture<List<RepairSessionResult>> allSessions = Futures.successfulAsList(futures);
    ListenableFuture anticompactionResult = Futures.transform(allSessions,
            new AsyncFunction<List<RepairSessionResult>, Object>() {
                @SuppressWarnings("unchecked")
                public ListenableFuture apply(List<RepairSessionResult> results) throws Exception {
                    // filter out null(=failed) results and get successful ranges
                    for (RepairSessionResult sessionResult : results) {
                        if (sessionResult != null) {
                            successfulRanges.add(sessionResult.range);
                        } else {
                            hasFailure.compareAndSet(false, true);
                        }
                    }
                    return ActiveRepairService.instance.finishParentSession(parentSession, allNeighbors,
                            successfulRanges);
                }
            });
    Futures.addCallback(anticompactionResult, new FutureCallback<Object>() {
        public void onSuccess(Object result) {
            SystemDistributedKeyspace.successfulParentRepair(parentSession, successfulRanges);
            if (hasFailure.get()) {
                fireProgressEvent(tag, new ProgressEvent(ProgressEventType.ERROR, progress.get(), totalProgress,
                        "Some repair failed"));
            } else {
                fireProgressEvent(tag, new ProgressEvent(ProgressEventType.SUCCESS, progress.get(),
                        totalProgress, "Repair completed successfully"));
            }
            repairComplete();
        }

        public void onFailure(Throwable t) {
            fireProgressEvent(tag,
                    new ProgressEvent(ProgressEventType.ERROR, progress.get(), totalProgress, t.getMessage()));
            SystemDistributedKeyspace.failParentRepair(parentSession, t);
            repairComplete();
        }

        private void repairComplete() {
            String duration = DurationFormatUtils.formatDurationWords(System.currentTimeMillis() - startTime,
                    true, true);
            String message = String.format("Repair command #%d finished in %s", cmd, duration);
            fireProgressEvent(tag,
                    new ProgressEvent(ProgressEventType.COMPLETE, progress.get(), totalProgress, message));
            logger.info(message);
            if (options.isTraced() && traceState != null) {
                for (ProgressListener listener : listeners)
                    traceState.removeProgressListener(listener);
                // Because DebuggableThreadPoolExecutor#afterExecute and this callback
                // run in a nondeterministic order (within the same thread), the
                // TraceState may have been nulled out at this point. The TraceState
                // should be traceState, so just set it without bothering to check if it
                // actually was nulled out.
                Tracing.instance.set(traceState);
                Tracing.traceRepair(message);
                Tracing.instance.stopSession();
            }
            executor.shutdownNow();
        }
    });
}

From source file:org.opendaylight.camera.impl.CameraProvider.java

/**
 * Read the CameraStatus and, if currently Off, try to write the status to
 * On. If that succeeds, then we essentially have an exclusive lock and can
 * proceed to click the photo.//www .j av  a 2  s .  com
 *
 * @param input
 * @param futureResult
 * @param tries
 */
private void checkStatusandClickPhoto(final ClickPhotoInput input,
        final SettableFuture<RpcResult<Void>> futureResult, final int tries) {
    /*
     * We create a ReadWriteTransaction by using the databroker. Then, we
     * read the status of the camera with getCameraStatus() using the
     * databroker again. Once we have the status, we analyze it and then
     * databroker submit function is called to effectively change the camera
     * status. This all affects the MD-SAL tree, more specifically the part
     * of the tree that contain the camera (the nodes).
     */
    LOG.info("In checkStatusandClickPhoto()");
    final ReadWriteTransaction tx = db.newReadWriteTransaction();
    ListenableFuture<Optional<CameraParams>> readFuture = tx.read(LogicalDatastoreType.OPERATIONAL, CAMERA_IID);

    final ListenableFuture<Void> commitFuture = Futures.transform(readFuture,
            new AsyncFunction<Optional<CameraParams>, Void>() {

                @SuppressWarnings("deprecation")
                @Override
                public ListenableFuture<Void> apply(Optional<CameraParams> cameraParamsData) throws Exception {
                    // TODO Auto-generated method stub
                    if (cameraParamsData.isPresent()) {
                        status = cameraParamsData.get().getCameraStatus();
                    } else {
                        throw new Exception("Error reading CameraParams data from the store.");
                    }
                    LOG.info("Read camera status: {}", status);
                    if (status == CameraStatus.Off) {
                        //Check if numberOfPhotosAvailable is not 0, if yes Notify outOfStock
                        if (numberOfPhotosAvailable.get() == 0) {
                            LOG.info("No more photos availble for clicking");
                            notificationProvider.publish(new CameraOutOfPhotosBuilder().build());
                            return Futures.immediateFailedCheckedFuture(
                                    new TransactionCommitFailedException("", clickNoMorePhotosError()));
                        }
                        LOG.info("Setting Camera status to On");
                        // We're not currently clicking photo - try to
                        // update the status to On
                        // to indicate we're going to click photo. This acts
                        // as a lock to prevent
                        // concurrent clicking.
                        tx.put(LogicalDatastoreType.OPERATIONAL, CAMERA_IID,
                                buildCameraParams(CameraStatus.On));
                        return tx.submit();
                    }

                    LOG.info("Oops - already clicking photo!");
                    // Return an error since we are already clicking photo.
                    // This will get
                    // propagated to the commitFuture below which will
                    // interpret the null
                    // TransactionStatus in the RpcResult as an error
                    // condition.
                    return Futures.immediateFailedCheckedFuture(
                            new TransactionCommitFailedException("", clickPhotoInUseError()));
                }

                private RpcError clickNoMorePhotosError() {
                    return RpcResultBuilder.newError(ErrorType.APPLICATION, "resource-denied",
                            "No more photos available for clicking", "out-of-stock", null, null);
                }
            });
    Futures.addCallback(commitFuture, new FutureCallback<Void>() {

        @Override
        public void onFailure(Throwable t) {
            if (t instanceof OptimisticLockFailedException) {
                // Another thread is likely trying to click a photo
                // simultaneously and updated the
                // status before us. Try reading the status again - if
                // another click-photo is
                // now in progress, we should get CameraStatus.Off and fail.
                if ((tries - 1) > 0) {
                    LOG.info("Got OptimisticLockFailedException - trying again");
                    checkStatusandClickPhoto(input, futureResult, tries - 1);
                } else {
                    futureResult.set(RpcResultBuilder.<Void>failed()
                            .withError(ErrorType.APPLICATION, t.getMessage()).build());
                }
            } else {
                LOG.info("Failed to commit Camera status", t);
                // Probably already clicking a photo.
                futureResult.set(RpcResultBuilder.<Void>failed()
                        .withRpcErrors(((TransactionCommitFailedException) t).getErrorList()).build());
            }
        }

        @Override
        public void onSuccess(Void result) {
            // OK to click a photo
            currentClickPhotoTask.set(executor.submit(new ClickPhotoTask(input, futureResult)));

        }

    });
}

From source file:com.metamx.rdiclient.RdiClientImpl.java

private ListenableFuture<HttpResponseStatus> retryingPost(final RequestBuilder request, final int attempt,
        final int maxRetries) {
    final SettableFuture<HttpResponseStatus> retVal = SettableFuture.create();
    final ListenableFuture<HttpResponseStatus> response = Futures.transform(
            request.go(new StatusResponseHandler(Charsets.UTF_8)),
            new AsyncFunction<StatusResponseHolder, HttpResponseStatus>() {
                @Override/*from w  ww . j  a va 2  s. c o m*/
                public ListenableFuture<HttpResponseStatus> apply(StatusResponseHolder result)
                        throws Exception {
                    // Throw an RdiHttpResponseException in case of unexpected HTTP status codes.
                    if (result.getStatus().getCode() / 100 == 2) {
                        return Futures.immediateFuture(result.getStatus());
                    } else {
                        return Futures.immediateFailedFuture(new RdiHttpResponseException(result));
                    }
                }
            });
    Futures.addCallback(response, new FutureCallback<HttpResponseStatus>() {
        @Override
        public void onSuccess(HttpResponseStatus result) {
            retVal.set(result);
        }

        @Override
        public void onFailure(Throwable e) {
            final boolean shouldRetry;
            if (maxRetries <= 0) {
                shouldRetry = false;
            } else if (e instanceof IOException || e instanceof ChannelException) {
                shouldRetry = true;
            } else if (e instanceof RdiHttpResponseException) {
                final int statusCode = ((RdiHttpResponseException) e).getStatusCode();
                shouldRetry = statusCode / 100 == 5 || (statusCode / 100 == 4 && statusCode != 400);
            } else {
                shouldRetry = false;
            }

            if (shouldRetry) {
                final long sleepMillis = retryDuration(attempt);
                log.warn(e, "Failed try #%d, retrying in %,dms (%,d tries left).", attempt + 1, sleepMillis,
                        maxRetries);
                retryExecutor.schedule(new Runnable() {
                    @Override
                    public void run() {
                        final ListenableFuture<HttpResponseStatus> nextTry = retryingPost(request, attempt + 1,
                                maxRetries - 1);
                        Futures.addCallback(nextTry, new FutureCallback<HttpResponseStatus>() {
                            @Override
                            public void onSuccess(HttpResponseStatus result2) {
                                retVal.set(result2);
                            }

                            @Override
                            public void onFailure(Throwable e2) {
                                retVal.setException(e2);
                            }
                        });
                    }
                }, sleepMillis, TimeUnit.MILLISECONDS);
            } else if (e instanceof RdiException || e instanceof Error) {
                retVal.setException(e);
            } else {
                retVal.setException(new RdiException(String
                        .format("Got exception when posting events to urlString[%s].", config.getRdiUrl()), e));
            }
        }
    });

    return retVal;
}

From source file:io.vitess.client.VTGateConnection.java

/**
 * This method splits the query into small parts based on the splitColumn and Algorithm type provided.
 *
 * @param ctx                 Context on user and execution deadline if any.
 * @param keyspace            Keyspace to execute the query on.
 * @param query               Sql Query to be executed.
 * @param bindVars            Parameters to bind with sql.
 * @param splitColumns        Column to be used to split the data.
 * @param splitCount          Number of Partitions
 * @param numRowsPerQueryPart Limit the number of records per query part.
 * @param algorithm           EQUAL_SPLITS or FULL_SCAN
 * @return SQL Future with Query Parts//  w w  w  .j  av  a2s  .c om
 * @throws SQLException If anything fails on query execution.
 */
public SQLFuture<List<SplitQueryResponse.Part>> splitQuery(Context ctx, String keyspace, String query,
        @Nullable Map<String, ?> bindVars, Iterable<String> splitColumns, int splitCount,
        int numRowsPerQueryPart, Algorithm algorithm) throws SQLException {
    SplitQueryRequest.Builder requestBuilder = SplitQueryRequest.newBuilder()
            .setKeyspace(checkNotNull(keyspace)).setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
            .addAllSplitColumn(splitColumns).setSplitCount(splitCount)
            .setNumRowsPerQueryPart(numRowsPerQueryPart).setAlgorithm(algorithm);

    if (ctx.getCallerId() != null) {
        requestBuilder.setCallerId(ctx.getCallerId());
    }

    return new SQLFuture<>(transformAsync(client.splitQuery(ctx, requestBuilder.build()),
            new AsyncFunction<SplitQueryResponse, List<SplitQueryResponse.Part>>() {
                @Override
                public ListenableFuture<List<SplitQueryResponse.Part>> apply(SplitQueryResponse response)
                        throws Exception {
                    return Futures.immediateFuture(response.getSplitsList());
                }
            }, directExecutor()));
}

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

@Override
public synchronized void close() {
    Preconditions.checkState(!closing.get());
    closing.set(true);/*from w w w  . j av  a 2s.  c om*/

    // Unblock all waiting requests.
    for (SettableFuture<Void> request : resourceRequests) {
        request.set(null);
    }
    resourceRequests.clear();

    // Any processing that is currently taking place will be allowed to complete (as it won't notice
    // `closing` is true.
    // Any scheduled (but not executing) resource requests should notice `closing` is true and
    // mark themselves as cancelled.
    // Therefore `closeFuture` should allow us to wait for any resources that are in use.
    ListenableFuture<List<Object>> closeFuture = Futures.successfulAsList(pendingWork);

    // As silly as it seems this is the only reliable way to make sure we run the shutdown code.
    // Reusing an external executor means we run the risk of it being shut down before the cleanup
    // future is ready to run (which causes it to never run).
    // Using a direct executor means we run the chance of executing shutdown synchronously (which
    // we try to avoid).
    final ExecutorService executorService = MostExecutors.newSingleThreadExecutor("resource shutdown");

    // It is possible that more requests for work are scheduled at this point, however they should
    // all early-out due to `closing` being set to true, so we don't really care about those.
    shutdownFuture = Futures.transformAsync(closeFuture, new AsyncFunction<List<Object>, Void>() {
        @Override
        public ListenableFuture<Void> apply(List<Object> input) throws Exception {
            synchronized (ResourcePool.this) {
                if (parkedResources.size() != createdResources.size()) {
                    LOG.error("Whoops! Some resource are still in use during shutdown.");
                }
                // Now that pending work is done we can close all resources.
                for (R resource : createdResources) {
                    resource.close();
                }
                if (!resourceRequests.isEmpty()) {
                    LOG.error("Error shutting down ResourcePool: "
                            + "there should be no enqueued resource requests.");
                }
            }
            executorService.shutdown();
            return Futures.immediateFuture(null);
        }
    }, executorService);
}

From source file:com.orangerhymelabs.helenus.cassandra.document.AbstractDocumentRepository.java

public ListenableFuture<Document> upsert(Document entity) {
    ListenableFuture<ResultSet> future = submitUpsert(entity);
    return Futures.transformAsync(future, new AsyncFunction<ResultSet, Document>() {
        @Override/*  w  w  w.ja va  2s .  c o m*/
        public ListenableFuture<Document> apply(ResultSet result) throws Exception {
            if (result.wasApplied()) {
                return Futures.immediateFuture(entity);
            }

            //TODO: This doesn't provide any informational value... what should it be?
            return Futures.immediateFailedFuture(new StorageException(
                    String.format("Table %s failed to store document: %s", tableName, entity.toString())));
        }
    }, MoreExecutors.directExecutor());
}

From source file:io.vitess.client.VTGateConn.java

public SQLFuture<Cursor> executeEntityIds(Context ctx, String query, String keyspace, String entityColumnName,
        Map<byte[], ?> entityKeyspaceIds, @Nullable Map<String, ?> bindVars, TabletType tabletType,
        Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
    ExecuteEntityIdsRequest.Builder requestBuilder = ExecuteEntityIdsRequest.newBuilder()
            .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)).setKeyspace(checkNotNull(keyspace))
            .setEntityColumnName(checkNotNull(entityColumnName))
            .addAllEntityKeyspaceIds(//from w w  w  . jav a  2s .  c  o  m
                    Iterables.transform(entityKeyspaceIds.entrySet(), Proto.MAP_ENTRY_TO_ENTITY_KEYSPACE_ID))
            .setTabletType(checkNotNull(tabletType))
            .setOptions(Query.ExecuteOptions.newBuilder().setIncludedFields(includedFields));

    if (ctx.getCallerId() != null) {
        requestBuilder.setCallerId(ctx.getCallerId());
    }

    return new SQLFuture<Cursor>(transformAsync(client.executeEntityIds(ctx, requestBuilder.build()),
            new AsyncFunction<ExecuteEntityIdsResponse, Cursor>() {
                @Override
                public ListenableFuture<Cursor> apply(ExecuteEntityIdsResponse response) throws Exception {
                    Proto.checkError(response.getError());
                    return Futures.<Cursor>immediateFuture(new SimpleCursor(response.getResult()));
                }
            }, directExecutor()));
}