public static void writeTo(IndexMetaData indexMetaData, StreamOutput out) throws IOException {
   out.writeUTF(indexMetaData.index());
   out.writeLong(indexMetaData.version());
   out.writeByte(indexMetaData.state().id());
   writeSettingsToStream(indexMetaData.settings(), out);
   out.writeVInt(indexMetaData.mappings().size());
   for (MappingMetaData mappingMd : indexMetaData.mappings().values()) {
     MappingMetaData.writeTo(mappingMd, out);
   }
   out.writeVInt(indexMetaData.aliases().size());
   for (AliasMetaData aliasMd : indexMetaData.aliases().values()) {
     AliasMetaData.Builder.writeTo(aliasMd, out);
   }
   out.writeVInt(indexMetaData.customs().size());
   for (Map.Entry<String, Custom> entry : indexMetaData.customs().entrySet()) {
     out.writeUTF(entry.getKey());
     lookupFactorySafe(entry.getKey()).writeTo(entry.getValue(), out);
   }
 }
    public static void toXContent(
        IndexMetaData indexMetaData, XContentBuilder builder, ToXContent.Params params)
        throws IOException {
      builder.startObject(indexMetaData.index(), XContentBuilder.FieldCaseConversion.NONE);

      builder.field("version", indexMetaData.version());
      builder.field("state", indexMetaData.state().toString().toLowerCase(Locale.ENGLISH));

      boolean binary = params.paramAsBoolean("binary", false);

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

      builder.startArray("mappings");
      for (Map.Entry<String, MappingMetaData> entry : indexMetaData.mappings().entrySet()) {
        if (binary) {
          builder.value(entry.getValue().source().compressed());
        } else {
          byte[] data = entry.getValue().source().uncompressed();
          XContentParser parser = XContentFactory.xContent(data).createParser(data);
          Map<String, Object> mapping = parser.mapOrdered();
          parser.close();
          builder.map(mapping);
        }
      }
      builder.endArray();

      for (Map.Entry<String, Custom> entry : indexMetaData.customs().entrySet()) {
        builder.startObject(entry.getKey(), XContentBuilder.FieldCaseConversion.NONE);
        lookupFactorySafe(entry.getKey()).toXContent(entry.getValue(), builder, params);
        builder.endObject();
      }

      builder.startObject("aliases");
      for (AliasMetaData alias : indexMetaData.aliases().values()) {
        AliasMetaData.Builder.toXContent(alias, builder, params);
      }
      builder.endObject();

      builder.endObject();
    }
  private void applyMappings(ClusterChangedEvent event) {
    // go over and update mappings
    for (IndexMetaData indexMetaData : event.state().metaData()) {
      if (!indicesService.hasIndex(indexMetaData.index())) {
        // we only create / update here
        continue;
      }
      List<String> typesToRefresh = Lists.newArrayList();
      String index = indexMetaData.index();
      IndexService indexService = indicesService.indexService(index);
      if (indexService == null) {
        // got deleted on us, ignore (closing the node)
        return;
      }
      try {
        MapperService mapperService = indexService.mapperService();
        // first, go over and update the _default_ mapping (if exists)
        if (indexMetaData.mappings().containsKey(MapperService.DEFAULT_MAPPING)) {
          boolean requireRefresh =
              processMapping(
                  index,
                  mapperService,
                  MapperService.DEFAULT_MAPPING,
                  indexMetaData.mapping(MapperService.DEFAULT_MAPPING).source());
          if (requireRefresh) {
            typesToRefresh.add(MapperService.DEFAULT_MAPPING);
          }
        }

        // go over and add the relevant mappings (or update them)
        for (ObjectCursor<MappingMetaData> cursor : indexMetaData.mappings().values()) {
          MappingMetaData mappingMd = cursor.value;
          String mappingType = mappingMd.type();
          CompressedXContent mappingSource = mappingMd.source();
          if (mappingType.equals(MapperService.DEFAULT_MAPPING)) { // we processed _default_ first
            continue;
          }
          boolean requireRefresh = processMapping(index, mapperService, mappingType, mappingSource);
          if (requireRefresh) {
            typesToRefresh.add(mappingType);
          }
        }
        if (!typesToRefresh.isEmpty() && sendRefreshMapping) {
          nodeMappingRefreshAction.nodeMappingRefresh(
              event.state(),
              new NodeMappingRefreshAction.NodeMappingRefreshRequest(
                  index,
                  indexMetaData.indexUUID(),
                  typesToRefresh.toArray(new String[typesToRefresh.size()]),
                  event.state().nodes().localNodeId()));
        }
      } catch (Throwable t) {
        // if we failed the mappings anywhere, we need to fail the shards for this index, note, we
        // safeguard
        // by creating the processing the mappings on the master, or on the node the mapping was
        // introduced on,
        // so this failure typically means wrong node level configuration or something similar
        for (IndexShard indexShard : indexService) {
          ShardRouting shardRouting = indexShard.routingEntry();
          failAndRemoveShard(shardRouting, indexService, true, "failed to update mappings", t);
        }
      }
    }
  }
  @Test
  public void testSimpleJsonFromAndTo() throws IOException {
    MetaData metaData =
        newMetaDataBuilder()
            .maxNumberOfShardsPerNode(2)
            .put(newIndexMetaDataBuilder("test1").numberOfShards(1).numberOfReplicas(2))
            .put(
                newIndexMetaDataBuilder("test2")
                    .settings(settingsBuilder().put("setting1", "value1").put("setting2", "value2"))
                    .numberOfShards(2)
                    .numberOfReplicas(3))
            .put(
                newIndexMetaDataBuilder("test3")
                    .numberOfShards(1)
                    .numberOfReplicas(2)
                    .putMapping("mapping1", MAPPING_SOURCE1))
            .put(
                newIndexMetaDataBuilder("test4")
                    .settings(settingsBuilder().put("setting1", "value1").put("setting2", "value2"))
                    .numberOfShards(1)
                    .numberOfReplicas(2)
                    .putMapping("mapping1", MAPPING_SOURCE1)
                    .putMapping("mapping2", MAPPING_SOURCE2))
            .build();

    String metaDataSource = MetaData.Builder.toJson(metaData);
    System.out.println("ToJson: " + metaDataSource);

    MetaData parsedMetaData =
        MetaData.Builder.fromJson(
            Jackson.defaultJsonFactory().createJsonParser(metaDataSource), null);
    assertThat(parsedMetaData.maxNumberOfShardsPerNode(), equalTo(2));

    IndexMetaData indexMetaData = metaData.index("test1");
    assertThat(indexMetaData.numberOfShards(), equalTo(1));
    assertThat(indexMetaData.numberOfReplicas(), equalTo(2));
    assertThat(indexMetaData.settings().getAsMap().size(), equalTo(2));
    assertThat(indexMetaData.mappings().size(), equalTo(0));

    indexMetaData = metaData.index("test2");
    assertThat(indexMetaData.numberOfShards(), equalTo(2));
    assertThat(indexMetaData.numberOfReplicas(), equalTo(3));
    assertThat(indexMetaData.settings().getAsMap().size(), equalTo(4));
    assertThat(indexMetaData.settings().get("setting1"), equalTo("value1"));
    assertThat(indexMetaData.settings().get("setting2"), equalTo("value2"));
    assertThat(indexMetaData.mappings().size(), equalTo(0));

    indexMetaData = metaData.index("test3");
    assertThat(indexMetaData.numberOfShards(), equalTo(1));
    assertThat(indexMetaData.numberOfReplicas(), equalTo(2));
    assertThat(indexMetaData.settings().getAsMap().size(), equalTo(2));
    assertThat(indexMetaData.mappings().size(), equalTo(1));
    assertThat(indexMetaData.mappings().get("mapping1"), equalTo(MAPPING_SOURCE1));

    indexMetaData = metaData.index("test4");
    assertThat(indexMetaData.numberOfShards(), equalTo(1));
    assertThat(indexMetaData.numberOfReplicas(), equalTo(2));
    assertThat(indexMetaData.settings().getAsMap().size(), equalTo(4));
    assertThat(indexMetaData.settings().get("setting1"), equalTo("value1"));
    assertThat(indexMetaData.settings().get("setting2"), equalTo("value2"));
    assertThat(indexMetaData.mappings().size(), equalTo(2));
    assertThat(indexMetaData.mappings().get("mapping1"), equalTo(MAPPING_SOURCE1));
    assertThat(indexMetaData.mappings().get("mapping2"), equalTo(MAPPING_SOURCE2));
  }