/**
   * You can make any number of invalidation requests, but you can have only three invalidation
   * requests in progress at one time. Each request can contain up to 1,000 objects to invalidate.
   * If you exceed these limits, you get an error message.
   *
   * <p>It usually takes 10 to 15 minutes to complete your invalidation request, depending on the
   * size of your request.
   *
   * @param origin Origin server
   * @param method Distribution method
   * @param files Files to purge
   * @param recursive Recursivly for folders
   */
  @Override
  public void invalidate(
      String origin, Distribution.Method method, List<Path> files, boolean recursive) {
    try {
      this.check();
      this.message(
          MessageFormat.format(
              Locale.localizedString("Writing CDN configuration of {0}", "Status"), origin));

      final long reference = System.currentTimeMillis();
      Distribution d = distributionStatus.get(method).get(origin);
      if (null == d) {
        log.error(String.format("No cached distribution for origin %s", origin));
        return;
      }
      List<String> keys = this.getInvalidationKeys(files, recursive);
      if (keys.isEmpty()) {
        log.warn("No keys selected for invalidation");
        return;
      }
      CloudFrontService cf = this.getClient();
      cf.invalidateObjects(
          d.getId(),
          keys.toArray(new String[keys.size()]), // objects
          new Date(reference).toString() // Comment
          );
    } catch (CloudFrontServiceException e) {
      this.error("Cannot write CDN configuration", e);
    } catch (IOException e) {
      this.error("Cannot write CDN configuration", e);
    } finally {
      distributionStatus.get(method).clear();
    }
  }
  /**
   * Amazon CloudFront Extension to create a new distribution configuration *
   *
   * @param enabled Distribution status
   * @param method Distribution method
   * @param origin Name of the container
   * @param cnames DNS CNAME aliases for distribution
   * @param logging Access log configuration
   * @param defaultRootObject Index file for distribution. Only supported for download and custom
   *     origins.
   * @return Distribution configuration
   * @throws CloudFrontServiceException CloudFront failure details
   * @throws ConnectionCanceledException Authentication canceled
   */
  private org.jets3t.service.model.cloudfront.Distribution createDistribution(
      boolean enabled,
      Distribution.Method method,
      final String origin,
      String[] cnames,
      LoggingStatus logging,
      String defaultRootObject)
      throws ConnectionCanceledException, CloudFrontServiceException {

    final String reference = String.valueOf(System.currentTimeMillis());

    if (log.isDebugEnabled()) {
      log.debug(String.format("Create new %s distribution", method.toString()));
    }
    CloudFrontService cf = this.getClient();

    final String originId = UUID.randomUUID().toString();
    final CacheBehavior cacheBehavior =
        new CacheBehavior(originId, false, null, CacheBehavior.ViewerProtocolPolicy.ALLOW_ALL, 0L);

    if (method.equals(Distribution.STREAMING)) {
      final StreamingDistributionConfig config =
          new StreamingDistributionConfig(
              new S3Origin[] {new S3Origin(originId, origin, null)},
              reference,
              cnames,
              null,
              enabled,
              logging,
              null);
      return cf.createDistribution(config);
    }
    if (method.equals(Distribution.DOWNLOAD)) {
      DistributionConfig config =
          new DistributionConfig(
              new Origin[] {new S3Origin(originId, origin, null)},
              reference,
              cnames,
              null,
              enabled,
              logging,
              defaultRootObject,
              cacheBehavior,
              new CacheBehavior[] {});
      return cf.createDistribution(config);
    }
    if (method.equals(Distribution.CUSTOM) || method.equals(Distribution.WEBSITE_CDN)) {
      DistributionConfig config =
          new DistributionConfig(
              new Origin[] {
                new CustomOrigin(originId, origin, CustomOrigin.OriginProtocolPolicy.MATCH_VIEWER)
              },
              reference,
              cnames,
              null,
              enabled,
              logging,
              defaultRootObject,
              cacheBehavior,
              new CacheBehavior[] {});
      return cf.createDistribution(config);
    }
    throw new RuntimeException("Invalid distribution method:" + method);
  }