From f45ad10b1baaf09fd4a40d6b63d1cd093623eedc Mon Sep 17 00:00:00 2001 From: steckbrief Date: Mon, 6 Jun 2016 09:05:50 +0200 Subject: Related to FS#131, FS#129, FS#220: - FileTransferFailureReason including types introduced. A failure can be recoverable, non-recoverable or limited recoverable - in case file transfer with the highest weight factor fails, the next file transfer method is used - improved logging - javadoc comments added --- .../services/filetransfer/FileTransferEntity.java | 194 +++++++++++++++++---- 1 file changed, 160 insertions(+), 34 deletions(-) (limited to 'src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferEntity.java') diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferEntity.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferEntity.java index a44cf49d..e1b40fa6 100644 --- a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferEntity.java +++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferEntity.java @@ -1,60 +1,95 @@ package de.thedevstack.conversationsplus.services.filetransfer; import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import de.thedevstack.conversationsplus.entities.DownloadableFile; import de.thedevstack.conversationsplus.entities.Message; import de.thedevstack.conversationsplus.entities.Transferable; import de.thedevstack.conversationsplus.persistance.FileBackend; -import de.thedevstack.conversationsplus.utils.MessageUtil; +import de.thedevstack.conversationsplus.utils.StreamUtil; /** * */ public class FileTransferEntity implements Transferable { + /** + * Listeners to inform about a status change. + */ + private final List statusListeners = new ArrayList<>(); + /** + * The associated message. + */ private final Message message; - private int tries = 0; - private boolean transferred = false; - private boolean canceled = false; - private boolean failed = false; + /** + * Number of attempts. + */ + private int attempts = 0; + /** + * The status of the file transfer. + */ + private FileTransferStatusEnum transferStatus; + /** + * Number of bytes transmitted. + */ private long transmitted = 0; + /** + * The associated file. + */ private DownloadableFile file; + /** + * The associated file as stream. + */ private InputStream fileInputStream; + /** + * Initializes the FileTransferEntity based on the associated message. + * This initialization includes loading the file and associating this transferable to the message. + * @param message the message in which the file to transfer is contained. + */ public FileTransferEntity(Message message) { this.message = message; this.message.setTransferable(this); this.file = FileBackend.getFile(message, false); } - @Override - public boolean equals(Object o) { - FileTransferEntity other = (FileTransferEntity)o; - if ((this.message == null && other.message != null) - || (this.message != null && other.message == null)) { - return false; - } else if (this.message == null && other.message == null) { - return true; - } - return this.message.getUuid().equals(other.message.getUuid()); - } - + /** + * Start something. + * Empty implementation since documentation in interface is missing. + * @return false + */ @Override public boolean start() { return false; } + /** + * Returns the global transferable status. + * + * @return {@value STATUS_FAILED} if #isFailed returns true, {@value STATUS_UPLOADING} otherwise + */ @Override public int getStatus() { - int status = (failed) ? STATUS_FAILED : STATUS_UPLOADING; + int status = (isFailed()) ? STATUS_FAILED : STATUS_UPLOADING; return status; } + /** + * Returns the expected file size of the underlying file. + * @return the expected file size or 0 if no file is associated. + */ @Override public long getFileSize() { return file == null ? 0 : file.getExpectedSize(); } + /** + * Calculates the current progress in percent. + * + * @return the current progress in percent + */ @Override public int getProgress() { if (file == null) { @@ -63,46 +98,137 @@ public class FileTransferEntity implements Transferable { return (int) ((((double) transmitted) / file.getExpectedSize()) * 100); } + /** + * Cancels the file transfer and informs the listeners about cancellation. + */ @Override public void cancel() { - this.canceled = true; + this.transferStatus = FileTransferStatusEnum.CANCELED; + + this.close(); + + for (FileTransferStatusListener listener : this.statusListeners) { + listener.onCancel(this); + } + } + + /** + * Starts an transfer attempt. + */ + public void startAttempt() { + this.attempts++; + this.transferStatus = FileTransferStatusEnum.TRANSFERRING; + } + + /** + * Fails an file transfer and informs the listeners about failure. + * + * @param failureReason the reason of failure. + */ + public void fail(FileTransferFailureReason failureReason) { + this.transferStatus = FileTransferStatusEnum.FAILED; + + this.close(); + + failureReason.setAttempt(this.attempts); + for (FileTransferStatusListener listener : this.statusListeners) { + listener.onFailure(this, failureReason); + } + } + + /** + * Updates the progress by adding parameter value to current progress value. + * + * @param progress the number of newly transferred bytes + */ + public void updateProgress(long progress) { + if (0 == this.attempts) { + this.startAttempt(); + } + this.transmitted += progress; + } + + /** + * Set the status of the file transfer to FileTransferStatusEnum#TRANSFERRED and informs the listeners about success. + */ + public void transferred() { + this.transferStatus = FileTransferStatusEnum.TRANSFERRED; + + this.close(); + + for (FileTransferStatusListener listener : this.statusListeners) { + listener.onSuccess(this); + } } - public void fail() { - this.failed = true; + /** + * Closes the file input stream (if it is not yet closed) and removes association with message. + */ + private void close() { + StreamUtil.close(this.fileInputStream); this.getMessage().setTransferable(null); - MessageUtil.markMessage(this.getMessage(), Message.STATUS_SEND_FAILED); } - public Message getMessage() { - return message; + /** + * Whether the file is transferred or not. + * @return true if the file is successfully transferred, false otherwise + */ + public boolean isTransferred() { + return FileTransferStatusEnum.TRANSFERRED == this.transferStatus; } + /** + * Whether the file transfer is canceled or not. + * @return true if the file transfer was canceled, false otherwise + */ public boolean isCanceled() { - return this.canceled; + return FileTransferStatusEnum.CANCELED == this.transferStatus; } + /** + * Whether the file transfer failed or not. + * @return true if the file transfer failed, false otherwise + */ public boolean isFailed() { - return failed; + return FileTransferStatusEnum.FAILED == this.transferStatus; } - public void updateProgress(long progress) { - this.transmitted += progress; + public void setFileInputStream(InputStream fileInputStream) { + this.fileInputStream = fileInputStream; + } + + public InputStream getFileInputStream() { + return fileInputStream; + } + + public Message getMessage() { + return message; } public DownloadableFile getFile() { return file; } - public void transferred() { - this.transferred = true; + public void addFileTransferStatusListener(FileTransferStatusListener... listeners) { + this.statusListeners.addAll(Arrays.asList(listeners)); } - public void setFileInputStream(InputStream fileInputStream) { - this.fileInputStream = fileInputStream; + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + FileTransferEntity that = (FileTransferEntity) o; + + String uuid = message != null ? message.getUuid() : null; + String thatUuid = that.message != null ? that.message.getUuid() : null; + + return uuid != null ? uuid.equals(thatUuid) : thatUuid == null; + } - public InputStream getFileInputStream() { - return fileInputStream; + @Override + public int hashCode() { + return message != null && message.getUuid() != null ? message.getUuid().hashCode() : 0; } } -- cgit v1.2.3