@Override
    public HttpResponseOutputStream<File> write(final Path file, final TransferStatus status, final ConnectionCallback callback) throws BackgroundException {
        final DelayedHttpEntityCallable<File> command = new DelayedHttpEntityCallable<File>(file) {
            @Override
            public File call(final HttpEntity entity) throws BackgroundException {
                try {
                    final HttpPost request;
                    if(status.isExists()) {
                        request = new HttpPost(String.format("%s/files/%s/content?fields=%s", client.getBasePath(),
                                fileid.getFileId(file),
                                String.join(",", BoxAttributesFinderFeature.DEFAULT_FIELDS)));
                    }
                    else {
                        request = new HttpPost(String.format("%s/files/content?fields=%s", client.getBasePath(),
                                String.join(",", BoxAttributesFinderFeature.DEFAULT_FIELDS)));
                    }
                    final Checksum checksum = status.getChecksum();
                    if(Checksum.NONE != checksum) {
                        switch(checksum.algorithm) {
                            case sha1:
                                request.addHeader(HttpHeaders.CONTENT_MD5, checksum.hash);
                        }
                    }
                    final ByteArrayOutputStream content = new ByteArrayOutputStream();
                    new JSON().getContext(null).writeValue(content, new FilescontentAttributes()
                            .name(file.getName())
                            .parent(new FilescontentAttributesParent().id(fileid.getFileId(file.getParent())))
                            .contentCreatedAt(status.getCreated() != null ? new DateTime(status.getCreated()) : null)
                            .contentModifiedAt(status.getModified() != null ? new DateTime(status.getModified()) : null)
                    );
                    final MultipartEntityBuilder multipart = MultipartEntityBuilder.create();
                    multipart.addBinaryBody("attributes", content.toByteArray());
                    final ByteArrayOutputStream out = new ByteArrayOutputStream();
                    entity.writeTo(out);
                    multipart.addBinaryBody("file", out.toByteArray(),
                            null == status.getMime() ? ContentType.APPLICATION_OCTET_STREAM : ContentType.create(status.getMime()), file.getName());
                    request.setEntity(multipart.build());
                    if(status.isExists()) {
                        if(StringUtils.isNotBlank(status.getRemote().getETag())) {
                            request.addHeader(new BasicHeader(HttpHeaders.IF_MATCH, status.getRemote().getETag()));
                        }
                        else {
                            log.warn(String.format("Missing remote attributes in transfer status to read current ETag for %s", file));
                        }
                    }
                    final Files files = session.getClient().execute(request, new BoxClientErrorResponseHandler<Files>() {
                        @Override
                        public Files handleEntity(final HttpEntity entity) throws IOException {
                            return new JSON().getContext(null).readValue(entity.getContent(), Files.class);
                        }
                    });
                    if(log.isDebugEnabled()) {
                        log.debug(String.format("Received response %s for upload of %s", files, file));
                    }
                    if(files.getEntries().stream().findFirst().isPresent()) {
                        return files.getEntries().stream().findFirst().get();
                    }
                    throw new NotfoundException(file.getAbsolute());
                }
                catch(HttpResponseException e) {
                    throw new DefaultHttpResponseExceptionMappingService().map("Upload {0} failed", e, file);
                }
                catch(IOException e) {
                    throw new DefaultIOExceptionMappingService().map("Upload {0} failed", e, file);
                }
            }

            @Override
            public long getContentLength() {
                return -1L;
            }
        };
        return this.write(file, status, command);
    }
@Test
    public void testWrite() throws Exception {
        final BoxFileidProvider fileid = new BoxFileidProvider(session);
        final BoxWriteFeature feature = new BoxWriteFeature(session, fileid);
        final Path folder = new BoxDirectoryFeature(session, fileid).mkdir(
                new Path(Home.ROOT, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
        final long folderModification = new BoxAttributesFinderFeature(session, fileid).find(folder).getModificationDate();
        assertEquals(folderModification, folder.attributes().getModificationDate());
        // Makes sure to test overwrite
        final Path file = new BoxTouchFeature(session, fileid).touch(
                new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus().withCreated(1503654615002L));
        final byte[] content = RandomUtils.nextBytes(2047);
        final TransferStatus status = new TransferStatus();
        status.setModified(1503654614004L); //GMT: Friday, 25. August 2017 09:50:14.004
        status.setLength(content.length);
        status.setExists(true);
        status.setRemote(file.attributes());
        status.setMime(MimeTypeService.DEFAULT_CONTENT_TYPE);
        status.setChecksum(feature.checksum(file, status).compute(new ByteArrayInputStream(content), status));
        final HttpResponseOutputStream<File> out = feature.write(file, status, new DisabledConnectionCallback());
        final ByteArrayInputStream in = new ByteArrayInputStream(content);
        final TransferStatus progress = new TransferStatus();
        final BytecountStreamListener count = new BytecountStreamListener();
        new StreamCopier(progress, progress).withListener(count).transfer(in, out);
        assertEquals(content.length, count.getSent());
        in.close();
        out.close();
        assertNotNull(out.getStatus());
        assertTrue(new DefaultFindFeature(session).find(file));
        assertTrue(new BoxFindFeature(session, fileid).find(file));
        final PathAttributes attributes = new BoxAttributesFinderFeature(session, fileid).find(file);
        assertEquals(content.length, attributes.getSize());
        final byte[] compare = new byte[content.length];
        final InputStream stream = new BoxReadFeature(session, fileid).read(file, new TransferStatus().withLength(content.length), new DisabledConnectionCallback());
        IOUtils.readFully(stream, compare);
        stream.close();
        assertArrayEquals(content, compare);
        // Check folder attributes after write
        assertEquals(folderModification, new BoxAttributesFinderFeature(session, fileid).find(folder).getModificationDate(), 0L);
        final PathAttributes fileAttr = new BoxAttributesFinderFeature(session, fileid).find(file);
        assertNotEquals(file.attributes(), fileAttr);
        assertEquals(file.attributes().getCreationDate(), fileAttr.getCreationDate());
        assertNotEquals(file.attributes().getModificationDate(), fileAttr.getModificationDate());
        assertEquals(1503654615000L, fileAttr.getCreationDate()); //milliseconds are ignored by the Box - GMT: Friday, 25. August 2017 09:50:14
        assertEquals(1503654614000L, fileAttr.getModificationDate()); //milliseconds are ignored by the Box - GMT: Friday, 25. August 2017 09:50:14
        new BoxDeleteFeature(session, fileid).delete(Collections.singletonList(folder), new DisabledLoginCallback(), new Delete.DisabledCallback());
    }