Add fromXContent() methods for ReplicationResponse (#22196)

This commit adds the parsing fromXContent() methods to the ReplicationResponse.ShardInfo and ReplicationResponse.ShardInfo.Failure classes.
This commit is contained in:
Tanguy Leroux 2016-12-20 09:29:11 +01:00 committed by GitHub
parent 850f51db01
commit 290326e73e
2 changed files with 238 additions and 73 deletions

View File

@ -23,19 +23,26 @@ import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.action.ShardOperationFailedException;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Streamable;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.rest.RestStatus;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
import static org.elasticsearch.common.xcontent.XContentParserUtils.throwUnknownField;
/**
* Base class for write action responses.
*/
@ -186,6 +193,48 @@ public class ReplicationResponse extends ActionResponse {
return builder;
}
public static ShardInfo fromXContent(XContentParser parser) throws IOException {
XContentParser.Token token = parser.nextToken();
ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation);
String currentFieldName = parser.currentName();
if (_SHARDS.equals(currentFieldName) == false) {
throwUnknownField(currentFieldName, parser.getTokenLocation());
}
token = parser.nextToken();
ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation);
int total = 0, successful = 0;
List<Failure> failuresList = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (token.isValue()) {
if (TOTAL.equals(currentFieldName)) {
total = parser.intValue();
} else if (SUCCESSFUL.equals(currentFieldName)) {
successful = parser.intValue();
} else if (FAILED.equals(currentFieldName) == false) {
throwUnknownField(currentFieldName, parser.getTokenLocation());
}
} else if (token == XContentParser.Token.START_ARRAY) {
if (FAILURES.equals(currentFieldName)) {
failuresList = new ArrayList<>();
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
failuresList.add(Failure.fromXContent(parser));
}
} else {
throwUnknownField(currentFieldName, parser.getTokenLocation());
}
}
}
Failure[] failures = EMPTY;
if (failuresList != null) {
failures = failuresList.toArray(new Failure[failuresList.size()]);
}
return new ShardInfo(total, successful, failures);
}
@Override
public String toString() {
return "ShardInfo{" +
@ -338,6 +387,45 @@ public class ReplicationResponse extends ActionResponse {
builder.endObject();
return builder;
}
public static Failure fromXContent(XContentParser parser) throws IOException {
XContentParser.Token token = parser.currentToken();
ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation);
String shardIndex = null, nodeId = null;
int shardId = -1;
boolean primary = false;
RestStatus status = null;
ElasticsearchException reason = null;
String currentFieldName = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (token.isValue()) {
if (_INDEX.equals(currentFieldName)) {
shardIndex = parser.text();
} else if (_SHARD.equals(currentFieldName)) {
shardId = parser.intValue();
} else if (_NODE.equals(currentFieldName)) {
nodeId = parser.text();
} else if (STATUS.equals(currentFieldName)) {
status = RestStatus.valueOf(parser.text());
} else if (PRIMARY.equals(currentFieldName)) {
primary = parser.booleanValue();
} else {
throwUnknownField(currentFieldName, parser.getTokenLocation());
}
} else if (token == XContentParser.Token.START_OBJECT) {
if (REASON.equals(currentFieldName)) {
reason = ElasticsearchException.fromXContent(parser);
} else {
throwUnknownField(currentFieldName, parser.getTokenLocation());
}
}
}
return new Failure(new ShardId(shardIndex, IndexMetaData.INDEX_UUID_NA_VALUE, shardId), nodeId, reason, status, primary);
}
}
}
}

View File

