@Override
    public Path copy(final Path file, final Path target, final TransferStatus status, final ConnectionCallback callback, final StreamListener listener) throws BackgroundException {
        try {
            final EueApiClient client = new EueApiClient(session);
            if(status.isExists()) {
                if(log.isWarnEnabled()) {
                    log.warn(String.format("Trash file %s to be replaced with %s", target, file));
                }
                new EueTrashFeature(session, fileid).delete(Collections.singletonMap(target, status), callback, new Delete.DisabledCallback());
            }
            final String resourceId = fileid.getFileId(file);
            final String parentResourceId = fileid.getFileId(target.getParent());
            String targetResourceId = null;
            final ResourceCopyResponseEntries resourceCopyResponseEntries;
            switch(parentResourceId) {
                case EueResourceIdProvider.ROOT:
                case EueResourceIdProvider.TRASH:
                    resourceCopyResponseEntries = new CopyChildrenForAliasApiApi(client)
                            .resourceAliasAliasChildrenCopyPost(parentResourceId,
                                    Collections.singletonList(String.format("%s/resource/%s",
                                            session.getBasePath(), resourceId)), null, null, null,
                                    "rename", null);
                    break;
                default:
                    resourceCopyResponseEntries = new CopyChildrenApi(client).resourceResourceIdChildrenCopyPost(parentResourceId,
                            Collections.singletonList(String.format("%s/resource/%s", session.getBasePath(), resourceId)), null, null, null,
                            "rename", null);
            }
            if(null == resourceCopyResponseEntries) {
                // Copy of single file will return 200 status code with empty response body
            }
            else {
                for(ResourceCopyResponseEntry resourceCopyResponseEntry : resourceCopyResponseEntries.values()) {
                    switch(resourceCopyResponseEntry.getStatusCode()) {
                        case HttpStatus.SC_CREATED:
                            fileid.cache(target, EueResourceIdProvider.getResourceIdFromResourceUri(resourceCopyResponseEntry.getHeaders().getLocation()));
                            break;
                        default:
                            log.warn(String.format("Failure %s copying file %s", resourceCopyResponseEntries, file));
                            throw new EueExceptionMappingService().map(new ApiException(resourceCopyResponseEntry.getReason(),
                                    null, resourceCopyResponseEntry.getStatusCode(), client.getResponseHeaders()));
                    }
                }

            }
            listener.sent(status.getLength());
            if(!StringUtils.equals(file.getName(), target.getName())) {
                final ResourceUpdateModel resourceUpdateModel = new ResourceUpdateModel();
                final ResourceUpdateModelUpdate resourceUpdateModelUpdate = new ResourceUpdateModelUpdate();
                final Uifs uifs = new Uifs();
                uifs.setName(target.getName());
                resourceUpdateModelUpdate.setUifs(uifs);
                resourceUpdateModel.setUpdate(resourceUpdateModelUpdate);
                final ResourceMoveResponseEntries resourceMoveResponseEntries = new UpdateResourceApi(client).resourceResourceIdPatch(fileid.getFileId(target),
                        resourceUpdateModel, null, null, null);
                if(null == resourceMoveResponseEntries) {
                    // Move of single file will return 200 status code with empty response body
                }
                else {
                    for(ResourceMoveResponseEntry resourceMoveResponseEntry : resourceMoveResponseEntries.values()) {
                        switch(resourceMoveResponseEntry.getStatusCode()) {
                            case HttpStatus.SC_CREATED:
                                break;
                            default:
                                log.warn(String.format("Failure %s renaming file %s", resourceMoveResponseEntry, file));
                                throw new EueExceptionMappingService().map(new ApiException(resourceMoveResponseEntry.getReason(),
                                        null, resourceMoveResponseEntry.getStatusCode(), client.getResponseHeaders()));
                        }
                    }
                }
            }
            return target;
        }
        catch(ApiException e) {
            throw new EueExceptionMappingService().map("Cannot copy {0}", e, file);
        }
    }
@Test
    public void testCopyToExistingFile() throws Exception {
        final EueResourceIdProvider fileid = new EueResourceIdProvider(session);
        final Path folder = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
        new EueDirectoryFeature(session, fileid).mkdir(folder, new TransferStatus());
        final Path test = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
        final Local local = new Local(System.getProperty("java.io.tmpdir"), test.getName());
        final byte[] random = RandomUtils.nextBytes(2547);
        IOUtils.write(random, local.getOutputStream(false));
        final TransferStatus status = new TransferStatus().withLength(random.length);
        final EueWriteFeature.Chunk upload = new EueSingleUploadService(session, fileid, new EueWriteFeature(session, fileid)).upload(test, local, new BandwidthThrottle(BandwidthThrottle.UNLIMITED),
                new DisabledStreamListener(), status, new DisabledLoginCallback());
        assertNotNull(upload.getResourceId());
        local.delete();
        assertTrue(new EueFindFeature(session, fileid).find(test));
        final Path copy = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
        new EueTouchFeature(session, fileid).touch(copy, new TransferStatus().withLength(0L));
        new EueCopyFeature(session, fileid).copy(test, copy, new TransferStatus().exists(true), new DisabledConnectionCallback(), new DisabledStreamListener());
        final Find find = new DefaultFindFeature(session);
        assertTrue(find.find(test));
        assertTrue(find.find(copy));
        new EueDeleteFeature(session, fileid).delete(Arrays.asList(test, copy), new DisabledLoginCallback(), new Delete.DisabledCallback());
    }