class DefaultComponentMetadataProducer implements ComponentMetadataProducer {

  @Override
  public String getMetadata(final Component component,
                            final Iterable<Asset> assets,
                            final Map<String, Object> additional)
  {
    checkNotNull(component);
    checkNotNull(assets);
    checkNotNull(additional);

    Map<String, Object> metadata = new HashMap<>();
    put(metadata, FORMAT, component.format());
    put(metadata, GROUP, component.group());
    put(metadata, NAME, component.name());
    put(metadata, VERSION, component.version());
    put(metadata, ATTRIBUTES, component.attributes().backing());

    // Prepend numbers in the version with 0s to make each number 5 digits
    String normalizedVersion = getNormalizedVersion(component);
    put(metadata, NORMALIZED_VERSION, normalizedVersion);

    put(metadata, IS_PRERELEASE_KEY, isPrerelease(component, assets));
    lastBlobUpdated(assets)
        .ifPresent(dateTime -> put(metadata, LAST_BLOB_UPDATED_KEY, dateTime.toString(DATE_TIME_FORMATTER)));
    lastDownloaded(assets)
        .ifPresent(dateTime -> put(metadata, LAST_DOWNLOADED_KEY, dateTime.toString(DATE_TIME_FORMATTER)));

    List<Map<String, Object>> allAssetMetadata = new ArrayList<>();
    for (Asset asset : assets) {
      Map<String, Object> assetMetadata = new HashMap<>();
      put(assetMetadata, ID, documentId(asset));
      put(assetMetadata, NAME, asset.name());
      put(assetMetadata, CONTENT_TYPE, asset.contentType());
      put(assetMetadata, ATTRIBUTES, asset.attributes().backing());

      allAssetMetadata.add(assetMetadata);
    }
    if (!allAssetMetadata.isEmpty()) {
      metadata.put(ASSETS, allAssetMetadata);
    }

    for (ComponentMetadataProducerExtension componentMetadataProducerExtension : componentMetadataProducerExtensions) {
      metadata.putAll(componentMetadataProducerExtension.getComponentMetadata(component));
    }

    metadata.putAll(additional);

    try {
      return JsonUtils.from(metadata);
    }
    catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  @Inject public  DefaultComponentMetadataProducer(final Set<ComponentMetadataProducerExtension> componentMetadataProducerExtensions);

}