/*
* HelloNzb -- The Binary Usenet Tool
* Copyright (C) 2010-2013 Matthias F. Brandstetter
* https://sourceforge.net/projects/hellonzb/
*
* 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 me.mabra.hellonzb.nntpclient;
import me.mabra.hellonzb.HelloNzb;
import me.mabra.hellonzb.parser.DownloadFile;
import me.mabra.hellonzb.util.MyLogger;
import me.mabra.hellonzb.nntpclient.nioengine.RspHandler;
import me.mabra.hellonzb.nntpclient.nioengine.NettyNioClient;
import me.mabra.hellonzb.parser.DownloadFileSegment;
import java.awt.*;
import java.util.ArrayList;
/**
* Similar to the main NntpFileDownloader class.
* But used for connections to the backup server (if set).
*
* @author Matthias F. Brandstetter
*/
public class BackupFileDownloader implements Runnable
{
final private HelloNzb mainApp;
final private NettyNioClient nioClient;
final private MyLogger logger;
private DlSegmentQueue segQueue;
private ArrayList<RspHandler> activeRspHandlers;
private ArrayList<RspHandler> finishedRspHandlers;
private boolean pause;
private boolean shutdown;
/**
* Class constructor.
*/
public BackupFileDownloader(HelloNzb main, NettyNioClient client)
{
mainApp = main;
nioClient = client;
logger = mainApp.getLogger();
pause = false;
shutdown = false;
segQueue = new DlSegmentQueue();
activeRspHandlers = new ArrayList<>();
finishedRspHandlers = new ArrayList<>();
}
/**
* This method starts the thread and makes this backup file downloader available.
*/
public void run()
{
int runningThreads = 0;
final int maxThreads = Integer.parseInt(mainApp.getPrefValue("ServerSettingsBackupThreadCount"));
while(!shutdown)
{
while(segQueue.hasSegments() && runningThreads < maxThreads && !pause && nioClient.hasFreeSlot())
{
// get next segment in queue
DownloadFileSegment nextSeg = segQueue.nextSegment();
if(nextSeg == null)
break;
String filename = nextSeg.getDlFile().getFilename();
logger.msg("Downloading from backup server next segment of file: " + filename, MyLogger.SEV_DEBUG);
// create new response handler
RspHandler newHandler = new RspHandler(nextSeg, true);
synchronized(activeRspHandlers)
{
activeRspHandlers.add(newHandler);
}
// start data download and increase thread counter
nioClient.fetchArticleData(nextSeg.getGroups().firstElement(), nextSeg.getArticleId(), newHandler);
runningThreads++;
}
// check if the next element of the result set is already finished
int actRspHdlsSize;
synchronized(activeRspHandlers)
{
actRspHdlsSize = activeRspHandlers.size();
}
ArrayList<RspHandler> toRemoveVector = new ArrayList<>();
for(int i = 0; i < actRspHdlsSize; i++)
{
RspHandler handler;
synchronized(activeRspHandlers)
{
handler = activeRspHandlers.get(i);
}
// all data downloaded?
if(handler.isFinished())
{
synchronized(finishedRspHandlers)
{
finishedRspHandlers.add(handler);
}
toRemoveVector.add(handler);
runningThreads--;
}
}
// remove all finished handlers from active queue
synchronized(activeRspHandlers)
{
activeRspHandlers.removeAll(toRemoveVector);
}
toRemoveVector.clear();
try
{
Thread.sleep(10);
}
catch(InterruptedException ex)
{
shutdown = true;
}
} // end of main loop
logger.msg("Backup FileDownloader loop ended.", MyLogger.SEV_DEBUG);
}
/**
* Check whether the given filename is currently being downloaded.
*/
public boolean isActivelyDownloaded(String filename)
{
synchronized(activeRspHandlers)
{
for(RspHandler handler : activeRspHandlers)
{
String handlerFile = handler.dlFileSeg().getDlFile().getFilename();
if(filename.equals(handlerFile))
return true;
}
}
synchronized(finishedRspHandlers)
{
for(RspHandler handler : finishedRspHandlers)
{
String handlerFile = handler.dlFileSeg().getDlFile().getFilename();
if(filename.equals(handlerFile))
return true;
}
}
return false;
}
/**
* Add a new segment to download to this downloader's queue.
*/
public void addSegment(DownloadFileSegment seg)
{
segQueue.addSegment(seg);
}
/**
* Remove all those segements from the queue, that belong to the given file.
*/
public void removeFileSegmentsFromQueue(String filename)
{
segQueue.removeSegments(filename);
}
/**
* Get all finished response handlers.
*/
public ArrayList<RspHandler> getFinishedHandlers()
{
synchronized(finishedRspHandlers)
{
ArrayList<RspHandler> result = new ArrayList<>(finishedRspHandlers);
finishedRspHandlers.clear();
return result;
}
}
/**
* Whether or not one or more response handler(s) is/are ready.
*/
public boolean hasFinishedHandlers()
{
synchronized(finishedRspHandlers)
{
return finishedRspHandlers.size() > 0;
}
}
/**
* Called from main app when this thread should pause working.
*/
public void setPaused(boolean p)
{
pause = p;
}
/**
* Shutdown this downloader, which stops the parent thread.
*/
public void shutdown()
{
shutdown = true;
}
/******************************************************************************************/
public class DlSegmentQueue
{
private ArrayList<DownloadFileSegment> queue;
public DlSegmentQueue()
{
queue = new ArrayList<>();
}
synchronized void addSegment(DownloadFileSegment segment)
{
assert segment != null;
queue.add(segment);
}
synchronized DownloadFileSegment nextSegment()
{
if(hasSegments())
return queue.remove(0);
else
return null;
}
synchronized void removeSegments(String filename)
{
ArrayList<DownloadFileSegment> toRemove = new ArrayList<>();
for(DownloadFileSegment seg : queue)
{
DownloadFile dlFile = seg.getDlFile();
if(dlFile.getFilename().equals(filename))
toRemove.add(seg);
}
queue.removeAll(toRemove);
}
synchronized boolean hasSegments()
{
return queue.size() > 0;
}
}
}