package de.thedevstack.conversationsplus.services.filetransfer; import java.util.HashMap; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import de.thedevstack.android.logcat.Logging; import de.thedevstack.conversationsplus.Config; import de.thedevstack.conversationsplus.entities.Message; import de.thedevstack.conversationsplus.services.FileTransferService; import de.thedevstack.conversationsplus.services.filetransfer.http.upload.HttpFileTransferEntity; import de.thedevstack.conversationsplus.utils.MessageUtil; /** * */ public class FileTransferManager implements FileTransferStatusListener { private SortedSet transferServices; private static final FileTransferManager INSTANCE = new FileTransferManager(); private final HashMap activeTransfers = new HashMap<>(); private FileTransferManager() { this.transferServices = new TreeSet<>(); } public static FileTransferManager getInstance() { return INSTANCE; } public static void init(FileTransferService... fileTransferServices) { if (null != fileTransferServices && fileTransferServices.length > 0) { for (FileTransferService fts : fileTransferServices) { addFileTransferService(fts); } } } public static void init(HashMap fileTransferServices) { for (Map.Entry entry : fileTransferServices.entrySet()) { addFileTransferService(entry.getKey(), entry.getValue()); } } public static void addFileTransferService(int weight, FileTransferService fts) { fts.addFileTransferStatusListener(INSTANCE); INSTANCE.transferServices.add(new WeightedTransferService(weight, fts)); } public static void addFileTransferService(FileTransferService fts) { int weight = 1; if (!INSTANCE.transferServices.isEmpty()) { weight = INSTANCE.transferServices.last().weight + 1; } addFileTransferService(weight, fts); } /** * Transfers a file for the corresponding message. * * @param message the message containing the file to transfer * @return true if the file transfer was successful, false otherwise */ public boolean transferFile(Message message) { return this.transferFile(message, false); } /** * Transfers a file for the corresponding message. * * @param message the message containing the file to transfer * @param delay whether the message is delayed or not * @return true if the file transfer was successful, false otherwise */ public boolean transferFile(Message message, boolean delay) { Logging.d(Config.LOGTAG, "send file message"); boolean transferSuccessfullyStarted = false; for (WeightedTransferService wts : this.transferServices) { try { if (wts.fileTransferService.accept(message)) { transferSuccessfullyStarted = this.startFileTransfer(message, delay, wts); if (transferSuccessfullyStarted) { break; } } } catch (Exception e) { //TODO Do real exception handling!!!!! } } return transferSuccessfullyStarted; } /** * Checks whether a message can be sent using this service or not. * * @param message the message to be checked * @return true if the message can be processed, false otherwise */ public boolean accept(Message message) { return message.needsUploading(); } @Override public void onFailure(FileTransferEntity entity, FileTransferFailureReason failureReason) { WeightedTransferService wts = this.activeTransfers.get(entity.getMessage().getUuid()); if (null == wts) { return; } boolean delayed = (entity instanceof HttpFileTransferEntity) && ((HttpFileTransferEntity) entity).isDelayed(); if (failureReason.isRecoverable()) { wts.fileTransferService.transferFile(entity.getMessage(), delayed); } else { boolean retransferStarted = false; this.activeTransfers.remove(entity.getMessage().getUuid()); for (WeightedTransferService newWts : this.transferServices.tailSet(wts)) { if (newWts == wts) { // Same Reference continue; } if (newWts.fileTransferService.accept(entity.getMessage())) { retransferStarted = startFileTransfer(entity.getMessage(), delayed, newWts); if (retransferStarted) { break; } } } if (!retransferStarted) { MessageUtil.markMessage(entity.getMessage(), Message.STATUS_SEND_FAILED); } } } @Override public void onCancel(FileTransferEntity entity) { this.activeTransfers.remove(entity.getMessage().getUuid()); MessageUtil.markMessage(entity.getMessage(), Message.STATUS_SEND_FAILED); // TODO New Status CANCELED! } @Override public void onSuccess(FileTransferEntity entity) { this.activeTransfers.remove(entity.getMessage().getUuid()); } private boolean startFileTransfer(Message message, boolean delayed, WeightedTransferService wts) { boolean transferSuccessfullyStarted = wts.fileTransferService.transferFile(message, delayed); if (transferSuccessfullyStarted) { this.activeTransfers.put(message.getUuid(), wts); } return transferSuccessfullyStarted; } static class WeightedTransferService implements Comparable { int weight; FileTransferService fileTransferService; WeightedTransferService(int weight, FileTransferService service) { this.weight = weight; this.fileTransferService = service; } /** * Compares this object to the specified object to determine their relative * order. * * @param another the object to compare to this instance. * @return a negative integer if this instance is less than {@code another}; * a positive integer if this instance is greater than * {@code another}; 0 if this instance has the same order as * {@code another}. * @throws ClassCastException if {@code another} cannot be converted into something * comparable to {@code this} instance. */ @Override public int compareTo(WeightedTransferService another) { return this.weight - another.weight; } } }