public static void toXContent(
        MetaData metaData, XContentBuilder builder, ToXContent.Params params) throws IOException {
      XContentContext context = XContentContext.valueOf(params.param(CONTEXT_MODE_PARAM, "API"));

      builder.startObject("meta-data");

      builder.field("version", metaData.version());
      builder.field("cluster_uuid", metaData.clusterUUID);

      if (!metaData.persistentSettings().getAsMap().isEmpty()) {
        builder.startObject("settings");
        for (Map.Entry<String, String> entry :
            metaData.persistentSettings().getAsMap().entrySet()) {
          builder.field(entry.getKey(), entry.getValue());
        }
        builder.endObject();
      }

      if (context == XContentContext.API && !metaData.transientSettings().getAsMap().isEmpty()) {
        builder.startObject("transient_settings");
        for (Map.Entry<String, String> entry : metaData.transientSettings().getAsMap().entrySet()) {
          builder.field(entry.getKey(), entry.getValue());
        }
        builder.endObject();
      }

      builder.startObject("templates");
      for (ObjectCursor<IndexTemplateMetaData> cursor : metaData.templates().values()) {
        IndexTemplateMetaData.Builder.toXContent(cursor.value, builder, params);
      }
      builder.endObject();

      if (context == XContentContext.API && !metaData.indices().isEmpty()) {
        builder.startObject("indices");
        for (IndexMetaData indexMetaData : metaData) {
          IndexMetaData.Builder.toXContent(indexMetaData, builder, params);
        }
        builder.endObject();
      }

      for (ObjectObjectCursor<String, Custom> cursor : metaData.customs()) {
        Custom proto = lookupPrototypeSafe(cursor.key);
        if (proto.context().contains(context)) {
          builder.startObject(cursor.key);
          cursor.value.toXContent(builder, params);
          builder.endObject();
        }
      }
      builder.endObject();
    }
 @Override
 public MetaData readFrom(StreamInput in) throws IOException {
   Builder builder = new Builder();
   builder.version = in.readLong();
   builder.clusterUUID = in.readString();
   builder.transientSettings(readSettingsFromStream(in));
   builder.persistentSettings(readSettingsFromStream(in));
   int size = in.readVInt();
   for (int i = 0; i < size; i++) {
     builder.put(IndexMetaData.Builder.readFrom(in), false);
   }
   size = in.readVInt();
   for (int i = 0; i < size; i++) {
     builder.put(IndexTemplateMetaData.Builder.readFrom(in));
   }
   int customSize = in.readVInt();
   for (int i = 0; i < customSize; i++) {
     String type = in.readString();
     Custom customIndexMetaData = lookupPrototypeSafe(type).readFrom(in);
     builder.putCustom(type, customIndexMetaData);
   }
   return builder.build();
 }
 public Builder put(IndexTemplateMetaData.Builder template) {
   return put(template.build());
 }
    public static MetaData fromXContent(XContentParser parser) throws IOException {
      Builder builder = new Builder();

      // we might get here after the meta-data element, or on a fresh parser
      XContentParser.Token token = parser.currentToken();
      String currentFieldName = parser.currentName();
      if (!"meta-data".equals(currentFieldName)) {
        token = parser.nextToken();
        if (token == XContentParser.Token.START_OBJECT) {
          // move to the field name (meta-data)
          token = parser.nextToken();
          if (token != XContentParser.Token.FIELD_NAME) {
            throw new IllegalArgumentException("Expected a field name but got " + token);
          }
          // move to the next object
          token = parser.nextToken();
        }
        currentFieldName = parser.currentName();
      }

      if (!"meta-data".equals(parser.currentName())) {
        throw new IllegalArgumentException(
            "Expected [meta-data] as a field name but got " + currentFieldName);
      }
      if (token != XContentParser.Token.START_OBJECT) {
        throw new IllegalArgumentException("Expected a START_OBJECT but got " + token);
      }

      while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
        if (token == XContentParser.Token.FIELD_NAME) {
          currentFieldName = parser.currentName();
        } else if (token == XContentParser.Token.START_OBJECT) {
          if ("settings".equals(currentFieldName)) {
            builder.persistentSettings(
                Settings.settingsBuilder()
                    .put(SettingsLoader.Helper.loadNestedFromMap(parser.mapOrdered()))
                    .build());
          } else if ("indices".equals(currentFieldName)) {
            while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
              builder.put(IndexMetaData.Builder.fromXContent(parser), false);
            }
          } else if ("templates".equals(currentFieldName)) {
            while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
              builder.put(IndexTemplateMetaData.Builder.fromXContent(parser, parser.currentName()));
            }
          } else {
            // check if its a custom index metadata
            Custom proto = lookupPrototype(currentFieldName);
            if (proto == null) {
              // TODO warn
              parser.skipChildren();
            } else {
              Custom custom = proto.fromXContent(parser);
              builder.putCustom(custom.type(), custom);
            }
          }
        } else if (token.isValue()) {
          if ("version".equals(currentFieldName)) {
            builder.version = parser.longValue();
          } else if ("cluster_uuid".equals(currentFieldName) || "uuid".equals(currentFieldName)) {
            builder.clusterUUID = parser.text();
          } else {
            throw new IllegalArgumentException("Unexpected field [" + currentFieldName + "]");
          }
        } else {
          throw new IllegalArgumentException("Unexpected token " + token);
        }
      }
      return builder.build();
    }