@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 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 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 ClusterState readFrom(
     StreamInput in, @Nullable Settings globalSettings, @Nullable DiscoveryNode localNode)
     throws IOException {
   Builder builder = new Builder();
   builder.version = in.readLong();
   builder.metaData = MetaData.Builder.readFrom(in, globalSettings);
   builder.routingTable = RoutingTable.Builder.readFrom(in);
   builder.nodes = DiscoveryNodes.Builder.readFrom(in, localNode);
   builder.blocks = ClusterBlocks.Builder.readClusterBlocks(in);
   builder.allocationExplanation = AllocationExplanation.readAllocationExplanation(in);
   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();
 }
 @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 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 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();
    }
    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();
    }