protected final ObjectMetadata updateMetadataWithContentCryptoMaterial(
     ObjectMetadata metadata, File file, ContentCryptoMaterial instruction) {
   if (metadata == null) metadata = new ObjectMetadata();
   if (file != null) {
     Mimetypes mimetypes = Mimetypes.getInstance();
     metadata.setContentType(mimetypes.getMimetype(file));
   }
   return instruction.toObjectMetadata(metadata);
 }
  @Override
  protected void putResource(File source, String destination, TransferProgress transferProgress)
      throws TransferFailedException, ResourceDoesNotExistException {
    String key = getKey(destination);

    mkdirs(key, 0);

    InputStream in = null;
    try {
      ObjectMetadata objectMetadata = new ObjectMetadata();
      objectMetadata.setContentLength(source.length());
      objectMetadata.setContentType(Mimetypes.getInstance().getMimetype(source));

      in = new TransferProgressFileInputStream(source, transferProgress);

      this.amazonS3.putObject(new PutObjectRequest(this.bucketName, key, in, objectMetadata));
    } catch (AmazonServiceException e) {
      throw new TransferFailedException(String.format("Cannot write file to '%s'", destination), e);
    } catch (FileNotFoundException e) {
      throw new ResourceDoesNotExistException(
          String.format("Cannot read file from '%s'", source), e);
    } finally {
      IoUtils.closeQuietly(in);
    }
  }
  /**
   * Update the request's ObjectMetadata with the necessary information for decrypting the object
   *
   * @param request Non-null PUT request encrypted using the given instruction
   * @param instruction Non-null instruction used to encrypt the data in this PUT request.
   * @deprecated no longer used and will be removed in the future
   */
  @Deprecated
  public static void updateMetadataWithEncryptionInstruction(
      PutObjectRequest request, EncryptionInstruction instruction) {
    byte[] keyBytesToStoreInMetadata = instruction.getEncryptedSymmetricKey();
    Cipher symmetricCipher = instruction.getSymmetricCipher();
    Map<String, String> materialsDescription = instruction.getMaterialsDescription();

    ObjectMetadata metadata = request.getMetadata();
    if (metadata == null) metadata = new ObjectMetadata();

    if (request.getFile() != null) {
      Mimetypes mimetypes = Mimetypes.getInstance();
      metadata.setContentType(mimetypes.getMimetype(request.getFile()));
    }

    updateMetadata(metadata, keyBytesToStoreInMetadata, symmetricCipher, materialsDescription);
    request.setMetadata(metadata);
  }
  /** Loads MIME type info from the file 'mime.types' in the classpath, if it's available. */
  public static synchronized Mimetypes getInstance() {
    if (mimetypes != null) return mimetypes;

    mimetypes = new Mimetypes();
    InputStream mimetypesFile = mimetypes.getClass().getResourceAsStream("/mime.types");
    if (mimetypesFile != null) {
      if (log.isDebugEnabled()) {
        log.debug("Loading mime types from file in the classpath: mime.types");
      }
      try {
        mimetypes.loadAndReplaceMimetypes(mimetypesFile);
      } catch (IOException e) {
        if (log.isErrorEnabled()) {
          log.error("Failed to load mime types from file in the classpath: mime.types", e);
        }
      }
    } else {
      if (log.isWarnEnabled()) {
        log.warn("Unable to find 'mime.types' file in classpath");
      }
    }
    return mimetypes;
  }