@Override
 public IndexMetaData readFrom(StreamInput in) throws IOException {
   Builder builder = new Builder(in.readString());
   builder.version(in.readLong());
   builder.state(State.fromId(in.readByte()));
   builder.settings(readSettingsFromStream(in));
   int mappingsSize = in.readVInt();
   for (int i = 0; i < mappingsSize; i++) {
     MappingMetaData mappingMd = MappingMetaData.PROTO.readFrom(in);
     builder.putMapping(mappingMd);
   }
   int aliasesSize = in.readVInt();
   for (int i = 0; i < aliasesSize; i++) {
     AliasMetaData aliasMd = AliasMetaData.Builder.readFrom(in);
     builder.putAlias(aliasMd);
   }
   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);
   }
   int activeAllocationIdsSize = in.readVInt();
   for (int i = 0; i < activeAllocationIdsSize; i++) {
     int key = in.readVInt();
     Set<String> allocationIds =
         DiffableUtils.StringSetValueSerializer.getInstance().read(in, key);
     builder.putActiveAllocationIds(key, allocationIds);
   }
   return builder.build();
 }
 @Override
 public IndexMetaData apply(IndexMetaData part) {
   Builder builder = builder(index);
   builder.version(version);
   builder.state(state);
   builder.settings(settings);
   builder.mappings.putAll(mappings.apply(part.mappings));
   builder.aliases.putAll(aliases.apply(part.aliases));
   builder.customs.putAll(customs.apply(part.customs));
   builder.activeAllocationIds.putAll(activeAllocationIds.apply(part.activeAllocationIds));
   return builder.build();
 }
 public static IndexMetaData readFrom(StreamInput in) throws IOException {
   Builder builder = new Builder(in.readUTF());
   builder.version(in.readLong());
   builder.state(State.fromId(in.readByte()));
   builder.settings(readSettingsFromStream(in));
   int mappingsSize = in.readVInt();
   for (int i = 0; i < mappingsSize; i++) {
     MappingMetaData mappingMd = MappingMetaData.readFrom(in);
     builder.putMapping(mappingMd);
   }
   int aliasesSize = in.readVInt();
   for (int i = 0; i < aliasesSize; i++) {
     AliasMetaData aliasMd = AliasMetaData.Builder.readFrom(in);
     builder.putAlias(aliasMd);
   }
   int customSize = in.readVInt();
   for (int i = 0; i < customSize; i++) {
     String type = in.readUTF();
     Custom customIndexMetaData = lookupFactorySafe(type).readFrom(in);
     builder.putCustom(type, customIndexMetaData);
   }
   return builder.build();
 }
    public static IndexMetaData fromXContent(XContentParser parser) throws IOException {
      if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
        parser.nextToken();
      }
      Builder builder = new Builder(parser.currentName());

      String currentFieldName = null;
      XContentParser.Token token = parser.nextToken();
      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.settings(
                ImmutableSettings.settingsBuilder()
                    .put(SettingsLoader.Helper.loadNestedFromMap(parser.mapOrdered())));
          } else if ("mappings".equals(currentFieldName)) {
            while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
              if (token == XContentParser.Token.FIELD_NAME) {
                currentFieldName = parser.currentName();
              } else if (token == XContentParser.Token.START_OBJECT) {
                String mappingType = currentFieldName;
                Map<String, Object> mappingSource =
                    MapBuilder.<String, Object>newMapBuilder()
                        .put(mappingType, parser.mapOrdered())
                        .map();
                builder.putMapping(new MappingMetaData(mappingType, mappingSource));
              }
            }
          } else if ("aliases".equals(currentFieldName)) {
            while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
              builder.putAlias(AliasMetaData.Builder.fromXContent(parser));
            }
          } else {
            // check if its a custom index metadata
            Custom.Factory<Custom> factory = lookupFactory(currentFieldName);
            if (factory == null) {
              // TODO warn
              parser.skipChildren();
            } else {
              builder.putCustom(factory.type(), factory.fromXContent(parser));
            }
          }
        } else if (token == XContentParser.Token.START_ARRAY) {
          if ("mappings".equals(currentFieldName)) {
            while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
              if (token == XContentParser.Token.VALUE_EMBEDDED_OBJECT) {
                builder.putMapping(new MappingMetaData(new CompressedString(parser.binaryValue())));
              } else {
                Map<String, Object> mapping = parser.mapOrdered();
                if (mapping.size() == 1) {
                  String mappingType = mapping.keySet().iterator().next();
                  builder.putMapping(new MappingMetaData(mappingType, mapping));
                }
              }
            }
          }
        } else if (token.isValue()) {
          if ("state".equals(currentFieldName)) {
            builder.state(State.fromString(parser.text()));
          } else if ("version".equals(currentFieldName)) {
            builder.version(parser.longValue());
          }
        }
      }
      return builder.build();
    }
    public static IndexMetaData fromXContent(XContentParser parser) throws IOException {
      if (parser.currentToken() == null) { // fresh parser? move to the first token
        parser.nextToken();
      }
      if (parser.currentToken()
          == XContentParser.Token.START_OBJECT) { // on a start object move to next token
        parser.nextToken();
      }
      if (parser.currentToken() != XContentParser.Token.FIELD_NAME) {
        throw new IllegalArgumentException(
            "expected field name but got a " + parser.currentToken());
      }
      Builder builder = new Builder(parser.currentName());

      String currentFieldName = null;
      XContentParser.Token token = parser.nextToken();
      if (token != XContentParser.Token.START_OBJECT) {
        throw new IllegalArgumentException("expected object but got a " + 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.settings(
                Settings.settingsBuilder()
                    .put(SettingsLoader.Helper.loadNestedFromMap(parser.mapOrdered())));
          } else if ("mappings".equals(currentFieldName)) {
            while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
              if (token == XContentParser.Token.FIELD_NAME) {
                currentFieldName = parser.currentName();
              } else if (token == XContentParser.Token.START_OBJECT) {
                String mappingType = currentFieldName;
                Map<String, Object> mappingSource =
                    MapBuilder.<String, Object>newMapBuilder()
                        .put(mappingType, parser.mapOrdered())
                        .map();
                builder.putMapping(new MappingMetaData(mappingType, mappingSource));
              } else {
                throw new IllegalArgumentException("Unexpected token: " + token);
              }
            }
          } else if ("aliases".equals(currentFieldName)) {
            while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
              builder.putAlias(AliasMetaData.Builder.fromXContent(parser));
            }
          } else if (KEY_ACTIVE_ALLOCATIONS.equals(currentFieldName)) {
            while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
              if (token == XContentParser.Token.FIELD_NAME) {
                currentFieldName = parser.currentName();
              } else if (token == XContentParser.Token.START_ARRAY) {
                String shardId = currentFieldName;
                Set<String> allocationIds = new HashSet<>();
                while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
                  if (token == XContentParser.Token.VALUE_STRING) {
                    allocationIds.add(parser.text());
                  }
                }
                builder.putActiveAllocationIds(Integer.valueOf(shardId), allocationIds);
              } else {
                throw new IllegalArgumentException("Unexpected token: " + token);
              }
            }
          } else if ("warmers".equals(currentFieldName)) {
            // TODO: do this in 4.0:
            // throw new IllegalArgumentException("Warmers are not supported anymore - are you
            // upgrading from 1.x?");
            // ignore: warmers have been removed in 3.0 and are
            // simply ignored when upgrading from 2.x
            assert Version.CURRENT.major <= 3;
            parser.skipChildren();
          } 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 == XContentParser.Token.START_ARRAY) {
          if ("mappings".equals(currentFieldName)) {
            while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
              if (token == XContentParser.Token.VALUE_EMBEDDED_OBJECT) {
                builder.putMapping(
                    new MappingMetaData(new CompressedXContent(parser.binaryValue())));
              } else {
                Map<String, Object> mapping = parser.mapOrdered();
                if (mapping.size() == 1) {
                  String mappingType = mapping.keySet().iterator().next();
                  builder.putMapping(new MappingMetaData(mappingType, mapping));
                }
              }
            }
          } else {
            throw new IllegalArgumentException("Unexpected field for an array " + currentFieldName);
          }
        } else if (token.isValue()) {
          if ("state".equals(currentFieldName)) {
            builder.state(State.fromString(parser.text()));
          } else if ("version".equals(currentFieldName)) {
            builder.version(parser.longValue());
          } else {
            throw new IllegalArgumentException("Unexpected field [" + currentFieldName + "]");
          }
        } else {
          throw new IllegalArgumentException("Unexpected token " + token);
        }
      }
      return builder.build();
    }