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

com.couchbase.client.java.analytics.DefaultAsyncAnalyticsDeferredResultHandle Maven / Gradle / Ivy

There is a newer version: 3.7.7
Show newest version
/*
 * Copyright (c) 2018 Couchbase, Inc.
 *
 * 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 com.couchbase.client.java.analytics;

import static com.couchbase.client.java.bucket.api.Utils.applyTimeout;
import static com.couchbase.client.java.util.OnSubscribeDeferAndWatch.deferAndWatch;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import com.couchbase.client.core.ClusterFacade;
import com.couchbase.client.core.annotations.InterfaceAudience;
import com.couchbase.client.core.annotations.InterfaceStability;
import com.couchbase.client.core.logging.CouchbaseLogger;
import com.couchbase.client.core.logging.CouchbaseLoggerFactory;
import com.couchbase.client.core.message.analytics.AnalyticsQueryResultRequest;
import com.couchbase.client.core.message.analytics.AnalyticsQueryStatusRequest;
import com.couchbase.client.core.message.analytics.GenericAnalyticsResponse;
import com.couchbase.client.core.time.Delay;
import com.couchbase.client.deps.io.netty.buffer.ByteBuf;
import com.couchbase.client.java.env.CouchbaseEnvironment;
import com.couchbase.client.java.error.CannotRetryException;
import com.couchbase.client.java.error.QueryExecutionException;
import com.couchbase.client.java.error.TemporaryFailureException;
import com.couchbase.client.java.error.TranscodingException;
import com.couchbase.client.java.transcoder.TranscoderUtils;
import com.couchbase.client.java.util.retry.RetryBuilder;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action4;
import rx.functions.Func1;

/**
 * Default implementation of {@link AsyncAnalyticsDeferredResultHandle}
 *
 * @author Subhashni Balakrishnan
 * @since 2.7.2
 */
@InterfaceStability.Experimental
@InterfaceAudience.Public
public class DefaultAsyncAnalyticsDeferredResultHandle implements AsyncAnalyticsDeferredResultHandle {

    private static CouchbaseLogger LOGGER = CouchbaseLoggerFactory.getInstance(DefaultAsyncAnalyticsDeferredResultHandle.class);

    private final CouchbaseEnvironment env;
    private final ClusterFacade core;
    private final String bucket;
    private final String username;
    private final String password;
    private final String statusHandle;
    private String resultHandle;
    private final long timeout;
    private final TimeUnit timeunit;

    public DefaultAsyncAnalyticsDeferredResultHandle(String handle, final CouchbaseEnvironment env, final ClusterFacade core,
                                       final String bucket, final String username, final String password,
                                       final long timeout, final TimeUnit timeunit) {
        this.statusHandle = handle;
        this.resultHandle = "";
        this.env = env;
        this.core = core;
        this.bucket = bucket;
        this.username = username;
        this.password = password;
        this.timeout = timeout;
        this.timeunit = timeunit;
    }

    @Override
    public String getStatusHandleUri() {
        return this.statusHandle;
    }

    @Override
    public String getResultHandleUri() {
        if (this.resultHandle.length() == 0) {
            throw new IllegalStateException("There is no result handle available, retry status until success");
        }
        return this.resultHandle;
    }

    @Override
    public Observable rows() {
        return this.rows(this.timeout, this.timeunit);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Observable rows(final long timeout, final TimeUnit timeunit) {
        if (this.resultHandle.length() == 0) {
            throw new QueryExecutionException("There is no result handle available to fetch rows, retry status call until success", null);
        }
        return deferAndWatch(new Func1>() {
            @Override
            public Observable call(final Subscriber subscriber) {
                AnalyticsQueryResultRequest request = new AnalyticsQueryResultRequest(resultHandle, bucket, username, password);
                request.subscriber(subscriber);
                return applyTimeout(core.send(request), request, env, timeout, timeunit);
            }
        }).flatMap(new Func1>() {
            @Override
            public Observable call(final GenericAnalyticsResponse response) {
                return response.rows().map(new Func1() {
                    @Override
                    public AsyncAnalyticsQueryRow call(ByteBuf byteBuf) {
                        try {
                            TranscoderUtils.ByteBufToArray rawData = TranscoderUtils.byteBufToByteArray(byteBuf);
                            byte[] copy = Arrays.copyOfRange(rawData.byteArray, rawData.offset, rawData.offset + rawData.length);
                            return new DefaultAsyncAnalyticsQueryRow(copy);
                        } catch (Exception e) {
                            throw new TranscodingException("Could not decode Analytics Query Row.", e);
                        } finally {
                            byteBuf.release();
                        }
                    }
                });
            }
        }).retryWhen(RetryBuilder.anyOf(TemporaryFailureException.class)
                        .delay(Delay.exponential(TimeUnit.MILLISECONDS, 500, 2))
                        .max(10)
                        .doOnRetry(new Action4() {
                            @Override
                            public void call(Integer attempt, Throwable error, Long delay, TimeUnit delayUnit) {
                                LOGGER.debug("Retrying status because of temp failure (attempt {}, delay {} {})", error.getMessage(), attempt, delay, delayUnit);
                            }
                        })
                        .build()
        ).onErrorResumeNext(new Func1>() {
                    @Override
                    public Observable call(Throwable throwable) {
                        if (throwable instanceof CannotRetryException) {
                            Observable.empty();
                        }
                        return Observable.error(throwable);
                    }
        });
    }

    @Override
    public Observable status() {
        return this.status(this.timeout, this.timeunit);
    }

    @Override
    public Observable status(final long timeout, final TimeUnit timeunit) {
        return deferAndWatch(new Func1>() {
            @Override
            public Observable call(final Subscriber subscriber) {
                AnalyticsQueryStatusRequest request = new AnalyticsQueryStatusRequest(statusHandle, bucket, username, password);
                request.subscriber(subscriber);
                return applyTimeout(core.send(request), request, env, timeout, timeunit);
            }
        }).flatMap(new Func1>() {
            @Override
            public Observable call(final GenericAnalyticsResponse response) {
                resultHandle = response.handle();
                return response.queryStatus();
            }
        }).retryWhen(RetryBuilder.anyOf(TemporaryFailureException.class)
                .delay(Delay.exponential(TimeUnit.MILLISECONDS, 500, 2))
                .max(10)
                .doOnRetry(new Action4() {
                    @Override
                    public void call(Integer attempt, Throwable error, Long delay, TimeUnit delayUnit) {
                        LOGGER.debug("Retrying status because of temp failure (attempt {}, delay {} {})", error.getMessage(), attempt, delay, delayUnit);
                    }
                })
                .build()
        ).onErrorResumeNext(new Func1>() {
            @Override
            public Observable call(Throwable throwable) {
                if (throwable instanceof CannotRetryException) {
                    Observable.empty();
                }
                return Observable.error(throwable);
            }
        });
    }

    @Override
    public String toString() {
        return "DefaultAsyncAnalyticsDeferredResultHandle{" +
                "statusUri='" + getStatusHandleUri() + '\'' +
                ", resultUri='" + getResultHandleUri() + '\'' +
                '}';
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy