class S3Helper {

    public DataStorageFolder moveFolder(String bucket, String rawOldPath, String rawNewPath)
            throws DataStorageException {
        if (StringUtils.isNullOrEmpty(rawOldPath) || StringUtils.isNullOrEmpty(rawNewPath)) {
            throw new DataStorageException(PATH_SHOULD_NOT_BE_EMPTY_MESSAGE);
        }
        final String oldPath = ProviderUtils.withTrailingDelimiter(rawOldPath);
        final String newPath = ProviderUtils.withTrailingDelimiter(rawNewPath);
        final String folderFullPath = newPath.substring(0, newPath.length() - 1);
        String[] parts = newPath.split(ProviderUtils.DELIMITER);
        final String folderName = parts[parts.length - 1];
        AmazonS3 client = getDefaultS3Client();
        checkItemExists(client, bucket, oldPath, true);
        checkItemDoesNotExist(client, bucket, newPath, true);
        ListObjectsRequest req = new ListObjectsRequest();
        req.setBucketName(bucket);
        ObjectListing listing = client.listObjects(req);
        boolean listingFinished = false;
        List<String> oldKeys = new ArrayList<>();
        while (!listingFinished) {
            for (S3ObjectSummary s3ObjectSummary : listing.getObjectSummaries()) {
                if (s3ObjectSummary.getSize() > COPYING_FILE_SIZE_LIMIT) {
                    throw new DataStorageException(String.format("Moving folder '%s' was aborted because " +
                                    "some of its files '%s' size exceeds the limit of %s bytes",
                            oldPath, s3ObjectSummary.getKey(), COPYING_FILE_SIZE_LIMIT));
                }
                String relativePath = s3ObjectSummary.getKey();
                if (relativePath.startsWith(oldPath)) {
                    oldKeys.add(relativePath);
                }
            }
            if (listing.isTruncated()) {
                listing = client.listNextBatchOfObjects(listing);
            } else {
                listingFinished = true;
            }
        }
        final List<MoveObjectRequest> moveRequests = oldKeys.stream()
                .map(oldKey -> new MoveObjectRequest(oldKey, newPath + oldKey.substring(oldPath.length())))
                .collect(Collectors.toList());
        moveS3Objects(client, bucket, moveRequests);
        DataStorageFolder folder = new DataStorageFolder();
        folder.setName(folderName);
        folder.setPath(folderFullPath);
        return folder;
    }

}