package com.github.obourgain.elasticsearch.http.handler.document.bulk;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.bulk.BulkAction;
import org.elasticsearch.action.bulk.BulkRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.obourgain.elasticsearch.http.client.HttpClient;
import com.github.obourgain.elasticsearch.http.concurrent.ListenerCompleterObserver;
import com.github.obourgain.elasticsearch.http.request.RequestUriBuilder;
import com.github.obourgain.elasticsearch.http.response.ErrorHandler;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.reactivex.netty.protocol.http.client.HttpClientRequest;
import io.reactivex.netty.protocol.http.client.HttpClientResponse;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action1;
import rx.functions.Func1;
/**
* @author olivier bourgain
*/
public class BulkActionHandler {
private static final Logger logger = LoggerFactory.getLogger(BulkActionHandler.class);
private final HttpClient httpClient;
public BulkActionHandler(HttpClient httpClient) {
this.httpClient = httpClient;
}
public BulkAction getAction() {
return BulkAction.INSTANCE;
}
public void execute(final BulkRequest request, final ActionListener<BulkResponse> listener) {
// TODO lots of options to test
logger.debug("bulk request {}", request);
try {
// probably don't care of this
// long estimatedSizeInBytes = request.estimatedSizeInBytes();
// TODO what is this ?
// List<Object> payloads = request.payloads();
RequestUriBuilder uriBuilder = new RequestUriBuilder().addEndpoint("_bulk");
uriBuilder.addQueryParameter("refresh", String.valueOf(request.refresh()));
uriBuilder.addQueryParameter("timeout", request.timeout().toString());
uriBuilder.addConsistencyLevel(request.consistencyLevel());
httpClient.getHttpClient().submit(HttpClientRequest.createPost(uriBuilder.toString())
.withContentSource(Observable.create(new ByteBufOnSubscribe(request))))
.flatMap(ErrorHandler.AS_FUNC)
.flatMap(new Func1<HttpClientResponse<ByteBuf>, Observable<BulkResponse>>() {
@Override
public Observable<BulkResponse> call(HttpClientResponse<ByteBuf> response) {
return response.getContent().flatMap(new Func1<ByteBuf, Observable<BulkResponse>>() {
@Override
public Observable<BulkResponse> call(ByteBuf byteBuf) {
return BulkResponse.parse(byteBuf);
}
});
}
})
.single()
.subscribe(new ListenerCompleterObserver<>(listener));
} catch (Exception e) {
listener.onFailure(e);
}
}
private static class ByteBufOnSubscribe implements Observable.OnSubscribe<ByteBuf> {
private final BulkRequest request;
public ByteBufOnSubscribe(BulkRequest request) {
this.request = request;
}
@Override
public void call(final Subscriber<? super ByteBuf> subscriber) {
subscriber.onStart();
Observable<byte[]> actions = BulkActionMarshaller.lazyConvertToBytes(request.requests());
actions.forEach(new Action1<byte[]>() {
@Override
public void call(byte[] bytes) {
subscriber.onNext(PooledByteBufAllocator.DEFAULT.buffer().writeBytes(bytes));
}
});
// TODO may I reuse the buffer here ? could be a nice optimization
subscriber.onCompleted();
}
}
}