@Override
 public MetaData apply(MetaData part) {
   Builder builder = builder();
   builder.clusterUUID(clusterUUID);
   builder.version(version);
   builder.transientSettings(transientSettings);
   builder.persistentSettings(persistentSettings);
   builder.indices(indices.apply(part.indices));
   builder.templates(templates.apply(part.templates));
   builder.customs(customs.apply(part.customs));
   return builder.build();
 }
 @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 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();
    }