public void delete(final Map<Path, TransferStatus> files, final PasswordCallback prompt, final Callback callback) throws BackgroundException {
        final Map<Path, List<ObjectKeyAndVersion>> map = new HashMap<>();
        final List<Path> containers = new ArrayList<>();
        for(Path file : files.keySet()) {
            if(containerService.isContainer(file)) {
                containers.add(file);
                continue;
            }
            callback.delete(file);
            final Path bucket = containerService.getContainer(file);
            if(file.getType().contains(Path.Type.upload)) {
                // In-progress multipart upload
                try {
                    multipartService.delete(new MultipartUpload(file.attributes().getVersionId(),
                            bucket.isRoot() ? StringUtils.EMPTY : bucket.getName(), containerService.getKey(file)));
                }
                catch(NotfoundException ignored) {
                    log.warn(String.format("Ignore failure deleting multipart upload %s", file));
                }
            }
            else {
                final List<ObjectKeyAndVersion> keys = new ArrayList<>();
                // Always returning 204 even if the key does not exist. Does not return 404 for non-existing keys
                keys.add(new ObjectKeyAndVersion(containerService.getKey(file), file.attributes().getVersionId()));
                if(map.containsKey(bucket)) {
                    map.get(bucket).addAll(keys);
                }
                else {
                    map.put(bucket, keys);
                }
            }
        }
        // Iterate over all containers and delete list of keys
        for(Map.Entry<Path, List<ObjectKeyAndVersion>> entry : map.entrySet()) {
            final Path container = entry.getKey();
            final List<ObjectKeyAndVersion> keys = entry.getValue();
            this.delete(container, keys, prompt);
        }
        for(Path file : containers) {
            callback.delete(file);
            // Finally delete bucket itself
            try {
                final String bucket = containerService.getContainer(file).getName();
                session.getClient().deleteBucket(bucket);
                session.getClient().getRegionEndpointCache().removeRegionForBucketName(bucket);
            }
            catch(ServiceException e) {
                throw new S3ExceptionMappingService().map("Cannot delete {0}", e, file);
            }
        }
    }
@Test
    public void testDeleteVersionedPlaceholder() throws Exception {
        final Path container = new Path("versioning-test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
        final String name = new AlphanumericRandomStringService().random();
        final S3AccessControlListFeature acl = new S3AccessControlListFeature(session);
        {
            final Path test = new S3DirectoryFeature(session, new S3WriteFeature(session, acl), acl).mkdir(
                    new Path(container, name, EnumSet.of(Path.Type.directory)), new TransferStatus());
            assertTrue(new S3FindFeature(session, acl).find(test));
            assertTrue(new DefaultFindFeature(session).find(test));
            new S3MultipleDeleteFeature(session, acl).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
            assertFalse(new S3FindFeature(session, acl).find(test));
        }
        {
            final Path test = new S3DirectoryFeature(session, new S3WriteFeature(session, acl), acl).mkdir(
                    new Path(container, name, EnumSet.of(Path.Type.directory)), new TransferStatus());
            assertTrue(new S3FindFeature(session, acl).find(test));
            assertTrue(new DefaultFindFeature(session).find(test));
            new S3MultipleDeleteFeature(session, acl).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
            assertFalse(new S3FindFeature(session, acl).find(test));
        }
        assertFalse(new S3VersionedObjectListService(session, acl).list(container, new DisabledListProgressListener()).contains(
                new Path(container, name, EnumSet.of(Path.Type.directory))));
    }