@Override
  public void close() throws IOException {
    if (mClosed) {
      return;
    }
    mLocalOutputStream.close();
    String path = getUploadPath();
    try {
      // Generate the object metadata by setting server side encryption, md5 checksum, the file
      // length, and encoding as octet stream since no assumptions are made about the file type
      ObjectMetadata meta = new ObjectMetadata();
      if (mSseEnabled) {
        meta.setSSEAlgorithm(ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION);
      }
      if (mHash != null) {
        meta.setContentMD5(new String(Base64.encode(mHash.digest())));
      }
      meta.setContentLength(mFile.length());
      meta.setContentType(Mimetypes.MIMETYPE_OCTET_STREAM);

      // Generate the put request and wait for the transfer manager to complete the upload
      PutObjectRequest putReq = new PutObjectRequest(mBucketName, path, mFile).withMetadata(meta);
      mContentHash = getTransferManager().upload(putReq).waitForUploadResult().getETag();
    } catch (Exception e) {
      LOG.error("Failed to upload {}", path, e);
      throw new IOException(e);
    } finally {
      // Delete the temporary file on the local machine if the transfer manager completed the
      // upload or if the upload failed.
      if (!mFile.delete()) {
        LOG.error("Failed to delete temporary file @ {}", mFile.getPath());
      }
      // Set the closed flag, close can be retried until mFile.delete is called successfully
      mClosed = true;
    }
  }
@Test
  public void close() throws Exception {
    mStream.close();
    assertEquals(mContentHash, mStream.getContentHash().get());
    Mockito.verify(mFile).delete();
  }