/* * Copyright (C) 2015 Shashank Tulsyan <shashaank at neembuu.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package neembuu.uploader; import neembuu.uploader.translation.Translation; import java.awt.SystemTray; import java.awt.TrayIcon; import java.io.File; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.logging.Level; import neembuu.uploader.interfaces.UploadStatus; import neembuu.uploader.interfaces.Uploader; import neembuu.uploader.interfaces.abstractimpl.AbstractUploader; import neembuu.uploader.settings.Application; import neembuu.uploader.settings.Settings; import neembuu.uploader.utils.NULogger; import neembuu.uploader.utils.UploadStatusUtils; /** * This class manages the queuing mechanism.. * * @author vigneshwaran */ public class QueueManager { //singleton instance private static QueueManager queueManager = new QueueManager(); //max no. of simultaneous uploads. 2 by default. private int maxNoOfUploads = 2; //number of current uploads private int currentlyUploading = 0; //boolean variable to check whether queue is locked or not. private volatile boolean queueLock = false; //boolean variable to check whether stopfurther is set or not. private boolean stopfurther = true; //return the singleton instance public static QueueManager getInstance() { return queueManager; } //noninstantiable private QueueManager() { } /** * set the maximum averageProgress of simultaneous uploads * * @param maxNoOfUploads */ public void setMaxNoOfUploads(int maxNoOfUploads) { this.maxNoOfUploads = maxNoOfUploads; } /** * Get the max no of simultaneous uploads * * @return */ public int getMaxNoOfUploads() { return maxNoOfUploads; } /** * Updates the queuing mechanism.. Doesn't affect queuing by averageProgress of times called. */ public void updateQueue() { //if queue is locked or uploads are at max or stopfurther is set, then return if ((stopfurther) || (queueLock) || (currentlyUploading >= maxNoOfUploads)) { return; } setFrameTitle(); ArrayList<Uploader> uls = NUTableModel.getSortedListCopy(); //Iterate from the top of the upload list everytime for (int i = 0; i < /*NUTableModel.uploadList*/uls.size(); i++) { Uploader uploader = /*NUTableModel.uploadList*/uls.get(i); //Find queued uploads if (uploader.getStatus() == UploadStatus.QUEUED) { //Start uploading NULogger.getLogger().log(Level.INFO, "{0}: Starting next upload..", getClass().getName()); uploader.startUpload(); //Increment the averageProgress of current uploads currentlyUploading++; //If current upload less than max allowed, then continue the loop.. Else break.. if (currentlyUploading >= maxNoOfUploads) { break; } } else if ((Application.get(Settings.class).autoretryfaileduploads() && uploader.getStatus() == UploadStatus.UPLOADFAILED) || uploader.getStatus() == UploadStatus.TORETRY) { try { NULogger.getLogger().log(Level.INFO, "{0}: Restarting upload ({1})", new Object[]{getClass().getName(), i}); File file = uploader.getFile(); Constructor<? extends Uploader> uploaderConstructor = uploader.getClass().getConstructor(); AbstractUploader retryingUploader = (AbstractUploader) uploaderConstructor.newInstance(); retryingUploader.setFile(file); NUTableModel.uploadList.set(i, retryingUploader); retryingUploader.setRetry(true); retryingUploader.startUpload(); //Increment the averageProgress of current uploads currentlyUploading++; //If current upload less than max allowed, then continue the loop.. Else break.. if (currentlyUploading >= maxNoOfUploads) { break; } } catch (Exception ex) { NULogger.getLogger().log(Level.INFO, "Retry failed for {0}. Cause: {1}", new Object[]{i, ex}); } } } } /** * Start next upload if any.. Decrements the current uploads averageProgress and * updates the queuing mechanism. */ public void startNextUploadIfAny() { currentlyUploading--; //If no more uploads in queue and no more uploads currently running, reset the title if (getQueuedUploadCount() == 0 && currentlyUploading == 0){ setFrameTitle(); try{ //If the tray icon is activated, then display message if(SystemTray.getSystemTray().getTrayIcons().length > 0) { SystemTray.getSystemTray().getTrayIcons()[0].displayMessage(Translation.T().neembuuuploader(), Translation.T().allUploadsCompleted(), TrayIcon.MessageType.INFO); } }catch(UnsupportedOperationException a){ //ignore } } else { updateQueue(); } } /** * To lock or unlock the queue. If you lock, don't forget to unlock it at * the end */ public void setQueueLock(boolean queueLock) { this.queueLock = queueLock; NULogger.getLogger().log(Level.INFO, "Queue Locked: {0}", queueLock); //if unlocking, update the queuing. //If locking, this call will return. updateQueue(); } /** * Set stopfurther true or false. * * @param value */ public void setStopFurther(boolean value) { this.stopfurther = value; NULogger.getLogger().log(Level.INFO, "Stop Further: {0}", stopfurther); //if false, update the queuing. //if true, this call will return back. updateQueue(); } /** * * @return whether stopfurther is set or not */ public boolean isStopFurther() { return stopfurther; } /** * @return whether queue is locked or not */ public boolean isQueueLocked() { return queueLock; } /** * Moves the selected rows to top of the list */ public void moveRowsTop() { //If no rows selected, return if (NeembuuUploader.getInstance().getTable().getSelectedRowCount() <= 0) { return; } //Lock Queue NULogger.getLogger().log(Level.INFO, "{0}: Locking Queue..", getClass().getName()); setQueueLock(true); //Get the rows from starting to end int starting = NeembuuUploader.getInstance().getTable().getSelectedRow(); int noofrows = NeembuuUploader.getInstance().getTable().getSelectedRowCount(); int ending = starting + noofrows; //Check if the rows are already at the top if (starting < 1) { NULogger.getLogger().info("Rows are already at top.."); NULogger.getLogger().log(Level.INFO, "{0}: Unlocking Queue..", getClass().getName()); setQueueLock(false); return; } NULogger.getLogger().info("Moving rows to top"); //Copy the references to the selected rows and insert into the top (index:0) of the array list. NUTableModel.uploadList.addAll(0, NUTableModel.uploadList.subList(starting, ending)); //Now the rows previously starting from 'starting' index will now be //starting from 'ending' index due to the insertion above. //Remove those duplicate rows noofrows times for (int i = 1; i <= noofrows; i++) { NUTableModel.uploadList.remove(ending); } //Now the rows will be at the top. Set selection to them from 0 to noofrows-1 NeembuuUploader.getInstance().getTable().setRowSelectionInterval(0, noofrows - 1); //Unlock Queue NULogger.getLogger().log(Level.INFO, "{0}: Unlocking Queue..", getClass().getName()); setQueueLock(false); } /** * Moves the selected rows up one row in the list */ public void moveRowsUp() { //If no rows selected, return if (NeembuuUploader.getInstance().getTable().getSelectedRowCount() <= 0) { return; } //Lock Queue NULogger.getLogger().log(Level.INFO, "{0}: Locking Queue..", getClass().getName()); setQueueLock(true); //Get the rows from starting to end int starting = NeembuuUploader.getInstance().getTable().getSelectedRow(); int noofrows = NeembuuUploader.getInstance().getTable().getSelectedRowCount(); int ending = starting + noofrows; //Check if the rows are already at the top if (starting < 1) { NULogger.getLogger().info("Rows are already at top.."); NULogger.getLogger().log(Level.INFO, "{0}: Unlocking Queue..", getClass().getName()); setQueueLock(false); return; } NULogger.getLogger().info("Moving rows up one level"); //Get the temporary reference to the row just above the starting row (index: starting -1) Uploader temp = NUTableModel.uploadList.get(starting - 1); //Now insert the duplicate just after the ending row. Now there are two copies of that row. NUTableModel.uploadList.add(ending, temp); //Now delete the above one.. NUTableModel.uploadList.remove(starting - 1); //Shift the row selection just 1 level above //starting index will be starting -1 //ending index is not ending -1. As we have just removed one row, it'll be ending-2 NeembuuUploader.getInstance().getTable().setRowSelectionInterval(starting - 1, ending - 2); //Unlock Queue NULogger.getLogger().log(Level.INFO, "{0}: Unlocking Queue..", getClass().getName()); setQueueLock(false); } /** * Moves the selected rows down one row in the list */ public void moveRowsDown() { //If no rows selected, return if (NeembuuUploader.getInstance().getTable().getSelectedRowCount() <= 0) { return; } //Lock Queue NULogger.getLogger().log(Level.INFO, "{0}: Locking Queue..", getClass().getName()); setQueueLock(true); //Get the rows from starting to end int starting = NeembuuUploader.getInstance().getTable().getSelectedRow(); int noofrows = NeembuuUploader.getInstance().getTable().getSelectedRowCount(); int ending = starting + noofrows; //Check if the rows are already at the bottom if (ending == NUTableModel.uploadList.size()) { NULogger.getLogger().info("Rows are already at the bottom.."); NULogger.getLogger().log(Level.INFO, "{0}: Unlocking Queue..", getClass().getName()); setQueueLock(false); return; } NULogger.getLogger().info("Moving rows down one level"); //Get the temporary reference to the row just below the starting row (index: ending) Uploader temp = NUTableModel.uploadList.get(ending); //Now insert the duplicate just before the starting row. Now there are two copies of that row. NUTableModel.uploadList.add(starting, temp); //Now delete the below one.. As we have inserted the row above, the index will now be ending + 1 NUTableModel.uploadList.remove(ending + 1); //Shift the row selection one level below //as we have inserted a row above, the rowselection (starting, ending-1) should be (starting+1,ending) NeembuuUploader.getInstance().getTable().setRowSelectionInterval(starting + 1, ending); //Unlock Queue NULogger.getLogger().log(Level.INFO, "{0}: Unlocking Queue..", getClass().getName()); setQueueLock(false); } /** * Moves selected rows to the bottom of the list */ public void moveRowsBottom() { //If no rows selected, return if (NeembuuUploader.getInstance().getTable().getSelectedRowCount() <= 0) { return; } //Lock Queue NULogger.getLogger().log(Level.INFO, "{0}: Locking Queue..", getClass().getName()); setQueueLock(true); //Get the rows from starting to end int starting = NeembuuUploader.getInstance().getTable().getSelectedRow(); int noofrows = NeembuuUploader.getInstance().getTable().getSelectedRowCount(); int ending = starting + noofrows; //Check if the rows are already at the bottom if (ending == NUTableModel.uploadList.size()) { NULogger.getLogger().info("Rows are already at the bottom.."); NULogger.getLogger().log(Level.INFO, "{0}: Unlocking Queue..", getClass().getName()); setQueueLock(false); return; } NULogger.getLogger().info("Moving rows to bottom"); //Copy the references to the selected rows and insert them at the end of the list. NUTableModel.uploadList.addAll(NUTableModel.uploadList.subList(starting, ending)); //Unlike movetotop, the indices of the previous rows will not change. //Because addition at the end will not affect the indices of the above rows. //Remove the dupes at noofrows times. for (int i = 1; i <= noofrows; i++) { NUTableModel.uploadList.remove(starting); } //Set the noofrows selected at the end.. //Starting index will be totalrowcount - noofselected rows //ending index will be totalrowcount - 1 NeembuuUploader.getInstance().getTable().setRowSelectionInterval(NeembuuUploader.getInstance().getTable().getRowCount() - noofrows, NeembuuUploader.getInstance().getTable().getRowCount() - 1); //Unlock Queue NULogger.getLogger().log(Level.INFO, "{0}: Unlocking Queue..", getClass().getName()); setQueueLock(false); } /** * Returns the count of queued upload. * It checks for two types of situation: * - upload status is QUEUED; * - upload status is UPLOADFAILED if the setting of auto retry uploads is * actived. * @return Returns the count of queued upload. */ public int getQueuedUploadCount() { //Initialize count as 0 int count = 0; //Iterate through every row for (int i = 0; i < NUTableModel.uploadList.size(); i++) { //if a row is queued, increment the count. if (UploadStatusUtils.isRowStatusOneOf(i, UploadStatus.QUEUED) || (Application.get(Settings.class).autoretryfaileduploads() && UploadStatusUtils.isRowStatusOneOf(i, UploadStatus.UPLOADFAILED)) ) { count++; } } //and return it. return count; } /** * * @return The averageProgress of finished or failed uploads. */ public int getFinishedOrFailedUploadCount(){ //Initialize count as 0 int count = 0; //Iterate through every row for (int i = 0; i < NUTableModel.uploadList.size(); i++) { //if a row is queued, increment the count. if ( UploadStatusUtils.isRowStatusOneOf(i, UploadStatus.RETRYFAILED, UploadStatus.UPLOADFAILED, UploadStatus.UPLOADFINISHED, UploadStatus.UPLOADINVALID)) { count++; } } //and return it. return count; } /** * Set the Neembuu Uploader frame title. */ private void setFrameTitle(){ if(Application.get(Settings.class).showoverallprogress()){ if(getQueuedUploadCount() == 0 && currentlyUploading == 0){ NeembuuUploader.getInstance().resetTitle(); } else{ int averageProgress = getUploadProgressPercentage(); NeembuuUploader.getInstance().setTitle( averageProgress + "% " + Translation.T().neembuuuploader()); } } } /** * Get upload progress percentage (could be more intelligent, checking the file size). * @return Returns average upload progress. */ private int getUploadProgressPercentage(){ int sum = 0; int progress = 0; //Iterate through every row for (int i = 0; i < NUTableModel.uploadList.size(); i++) { progress = (Integer) NeembuuUploader.getInstance().getTable().getValueAt(i, NUTableModel.PROGRESS); if (UploadStatusUtils.isRowStatusOneOf(i, UploadStatus.RETRYFAILED, UploadStatus.UPLOADFAILED, UploadStatus.UPLOADFINISHED, UploadStatus.UPLOADINVALID)) { progress = 100; } sum += progress; } return sum/NUTableModel.uploadList.size(); } }