@Override
  public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
    if (getTaskFailures() != null && getTaskFailures().size() > 0) {
      builder.startArray("task_failures");
      for (TaskOperationFailure ex : getTaskFailures()) {
        builder.startObject();
        builder.value(ex);
        builder.endObject();
      }
      builder.endArray();
    }

    if (getNodeFailures() != null && getNodeFailures().size() > 0) {
      builder.startArray("node_failures");
      for (FailedNodeException ex : getNodeFailures()) {
        builder.startObject();
        ex.toXContent(builder, params);
        builder.endObject();
      }
      builder.endArray();
    }

    builder.startObject("nodes");
    for (Map.Entry<DiscoveryNode, List<TaskInfo>> entry : getPerNodeTasks().entrySet()) {
      DiscoveryNode node = entry.getKey();
      builder.startObject(node.getId(), XContentBuilder.FieldCaseConversion.NONE);
      builder.field("name", node.name());
      builder.field("transport_address", node.address().toString());
      builder.field("host", node.getHostName());
      builder.field("ip", node.getAddress());

      if (!node.attributes().isEmpty()) {
        builder.startObject("attributes");
        for (ObjectObjectCursor<String, String> attr : node.attributes()) {
          builder.field(attr.key, attr.value, XContentBuilder.FieldCaseConversion.NONE);
        }
        builder.endObject();
      }
      builder.startArray("tasks");
      for (TaskInfo task : entry.getValue()) {
        task.toXContent(builder, params);
      }
      builder.endArray();
      builder.endObject();
    }
    builder.endObject();
    return builder;
  }
 private Response newResponse(
     Request request,
     AtomicReferenceArray responses,
     List<NoShardAvailableActionException> unavailableShardExceptions,
     Map<String, List<ShardRouting>> nodes,
     ClusterState clusterState) {
   int totalShards = 0;
   int successfulShards = 0;
   List<ShardOperationResult> broadcastByNodeResponses = new ArrayList<>();
   List<ShardOperationFailedException> exceptions = new ArrayList<>();
   for (int i = 0; i < responses.length(); i++) {
     if (responses.get(i) instanceof FailedNodeException) {
       FailedNodeException exception = (FailedNodeException) responses.get(i);
       totalShards += nodes.get(exception.nodeId()).size();
       for (ShardRouting shard : nodes.get(exception.nodeId())) {
         exceptions.add(
             new DefaultShardOperationFailedException(shard.getIndex(), shard.getId(), exception));
       }
     } else {
       NodeResponse response = (NodeResponse) responses.get(i);
       broadcastByNodeResponses.addAll(response.results);
       totalShards += response.getTotalShards();
       successfulShards += response.getSuccessfulShards();
       for (BroadcastShardOperationFailedException throwable : response.getExceptions()) {
         if (!TransportActions.isShardNotAvailableException(throwable)) {
           exceptions.add(
               new DefaultShardOperationFailedException(
                   throwable.getIndex(), throwable.getShardId().getId(), throwable));
         }
       }
     }
   }
   totalShards += unavailableShardExceptions.size();
   int failedShards = exceptions.size();
   return newResponse(
       request,
       totalShards,
       successfulShards,
       failedShards,
       broadcastByNodeResponses,
       exceptions,
       clusterState);
 }
 public void testFailedNodeException() throws IOException {
   FailedNodeException ex = serialize(new FailedNodeException("the node", "the message", null));
   assertEquals("the node", ex.nodeId());
   assertEquals("the message", ex.getMessage());
 }