private UploadResult uploadInMultipleParts(final String accountId,
            final String vaultName, final String archiveDescription,
            final File file, ProgressListener progressListener) {
        final long partSize = calculatePartSize(file.length());
        String partSizeString = Long.toString(partSize);

        publishProgress(progressListener, ProgressEventType.TRANSFER_PREPARING_EVENT);
        String uploadId = null;
        try {
            InitiateMultipartUploadResult initiateResult = glacier.initiateMultipartUpload(new InitiateMultipartUploadRequest()
                .withAccountId(accountId)
                .withArchiveDescription(archiveDescription)
                .withVaultName(vaultName)
                .withPartSize(partSizeString));
            uploadId = initiateResult.getUploadId();
        } catch (Throwable t) {
            publishProgress(progressListener, ProgressEventType.TRANSFER_FAILED_EVENT);
            throw failure(t);
        }
        publishProgress(progressListener, ProgressEventType.TRANSFER_STARTED_EVENT);
        final String fileNotFoundMsg = "Unable to find file '"
                + file.getAbsolutePath() + "'";
        try {
            List<byte[]> binaryChecksums = new LinkedList<byte[]>();

            long currentPosition = 0;
            while (currentPosition < file.length()) {
                long length = partSize;
                if (currentPosition + partSize > file.length()) {
                    length = file.length() - currentPosition;
                }

                Exception failedException = null;
                boolean completed = false;
                int tries = 0;
                    while (!completed && tries < 5){
                        tries++;
                        InputSubstream inputSubStream = null;
                        try {
                            inputSubStream = new InputSubstream(
                                    newResettableInputStream(file, fileNotFoundMsg)
                                        .disableClose(), // requires explicit release
                                    currentPosition, length, true);
                            String checksum = TreeHashGenerator.calculateTreeHash(inputSubStream);
                            byte[] binaryChecksum = BinaryUtils.fromHex(checksum);
                            inputSubStream.reset();
                            UploadMultipartPartRequest req = new UploadMultipartPartRequest()
                                .withAccountId(accountId)
                                .withChecksum(checksum)
                                .withBody(inputSubStream)
                                .withRange("bytes " + currentPosition + "-" + (currentPosition + length - 1) + "/*")
                                .withUploadId(uploadId)
                                .withVaultName(vaultName)
                                .withGeneralProgressListener(progressListener)
                                ;
                            
                            glacier.uploadMultipartPart(req);
                            completed = true;
                            binaryChecksums.add(binaryChecksum);
                        } catch (Exception e){
                            failedException = e;
                        } finally {
                            // We opened the file underneath; so need to release it
                            release(inputSubStream, log);
                        }
                    } // end inner while
                if (!completed && failedException!=null)
                    throw failedException;
                currentPosition += partSize;
            } // end outer while

            String checksum = TreeHashGenerator.calculateTreeHash(binaryChecksums);

            String archiveSize = Long.toString(file.length());
            CompleteMultipartUploadResult completeMultipartUploadResult =
                glacier.completeMultipartUpload(new CompleteMultipartUploadRequest()
                    .withAccountId(accountId)
                    .withArchiveSize(archiveSize)
                    .withVaultName(vaultName)
                    .withChecksum(checksum)
                    .withUploadId(uploadId));

            String artifactId = completeMultipartUploadResult.getArchiveId();
            publishProgress(progressListener, ProgressEventType.TRANSFER_COMPLETED_EVENT);
            return new UploadResult(artifactId);
        } catch (Throwable t) {
            publishProgress(progressListener, ProgressEventType.TRANSFER_FAILED_EVENT);
            glacier.abortMultipartUpload(new AbortMultipartUploadRequest(accountId, vaultName, uploadId));
            throw failure(t, "Unable to finish the upload");
        }
    }
Calculates the part size to use when uploading an archive of the
specified size using Glacier's multipart upload APIs. Because of the tree
hashing algorithm, part sizes must be aligned on 2^n MB boundaries (ex:
1MB, 2MB, 4MB, 8MB, etc). All parts must be the same size, except for the
last part.

@param fileSize
           The size of the file being uploaded.

@return The part size to use in the multipart upload.
aws-java-sdk-glacier/src/main/java/com/amazonaws/services/glacier/transfer/ArchiveTransferManager.java