@Override
  public boolean touch(URI uri)
      throws IOException {
    try {
      HeadObjectResponse s3ObjectMetadata = getS3ObjectMetadata(uri);
      String encodedUrl = URLEncoder.encode(uri.getHost() + uri.getPath(), StandardCharsets.UTF_8);

      String path = sanitizePath(uri.getPath());
      CopyObjectRequest request = generateCopyObjectRequest(encodedUrl, uri, path,
          ImmutableMap.of("lastModified", String.valueOf(System.currentTimeMillis())));
      _s3Client.copyObject(request);
      long newUpdateTime = getS3ObjectMetadata(uri).lastModified().toEpochMilli();
      return newUpdateTime > s3ObjectMetadata.lastModified().toEpochMilli();
    } catch (NoSuchKeyException e) {
      String path = sanitizePath(uri.getPath());
      PutObjectRequest putObjectRequest = generatePutObjectRequest(uri, path);
      _s3Client.putObject(putObjectRequest, RequestBody.fromBytes(new byte[0]));
      return true;
    } catch (S3Exception e) {
      throw new IOException(e);
    }
  }
@Test
  public void testTouchFileInBucket()
      throws Exception {

    String[] originalFiles = new String[]{"a-touch.txt", "b-touch.txt", "c-touch.txt"};

    for (String fileName : originalFiles) {
      _s3PinotFS.touch(URI.create(String.format(FILE_FORMAT, SCHEME, BUCKET, fileName)));
    }
    ListObjectsV2Response listObjectsV2Response =
        _s3Client.listObjectsV2(S3TestUtils.getListObjectRequest(BUCKET, "", true));

    String[] response = listObjectsV2Response.contents().stream().map(S3Object::key).filter(x -> x.contains("touch"))
        .toArray(String[]::new);

    Assert.assertEquals(response.length, originalFiles.length);
    Assert.assertTrue(Arrays.equals(response, originalFiles));
  }