@Override
    public File upload(final Path file, final Local local, final BandwidthThrottle throttle, final StreamListener listener,
                       final TransferStatus status, final ConnectionCallback callback) throws BackgroundException {
        final ThreadPool pool = ThreadPoolFactory.get("multipart", concurrency);
        try {
            if(status.getChecksum().algorithm != HashAlgorithm.sha1) {
                status.setChecksum(new SHA1ChecksumCompute().compute(local.getInputStream(), status));
            }
            final List<Future<Part>> parts = new ArrayList<>();
            long offset = 0;
            long remaining = status.getLength();
            final BoxUploadHelper helper = new BoxUploadHelper(session, fileid);
            final UploadSession uploadSession = helper.createUploadSession(status, file);
            for(int partNumber = 1; remaining > 0; partNumber++) {
                final long length = Math.min(uploadSession.getPartSize(), remaining);
                parts.add(this.submit(pool, file, local, throttle, listener, status,
                        uploadSession.getId(), partNumber, offset, length, callback));
                remaining -= length;
                offset += length;
            }
            // Checksums for uploaded segments
            final List<Part> chunks = Interruptibles.awaitAll(parts);
            final Files files = helper.commitUploadSession(file, uploadSession.getId(), status,
                    chunks.stream().map(f -> new UploadPart().sha1(f.part.getSha1())
                            .size(f.status.getLength()).offset(f.status.getOffset()).partId(f.part.getId())).collect(Collectors.toList()));
            final Optional<File> optional = files.getEntries().stream().findFirst();
            if(optional.isPresent()) {
                final File commited = optional.get();
                // Mark parent status as complete
                status.withResponse(new BoxAttributesFinderFeature(session, fileid).toAttributes(commited)).setComplete();
                return commited;
            }
            throw new NotfoundException(file.getAbsolute());
        }
        finally {
            // Cancel future tasks
            pool.shutdown(false);
        }
    }
@Test
    public void testUploadLargeFileInChunks() throws Exception {
        final BoxFileidProvider fileid = new BoxFileidProvider(session);
        final BoxLargeUploadService s = new BoxLargeUploadService(session, fileid, new BoxChunkedWriteFeature(session, fileid));
        final Path container = new BoxDirectoryFeature(session, fileid).mkdir(new Path(
                new AlphanumericRandomStringService().random(), EnumSet.of(AbstractPath.Type.directory)), new TransferStatus());
        final String name = new AlphanumericRandomStringService().random();
        final Path file = new Path(container, name, EnumSet.of(Path.Type.file));
        final Local local = new Local(System.getProperty("java.io.tmpdir"), name);
        final byte[] content = RandomUtils.nextBytes(20 * 1024 * 1024);
        IOUtils.write(content, local.getOutputStream(false));
        final TransferStatus status = new TransferStatus();
        status.setChecksum(new SHA1ChecksumCompute().compute(local.getInputStream(), new TransferStatus()));
        status.setLength(content.length);
        final BytecountStreamListener count = new BytecountStreamListener();
        final File response = s.upload(file, local, new BandwidthThrottle(BandwidthThrottle.UNLIMITED), count, status, new DisabledConnectionCallback());
        assertTrue(status.isComplete());
        assertNotNull(response.getSha1());
        assertEquals(content.length, count.getSent());
        assertTrue(status.isComplete());
        assertEquals(content.length, status.getResponse().getSize());
        assertTrue(new BoxFindFeature(session, fileid).find(file));
        assertEquals(content.length, new BoxAttributesFinderFeature(session, fileid).find(file).getSize());
        final byte[] compare = new byte[content.length];
        IOUtils.readFully(new BoxReadFeature(session, fileid).read(file, new TransferStatus().withLength(content.length), new DisabledConnectionCallback()), compare);
        assertArrayEquals(content, compare);
        new BoxDeleteFeature(session, fileid).delete(Collections.singletonList(container), new DisabledLoginCallback(), new Delete.DisabledCallback());
        local.delete();
    }