@ -21,9 +21,8 @@ package org.elasticsearch.action.support.replication;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.RoutingMissingException;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.Index;
@ -117,97 +116,175 @@ public class ReplicationResponseTests extends ESTestCase {
}
public void testShardInfoToXContent() throws IOException {
ReplicationResponse.ShardInfo shardInfo = new ReplicationResponse.ShardInfo(5, 3);
final XContentType xContentType = randomFrom(XContentType.values());
final XContent xContent = randomFrom(XContentType.values()).xContent();
try (XContentBuilder builder = XContentBuilder.builder(xContent)) {
builder.startObject();
shardInfo.toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endObject();
final ReplicationResponse.ShardInfo shardInfo = new ReplicationResponse.ShardInfo(5, 3);
final BytesReference shardInfoBytes = XContentHelper.toXContent(shardInfo, xContentType, true);
// Expected JSON is {"_shards":{"total":5,"successful":3,"failed":0}}
try (XContentParser parser = xContent.createParser(builder.bytes())) {
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("_shards", parser.currentName());
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("total", parser.currentName());
assertEquals(XContentParser.Token.VALUE_NUMBER, parser.nextToken());
assertEquals(shardInfo.getTotal(), parser.intValue());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("successful", parser.currentName());
assertEquals(XContentParser.Token.VALUE_NUMBER, parser.nextToken());
assertEquals(shardInfo.getSuccessful(), parser.intValue());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("failed", parser.currentName());
assertEquals(XContentParser.Token.VALUE_NUMBER, parser.nextToken());
assertEquals(shardInfo.getFailed(), parser.intValue());
assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
assertNull(parser.nextToken());
}
// Expected JSON is {"_shards":{"total":5,"successful":3,"failed":0}}
try (XContentParser parser = xContentType.xContent().createParser(shardInfoBytes)) {
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("_shards", parser.currentName());
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("total", parser.currentName());
assertEquals(XContentParser.Token.VALUE_NUMBER, parser.nextToken());
assertEquals(shardInfo.getTotal(), parser.intValue());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("successful", parser.currentName());
assertEquals(XContentParser.Token.VALUE_NUMBER, parser.nextToken());
assertEquals(shardInfo.getSuccessful(), parser.intValue());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("failed", parser.currentName());
assertEquals(XContentParser.Token.VALUE_NUMBER, parser.nextToken());
assertEquals(shardInfo.getFailed(), parser.intValue());
assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
assertNull(parser.nextToken());
}
}
public void testRandomShardInfoToXContent() throws IOException {
public void testShardInfoToAndFromXContent() throws IOException {
final XContentType xContentType = randomFrom(XContentType.values());
final ReplicationResponse.ShardInfo shardInfo = new ReplicationResponse.ShardInfo(randomIntBetween(1, 5), randomIntBetween(1, 5));
final BytesReference shardInfoBytes = XContentHelper.toXContent(shardInfo, xContentType, true);
ReplicationResponse.ShardInfo parsedShardInfo;
try (XContentParser parser = xContentType.xContent().createParser(shardInfoBytes)) {
// Move to the start object that was manually added when building the object
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
parsedShardInfo = ReplicationResponse.ShardInfo.fromXContent(parser);
assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
assertNull(parser.nextToken());
}
// We can use assertEquals because the shardInfo doesn't have a failure (and exceptions)
assertEquals(shardInfo, parsedShardInfo);
BytesReference parsedShardInfoBytes = XContentHelper.toXContent(parsedShardInfo, xContentType, true);
assertEquals(shardInfoBytes, parsedShardInfoBytes);
}
public void testShardInfoWithFailureToXContent() throws IOException {
final XContentType xContentType = randomFrom(XContentType.values());
final ReplicationResponse.ShardInfo shardInfo = randomShardInfo();
final BytesReference shardInfoBytes = XContentHelper.toXContent(shardInfo, xContentType, true);
final XContent xContent = randomFrom(XContentType.values()).xContent();
try (XContentBuilder builder = XContentBuilder.builder(xContent)) {
builder.startObject();
shardInfo.toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endObject();
try (XContentParser parser = xContentType.xContent().createParser(shardInfoBytes)) {
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("_shards", parser.currentName());
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("total", parser.currentName());
assertEquals(XContentParser.Token.VALUE_NUMBER, parser.nextToken());
assertEquals(shardInfo.getTotal(), parser.intValue());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("successful", parser.currentName());
assertEquals(XContentParser.Token.VALUE_NUMBER, parser.nextToken());
assertEquals(shardInfo.getSuccessful(), parser.intValue());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("failed", parser.currentName());
assertEquals(XContentParser.Token.VALUE_NUMBER, parser.nextToken());
assertEquals(shardInfo.getFailed(), parser.intValue());
try (XContentParser parser = xContent.createParser(builder.bytes())) {
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
if (shardInfo.getFailures() != null && shardInfo.getFailures().length > 0) {
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("_shards", parser.currentName());
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("total", parser.currentName());
assertEquals(XContentParser.Token.VALUE_NUMBER, parser.nextToken());
assertEquals(shardInfo.getTotal(), parser.intValue());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("successful", parser.currentName());
assertEquals(XContentParser.Token.VALUE_NUMBER, parser.nextToken());
assertEquals(shardInfo.getSuccessful(), parser.intValue());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("failed", parser.currentName());
assertEquals(XContentParser.Token.VALUE_NUMBER, parser.nextToken());
assertEquals(shardInfo.getFailed(), parser.intValue());
assertEquals("failures", parser.currentName());
assertEquals(XContentParser.Token.START_ARRAY, parser.nextToken());
if (shardInfo.getFailures() != null && shardInfo.getFailures().length > 0) {
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals("failures", parser.currentName());
assertEquals(XContentParser.Token.START_ARRAY, parser.nextToken());
for (int i = 0; i < shardInfo.getFailures().length; i++) {
assertFailure(parser, shardInfo.getFailures()[i]);
}
assertEquals(XContentParser.Token.END_ARRAY, parser.nextToken());
for (int i = 0; i < shardInfo.getFailures().length; i++) {
assertFailure(parser, shardInfo.getFailures()[i]);
}
assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
assertNull(parser.nextToken());
assertEquals(XContentParser.Token.END_ARRAY, parser.nextToken());
}
assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
assertNull(parser.nextToken());
}
}
public void testRandomShardInfoFromXContent() throws IOException {
final XContentType xContentType = randomFrom(XContentType.values());
final ReplicationResponse.ShardInfo shardInfo = randomShardInfo();
final BytesReference shardInfoBytes = XContentHelper.toXContent(shardInfo, xContentType, true);
ReplicationResponse.ShardInfo parsedShardInfo;
try (XContentParser parser = xContentType.xContent().createParser(shardInfoBytes)) {
// Move to the start object that was manually added when building the object
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
parsedShardInfo = ReplicationResponse.ShardInfo.fromXContent(parser);
assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
assertNull(parser.nextToken());
}
// We can't use assertEquals to compare the original ShardInfo with the parsed ShardInfo
// because it may include random failures with exceptions, and exception types are not
// preserved during ToXContent->FromXContent process.
assertNotNull(parsedShardInfo);
assertEquals(shardInfo.getTotal(), parsedShardInfo.getTotal());
assertEquals(shardInfo.getSuccessful(), parsedShardInfo.getSuccessful());
assertEquals(shardInfo.getFailed(), parsedShardInfo.getFailed());
assertEquals(shardInfo.getFailures().length, parsedShardInfo.getFailures().length);
for (int i = 0; i < shardInfo.getFailures().length; i++) {
ReplicationResponse.ShardInfo.Failure parsedFailure = parsedShardInfo.getFailures()[i];
ReplicationResponse.ShardInfo.Failure failure = shardInfo.getFailures()[i];
assertEquals(failure.index(), parsedFailure.index());
assertEquals(failure.shardId(), parsedFailure.shardId());
assertEquals(failure.nodeId(), parsedFailure.nodeId());
assertEquals(failure.status(), parsedFailure.status());
assertEquals(failure.primary(), parsedFailure.primary());
Throwable cause = failure.getCause();
String expectedMessage = "Elasticsearch exception [type=" + ElasticsearchException.getExceptionName(cause)
+ ", reason=" + cause.getMessage() + "]";
assertEquals(expectedMessage, parsedFailure.getCause().getMessage());
}
}
public void testRandomFailureToXContent() throws IOException {
ReplicationResponse.ShardInfo.Failure shardInfoFailure = randomFailure();
final XContentType xContentType = randomFrom(XContentType.values());
final XContent xContent = randomFrom(XContentType.values()).xContent();
try (XContentBuilder builder = XContentBuilder.builder(xContent)) {
shardInfoFailure.toXContent(builder, ToXContent.EMPTY_PARAMS);
final ReplicationResponse.ShardInfo.Failure shardInfoFailure = randomFailure();
final BytesReference shardInfoBytes = XContentHelper.toXContent(shardInfoFailure, xContentType, false);
try (XContentParser parser = xContent.createParser(builder.bytes())) {
assertFailure(parser, shardInfoFailure);
}
try (XContentParser parser = xContentType.xContent().createParser(shardInfoBytes)) {
assertFailure(parser, shardInfoFailure);
}
}
public void testRandomFailureToAndFromXContent() throws IOException {
final XContentType xContentType = randomFrom(XContentType.values());
final ReplicationResponse.ShardInfo.Failure shardInfoFailure = randomFailure();
final BytesReference shardInfoBytes = XContentHelper.toXContent(shardInfoFailure, xContentType, false);
ReplicationResponse.ShardInfo.Failure parsedFailure;
try (XContentParser parser = xContentType.xContent().createParser(shardInfoBytes)) {
// Move to the first start object
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
parsedFailure = ReplicationResponse.ShardInfo.Failure.fromXContent(parser);
assertNull(parser.nextToken());
}
assertEquals(shardInfoFailure.index(), parsedFailure.index());
assertEquals(shardInfoFailure.shardId(), parsedFailure.shardId());
assertEquals(shardInfoFailure.nodeId(), parsedFailure.nodeId());
assertEquals(shardInfoFailure.status(), parsedFailure.status());
assertEquals(shardInfoFailure.primary(), parsedFailure.primary());
Throwable cause = shardInfoFailure.getCause();
String expectedMessage = "Elasticsearch exception [type=" + ElasticsearchException.getExceptionName(cause)
+ ", reason=" + cause.getMessage() + "]";
assertEquals(expectedMessage, parsedFailure.getCause().getMessage());
}
private static void assertFailure(XContentParser parser, ReplicationResponse.ShardInfo.Failure failure) throws IOException {
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());