package org.elasticsearch.action.bulk;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.bytes.ChannelBufferBytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.rest.RestStatus;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.xbib.elasticsearch.helper.client.http.HttpAction;
import org.xbib.elasticsearch.helper.client.http.HttpInvocationContext;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class HttpBulkAction extends HttpAction<BulkRequest, BulkResponse> {
public HttpBulkAction(Settings settings) {
super(settings, BulkAction.NAME);
}
@Override
protected HttpRequest createHttpRequest(URL base, BulkRequest request) {
StringBuilder bulkContent = new StringBuilder();
for (ActionRequest actionRequest : request.requests()) {
if (actionRequest instanceof IndexRequest) {
IndexRequest indexRequest = (IndexRequest) actionRequest;
bulkContent.append("{\"").append(indexRequest.opType().lowercase()).append("\":{");
bulkContent.append("\"_index\":\"").append(indexRequest.index()).append("\"");
bulkContent.append(",\"_type\":\"").append(indexRequest.type()).append("\"");
if (indexRequest.id() != null) {
bulkContent.append(",\"_id\":\"").append(indexRequest.id()).append("\"");
}
if (indexRequest.routing() != null) {
bulkContent.append(",\"_routing\":\"").append(indexRequest.routing()).append("\""); // _routing
}
if (indexRequest.parent() != null) {
bulkContent.append(",\"_parent\":\"").append(indexRequest.parent()).append("\"");
}
if (indexRequest.timestamp() != null) {
bulkContent.append(",\"_timestamp\":\"").append(indexRequest.timestamp()).append("\"");
}
// avoid _ttl <= 0 at all cost!
if (indexRequest.ttl() != null && indexRequest.ttl().seconds() > 0) {
bulkContent.append(",\"_ttl\":\"").append(indexRequest.ttl()).append("\"");
}
if (indexRequest.version() > 0) {
bulkContent.append(",\"_version\":\"").append(indexRequest.version()).append("\"");
if (indexRequest.versionType() != null) {
bulkContent.append(",\"_version_type\":\"").append(indexRequest.versionType().name()).append("\"");
}
}
bulkContent.append("}}\n");
bulkContent.append(indexRequest.source().toUtf8());
bulkContent.append("\n");
} else if (actionRequest instanceof DeleteRequest) {
DeleteRequest deleteRequest = (DeleteRequest) actionRequest;
bulkContent.append("{\"delete\":{");
bulkContent.append("\"_index\":\"").append(deleteRequest.index()).append("\"");
bulkContent.append(",\"_type\":\"").append(deleteRequest.type()).append("\"");
bulkContent.append(",\"_id\":\"").append(deleteRequest.id()).append("\"");
if (deleteRequest.routing() != null) {
bulkContent.append(",\"_routing\":\"").append(deleteRequest.routing()).append("\""); // _routing
}
bulkContent.append("}}\n");
}
}
return newPostRequest(base, "/_bulk", bulkContent);
}
@Override
@SuppressWarnings("unchecked")
protected BulkResponse createResponse(HttpInvocationContext<BulkRequest,BulkResponse> httpInvocationContext) {
if (httpInvocationContext == null) {
throw new IllegalStateException("no http context");
}
HttpResponse httpResponse = httpInvocationContext.getHttpResponse();
try {
BytesReference ref = new ChannelBufferBytesReference(httpResponse.getContent());
Map<String,Object> map = JsonXContent.jsonXContent.createParser(ref).map();
long tookInMillis = map.containsKey("took") ? (Integer)map.get("took") : -1L;
BulkItemResponse[] responses = parseItems((List<Map<String,?>>)map.get("items"));
return new BulkResponse(responses, tookInMillis);
} catch (IOException e) {
//
}
return null;
}
@SuppressWarnings("unchecked")
private BulkItemResponse[] parseItems(List<Map<String,?>> items) {
List<BulkItemResponse> list = new ArrayList<>();
int i = 0;
for (Map<String,?> item: items) {
if (item.containsKey(UPDATE_OP)) {
item = (Map<String,?>)item.get(UPDATE_OP);
String index = (String) item.get(INDEX);
String type = (String) item.get(TYPE);
String id = (String) item.get(ID);
if (item.containsKey(ERROR)) {
ElasticsearchException e = new ElasticsearchException(item.get(ERROR).toString());
BulkItemResponse.Failure failure = new BulkItemResponse.Failure(index, type, id, e);
list.add(new BulkItemResponse(i++, UPDATE_OP, failure));
} else {
UpdateResponse updateResponse = new UpdateResponse(index, type, id,
item.containsKey(VERSION) ? (Integer) item.get(VERSION) : -1L,
false);
list.add(new BulkItemResponse(i++, UPDATE_OP, updateResponse));
}
} else if (item.containsKey(INDEX_OP)) {
item = (Map<String,?>)item.get(INDEX_OP);
String index = (String) item.get(INDEX);
String type = (String) item.get(TYPE);
String id = (String) item.get(ID);
if (item.containsKey(ERROR)) {
ElasticsearchException e = new ElasticsearchException(item.get(ERROR).toString());
BulkItemResponse.Failure failure = new BulkItemResponse.Failure(index, type, id, e);
list.add(new BulkItemResponse(i++, INDEX_OP, failure));
} else {
int status = (Integer) item.get(STATUS);
IndexResponse indexResponse = new IndexResponse(index, type, id,
item.containsKey(VERSION) ? (Integer) item.get(VERSION) : -1L,
status == RestStatus.CREATED.getStatus());
list.add(new BulkItemResponse(i++, INDEX_OP, indexResponse));
}
} else if (item.containsKey(CREATE_OP)) {
item = (Map<String,?>)item.get(CREATE_OP);
String index = (String) item.get(INDEX);
String type = (String) item.get(TYPE);
String id = (String) item.get(ID);
if (item.containsKey(ERROR)) {
ElasticsearchException e = new ElasticsearchException(item.get(ERROR).toString());
BulkItemResponse.Failure failure = new BulkItemResponse.Failure(index, type, id, e);
list.add(new BulkItemResponse(i++, CREATE_OP, failure));
} else {
int status = (Integer) item.get(STATUS);
IndexResponse indexResponse = new IndexResponse(index, type, id,
item.containsKey(VERSION) ? (Integer) item.get(VERSION) : -1L,
status == RestStatus.CREATED.getStatus());
list.add(new BulkItemResponse(i++, CREATE_OP, indexResponse));
}
} else if (item.containsKey(DELETE_OP)) {
item = (Map<String,?>)item.get(DELETE_OP);
String index = (String) item.get(INDEX);
String type = (String) item.get(TYPE);
String id = (String) item.get(ID);
if (item.containsKey(ERROR)) {
ElasticsearchException e = new ElasticsearchException(item.get(ERROR).toString());
BulkItemResponse.Failure failure = new BulkItemResponse.Failure(index, type, id, e);
list.add(new BulkItemResponse(i++, DELETE_OP, failure));
} else {
int status = (Integer) item.get(STATUS);
DeleteResponse deleteResponse = new DeleteResponse(index, type, id,
item.containsKey(VERSION) ? (Integer) item.get(VERSION) : -1L,
status != RestStatus.NOT_FOUND.getStatus());
list.add(new BulkItemResponse(i++, DELETE_OP, deleteResponse));
}
}
}
return list.toArray(new BulkItemResponse[list.size()]);
}
private final static String INDEX = "_index";
private final static String TYPE = "_type";
private final static String ID = "_id";
private final static String VERSION = "_version";
private final static String INDEX_OP = "index";
private final static String CREATE_OP = "create";
private final static String DELETE_OP = "delete";
private final static String UPDATE_OP = "update";
private final static String ERROR = "error";
private final static String STATUS = "status";
}