diff --git a/.idea/dictionaries/kimchy.xml b/.idea/dictionaries/kimchy.xml index c28b83d2963..3b42a495ff4 100644 --- a/.idea/dictionaries/kimchy.xml +++ b/.idea/dictionaries/kimchy.xml @@ -82,6 +82,7 @@ versioned wildcards xcontent + xson yaml diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/count/CountRequest.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/count/CountRequest.java index 17834d437b7..7780016df52 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/action/count/CountRequest.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/count/CountRequest.java @@ -19,18 +19,27 @@ package org.elasticsearch.action.count; +import org.elasticsearch.ElasticSearchGenerationException; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.Actions; import org.elasticsearch.action.support.broadcast.BroadcastOperationRequest; import org.elasticsearch.action.support.broadcast.BroadcastOperationThreading; +import org.elasticsearch.client.Requests; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.util.Required; import org.elasticsearch.util.Strings; import org.elasticsearch.util.Unicode; +import org.elasticsearch.util.io.FastByteArrayOutputStream; import org.elasticsearch.util.io.stream.StreamInput; import org.elasticsearch.util.io.stream.StreamOutput; +import org.elasticsearch.util.xcontent.XContentFactory; +import org.elasticsearch.util.xcontent.XContentType; +import org.elasticsearch.util.xcontent.builder.BinaryXContentBuilder; import javax.annotation.Nullable; import java.io.IOException; import java.util.Arrays; +import java.util.Map; /** * A request to count the number of documents matching a specific query. Best created with @@ -46,6 +55,8 @@ import java.util.Arrays; */ public class CountRequest extends BroadcastOperationRequest { + private static final XContentType contentType = Requests.CONTENT_TYPE; + public static final float DEFAULT_MIN_SCORE = -1f; private float minScore = DEFAULT_MIN_SCORE; @@ -53,6 +64,8 @@ public class CountRequest extends BroadcastOperationRequest { private String[] types = Strings.EMPTY_ARRAY; @Nullable private String queryParserName; + private transient QueryBuilder queryBuilder = null; + CountRequest() { } @@ -64,6 +77,14 @@ public class CountRequest extends BroadcastOperationRequest { super(indices, null); } + @Override public ActionRequestValidationException validate() { + ActionRequestValidationException validationException = super.validate(); + if (querySource == null && queryBuilder == null) { + validationException = Actions.addValidationError("query is missing", validationException); + } + return validationException; + } + /** * Controls the operation threading model. */ @@ -113,6 +134,10 @@ public class CountRequest extends BroadcastOperationRequest { * The query source to execute. */ byte[] querySource() { + if (querySource == null && queryBuilder != null) { + // did not get serialized... + querySource = queryBuilder.buildAsBytes(contentType); + } return querySource; } @@ -122,7 +147,22 @@ public class CountRequest extends BroadcastOperationRequest { * @see org.elasticsearch.index.query.xcontent.QueryBuilders */ @Required public CountRequest query(QueryBuilder queryBuilder) { - return query(queryBuilder.buildAsBytes()); + this.queryBuilder = queryBuilder; + return this; + } + + /** + * The query source to execute in the form of a map. + */ + @Required public CountRequest query(Map querySource) { + try { + BinaryXContentBuilder builder = XContentFactory.contentBinaryBuilder(contentType); + builder.map(querySource); + this.querySource = builder.copiedBytes(); + } catch (IOException e) { + throw new ElasticSearchGenerationException("Failed to generate [" + querySource + "]", e); + } + return this; } /** @@ -191,8 +231,14 @@ public class CountRequest extends BroadcastOperationRequest { @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); out.writeFloat(minScore); - out.writeVInt(querySource.length); - out.writeBytes(querySource); + if (querySource != null) { + out.writeVInt(querySource.length); + out.writeBytes(querySource); + } else { + FastByteArrayOutputStream os = queryBuilder.buildAsUnsafeBytes(contentType); + out.writeVInt(os.size()); + out.writeBytes(os.unsafeByteArray(), 0, os.size()); + } if (queryParserName == null) { out.writeBoolean(false); } else { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/deletebyquery/DeleteByQueryRequest.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/deletebyquery/DeleteByQueryRequest.java index 381f2ffce24..89de0e2d9d0 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/action/deletebyquery/DeleteByQueryRequest.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/deletebyquery/DeleteByQueryRequest.java @@ -22,11 +22,13 @@ package org.elasticsearch.action.deletebyquery; import org.elasticsearch.ElasticSearchGenerationException; import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.support.replication.IndicesReplicationOperationRequest; +import org.elasticsearch.client.Requests; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.util.Required; import org.elasticsearch.util.Strings; import org.elasticsearch.util.TimeValue; import org.elasticsearch.util.Unicode; +import org.elasticsearch.util.io.FastByteArrayOutputStream; import org.elasticsearch.util.io.stream.StreamInput; import org.elasticsearch.util.io.stream.StreamOutput; import org.elasticsearch.util.xcontent.XContentFactory; @@ -53,10 +55,14 @@ import static org.elasticsearch.action.Actions.*; */ public class DeleteByQueryRequest extends IndicesReplicationOperationRequest { + private static final XContentType contentType = Requests.CONTENT_TYPE; + private byte[] querySource; private String queryParserName; private String[] types = Strings.EMPTY_ARRAY; + private transient QueryBuilder queryBuilder; + /** * Constructs a new delete by query request to run against the provided indices. No indices means * it will run against all indices. @@ -78,7 +84,7 @@ public class DeleteByQueryRequest extends IndicesReplicationOperationRequest { @Override public ActionRequestValidationException validate() { ActionRequestValidationException validationException = super.validate(); - if (querySource == null) { + if (querySource == null && queryBuilder == null) { validationException = addValidationError("query is missing", validationException); } return validationException; @@ -93,6 +99,9 @@ public class DeleteByQueryRequest extends IndicesReplicationOperationRequest { * The query source to execute. */ byte[] querySource() { + if (querySource == null && queryBuilder != null) { + querySource = queryBuilder.buildAsBytes(); + } return querySource; } @@ -102,7 +111,8 @@ public class DeleteByQueryRequest extends IndicesReplicationOperationRequest { * @see org.elasticsearch.index.query.xcontent.QueryBuilders */ @Required public DeleteByQueryRequest query(QueryBuilder queryBuilder) { - return query(queryBuilder.buildAsBytes()); + this.queryBuilder = queryBuilder; + return this; } /** @@ -118,7 +128,7 @@ public class DeleteByQueryRequest extends IndicesReplicationOperationRequest { */ @Required public DeleteByQueryRequest query(Map querySource) { try { - BinaryXContentBuilder builder = XContentFactory.contentBinaryBuilder(XContentType.JSON); + BinaryXContentBuilder builder = XContentFactory.contentBinaryBuilder(contentType); builder.map(querySource); this.querySource = builder.copiedBytes(); } catch (IOException e) { @@ -184,8 +194,14 @@ public class DeleteByQueryRequest extends IndicesReplicationOperationRequest { public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); - out.writeVInt(querySource.length); - out.writeBytes(querySource); + if (querySource != null) { + out.writeVInt(querySource.length); + out.writeBytes(querySource); + } else { + FastByteArrayOutputStream os = queryBuilder.buildAsUnsafeBytes(contentType); + out.writeVInt(os.size()); + out.writeBytes(os.unsafeByteArray(), 0, os.size()); + } if (queryParserName == null) { out.writeBoolean(false); } else { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/index/IndexRequest.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/index/IndexRequest.java index 8f96d0c0d46..92f4cfd33b8 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/action/index/IndexRequest.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/index/IndexRequest.java @@ -105,6 +105,8 @@ public class IndexRequest extends ShardReplicationOperationRequest { private byte[] source; private OpType opType = OpType.INDEX; + private transient XContentBuilder sourceBuilder; + public IndexRequest() { } @@ -136,7 +138,7 @@ public class IndexRequest extends ShardReplicationOperationRequest { if (type == null) { validationException = addValidationError("type is missing", validationException); } - if (source == null) { + if (source == null && sourceBuilder == null) { validationException = addValidationError("source is missing", validationException); } return validationException; @@ -201,6 +203,13 @@ public class IndexRequest extends ShardReplicationOperationRequest { * The source of the JSON document to index. */ byte[] source() { + if (source == null && sourceBuilder != null) { + try { + source = sourceBuilder.copiedBytes(); + } catch (IOException e) { + throw new ElasticSearchGenerationException("Failed to build source", e); + } + } return source; } @@ -234,12 +243,9 @@ public class IndexRequest extends ShardReplicationOperationRequest { /** * Sets the content source to index. */ - @Required public IndexRequest source(XContentBuilder jsonBuilder) { - try { - return source(jsonBuilder.copiedBytes()); - } catch (IOException e) { - throw new ElasticSearchIllegalArgumentException("Failed to build json for index request", e); - } + @Required public IndexRequest source(XContentBuilder sourceBuilder) { + this.sourceBuilder = sourceBuilder; + return this; } /** @@ -318,8 +324,13 @@ public class IndexRequest extends ShardReplicationOperationRequest { out.writeBoolean(true); out.writeUTF(id); } - out.writeVInt(source.length); - out.writeBytes(source); + if (source != null) { + out.writeVInt(source.length); + out.writeBytes(source); + } else { + out.writeVInt(sourceBuilder.unsafeBytesLength()); + out.writeBytes(sourceBuilder.unsafeBytes(), 0, sourceBuilder.unsafeBytesLength()); + } out.writeByte(opType.id()); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/mlt/MoreLikeThisRequest.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/mlt/MoreLikeThisRequest.java index d7c4f691941..7040dec8feb 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/action/mlt/MoreLikeThisRequest.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/mlt/MoreLikeThisRequest.java @@ -25,12 +25,14 @@ import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.Actions; import org.elasticsearch.action.search.SearchType; +import org.elasticsearch.client.Requests; import org.elasticsearch.search.Scroll; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.util.Bytes; import org.elasticsearch.util.Required; import org.elasticsearch.util.Strings; import org.elasticsearch.util.Unicode; +import org.elasticsearch.util.io.FastByteArrayOutputStream; import org.elasticsearch.util.io.stream.StreamInput; import org.elasticsearch.util.io.stream.StreamOutput; import org.elasticsearch.util.xcontent.XContentFactory; @@ -55,6 +57,8 @@ import static org.elasticsearch.search.Scroll.*; */ public class MoreLikeThisRequest implements ActionRequest { + private static final XContentType contentType = Requests.CONTENT_TYPE; + private String index; private String type; @@ -80,6 +84,7 @@ public class MoreLikeThisRequest implements ActionRequest { private Scroll searchScroll; private byte[] searchSource; + private transient SearchSourceBuilder searchSourceBuiler; private boolean threadedListener = false; @@ -306,7 +311,8 @@ public class MoreLikeThisRequest implements ActionRequest { * more like this documents. */ public MoreLikeThisRequest searchSource(SearchSourceBuilder sourceBuilder) { - return searchSource(sourceBuilder.build()); + this.searchSourceBuiler = sourceBuilder; + return this; } /** @@ -342,6 +348,9 @@ public class MoreLikeThisRequest implements ActionRequest { * more like this documents. */ public byte[] searchSource() { + if (searchSource == null && searchSourceBuiler != null) { + searchSource = searchSourceBuiler.buildAsBytes(contentType); + } return this.searchSource; } @@ -589,11 +598,17 @@ public class MoreLikeThisRequest implements ActionRequest { out.writeBoolean(true); searchScroll.writeTo(out); } - if (searchSource == null) { + if (searchSource == null && searchSourceBuiler == null) { out.writeVInt(0); } else { - out.writeVInt(searchSource.length); - out.writeBytes(searchSource); + if (searchSource != null) { + out.writeVInt(searchSource.length); + out.writeBytes(searchSource); + } else { + FastByteArrayOutputStream os = searchSourceBuiler.buildAsUnsafeBytes(contentType); + out.writeVInt(os.size()); + out.writeBytes(os.unsafeByteArray(), 0, os.size()); + } } } } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/search/SearchRequest.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/search/SearchRequest.java index 289bd4ad77f..15aed2010b9 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/action/search/SearchRequest.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/search/SearchRequest.java @@ -23,12 +23,14 @@ import org.elasticsearch.ElasticSearchGenerationException; import org.elasticsearch.ElasticSearchIllegalArgumentException; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.client.Requests; import org.elasticsearch.search.Scroll; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.util.Bytes; import org.elasticsearch.util.Strings; import org.elasticsearch.util.TimeValue; import org.elasticsearch.util.Unicode; +import org.elasticsearch.util.io.FastByteArrayOutputStream; import org.elasticsearch.util.io.stream.StreamInput; import org.elasticsearch.util.io.stream.StreamOutput; import org.elasticsearch.util.xcontent.XContentFactory; @@ -58,6 +60,8 @@ import static org.elasticsearch.util.TimeValue.*; */ public class SearchRequest implements ActionRequest { + private static final XContentType contentType = Requests.CONTENT_TYPE; + private SearchType searchType = SearchType.DEFAULT; private String[] indices; @@ -77,6 +81,9 @@ public class SearchRequest implements ActionRequest { private boolean listenerThreaded = false; private SearchOperationThreading operationThreading = SearchOperationThreading.SINGLE_THREAD; + private transient SearchSourceBuilder sourceBuilder; + private transient SearchSourceBuilder extraSourceBuilder; + SearchRequest() { } @@ -98,7 +105,7 @@ public class SearchRequest implements ActionRequest { @Override public ActionRequestValidationException validate() { ActionRequestValidationException validationException = null; - if (source == null && extraSource == null) { + if (source == null && sourceBuilder == null && extraSource == null && extraSourceBuilder == null) { validationException = addValidationError("search source is missing", validationException); } return validationException; @@ -188,7 +195,8 @@ public class SearchRequest implements ActionRequest { * The source of the search request. */ public SearchRequest source(SearchSourceBuilder sourceBuilder) { - return source(sourceBuilder.build()); + this.sourceBuilder = sourceBuilder; + return this; } /** @@ -204,7 +212,7 @@ public class SearchRequest implements ActionRequest { */ public SearchRequest source(Map source) { try { - BinaryXContentBuilder builder = XContentFactory.contentBinaryBuilder(XContentType.JSON); + BinaryXContentBuilder builder = XContentFactory.contentBinaryBuilder(contentType); builder.map(source); this.source = builder.copiedBytes(); } catch (IOException e) { @@ -225,6 +233,9 @@ public class SearchRequest implements ActionRequest { * The search source to execute. */ public byte[] source() { + if (source == null && sourceBuilder != null) { + source = sourceBuilder.buildAsBytes(contentType); + } return source; } @@ -232,12 +243,13 @@ public class SearchRequest implements ActionRequest { * Allows to provide additional source that will be used as well. */ public SearchRequest extraSource(SearchSourceBuilder sourceBuilder) { - return extraSource(sourceBuilder.build()); + this.extraSourceBuilder = sourceBuilder; + return this; } public SearchRequest extraSource(Map extraSource) { try { - BinaryXContentBuilder builder = XContentFactory.contentBinaryBuilder(XContentType.JSON); + BinaryXContentBuilder builder = XContentFactory.contentBinaryBuilder(contentType); builder.map(extraSource); this.extraSource = builder.copiedBytes(); } catch (IOException e) { @@ -265,6 +277,9 @@ public class SearchRequest implements ActionRequest { * Additional search source to execute. */ public byte[] extraSource() { + if (extraSource == null && extraSourceBuilder != null) { + extraSource = extraSourceBuilder.buildAsBytes(contentType); + } return this.extraSource; } @@ -405,17 +420,29 @@ public class SearchRequest implements ActionRequest { out.writeBoolean(true); timeout.writeTo(out); } - if (source == null) { + if (source == null && sourceBuilder == null) { out.writeVInt(0); } else { - out.writeVInt(source.length); - out.writeBytes(source); + if (source != null) { + out.writeVInt(source.length); + out.writeBytes(source); + } else { + FastByteArrayOutputStream os = sourceBuilder.buildAsUnsafeBytes(contentType); + out.writeVInt(os.size()); + out.writeBytes(os.unsafeByteArray(), 0, os.size()); + } } - if (extraSource == null) { + if (extraSource == null && extraSourceBuilder == null) { out.writeVInt(0); } else { - out.writeVInt(extraSource.length); - out.writeBytes(extraSource); + if (extraSource != null) { + out.writeVInt(extraSource.length); + out.writeBytes(extraSource); + } else { + FastByteArrayOutputStream os = extraSourceBuilder.buildAsUnsafeBytes(contentType); + out.writeVInt(os.size()); + out.writeBytes(os.unsafeByteArray(), 0, os.size()); + } } out.writeVInt(types.length); for (String type : types) { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/client/Requests.java b/modules/elasticsearch/src/main/java/org/elasticsearch/client/Requests.java index 7cc09a3d0f5..c427b6ac00c 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/client/Requests.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/client/Requests.java @@ -45,14 +45,20 @@ import org.elasticsearch.action.mlt.MoreLikeThisRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.action.terms.TermsRequest; +import org.elasticsearch.util.xcontent.XContentType; /** * A handy one stop shop for creating requests (make sure to import static this class). * - * @author kimchy (Shay Banon) + * @author kimchy (shay.banon) */ public class Requests { + /** + * The content type used to generate request builders (query / search). + */ + public static XContentType CONTENT_TYPE = XContentType.XSON; + public static IndexRequest indexRequest() { return new IndexRequest(); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/http/netty/NettyHttpRequest.java b/modules/elasticsearch/src/main/java/org/elasticsearch/http/netty/NettyHttpRequest.java index bac47528e53..2d8c25896d8 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/http/netty/NettyHttpRequest.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/http/netty/NettyHttpRequest.java @@ -22,11 +22,9 @@ package org.elasticsearch.http.netty; import org.elasticsearch.http.HttpRequest; import org.elasticsearch.rest.support.AbstractRestRequest; import org.elasticsearch.rest.support.RestUtils; -import org.jboss.netty.buffer.ChannelBufferInputStream; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; -import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -90,10 +88,6 @@ public class NettyHttpRequest extends AbstractRestRequest implements HttpRequest return request.getContent().readableBytes() > 0; } - @Override public InputStream contentAsStream() { - return new ChannelBufferInputStream(request.getContent()); - } - @Override public byte[] contentAsBytes() { byte[] data = new byte[request.getContent().readableBytes()]; request.getContent().getBytes(request.getContent().readerIndex(), data); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/XContentObjectMapper.java b/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/XContentObjectMapper.java index 5ccbb536f6a..f5fe3805aeb 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/XContentObjectMapper.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/index/mapper/xcontent/XContentObjectMapper.java @@ -428,11 +428,19 @@ public class XContentObjectMapper implements XContentMapper, XContentIncludeInAl } else if (token == XContentParser.Token.VALUE_NUMBER) { XContentParser.NumberType numberType = context.parser().numberType(); if (numberType == XContentParser.NumberType.INT) { - mapper = integerField(currentFieldName).build(builderContext); + if (context.parser().estimatedNumberType()) { + mapper = longField(currentFieldName).build(builderContext); + } else { + mapper = integerField(currentFieldName).build(builderContext); + } } else if (numberType == XContentParser.NumberType.LONG) { mapper = longField(currentFieldName).build(builderContext); } else if (numberType == XContentParser.NumberType.FLOAT) { - mapper = floatField(currentFieldName).build(builderContext); + if (context.parser().estimatedNumberType()) { + mapper = doubleField(currentFieldName).build(builderContext); + } else { + mapper = floatField(currentFieldName).build(builderContext); + } } else if (numberType == XContentParser.NumberType.DOUBLE) { mapper = doubleField(currentFieldName).build(builderContext); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/rest/RestRequest.java b/modules/elasticsearch/src/main/java/org/elasticsearch/rest/RestRequest.java index 02df2482a70..7460649c4fa 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/rest/RestRequest.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/rest/RestRequest.java @@ -23,7 +23,6 @@ import org.elasticsearch.util.SizeValue; import org.elasticsearch.util.TimeValue; import org.elasticsearch.util.xcontent.ToXContent; -import java.io.InputStream; import java.util.List; import java.util.Map; import java.util.Set; @@ -51,8 +50,6 @@ public interface RestRequest extends ToXContent.Params { boolean hasContent(); - InputStream contentAsStream(); - byte[] contentAsBytes(); String contentAsString(); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java b/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java index b2e40e7f094..da70e935861 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java @@ -145,7 +145,7 @@ public class RestSearchAction extends BaseRestHandler { return searchRequest; } - private byte[] parseSearchSource(RestRequest request) { + private SearchSourceBuilder parseSearchSource(RestRequest request) { SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); String queryString = request.param("q"); if (queryString != null) { @@ -227,7 +227,6 @@ public class RestSearchAction extends BaseRestHandler { } } - // TODO add different parameters to the source - return searchSourceBuilder.build(); + return searchSourceBuilder; } } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/support/RestXContentBuilder.java b/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/support/RestXContentBuilder.java index 289bc995e13..494dd06b5f4 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/support/RestXContentBuilder.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/support/RestXContentBuilder.java @@ -32,7 +32,18 @@ import java.io.IOException; public class RestXContentBuilder { public static BinaryXContentBuilder restContentBuilder(RestRequest request) throws IOException { - BinaryXContentBuilder builder = XContentFactory.contentBinaryBuilder(XContentType.JSON); + XContentType contentType = XContentType.fromRestContentType(request.header("Content-Type")); + if (contentType == null) { + // try and guess it from the body, if exists + if (request.hasContent()) { + contentType = XContentFactory.xContentType(request.contentAsBytes()); + } + } + if (contentType == null) { + // default to JSON + contentType = XContentType.JSON; + } + BinaryXContentBuilder builder = XContentFactory.contentBinaryBuilder(contentType); if (request.paramAsBoolean("pretty", false)) { builder.prettyPrint(); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java index 0835f969142..bbd98384acf 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java @@ -20,14 +20,16 @@ package org.elasticsearch.search.builder; import org.elasticsearch.index.query.xcontent.XContentQueryBuilder; -import org.elasticsearch.search.SearchException; import org.elasticsearch.util.gnu.trove.TObjectFloatHashMap; import org.elasticsearch.util.gnu.trove.TObjectFloatIterator; +import org.elasticsearch.util.io.FastByteArrayOutputStream; import org.elasticsearch.util.xcontent.ToXContent; import org.elasticsearch.util.xcontent.XContentFactory; import org.elasticsearch.util.xcontent.XContentType; +import org.elasticsearch.util.xcontent.builder.BinaryXContentBuilder; import org.elasticsearch.util.xcontent.builder.XContentBuilder; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -40,7 +42,7 @@ import static org.elasticsearch.util.gcommon.collect.Lists.*; * @author kimchy (shay.banon) * @see org.elasticsearch.action.search.SearchRequest#source(SearchSourceBuilder) */ -public class SearchSourceBuilder { +public class SearchSourceBuilder implements ToXContent { public static enum Order { ASC, @@ -253,87 +255,106 @@ public class SearchSourceBuilder { return this; } + public FastByteArrayOutputStream buildAsUnsafeBytes() throws SearchSourceBuilderException { + return buildAsUnsafeBytes(XContentType.JSON); + } - public byte[] build() throws SearchException { + public FastByteArrayOutputStream buildAsUnsafeBytes(XContentType contentType) throws SearchSourceBuilderException { try { - XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON); - builder.startObject(); + BinaryXContentBuilder builder = XContentFactory.contentBinaryBuilder(contentType); + toXContent(builder, ToXContent.EMPTY_PARAMS); + return builder.unsafeStream(); + } catch (Exception e) { + throw new SearchSourceBuilderException("Failed to build search source", e); + } + } - ToXContent.Params params = ToXContent.EMPTY_PARAMS; - - if (from != -1) { - builder.field("from", from); - } - if (size != -1) { - builder.field("size", size); - } - if (queryParserName != null) { - builder.field("query_parser_name", queryParserName); - } - - if (queryBuilder != null) { - builder.field("query"); - queryBuilder.toXContent(builder, params); - } - - if (explain != null) { - builder.field("explain", explain); - } - - if (fieldNames != null) { - if (fieldNames.size() == 1) { - builder.field("fields", fieldNames.get(0)); - } else { - builder.startArray("fields"); - for (String fieldName : fieldNames) { - builder.value(fieldName); - } - builder.endArray(); - } - } - - if (sortFields != null) { - builder.field("sort"); - builder.startObject(); - for (SortTuple sortTuple : sortFields) { - builder.field(sortTuple.fieldName()); - builder.startObject(); - if (sortTuple.reverse) { - builder.field("reverse", true); - } - if (sortTuple.type != null) { - builder.field("type", sortTuple.type()); - } - builder.endObject(); - } - builder.endObject(); - } - - if (indexBoost != null) { - builder.startObject("indices_boost"); - for (TObjectFloatIterator it = indexBoost.iterator(); it.hasNext();) { - it.advance(); - builder.field(it.key(), it.value()); - } - builder.endObject(); - } - - if (facetsBuilder != null) { - facetsBuilder.toXContent(builder, params); - } - - if (highlightBuilder != null) { - highlightBuilder.toXContent(builder, params); - } - - builder.endObject(); + public byte[] buildAsBytes() throws SearchSourceBuilderException { + return buildAsBytes(XContentType.JSON); + } + public byte[] buildAsBytes(XContentType contentType) throws SearchSourceBuilderException { + try { + XContentBuilder builder = XContentFactory.contentBinaryBuilder(contentType); + toXContent(builder, EMPTY_PARAMS); return builder.copiedBytes(); } catch (Exception e) { throw new SearchSourceBuilderException("Failed to build search source", e); } } + + @Override public void toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + + if (from != -1) { + builder.field("from", from); + } + if (size != -1) { + builder.field("size", size); + } + if (queryParserName != null) { + builder.field("query_parser_name", queryParserName); + } + + if (queryBuilder != null) { + builder.field("query"); + queryBuilder.toXContent(builder, params); + } + + if (explain != null) { + builder.field("explain", explain); + } + + if (fieldNames != null) { + if (fieldNames.size() == 1) { + builder.field("fields", fieldNames.get(0)); + } else { + builder.startArray("fields"); + for (String fieldName : fieldNames) { + builder.value(fieldName); + } + builder.endArray(); + } + } + + if (sortFields != null) { + builder.field("sort"); + builder.startObject(); + for (SortTuple sortTuple : sortFields) { + builder.field(sortTuple.fieldName()); + builder.startObject(); + if (sortTuple.reverse) { + builder.field("reverse", true); + } + if (sortTuple.type != null) { + builder.field("type", sortTuple.type()); + } + builder.endObject(); + } + builder.endObject(); + } + + if (indexBoost != null) { + builder.startObject("indices_boost"); + for (TObjectFloatIterator it = indexBoost.iterator(); it.hasNext();) { + it.advance(); + builder.field(it.key(), it.value()); + } + builder.endObject(); + } + + if (facetsBuilder != null) { + facetsBuilder.toXContent(builder, params); + } + + if (highlightBuilder != null) { + highlightBuilder.toXContent(builder, params); + } + + builder.endObject(); + } + private static class SortTuple { private final String fieldName; private final boolean reverse; diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/ToXContent.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/ToXContent.java index b70264878b1..89d26d1131c 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/ToXContent.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/ToXContent.java @@ -25,6 +25,8 @@ import java.io.IOException; import java.util.Map; /** + * An interface allowing to transfer an object to "XContent" using an {@link org.elasticsearch.util.xcontent.builder.XContentBuilder}. + * * @author kimchy (shay.banon) */ public interface ToXContent { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContent.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContent.java index 10a35840efe..c8ffc1e614c 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContent.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContent.java @@ -22,23 +22,49 @@ package org.elasticsearch.util.xcontent; import java.io.*; /** + * A generic abstraction on top of handling content, inspired by JSON and pull parsing. + * * @author kimchy (shay.banon) */ public interface XContent { + /** + * The type this content handles and produces. + */ XContentType type(); + /** + * Creates a new generator using the provided output stream. + */ XContentGenerator createGenerator(OutputStream os) throws IOException; + /** + * Creates a new generator using the provided writer. + */ XContentGenerator createGenerator(Writer writer) throws IOException; + /** + * Creates a parser over the provided string content. + */ XContentParser createParser(String content) throws IOException; + /** + * Creates a parser over the provided input stream. + */ XContentParser createParser(InputStream is) throws IOException; + /** + * Creates a parser over the provided bytes. + */ XContentParser createParser(byte[] data) throws IOException; + /** + * Creates a parser over the provided bytes. + */ XContentParser createParser(byte[] data, int offset, int length) throws IOException; + /** + * Creates a parser over the provided reader. + */ XContentParser createParser(Reader reader) throws IOException; } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentFactory.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentFactory.java index 0618a0b4601..a2fdbaca8b8 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentFactory.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentFactory.java @@ -20,14 +20,17 @@ package org.elasticsearch.util.xcontent; import org.elasticsearch.ElasticSearchIllegalArgumentException; -import org.elasticsearch.ElasticSearchIllegalStateException; import org.elasticsearch.util.xcontent.builder.BinaryXContentBuilder; import org.elasticsearch.util.xcontent.builder.TextXContentBuilder; import org.elasticsearch.util.xcontent.json.JsonXContent; +import org.elasticsearch.util.xcontent.xson.XsonType; +import org.elasticsearch.util.xcontent.xson.XsonXContent; import java.io.IOException; /** + * A one stop to use {@link org.elasticsearch.util.xcontent.XContent} and {@link org.elasticsearch.util.xcontent.builder.XContentBuilder}. + * * @author kimchy (shay.banon) */ public class XContentFactory { @@ -37,28 +40,52 @@ public class XContentFactory { private static final XContent[] contents; static { - contents = new XContent[1]; + contents = new XContent[2]; contents[0] = new JsonXContent(); + contents[1] = new XsonXContent(); } + /** + * Returns a binary content builder using JSON format ({@link org.elasticsearch.util.xcontent.XContentType#JSON}. + */ public static BinaryXContentBuilder jsonBuilder() throws IOException { return contentBinaryBuilder(XContentType.JSON); } + /** + * Returns a binary content builder using XSON format ({@link org.elasticsearch.util.xcontent.XContentType#XSON}. + */ + public static BinaryXContentBuilder xsonBuilder() throws IOException { + return contentBinaryBuilder(XContentType.XSON); + } + + /** + * Returns a binary content builder for the provided content type. + */ public static BinaryXContentBuilder contentBuilder(XContentType type) throws IOException { if (type == XContentType.JSON) { return JsonXContent.contentBinaryBuilder(); + } else if (type == XContentType.XSON) { + return XsonXContent.contentBinaryBuilder(); } throw new ElasticSearchIllegalArgumentException("No matching content type for " + type); } + /** + * Returns a binary content builder for the provided content type. + */ public static BinaryXContentBuilder contentBinaryBuilder(XContentType type) throws IOException { if (type == XContentType.JSON) { return JsonXContent.contentBinaryBuilder(); + } else if (type == XContentType.XSON) { + return XsonXContent.contentBinaryBuilder(); } throw new ElasticSearchIllegalArgumentException("No matching content type for " + type); } + /** + * Returns a textual content builder for the provided content type. Note, XSON does not support this... . + */ public static TextXContentBuilder contentTextBuilder(XContentType type) throws IOException { if (type == XContentType.JSON) { return JsonXContent.contentTextBuilder(); @@ -66,10 +93,16 @@ public class XContentFactory { throw new ElasticSearchIllegalArgumentException("No matching content type for " + type); } + /** + * Returns the {@link org.elasticsearch.util.xcontent.XContent} for the provided content type. + */ public static XContent xContent(XContentType type) { return contents[type.index()]; } + /** + * Guesses the content type based on the provided char sequence. + */ public static XContentType xContentType(CharSequence content) { int length = content.length() < GUESS_HEADER_LENGTH ? content.length() : GUESS_HEADER_LENGTH; for (int i = 0; i < length; i++) { @@ -78,32 +111,50 @@ public class XContentFactory { return XContentType.JSON; } } - throw new ElasticSearchIllegalStateException("Failed to derive xContent from byte stream"); + return null; } + /** + * Guesses the content (type) based on the provided char sequence. + */ public static XContent xContent(CharSequence content) { return xContent(xContentType(content)); } + /** + * Guesses the content type based on the provided bytes. + */ public static XContent xContent(byte[] data) { return xContent(data, 0, data.length); } + /** + * Guesses the content type based on the provided bytes. + */ public static XContent xContent(byte[] data, int offset, int length) { return xContent(xContentType(data, offset, length)); } + /** + * Guesses the content type based on the provided bytes. + */ public static XContentType xContentType(byte[] data) { return xContentType(data, 0, data.length); } + /** + * Guesses the content type based on the provided bytes. + */ public static XContentType xContentType(byte[] data, int offset, int length) { length = length < GUESS_HEADER_LENGTH ? length : GUESS_HEADER_LENGTH; + if (length > 1 && data[0] == XsonType.HEADER) { + return XContentType.XSON; + } for (int i = offset; i < length; i++) { if (data[i] == '{') { return XContentType.JSON; } } - throw new ElasticSearchIllegalStateException("Failed to derive xContent from byte stream"); + return null; } } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentGenerator.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentGenerator.java index ca3be3e5df6..a0a847b550a 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentGenerator.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentGenerator.java @@ -20,8 +20,6 @@ package org.elasticsearch.util.xcontent; import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; /** * @author kimchy (shay.banon) @@ -54,14 +52,10 @@ public interface XContentGenerator { void writeNumber(long v) throws IOException; - void writeNumber(BigInteger v) throws IOException; - void writeNumber(double d) throws IOException; void writeNumber(float f) throws IOException; - void writeNumber(BigDecimal dec) throws IOException; - void writeBoolean(boolean state) throws IOException; void writeNull() throws IOException; @@ -81,8 +75,6 @@ public interface XContentGenerator { void writeNumberField(String fieldName, float value) throws IOException; - void writeNumberField(String fieldName, BigDecimal value) throws IOException; - void writeBinaryField(String fieldName, byte[] data) throws IOException; void writeArrayFieldStart(String fieldName) throws IOException; diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentParser.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentParser.java index 4473e10bdaf..1d71be351d9 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentParser.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentParser.java @@ -20,7 +20,6 @@ package org.elasticsearch.util.xcontent; import java.io.IOException; -import java.math.BigInteger; import java.util.Map; /** @@ -78,7 +77,7 @@ public interface XContentParser { } enum NumberType { - INT, LONG, BIG_INTEGER, FLOAT, DOUBLE, BIG_DECIMAL + INT, LONG, FLOAT, DOUBLE } XContentType contentType(); @@ -107,7 +106,11 @@ public interface XContentParser { NumberType numberType() throws IOException; - byte byteValue() throws IOException; + /** + * Is the number type estimated or not (i.e. an int might actually be a long, its just low enough + * to be an int). + */ + boolean estimatedNumberType(); short shortValue() throws IOException; @@ -115,14 +118,10 @@ public interface XContentParser { long longValue() throws IOException; - BigInteger bigIntegerValue() throws IOException; - float floatValue() throws IOException; double doubleValue() throws IOException; - java.math.BigDecimal decimalValue() throws IOException; - boolean booleanValue() throws IOException; byte[] binaryValue() throws IOException; diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentType.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentType.java index 64e387f5da9..634d24511cd 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentType.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/XContentType.java @@ -24,7 +24,23 @@ package org.elasticsearch.util.xcontent; */ public enum XContentType { - JSON(0); + JSON(0), + XSON(1); + + public static XContentType fromRestContentType(String contentType) { + if (contentType == null) { + return null; + } + if ("application/json".equals(contentType)) { + return JSON; + } + + if ("application/xson".equals(contentType)) { + return XSON; + } + + return null; + } private int index; diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/json/JsonXContent.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/json/JsonXContent.java index 955840dd4ac..84facf62b4c 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/json/JsonXContent.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/json/JsonXContent.java @@ -36,6 +36,8 @@ import org.elasticsearch.util.xcontent.builder.TextXContentBuilder; import java.io.*; /** + * A JSON based content implementation using Jackson. + * * @author kimchy (shay.banon) */ public class JsonXContent implements XContent { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/json/JsonXContentGenerator.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/json/JsonXContentGenerator.java index 9c2e653f13d..7187466a9f1 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/json/JsonXContentGenerator.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/json/JsonXContentGenerator.java @@ -24,8 +24,6 @@ import org.elasticsearch.util.xcontent.XContentGenerator; import org.elasticsearch.util.xcontent.XContentType; import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; /** * @author kimchy (shay.banon) @@ -90,10 +88,6 @@ public class JsonXContentGenerator implements XContentGenerator { generator.writeNumber(v); } - @Override public void writeNumber(BigInteger v) throws IOException { - generator.writeNumber(v); - } - @Override public void writeNumber(double d) throws IOException { generator.writeNumber(d); } @@ -102,10 +96,6 @@ public class JsonXContentGenerator implements XContentGenerator { generator.writeNumber(f); } - @Override public void writeNumber(BigDecimal dec) throws IOException { - generator.writeNumber(dec); - } - @Override public void writeBoolean(boolean state) throws IOException { generator.writeBoolean(state); } @@ -142,10 +132,6 @@ public class JsonXContentGenerator implements XContentGenerator { generator.writeNumberField(fieldName, value); } - @Override public void writeNumberField(String fieldName, BigDecimal value) throws IOException { - generator.writeNumberField(fieldName, value); - } - @Override public void writeBinaryField(String fieldName, byte[] data) throws IOException { generator.writeBinaryField(fieldName, data); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/json/JsonXContentParser.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/json/JsonXContentParser.java index 9337428557a..4c545fa1327 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/json/JsonXContentParser.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/json/JsonXContentParser.java @@ -22,14 +22,10 @@ package org.elasticsearch.util.xcontent.json; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonToken; import org.elasticsearch.ElasticSearchIllegalStateException; -import org.elasticsearch.util.xcontent.XContentParser; import org.elasticsearch.util.xcontent.XContentType; import org.elasticsearch.util.xcontent.support.AbstractXContentParser; import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Map; /** * @author kimchy (shay.banon) @@ -62,6 +58,10 @@ public class JsonXContentParser extends AbstractXContentParser { return convertNumberType(parser.getNumberType()); } + @Override public boolean estimatedNumberType() { + return true; + } + @Override public String currentName() throws IOException { return parser.getCurrentName(); } @@ -90,10 +90,6 @@ public class JsonXContentParser extends AbstractXContentParser { return parser.getNumberValue(); } - @Override public byte byteValue() throws IOException { - return parser.getByteValue(); - } - @Override public short doShortValue() throws IOException { return parser.getShortValue(); } @@ -106,10 +102,6 @@ public class JsonXContentParser extends AbstractXContentParser { return parser.getLongValue(); } - @Override public BigInteger bigIntegerValue() throws IOException { - return parser.getBigIntegerValue(); - } - @Override public float doFloatValue() throws IOException { return parser.getFloatValue(); } @@ -118,10 +110,6 @@ public class JsonXContentParser extends AbstractXContentParser { return parser.getDoubleValue(); } - @Override public BigDecimal decimalValue() throws IOException { - return parser.getDecimalValue(); - } - @Override public byte[] binaryValue() throws IOException { return parser.getBinaryValue(); } @@ -144,10 +132,6 @@ public class JsonXContentParser extends AbstractXContentParser { return NumberType.FLOAT; case DOUBLE: return NumberType.DOUBLE; - case BIG_DECIMAL: - return NumberType.BIG_DECIMAL; - case BIG_INTEGER: - return NumberType.BIG_INTEGER; } throw new ElasticSearchIllegalStateException("No matching token for number_type [" + numberType + "]"); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/support/AbstractXContentGenerator.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/support/AbstractXContentGenerator.java new file mode 100644 index 00000000000..31c01c239eb --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/support/AbstractXContentGenerator.java @@ -0,0 +1,80 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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 org.elasticsearch.util.xcontent.support; + +import org.elasticsearch.util.xcontent.XContentGenerator; + +import java.io.IOException; + +/** + * @author kimchy (shay.banon) + */ +public abstract class AbstractXContentGenerator implements XContentGenerator { + + @Override public void writeStringField(String fieldName, String value) throws IOException { + writeFieldName(fieldName); + writeString(value); + } + + @Override public void writeBooleanField(String fieldName, boolean value) throws IOException { + writeFieldName(fieldName); + writeBoolean(value); + } + + @Override public void writeNullField(String fieldName) throws IOException { + writeFieldName(fieldName); + writeNull(); + } + + @Override public void writeNumberField(String fieldName, int value) throws IOException { + writeFieldName(fieldName); + writeNumber(value); + } + + @Override public void writeNumberField(String fieldName, long value) throws IOException { + writeFieldName(fieldName); + writeNumber(value); + } + + @Override public void writeNumberField(String fieldName, double value) throws IOException { + writeFieldName(fieldName); + writeNumber(value); + } + + @Override public void writeNumberField(String fieldName, float value) throws IOException { + writeFieldName(fieldName); + writeNumber(value); + } + + @Override public void writeBinaryField(String fieldName, byte[] data) throws IOException { + writeFieldName(fieldName); + writeBinary(data); + } + + @Override public void writeArrayFieldStart(String fieldName) throws IOException { + writeFieldName(fieldName); + writeStartArray(); + } + + @Override public void writeObjectFieldStart(String fieldName) throws IOException { + writeFieldName(fieldName); + writeStartObject(); + } +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/xson/XsonType.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/xson/XsonType.java new file mode 100644 index 00000000000..a8207ac2f46 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/xson/XsonType.java @@ -0,0 +1,52 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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 org.elasticsearch.util.xcontent.xson; + +/** + * @author kimchy (shay.banon) + */ +public enum XsonType { + + START_ARRAY((byte) 0x01), + END_ARRAY((byte) 0x02), + START_OBJECT((byte) 0x03), + END_OBJECT((byte) 0x04), + FIELD_NAME((byte) 0x05), + VALUE_STRING((byte) 0x06), + VALUE_BINARY((byte) 0x07), + VALUE_INTEGER((byte) 0x08), + VALUE_LONG((byte) 0x09), + VALUE_FLOAT((byte) 0x0A), + VALUE_DOUBLE((byte) 0x0B), + VALUE_BOOLEAN((byte) 0x0C), + VALUE_NULL((byte) 0x0D),; + + public static final int HEADER = 0x00; + + private final byte code; + + XsonType(byte code) { + this.code = code; + } + + public byte code() { + return code; + } +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/xson/XsonXContent.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/xson/XsonXContent.java new file mode 100644 index 00000000000..8826d918be4 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/xson/XsonXContent.java @@ -0,0 +1,99 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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 org.elasticsearch.util.xcontent.xson; + +import org.elasticsearch.ElasticSearchException; +import org.elasticsearch.ElasticSearchIllegalStateException; +import org.elasticsearch.util.ThreadLocals; +import org.elasticsearch.util.io.FastByteArrayInputStream; +import org.elasticsearch.util.xcontent.XContent; +import org.elasticsearch.util.xcontent.XContentGenerator; +import org.elasticsearch.util.xcontent.XContentParser; +import org.elasticsearch.util.xcontent.XContentType; +import org.elasticsearch.util.xcontent.builder.BinaryXContentBuilder; + +import java.io.*; + +/** + * A binary representation of content (basically, JSON encoded in optimized binary format). + * + * @author kimchy (shay.banon) + */ +public class XsonXContent implements XContent { + + public static class CachedBinaryBuilder { + + private static final ThreadLocal> cache = new ThreadLocal>() { + @Override protected ThreadLocals.CleanableValue initialValue() { + try { + BinaryXContentBuilder builder = new BinaryXContentBuilder(new XsonXContent()); + return new ThreadLocals.CleanableValue(builder); + } catch (IOException e) { + throw new ElasticSearchException("Failed to create xson generator", e); + } + } + }; + + /** + * Returns the cached thread local generator, with its internal {@link StringBuilder} cleared. + */ + static BinaryXContentBuilder cached() throws IOException { + ThreadLocals.CleanableValue cached = cache.get(); + cached.get().reset(); + return cached.get(); + } + } + + public static BinaryXContentBuilder contentBinaryBuilder() throws IOException { + return CachedBinaryBuilder.cached(); + } + + @Override public XContentType type() { + return XContentType.XSON; + } + + @Override public XContentGenerator createGenerator(OutputStream os) throws IOException { + return new XsonXContentGenerator(os); + } + + @Override public XContentGenerator createGenerator(Writer writer) throws IOException { + throw new ElasticSearchIllegalStateException("Can't create generator over xson with textual data"); + } + + @Override public XContentParser createParser(String content) throws IOException { + throw new ElasticSearchIllegalStateException("Can't create parser over xson for textual data"); + } + + @Override public XContentParser createParser(InputStream is) throws IOException { + return new XsonXContentParser(is); + } + + @Override public XContentParser createParser(byte[] data) throws IOException { + return new XsonXContentParser(new FastByteArrayInputStream(data)); + } + + @Override public XContentParser createParser(byte[] data, int offset, int length) throws IOException { + return new XsonXContentParser(new FastByteArrayInputStream(data, offset, length)); + } + + @Override public XContentParser createParser(Reader reader) throws IOException { + throw new ElasticSearchIllegalStateException("Can't create parser over xson for textual data"); + } +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/xson/XsonXContentGenerator.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/xson/XsonXContentGenerator.java new file mode 100644 index 00000000000..b9da606bb49 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/xson/XsonXContentGenerator.java @@ -0,0 +1,211 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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 org.elasticsearch.util.xcontent.xson; + +import org.apache.lucene.util.UnicodeUtil; +import org.elasticsearch.util.Unicode; +import org.elasticsearch.util.xcontent.XContentGenerator; +import org.elasticsearch.util.xcontent.XContentType; +import org.elasticsearch.util.xcontent.support.AbstractXContentGenerator; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * @author kimchy (shay.banon) + */ +public class XsonXContentGenerator extends AbstractXContentGenerator implements XContentGenerator { + + private final OutputStream out; + + public XsonXContentGenerator(OutputStream out) throws IOException { + this.out = out; + outInt(XsonType.HEADER); + } + + @Override public XContentType contentType() { + return XContentType.XSON; + } + + @Override public void usePrettyPrint() { + // irrelevant + } + + @Override public void writeStartArray() throws IOException { + out.write(XsonType.START_ARRAY.code()); + } + + @Override public void writeEndArray() throws IOException { + out.write(XsonType.END_ARRAY.code()); + } + + @Override public void writeStartObject() throws IOException { + out.write(XsonType.START_OBJECT.code()); + } + + @Override public void writeEndObject() throws IOException { + out.write(XsonType.END_OBJECT.code()); + } + + @Override public void writeFieldName(String name) throws IOException { + out.write(XsonType.FIELD_NAME.code()); + outUTF(name); + } + + @Override public void writeString(String text) throws IOException { + out.write(XsonType.VALUE_STRING.code()); + outUTF(text); + } + + @Override public void writeString(char[] text, int offset, int len) throws IOException { + writeString(new String(text, offset, len)); + } + + @Override public void writeBinary(byte[] data, int offset, int len) throws IOException { + out.write(XsonType.VALUE_BINARY.code()); + outVInt(len); + out.write(data, offset, len); + } + + @Override public void writeBinary(byte[] data) throws IOException { + out.write(XsonType.VALUE_BINARY.code()); + outVInt(data.length); + out.write(data); + } + + @Override public void writeNumber(int v) throws IOException { + out.write(XsonType.VALUE_INTEGER.code()); + outInt(v); + } + + @Override public void writeNumber(long v) throws IOException { + out.write(XsonType.VALUE_LONG.code()); + outLong(v); + } + + @Override public void writeNumber(double d) throws IOException { + out.write(XsonType.VALUE_DOUBLE.code()); + outDouble(d); + } + + @Override public void writeNumber(float f) throws IOException { + out.write(XsonType.VALUE_FLOAT.code()); + outFloat(f); + } + + @Override public void writeBoolean(boolean state) throws IOException { + out.write(XsonType.VALUE_BOOLEAN.code()); + outBoolean(state); + } + + @Override public void writeNull() throws IOException { + out.write(XsonType.VALUE_NULL.code()); + } + + @Override public void writeRawFieldStart(String fieldName) throws IOException { + writeFieldName(fieldName); + } + + @Override public void flush() throws IOException { + out.flush(); + } + + @Override public void close() throws IOException { + out.close(); + } + + + private void outShort(short v) throws IOException { + out.write((byte) (v >> 8)); + out.write((byte) v); + } + + /** + * Writes an int as four bytes. + */ + private void outInt(int i) throws IOException { + out.write((byte) (i >> 24)); + out.write((byte) (i >> 16)); + out.write((byte) (i >> 8)); + out.write((byte) i); + } + + /** + * Writes an int in a variable-length format. Writes between one and + * five bytes. Smaller values take fewer bytes. Negative numbers are not + * supported. + */ + private void outVInt(int i) throws IOException { + while ((i & ~0x7F) != 0) { + out.write((byte) ((i & 0x7f) | 0x80)); + i >>>= 7; + } + out.write((byte) i); + } + + /** + * Writes a long as eight bytes. + */ + private void outLong(long i) throws IOException { + outInt((int) (i >> 32)); + outInt((int) i); + } + + /** + * Writes an long in a variable-length format. Writes between one and five + * bytes. Smaller values take fewer bytes. Negative numbers are not + * supported. + */ + private void outVLong(long i) throws IOException { + while ((i & ~0x7F) != 0) { + out.write((byte) ((i & 0x7f) | 0x80)); + i >>>= 7; + } + out.write((byte) i); + } + + /** + * Writes a string. + */ + private void outUTF(String s) throws IOException { + UnicodeUtil.UTF8Result utf8Result = Unicode.unsafeFromStringAsUtf8(s); + outVInt(utf8Result.length); + out.write(utf8Result.result, 0, utf8Result.length); + } + + private void outFloat(float v) throws IOException { + outInt(Float.floatToIntBits(v)); + } + + private void outDouble(double v) throws IOException { + outLong(Double.doubleToLongBits(v)); + } + + + private static byte ZERO = 0; + private static byte ONE = 1; + + /** + * Writes a boolean. + */ + private void outBoolean(boolean b) throws IOException { + out.write(b ? ONE : ZERO); + } +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/xson/XsonXContentParser.java b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/xson/XsonXContentParser.java new file mode 100644 index 00000000000..b33d8cb2030 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/util/xcontent/xson/XsonXContentParser.java @@ -0,0 +1,390 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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 org.elasticsearch.util.xcontent.xson; + +import org.apache.lucene.util.StringHelper; +import org.elasticsearch.util.ThreadLocals; +import org.elasticsearch.util.Unicode; +import org.elasticsearch.util.xcontent.XContentType; +import org.elasticsearch.util.xcontent.support.AbstractXContentParser; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +/** + * @author kimchy (shay.banon) + */ +public class XsonXContentParser extends AbstractXContentParser { + + private static ThreadLocal> cachedBytes = new ThreadLocal>() { + @Override protected ThreadLocals.CleanableValue initialValue() { + return new ThreadLocals.CleanableValue(new byte[256]); + } + }; + + private final InputStream is; + + private Token currentToken; + + private XsonType xsonType; + + private NumberType currentNumberType; + + private String currentName; + + private Unicode.UTF16Result utf16Result; + + private int valueInt; + private long valueLong; + private float valueFloat; + private double valueDouble; + private boolean valueBoolean; + private byte[] valueBytes; + + public XsonXContentParser(InputStream is) throws IOException { + this.is = is; + int header = inInt(); + if (header != XsonType.HEADER) { + throw new IOException("Not xson type header"); + } + } + + @Override public XContentType contentType() { + return XContentType.XSON; + } + + @Override public Token nextToken() throws IOException { + byte tokenType = (byte) is.read(); + if (tokenType == -1) { + xsonType = null; + currentToken = null; + currentNumberType = null; + return null; + } else if (tokenType == XsonType.START_ARRAY.code()) { + xsonType = XsonType.START_ARRAY; + currentToken = Token.START_ARRAY; + } else if (tokenType == XsonType.END_ARRAY.code()) { + xsonType = XsonType.END_ARRAY; + currentToken = Token.END_ARRAY; + } else if (tokenType == XsonType.START_OBJECT.code()) { + xsonType = XsonType.START_OBJECT; + currentToken = Token.START_OBJECT; + } else if (tokenType == XsonType.END_OBJECT.code()) { + xsonType = XsonType.END_OBJECT; + currentToken = Token.END_OBJECT; + } else if (tokenType == XsonType.FIELD_NAME.code()) { + xsonType = XsonType.FIELD_NAME; + currentToken = Token.FIELD_NAME; + // read the field name (interned) + currentName = StringHelper.intern(inUTF()); + } else if (tokenType == XsonType.VALUE_STRING.code()) { + xsonType = XsonType.VALUE_STRING; + currentToken = Token.VALUE_STRING; + inUtf16(); + } else if (tokenType == XsonType.VALUE_BINARY.code()) { + xsonType = XsonType.VALUE_BINARY; + currentToken = Token.VALUE_STRING; + int length = inVInt(); + valueBytes = new byte[length]; + inBytes(valueBytes, 0, length); + } else if (tokenType == XsonType.VALUE_INTEGER.code()) { + xsonType = XsonType.VALUE_INTEGER; + currentToken = Token.VALUE_NUMBER; + currentNumberType = NumberType.INT; + valueInt = inInt(); + } else if (tokenType == XsonType.VALUE_LONG.code()) { + xsonType = XsonType.VALUE_LONG; + currentToken = Token.VALUE_NUMBER; + currentNumberType = NumberType.LONG; + valueLong = inLong(); + } else if (tokenType == XsonType.VALUE_FLOAT.code()) { + xsonType = XsonType.VALUE_FLOAT; + currentToken = Token.VALUE_NUMBER; + currentNumberType = NumberType.FLOAT; + valueFloat = inFloat(); + } else if (tokenType == XsonType.VALUE_DOUBLE.code()) { + xsonType = XsonType.VALUE_DOUBLE; + currentToken = Token.VALUE_NUMBER; + currentNumberType = NumberType.DOUBLE; + valueDouble = inDouble(); + } else if (tokenType == XsonType.VALUE_BOOLEAN.code()) { + xsonType = XsonType.VALUE_BOOLEAN; + currentToken = Token.VALUE_BOOLEAN; + valueBoolean = inBoolean(); + } else if (tokenType == XsonType.VALUE_NULL.code()) { + xsonType = XsonType.VALUE_NULL; + currentToken = Token.VALUE_NULL; + } + return currentToken; + } + + @Override public void skipChildren() throws IOException { + if (xsonType != XsonType.START_OBJECT && xsonType != XsonType.START_ARRAY) { + return; + } + int open = 1; + + /* Since proper matching of start/end markers is handled + * by nextToken(), we'll just count nesting levels here + */ + while (true) { + nextToken(); + if (xsonType == null) { + return; + } + switch (xsonType) { + case START_OBJECT: + case START_ARRAY: + ++open; + break; + case END_OBJECT: + case END_ARRAY: + if (--open == 0) { + return; + } + break; + } + } + } + + @Override public Token currentToken() { + return currentToken; + } + + @Override public String currentName() throws IOException { + return currentName; + } + + @Override public String text() throws IOException { + return new String(utf16Result.result, 0, utf16Result.length); + } + + @Override public char[] textCharacters() throws IOException { + return utf16Result.result; + } + + @Override public int textLength() throws IOException { + return utf16Result.length; + } + + @Override public int textOffset() throws IOException { + return 0; + } + + @Override public Number numberValue() throws IOException { + if (currentNumberType == NumberType.INT) { + return valueInt; + } else if (currentNumberType == NumberType.LONG) { + return valueLong; + } else if (currentNumberType == NumberType.FLOAT) { + return valueFloat; + } else if (currentNumberType == NumberType.DOUBLE) { + return valueDouble; + } + throw new IOException("No number type"); + } + + @Override public NumberType numberType() throws IOException { + return currentNumberType; + } + + @Override public boolean estimatedNumberType() { + return false; + } + + @Override public byte[] binaryValue() throws IOException { + return valueBytes; + } + + @Override protected boolean doBooleanValue() throws IOException { + return valueBoolean; + } + + @Override protected short doShortValue() throws IOException { + if (currentNumberType == NumberType.INT) { + return (short) valueInt; + } else if (currentNumberType == NumberType.LONG) { + return (short) valueLong; + } else if (currentNumberType == NumberType.FLOAT) { + return (short) valueFloat; + } else if (currentNumberType == NumberType.DOUBLE) { + return (short) valueDouble; + } + throw new IOException("No number type"); + } + + @Override protected int doIntValue() throws IOException { + if (currentNumberType == NumberType.INT) { + return valueInt; + } else if (currentNumberType == NumberType.LONG) { + return (int) valueLong; + } else if (currentNumberType == NumberType.FLOAT) { + return (int) valueFloat; + } else if (currentNumberType == NumberType.DOUBLE) { + return (int) valueDouble; + } + throw new IOException("No number type"); + } + + @Override protected long doLongValue() throws IOException { + if (currentNumberType == NumberType.LONG) { + return valueLong; + } else if (currentNumberType == NumberType.INT) { + return (long) valueInt; + } else if (currentNumberType == NumberType.FLOAT) { + return (long) valueFloat; + } else if (currentNumberType == NumberType.DOUBLE) { + return (long) valueDouble; + } + throw new IOException("No number type"); + } + + @Override protected float doFloatValue() throws IOException { + if (currentNumberType == NumberType.FLOAT) { + return valueFloat; + } else if (currentNumberType == NumberType.INT) { + return (float) valueInt; + } else if (currentNumberType == NumberType.LONG) { + return (float) valueLong; + } else if (currentNumberType == NumberType.DOUBLE) { + return (float) valueDouble; + } + throw new IOException("No number type"); + } + + @Override protected double doDoubleValue() throws IOException { + if (currentNumberType == NumberType.DOUBLE) { + return valueDouble; + } else if (currentNumberType == NumberType.INT) { + return (double) valueInt; + } else if (currentNumberType == NumberType.FLOAT) { + return (double) valueFloat; + } else if (currentNumberType == NumberType.LONG) { + return (double) valueLong; + } + throw new IOException("No number type"); + } + + @Override public void close() { + try { + is.close(); + } catch (IOException e) { + // ignore + } + } + + private short inShort() throws IOException { + return (short) (((is.read() & 0xFF) << 8) | (is.read() & 0xFF)); + } + + /** + * Reads four bytes and returns an int. + */ + private int inInt() throws IOException { + return ((is.read() & 0xFF) << 24) | ((is.read() & 0xFF) << 16) + | ((is.read() & 0xFF) << 8) | (is.read() & 0xFF); + } + + /** + * Reads an int stored in variable-length format. Reads between one and + * five bytes. Smaller values take fewer bytes. Negative numbers are not + * supported. + */ + private int inVInt() throws IOException { + int b = is.read(); + int i = b & 0x7F; + for (int shift = 7; (b & 0x80) != 0; shift += 7) { + b = is.read(); + i |= (b & 0x7F) << shift; + } + return i; + } + + /** + * Reads eight bytes and returns a long. + */ + private long inLong() throws IOException { + return (((long) inInt()) << 32) | (inInt() & 0xFFFFFFFFL); + } + + /** + * Reads a long stored in variable-length format. Reads between one and + * nine bytes. Smaller values take fewer bytes. Negative numbers are not + * supported. + */ + private long readVLong() throws IOException { + int b = is.read(); + long i = b & 0x7F; + for (int shift = 7; (b & 0x80) != 0; shift += 7) { + b = is.read(); + i |= (b & 0x7FL) << shift; + } + return i; + } + + private String inUTF() throws IOException { + inUtf16(); + return new String(utf16Result.result, 0, utf16Result.length); + } + + /** + * Reads a string. + */ + private void inUtf16() throws IOException { + int length = inVInt(); + byte[] bytes = cachedBytes.get().get(); + if (bytes == null || length > bytes.length) { + bytes = new byte[(int) (length * 1.25)]; + cachedBytes.get().set(bytes); + } + inBytes(bytes, 0, length); + utf16Result = Unicode.fromBytesAsUtf16(bytes, 0, length); + } + + private float inFloat() throws IOException { + return Float.intBitsToFloat(inInt()); + } + + private double inDouble() throws IOException { + return Double.longBitsToDouble(inLong()); + } + + /** + * Reads a boolean. + */ + private boolean inBoolean() throws IOException { + byte ch = (byte) is.read(); + if (ch < 0) + throw new EOFException(); + return (ch != 0); + } + + private void inBytes(byte[] b, int offset, int len) throws IOException { + int n = 0; + while (n < len) { + int count = is.read(b, offset + n, len - n); + if (count < 0) + throw new EOFException(); + n += count; + } + } + +} diff --git a/modules/elasticsearch/src/test/java/org/elasticsearch/index/query/xcontent/SimpleIndexQueryParserTests.java b/modules/elasticsearch/src/test/java/org/elasticsearch/index/query/xcontent/SimpleIndexQueryParserTests.java index 95d2a5e5839..19085f5575c 100644 --- a/modules/elasticsearch/src/test/java/org/elasticsearch/index/query/xcontent/SimpleIndexQueryParserTests.java +++ b/modules/elasticsearch/src/test/java/org/elasticsearch/index/query/xcontent/SimpleIndexQueryParserTests.java @@ -606,7 +606,7 @@ public class SimpleIndexQueryParserTests { assertThat(parsedQuery, instanceOf(SpanTermQuery.class)); SpanTermQuery termQuery = (SpanTermQuery) parsedQuery; // since age is automatically registered in data, we encode it as numeric - assertThat(termQuery.getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(34)))); + assertThat(termQuery.getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(34)))); } @Test public void testSpanTermQuery() throws IOException { @@ -616,7 +616,7 @@ public class SimpleIndexQueryParserTests { assertThat(parsedQuery, instanceOf(SpanTermQuery.class)); SpanTermQuery termQuery = (SpanTermQuery) parsedQuery; // since age is automatically registered in data, we encode it as numeric - assertThat(termQuery.getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(34)))); + assertThat(termQuery.getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(34)))); } @Test public void testSpanNotQueryBuilder() throws IOException { @@ -625,8 +625,8 @@ public class SimpleIndexQueryParserTests { assertThat(parsedQuery, instanceOf(SpanNotQuery.class)); SpanNotQuery spanNotQuery = (SpanNotQuery) parsedQuery; // since age is automatically registered in data, we encode it as numeric - assertThat(((SpanTermQuery) spanNotQuery.getInclude()).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(34)))); - assertThat(((SpanTermQuery) spanNotQuery.getExclude()).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(35)))); + assertThat(((SpanTermQuery) spanNotQuery.getInclude()).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(34)))); + assertThat(((SpanTermQuery) spanNotQuery.getExclude()).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(35)))); } @Test public void testSpanNotQuery() throws IOException { @@ -636,8 +636,8 @@ public class SimpleIndexQueryParserTests { assertThat(parsedQuery, instanceOf(SpanNotQuery.class)); SpanNotQuery spanNotQuery = (SpanNotQuery) parsedQuery; // since age is automatically registered in data, we encode it as numeric - assertThat(((SpanTermQuery) spanNotQuery.getInclude()).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(34)))); - assertThat(((SpanTermQuery) spanNotQuery.getExclude()).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(35)))); + assertThat(((SpanTermQuery) spanNotQuery.getInclude()).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(34)))); + assertThat(((SpanTermQuery) spanNotQuery.getExclude()).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(35)))); } @Test public void testSpanFirstQueryBuilder() throws IOException { @@ -646,7 +646,7 @@ public class SimpleIndexQueryParserTests { assertThat(parsedQuery, instanceOf(SpanFirstQuery.class)); SpanFirstQuery spanFirstQuery = (SpanFirstQuery) parsedQuery; // since age is automatically registered in data, we encode it as numeric - assertThat(((SpanTermQuery) spanFirstQuery.getMatch()).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(34)))); + assertThat(((SpanTermQuery) spanFirstQuery.getMatch()).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(34)))); assertThat(spanFirstQuery.getEnd(), equalTo(12)); } @@ -657,7 +657,7 @@ public class SimpleIndexQueryParserTests { assertThat(parsedQuery, instanceOf(SpanFirstQuery.class)); SpanFirstQuery spanFirstQuery = (SpanFirstQuery) parsedQuery; // since age is automatically registered in data, we encode it as numeric - assertThat(((SpanTermQuery) spanFirstQuery.getMatch()).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(34)))); + assertThat(((SpanTermQuery) spanFirstQuery.getMatch()).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(34)))); assertThat(spanFirstQuery.getEnd(), equalTo(12)); } @@ -667,9 +667,9 @@ public class SimpleIndexQueryParserTests { assertThat(parsedQuery, instanceOf(SpanNearQuery.class)); SpanNearQuery spanNearQuery = (SpanNearQuery) parsedQuery; assertThat(spanNearQuery.getClauses().length, equalTo(3)); - assertThat(((SpanTermQuery) spanNearQuery.getClauses()[0]).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(34)))); - assertThat(((SpanTermQuery) spanNearQuery.getClauses()[1]).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(35)))); - assertThat(((SpanTermQuery) spanNearQuery.getClauses()[2]).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(36)))); + assertThat(((SpanTermQuery) spanNearQuery.getClauses()[0]).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(34)))); + assertThat(((SpanTermQuery) spanNearQuery.getClauses()[1]).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(35)))); + assertThat(((SpanTermQuery) spanNearQuery.getClauses()[2]).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(36)))); assertThat(spanNearQuery.isInOrder(), equalTo(false)); } @@ -680,9 +680,9 @@ public class SimpleIndexQueryParserTests { assertThat(parsedQuery, instanceOf(SpanNearQuery.class)); SpanNearQuery spanNearQuery = (SpanNearQuery) parsedQuery; assertThat(spanNearQuery.getClauses().length, equalTo(3)); - assertThat(((SpanTermQuery) spanNearQuery.getClauses()[0]).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(34)))); - assertThat(((SpanTermQuery) spanNearQuery.getClauses()[1]).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(35)))); - assertThat(((SpanTermQuery) spanNearQuery.getClauses()[2]).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(36)))); + assertThat(((SpanTermQuery) spanNearQuery.getClauses()[0]).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(34)))); + assertThat(((SpanTermQuery) spanNearQuery.getClauses()[1]).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(35)))); + assertThat(((SpanTermQuery) spanNearQuery.getClauses()[2]).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(36)))); assertThat(spanNearQuery.isInOrder(), equalTo(false)); } @@ -692,9 +692,9 @@ public class SimpleIndexQueryParserTests { assertThat(parsedQuery, instanceOf(SpanOrQuery.class)); SpanOrQuery spanOrQuery = (SpanOrQuery) parsedQuery; assertThat(spanOrQuery.getClauses().length, equalTo(3)); - assertThat(((SpanTermQuery) spanOrQuery.getClauses()[0]).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(34)))); - assertThat(((SpanTermQuery) spanOrQuery.getClauses()[1]).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(35)))); - assertThat(((SpanTermQuery) spanOrQuery.getClauses()[2]).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(36)))); + assertThat(((SpanTermQuery) spanOrQuery.getClauses()[0]).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(34)))); + assertThat(((SpanTermQuery) spanOrQuery.getClauses()[1]).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(35)))); + assertThat(((SpanTermQuery) spanOrQuery.getClauses()[2]).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(36)))); } @Test public void testSpanOrQuery() throws IOException { @@ -704,9 +704,9 @@ public class SimpleIndexQueryParserTests { assertThat(parsedQuery, instanceOf(SpanOrQuery.class)); SpanOrQuery spanOrQuery = (SpanOrQuery) parsedQuery; assertThat(spanOrQuery.getClauses().length, equalTo(3)); - assertThat(((SpanTermQuery) spanOrQuery.getClauses()[0]).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(34)))); - assertThat(((SpanTermQuery) spanOrQuery.getClauses()[1]).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(35)))); - assertThat(((SpanTermQuery) spanOrQuery.getClauses()[2]).getTerm(), equalTo(new Term("age", NumericUtils.intToPrefixCoded(36)))); + assertThat(((SpanTermQuery) spanOrQuery.getClauses()[0]).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(34)))); + assertThat(((SpanTermQuery) spanOrQuery.getClauses()[1]).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(35)))); + assertThat(((SpanTermQuery) spanOrQuery.getClauses()[2]).getTerm(), equalTo(new Term("age", NumericUtils.longToPrefixCoded(36)))); } @Test public void testQueryFilterBuilder() throws Exception { diff --git a/modules/elasticsearch/src/test/java/org/elasticsearch/util/xcontent/xson/JsonVsXsonTests.java b/modules/elasticsearch/src/test/java/org/elasticsearch/util/xcontent/xson/JsonVsXsonTests.java new file mode 100644 index 00000000000..81f518cb6d8 --- /dev/null +++ b/modules/elasticsearch/src/test/java/org/elasticsearch/util/xcontent/xson/JsonVsXsonTests.java @@ -0,0 +1,93 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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 org.elasticsearch.util.xcontent.xson; + +import org.elasticsearch.util.io.FastByteArrayOutputStream; +import org.elasticsearch.util.xcontent.XContentFactory; +import org.elasticsearch.util.xcontent.XContentGenerator; +import org.elasticsearch.util.xcontent.XContentParser; +import org.elasticsearch.util.xcontent.XContentType; +import org.testng.annotations.Test; + +import java.io.IOException; + +import static org.hamcrest.MatcherAssert.*; +import static org.hamcrest.Matchers.*; + +/** + * @author kimchy (shay.banon) + */ +public class JsonVsXsonTests { + + @Test public void compareParsingTokens() throws IOException { + FastByteArrayOutputStream xsonOs = new FastByteArrayOutputStream(); + XContentGenerator xsonGen = XContentFactory.xContent(XContentType.XSON).createGenerator(xsonOs); + + FastByteArrayOutputStream jsonOs = new FastByteArrayOutputStream(); + XContentGenerator jsonGen = XContentFactory.xContent(XContentType.JSON).createGenerator(jsonOs); + + xsonGen.writeStartObject(); + jsonGen.writeStartObject(); + + xsonGen.writeStringField("test", "value"); + jsonGen.writeStringField("test", "value"); + + xsonGen.writeArrayFieldStart("arr"); + jsonGen.writeArrayFieldStart("arr"); + xsonGen.writeNumber(1); + jsonGen.writeNumber(1); + xsonGen.writeNull(); + jsonGen.writeNull(); + xsonGen.writeEndArray(); + jsonGen.writeEndArray(); + + xsonGen.writeEndObject(); + jsonGen.writeEndObject(); + + xsonGen.close(); + jsonGen.close(); + + verifySameTokens(XContentFactory.xContent(XContentType.JSON).createParser(jsonOs.copiedByteArray()), XContentFactory.xContent(XContentType.XSON).createParser(xsonOs.copiedByteArray())); + } + + private void verifySameTokens(XContentParser parser1, XContentParser parser2) throws IOException { + while (true) { + XContentParser.Token token1 = parser1.nextToken(); + XContentParser.Token token2 = parser2.nextToken(); + if (token1 == null) { + assertThat(token2, nullValue()); + return; + } + assertThat(token1, equalTo(token2)); + switch (token1) { + case FIELD_NAME: + assertThat(parser1.currentName(), equalTo(parser2.currentName())); + break; + case VALUE_STRING: + assertThat(parser1.text(), equalTo(parser2.text())); + break; + case VALUE_NUMBER: + assertThat(parser1.numberType(), equalTo(parser2.numberType())); + assertThat(parser1.numberValue(), equalTo(parser2.numberValue())); + break; + } + } + } +} diff --git a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/SingleInstanceEmbeddedSearchTests.java b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/SingleInstanceEmbeddedSearchTests.java index 05bb855f47b..3f95a9cda1f 100644 --- a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/SingleInstanceEmbeddedSearchTests.java +++ b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/SingleInstanceEmbeddedSearchTests.java @@ -45,10 +45,10 @@ import org.testng.annotations.Test; import java.util.Map; -import static org.elasticsearch.util.gcommon.collect.Lists.*; import static org.elasticsearch.client.Requests.*; import static org.elasticsearch.index.query.xcontent.QueryBuilders.*; import static org.elasticsearch.search.builder.SearchSourceBuilder.*; +import static org.elasticsearch.util.gcommon.collect.Lists.*; import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.Matchers.*; @@ -194,7 +194,7 @@ public class SingleInstanceEmbeddedSearchTests extends AbstractNodesTests { private InternalSearchRequest searchRequest(SearchSourceBuilder builder) { - return new InternalSearchRequest("test", 0, builder.build()); + return new InternalSearchRequest("test", 0, builder.buildAsBytes()); } private void index(Client client, String id, String nameValue, int age) { diff --git a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/TwoInstanceEmbeddedSearchTests.java b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/TwoInstanceEmbeddedSearchTests.java index 19bff08d0b2..8eae3f2a95d 100644 --- a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/TwoInstanceEmbeddedSearchTests.java +++ b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/TwoInstanceEmbeddedSearchTests.java @@ -19,8 +19,6 @@ package org.elasticsearch.test.integration.search; -import org.elasticsearch.util.gcommon.collect.ImmutableMap; -import org.elasticsearch.util.gcommon.collect.Sets; import org.elasticsearch.client.Client; import org.elasticsearch.client.Requests; import org.elasticsearch.cluster.ClusterService; @@ -45,6 +43,8 @@ import org.elasticsearch.search.query.QuerySearchResult; import org.elasticsearch.search.query.QuerySearchResultProvider; import org.elasticsearch.test.integration.AbstractNodesTests; import org.elasticsearch.util.TimeValue; +import org.elasticsearch.util.gcommon.collect.ImmutableMap; +import org.elasticsearch.util.gcommon.collect.Sets; import org.elasticsearch.util.trove.ExtTIntArrayList; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -55,12 +55,12 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; -import static org.elasticsearch.util.gcommon.collect.Lists.*; -import static org.elasticsearch.util.gcommon.collect.Maps.*; import static org.elasticsearch.client.Requests.*; import static org.elasticsearch.index.query.xcontent.QueryBuilders.*; import static org.elasticsearch.search.builder.SearchSourceBuilder.*; import static org.elasticsearch.util.TimeValue.*; +import static org.elasticsearch.util.gcommon.collect.Lists.*; +import static org.elasticsearch.util.gcommon.collect.Maps.*; import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.Matchers.*; @@ -354,7 +354,7 @@ public class TwoInstanceEmbeddedSearchTests extends AbstractNodesTests { } private InternalSearchRequest searchRequest(ShardRouting shardRouting, SearchSourceBuilder builder) { - return new InternalSearchRequest(shardRouting, builder.build()); + return new InternalSearchRequest(shardRouting, builder.buildAsBytes()); } private void index(Client client, String id, String nameValue, int age) { diff --git a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/TwoInstanceUnbalancedShardsEmbeddedSearchTests.java b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/TwoInstanceUnbalancedShardsEmbeddedSearchTests.java index 2be0de93b08..13e53d31ae4 100644 --- a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/TwoInstanceUnbalancedShardsEmbeddedSearchTests.java +++ b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/TwoInstanceUnbalancedShardsEmbeddedSearchTests.java @@ -19,9 +19,6 @@ package org.elasticsearch.test.integration.search; -import org.elasticsearch.util.gcommon.collect.ImmutableMap; -import org.elasticsearch.util.guice.inject.AbstractModule; -import org.elasticsearch.util.guice.inject.Inject; import org.elasticsearch.client.Client; import org.elasticsearch.client.Requests; import org.elasticsearch.cluster.ClusterService; @@ -50,6 +47,9 @@ import org.elasticsearch.search.query.QuerySearchResult; import org.elasticsearch.search.query.QuerySearchResultProvider; import org.elasticsearch.test.integration.AbstractNodesTests; import org.elasticsearch.util.TimeValue; +import org.elasticsearch.util.gcommon.collect.ImmutableMap; +import org.elasticsearch.util.guice.inject.AbstractModule; +import org.elasticsearch.util.guice.inject.Inject; import org.elasticsearch.util.settings.Settings; import org.elasticsearch.util.trove.ExtTIntArrayList; import org.testng.annotations.AfterClass; @@ -60,12 +60,12 @@ import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; -import static org.elasticsearch.util.gcommon.collect.Lists.*; -import static org.elasticsearch.util.gcommon.collect.Maps.*; import static org.elasticsearch.client.Requests.*; import static org.elasticsearch.index.query.xcontent.QueryBuilders.*; import static org.elasticsearch.search.builder.SearchSourceBuilder.*; import static org.elasticsearch.util.TimeValue.*; +import static org.elasticsearch.util.gcommon.collect.Lists.*; +import static org.elasticsearch.util.gcommon.collect.Maps.*; import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.Matchers.*; @@ -360,7 +360,7 @@ public class TwoInstanceUnbalancedShardsEmbeddedSearchTests extends AbstractNode } private static InternalSearchRequest searchRequest(ShardRouting shardRouting, SearchSourceBuilder builder) { - return new InternalSearchRequest(shardRouting, builder.build()); + return new InternalSearchRequest(shardRouting, builder.buildAsBytes()); } private void index(Client client, String id, String nameValue, int age) { diff --git a/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/client/GClient.groovy b/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/client/GClient.groovy index 961c8ad240e..b17623dad0b 100644 --- a/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/client/GClient.groovy +++ b/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/client/GClient.groovy @@ -38,7 +38,8 @@ import org.elasticsearch.action.terms.TermsResponse import org.elasticsearch.client.Client import org.elasticsearch.client.internal.InternalClient import org.elasticsearch.groovy.client.action.GActionFuture -import org.elasticsearch.groovy.util.json.JsonBuilder +import org.elasticsearch.groovy.util.xcontent.GXContentBuilder +import org.elasticsearch.util.xcontent.XContentType /** * @author kimchy (shay.banon) @@ -47,47 +48,51 @@ class GClient { static { IndexRequest.metaClass.setSource = {Closure c -> - delegate.source(new JsonBuilder().buildAsBytes(c)) + delegate.source(new GXContentBuilder().buildAsBytes(c, indexContentType)) } IndexRequest.metaClass.source = {Closure c -> - delegate.source(new JsonBuilder().buildAsBytes(c)) + delegate.source(new GXContentBuilder().buildAsBytes(c, indexContentType)) } DeleteByQueryRequest.metaClass.setQuery = {Closure c -> - delegate.query(new JsonBuilder().buildAsBytes(c)) + delegate.query(new GXContentBuilder().buildAsBytes(c, contentType)) } DeleteByQueryRequest.metaClass.query = {Closure c -> - delegate.query(new JsonBuilder().buildAsBytes(c)) + delegate.query(new GXContentBuilder().buildAsBytes(c, contentType)) } CountRequest.metaClass.setQuery = {Closure c -> - delegate.query(new JsonBuilder().buildAsBytes(c)) + delegate.query(new GXContentBuilder().buildAsBytes(c, contentType)) } CountRequest.metaClass.query = {Closure c -> - delegate.query(new JsonBuilder().buildAsBytes(c)) + delegate.query(new GXContentBuilder().buildAsBytes(c, contentType)) } SearchRequest.metaClass.setSource = {Closure c -> - delegate.source(new JsonBuilder().buildAsBytes(c)) + delegate.source(new GXContentBuilder().buildAsBytes(c, contentType)) } SearchRequest.metaClass.source = {Closure c -> - delegate.source(new JsonBuilder().buildAsBytes(c)) + delegate.source(new GXContentBuilder().buildAsBytes(c, contentType)) } SearchRequest.metaClass.setExtraSource = {Closure c -> - delegate.extraSource(new JsonBuilder().buildAsBytes(c)) + delegate.extraSource(new GXContentBuilder().buildAsBytes(c, contentType)) } SearchRequest.metaClass.extraSource = {Closure c -> - delegate.extraSource(new JsonBuilder().buildAsBytes(c)) + delegate.extraSource(new GXContentBuilder().buildAsBytes(c, contentType)) } MoreLikeThisRequest.metaClass.setSearchSource = {Closure c -> - delegate.searchSource(new JsonBuilder().buildAsBytes(c)) + delegate.searchSource(new GXContentBuilder().buildAsBytes(c, contentType)) } MoreLikeThisRequest.metaClass.searchSource = {Closure c -> - delegate.searchSource(new JsonBuilder().buildAsBytes(c)) + delegate.searchSource(new GXContentBuilder().buildAsBytes(c, contentType)) } } + static XContentType contentType = XContentType.XSON; + + static XContentType indexContentType = XContentType.JSON; + final Client client; int resolveStrategy = Closure.DELEGATE_FIRST diff --git a/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/client/GIndicesAdminClient.groovy b/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/client/GIndicesAdminClient.groovy index 8f258751b13..2bc147580e5 100644 --- a/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/client/GIndicesAdminClient.groovy +++ b/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/client/GIndicesAdminClient.groovy @@ -43,7 +43,7 @@ import org.elasticsearch.action.admin.indices.status.IndicesStatusResponse import org.elasticsearch.client.IndicesAdminClient import org.elasticsearch.client.internal.InternalClient import org.elasticsearch.groovy.client.action.GActionFuture -import org.elasticsearch.groovy.util.json.JsonBuilder +import org.elasticsearch.groovy.util.xcontent.GXContentBuilder /** * @author kimchy (shay.banon) @@ -52,23 +52,23 @@ class GIndicesAdminClient { static { CreateIndexRequest.metaClass.setSettings = {Closure c -> - delegate.settings(new JsonBuilder().buildAsString(c)) + delegate.settings(new GXContentBuilder().buildAsString(c)) } CreateIndexRequest.metaClass.settings = {Closure c -> - delegate.settings(new JsonBuilder().buildAsString(c)) + delegate.settings(new GXContentBuilder().buildAsString(c)) } CreateIndexRequest.metaClass.mapping = {String type, Closure c -> - delegate.mapping(type, new JsonBuilder().buildAsString(c)) + delegate.mapping(type, new GXContentBuilder().buildAsString(c)) } CreateIndexRequest.metaClass.setMapping = {String type, Closure c -> - delegate.mapping(type, new JsonBuilder().buildAsString(c)) + delegate.mapping(type, new GXContentBuilder().buildAsString(c)) } PutMappingRequest.metaClass.setSource = {Closure c -> - delegate.source(new JsonBuilder().buildAsString(c)) + delegate.source(new GXContentBuilder().buildAsString(c)) } PutMappingRequest.metaClass.source = {Closure c -> - delegate.source(new JsonBuilder().buildAsString(c)) + delegate.source(new GXContentBuilder().buildAsString(c)) } } diff --git a/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/node/GNodeBuilder.groovy b/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/node/GNodeBuilder.groovy index 1bd68c426c3..cfa54fdfc87 100644 --- a/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/node/GNodeBuilder.groovy +++ b/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/node/GNodeBuilder.groovy @@ -19,14 +19,14 @@ package org.elasticsearch.groovy.node -import org.elasticsearch.groovy.util.json.JsonBuilder +import org.elasticsearch.groovy.util.xcontent.GXContentBuilder import org.elasticsearch.node.Node import org.elasticsearch.node.internal.InternalNode import org.elasticsearch.util.settings.ImmutableSettings import org.elasticsearch.util.settings.loader.JsonSettingsLoader /** - * The node builder allow to build a {@link GNode} instance. + * The node builder allow to build a {@link GNode} instance. * * @author kimchy (shay.banon) */ @@ -41,7 +41,7 @@ public class GNodeBuilder { } def settings(Closure settings) { - byte[] settingsBytes = new JsonBuilder().buildAsBytes(settings); + byte[] settingsBytes = new GXContentBuilder().buildAsBytes(settings); settingsBuilder.put(new JsonSettingsLoader().load(settingsBytes)) } diff --git a/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/util/json/JsonBuilder.groovy b/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/util/xcontent/GXContentBuilder.groovy similarity index 95% rename from plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/util/json/JsonBuilder.groovy rename to plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/util/xcontent/GXContentBuilder.groovy index 00115b352ec..91de9af8f33 100644 --- a/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/util/json/JsonBuilder.groovy +++ b/plugins/client/groovy/src/main/groovy/org/elasticsearch/groovy/util/xcontent/GXContentBuilder.groovy @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.groovy.util.json +package org.elasticsearch.groovy.util.xcontent import org.elasticsearch.util.xcontent.XContentFactory import org.elasticsearch.util.xcontent.XContentType @@ -32,7 +32,7 @@ import org.elasticsearch.util.xcontent.builder.TextXContentBuilder * * @since 1.2 */ -class JsonBuilder { +class GXContentBuilder { static NODE_ELEMENT = "element" @@ -56,7 +56,11 @@ class JsonBuilder { } byte[] buildAsBytes(Closure c) { - BinaryXContentBuilder builder = XContentFactory.contentBinaryBuilder(XContentType.JSON); + return buildAsBytes(c, XContentType.JSON); + } + + byte[] buildAsBytes(Closure c, XContentType contentType) { + BinaryXContentBuilder builder = XContentFactory.contentBinaryBuilder(contentType); def json = build(c) builder.map(json); return builder.copiedBytes(); @@ -164,7 +168,7 @@ class JsonBuilder { value = value.collect { if (it instanceof Closure) { def callable = it - final JsonBuilder localBuilder = new JsonBuilder() + final GXContentBuilder localBuilder = new GXContentBuilder() callable.delegate = localBuilder callable.resolveStrategy = Closure.DELEGATE_FIRST final Map nestedObject = localBuilder.buildRoot(callable) diff --git a/plugins/client/groovy/src/test/groovy/org/elasticsearch/groovy/test/client/SimpleActionsTests.groovy b/plugins/client/groovy/src/test/groovy/org/elasticsearch/groovy/test/client/SimpleActionsTests.groovy index 4699a5806e4..89e6ec7ef41 100644 --- a/plugins/client/groovy/src/test/groovy/org/elasticsearch/groovy/test/client/SimpleActionsTests.groovy +++ b/plugins/client/groovy/src/test/groovy/org/elasticsearch/groovy/test/client/SimpleActionsTests.groovy @@ -54,7 +54,7 @@ class SimpleActionsTests { @Test void testSimpleOperations() { - def value1 = new org.elasticsearch.groovy.util.json.JsonBuilder().buildAsString { + def value1 = new org.elasticsearch.groovy.util.xcontent.GXContentBuilder().buildAsString { something = "test" } println value1 diff --git a/plugins/client/groovy/src/test/groovy/org/elasticsearch/groovy/util/json/JsonBuilderTests.groovy b/plugins/client/groovy/src/test/groovy/org/elasticsearch/groovy/util/xcontent/GXContentBuilderTests.groovy similarity index 89% rename from plugins/client/groovy/src/test/groovy/org/elasticsearch/groovy/util/json/JsonBuilderTests.groovy rename to plugins/client/groovy/src/test/groovy/org/elasticsearch/groovy/util/xcontent/GXContentBuilderTests.groovy index 5a51b0db818..0a5999bf3a7 100644 --- a/plugins/client/groovy/src/test/groovy/org/elasticsearch/groovy/util/json/JsonBuilderTests.groovy +++ b/plugins/client/groovy/src/test/groovy/org/elasticsearch/groovy/util/xcontent/GXContentBuilderTests.groovy @@ -17,15 +17,15 @@ * under the License. */ -package org.elasticsearch.groovy.util.json +package org.elasticsearch.groovy.util.xcontent /** * @author kimchy (shay.banon) */ -class JsonBuilderTests extends GroovyTestCase { +class GXContentBuilderTests extends GroovyTestCase { void testSimple() { - def builder = new JsonBuilder() + def builder = new GXContentBuilder() def result = builder.buildAsString { rootprop = "something" @@ -35,7 +35,7 @@ class JsonBuilderTests extends GroovyTestCase { } void testArrays() { - def builder = new JsonBuilder() + def builder = new GXContentBuilder() def result = builder.buildAsString { categories = ['a', 'b', 'c'] @@ -46,7 +46,7 @@ class JsonBuilderTests extends GroovyTestCase { } void testSubObjects() { - def builder = new JsonBuilder() + def builder = new GXContentBuilder() def result = builder.buildAsString { categories = ['a', 'b', 'c'] @@ -60,7 +60,7 @@ class JsonBuilderTests extends GroovyTestCase { } void testAssignedObjects() { - def builder = new JsonBuilder() + def builder = new GXContentBuilder() def result = builder.buildAsString { categories = ['a', 'b', 'c'] @@ -74,7 +74,7 @@ class JsonBuilderTests extends GroovyTestCase { } void testNamedArgumentHandling() { - def builder = new JsonBuilder() + def builder = new GXContentBuilder() def result = builder.buildAsString { categories = ['a', 'b', 'c'] rootprop = "something" @@ -87,7 +87,7 @@ class JsonBuilderTests extends GroovyTestCase { void testArrayOfClosures() { - def builder = new JsonBuilder() + def builder = new GXContentBuilder() def result = builder.buildAsString { foo = [{ bar = "hello" }] } @@ -96,7 +96,7 @@ class JsonBuilderTests extends GroovyTestCase { } void testRootElementList() { - def builder = new JsonBuilder() + def builder = new GXContentBuilder() def results = ['one', 'two', 'three'] @@ -117,7 +117,7 @@ class JsonBuilderTests extends GroovyTestCase { } void testExampleFromReferenceGuide() { - def builder = new JsonBuilder() + def builder = new GXContentBuilder() def results = ['one', 'two', 'three'] @@ -150,7 +150,7 @@ class JsonBuilderTests extends GroovyTestCase { } void testAppendToArray() { - def builder = new JsonBuilder() + def builder = new GXContentBuilder() def results = ['one', 'two', 'three'] diff --git a/plugins/transport/memcached/src/main/java/org/elasticsearch/memcached/MemcachedRestRequest.java b/plugins/transport/memcached/src/main/java/org/elasticsearch/memcached/MemcachedRestRequest.java index 054de540886..f57692a44fb 100644 --- a/plugins/transport/memcached/src/main/java/org/elasticsearch/memcached/MemcachedRestRequest.java +++ b/plugins/transport/memcached/src/main/java/org/elasticsearch/memcached/MemcachedRestRequest.java @@ -19,14 +19,12 @@ package org.elasticsearch.memcached; -import org.elasticsearch.util.gcommon.collect.ImmutableList; -import org.elasticsearch.util.gcommon.collect.ImmutableSet; import org.elasticsearch.rest.support.AbstractRestRequest; import org.elasticsearch.rest.support.RestUtils; import org.elasticsearch.util.Unicode; -import org.elasticsearch.util.io.FastByteArrayInputStream; +import org.elasticsearch.util.gcommon.collect.ImmutableList; +import org.elasticsearch.util.gcommon.collect.ImmutableSet; -import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -111,10 +109,6 @@ public class MemcachedRestRequest extends AbstractRestRequest { return data != null; } - @Override public InputStream contentAsStream() { - return new FastByteArrayInputStream(data); - } - @Override public byte[] contentAsBytes() { return data; }