Interface TransferListener
- All Known Implementing Classes:
LoggingTransferListener,TransferListenerInvoker
TransferListener interface may be implemented by your application in order to receive event-driven updates on the
progress of a transfer initiated by S3TransferManager. When you construct an UploadFileRequest or DownloadFileRequest request to submit to S3TransferManager, you may provide a variable number of TransferListeners to be associated with that request. Then, throughout the lifecycle of the request, S3TransferManager
will invoke the provided TransferListeners when important events occur, like additional bytes being transferred,
allowing you to monitor the ongoing progress of the transfer.
Each TransferListener callback is invoked with an immutable TransferListener.Context object. Depending on the current lifecycle
of the request, different TransferListener.Context objects have different attributes available (indicated by the provided context
interface). Most notably, every callback is given access to the current TransferProgressSnapshot, which contains
helpful progress-related methods like TransferProgressSnapshot.transferredBytes() and TransferProgressSnapshot.ratioTransferred().
A successful transfer callback lifecycle is sequenced as follows:
transferInitiated(Context.TransferInitiated)- A new transfer has been initiated. This method is called exactly once per transfer.TransferListener.Context.TransferInitiated.request()TransferListener.Context.TransferInitiated.progressSnapshot()bytesTransferred(Context.BytesTransferred)- Additional bytes have been submitted or received. This method may be called many times per transfer, depending on the transfer size and I/O buffer sizes.transferComplete(Context.TransferComplete)- The transfer has completed successfully. This method is called exactly once for a successful transfer.TransferListener.Context.TransferComplete.completedTransfer()
- Available context attributes:
- Additional available context attributes:
transferInitiated(Context.TransferInitiated) and
transferFailed(Context.TransferFailed) will be called exactly once. There are no guarantees on whether any other
callbacks are invoked.
There are a few important rules and best practices that govern the usage of TransferListeners:
TransferListenerimplementations should not block, sleep, or otherwise delay the calling thread. If you need to perform blocking operations, you should schedule them in a separate thread or executor that you control.- Be mindful that
bytesTransferred(Context.BytesTransferred)may be called extremely often (subject to I/O buffer sizes). Be careful in implementing expensive operations as a side effect. Consider rate-limiting your side effect operations, if needed. - In the case of multipart uploads, there may be some delay between the bytes being fully transferred and the transfer
successfully completing. Internally,
S3TransferManageruses the Amazon S3 multipart upload API and must finalize uploads with aCompleteMultipartUploadRequest. - For single part in-memory uploads, 100% of the bytes are read immediately into memory and progress is only reported once, after all bytes are sent and the HTTP response is received.
- For single part file uploads, progress is reported when bytes are read from the file rather than when bytes are sent so there will be some delay between when progress reaching 100% and the transfer successfully completing.
TransferListeners may be invoked by different threads. If yourTransferListeneris stateful, ensure that it is also thread-safe.TransferListeners are not intended to be used for control flow, and therefore your implementation should not throw. Any thrown exceptions will be suppressed and logged as an error.
A classical use case of TransferListener is to create a progress bar to monitor an ongoing transfer's progress.
Refer to the implementation of LoggingTransferListener for a basic example, or test it in your application by providing
the listener as part of your TransferRequest. E.g.,
Upload upload = tm.upload(UploadRequest.builder()
.putObjectRequest(b -> b.bucket("bucket").key("key"))
.source(Paths.get(...))
.addTransferListener(LoggingTransferListener.create())
.build());
And then a successful transfer may output something similar to:
Transfer initiated... | | 0.0% |== | 12.5% |===== | 25.0% |======= | 37.5% |========== | 50.0% |============ | 62.5% |=============== | 75.0% |================= | 87.5% |====================| 100.0% Transfer complete!
-
Nested Class Summary
Nested ClassesModifier and TypeInterfaceDescriptionstatic final classA wrapper class that groups together the different context interfaces that are exposed toTransferListeners. -
Method Summary
Modifier and TypeMethodDescriptiondefault voidAdditional bytes have been submitted or received.default voidThe transfer has completed successfully.default voidThe transfer failed.default voidA new transfer has been initiated.
-
Method Details
-
transferInitiated
A new transfer has been initiated. This method is called exactly once per transfer.Available context attributes:
-
bytesTransferred
Additional bytes have been submitted or received. This method may be called many times per transfer, depending on the transfer size and I/O buffer sizes.Available context attributes:
-
transferComplete
The transfer has completed successfully. This method is called exactly once for a successful transfer.Available context attributes:
-
transferFailed
The transfer failed. This method is called exactly once for a failed transfer.Available context attributes:
-