package share.folder.tree;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import common.util.NonNullObjectInputStream;
import share.folder.Folder;
import share.folder.tree.node.AbstractFolderTreeNode;
import main.settings.Settings;
public class ThreadedTreeManager
{
private FolderTree folderTree;
private ConcurrentHashMap<Folder, Thread> threadMap;
private Thread updaterThread;
private ReentrantReadWriteLock lock;
public ThreadedTreeManager()
{
folderTree = new FolderTree();
threadMap = new ConcurrentHashMap<Folder, Thread>();
updaterThread = null;
lock = new ReentrantReadWriteLock();
}
public Vector<AbstractFolderTreeNode> getTreeRoots()
{
return folderTree.getRoots();
}
public boolean readTreeFromFile()
{
FileInputStream fis;
try
{
fis = new FileInputStream(Settings.application.files.shared);
}
catch (FileNotFoundException e)
{
return false;
}
try
{
NonNullObjectInputStream ois = new NonNullObjectInputStream(fis);
folderTree = (FolderTree) ois.readObject();
}
catch (IOException e)
{
return false;
}
catch (ClassNotFoundException e)
{
return false;
}
catch (ClassCastException e)
{
return false;
}
return true;
}
private boolean writeTreeToFile()
{
try
{
FileOutputStream fos = new FileOutputStream(Settings.application.files.shared);
new ObjectOutputStream(fos).writeObject(folderTree);
}
catch (FileNotFoundException e)
{
return false;
}
catch (IOException e)
{
return false;
}
return true;
}
public synchronized void addFolder(Folder folder, boolean subfolders)
{
Thread thread = new Thread(new AdderThread(folder, subfolders),
"FolderTreeManager: add " + folder.getName());
startFolderThread(folder, thread);
}
public synchronized void removeFolder(Folder folder)
{
Thread thread = new Thread(new RemoverThread(folder), "FolderTreeManager: del "
+ folder.getName());
startFolderThread(folder, thread);
}
public synchronized void changeFolderMode(Folder folder, boolean subfolders)
{
Thread thread = new Thread(new ChangerThread(folder, subfolders),
"FolderTreeManager: change " + folder.getName());
startFolderThread(folder, thread);
}
public synchronized void updateFolders()
{
if ((updaterThread == null) || !updaterThread.isAlive())
{
updaterThread = new Thread(new UpdaterThread(), "FolderTreeManager: update");
updaterThread.start();
}
}
// TODO: avendo una join deve andare su un thread separato?
private void startFolderThread(Folder folder, Thread thread)
{
if (threadMap.containsKey(folder))
{
Thread oldThread = threadMap.get(folder);
if (oldThread.isAlive())
{
oldThread.interrupt();
try
{
oldThread.join();
}
catch (InterruptedException e)
{
// che devo fare in questo caso? e' stato interrotto il
// thread
// principale...
}
}
}
threadMap.put(folder, thread);
thread.start();
}
private abstract class AbstractThread implements Runnable
{
protected Folder folder;
protected AbstractThread(Folder folder)
{
this.folder = folder;
}
public void run()
{
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
lock.readLock().lock();
try
{
doJob();
}
catch (InterruptedException e)
{
// niente write se il thread e' interrotto
return;
}
finally
{
lock.readLock().unlock();
}
lock.writeLock().lock();
writeTreeToFile();
lock.writeLock().unlock();
// per supportare anche l'updater
if (folder != null)
{
synchronized (threadMap)
{
threadMap.remove(folder);
}
}
}
protected abstract void doJob() throws InterruptedException;
}
private class AdderThread extends AbstractThread
{
private boolean subfolders;
public AdderThread(Folder folder, boolean subfolders)
{
super(folder);
this.subfolders = subfolders;
}
protected void doJob() throws InterruptedException
{
folderTree.add(folder, subfolders);
}
}
private class RemoverThread extends AbstractThread
{
public RemoverThread(Folder folder)
{
super(folder);
}
protected void doJob() throws InterruptedException
{
folderTree.remove(folder);
}
}
private class ChangerThread extends AbstractThread
{
private boolean subfolders;
public ChangerThread(Folder folder, boolean subfolders)
{
super(folder);
this.subfolders = subfolders;
}
protected void doJob() throws InterruptedException
{
folderTree.change(folder, subfolders);
}
}
private class UpdaterThread extends AbstractThread
{
public UpdaterThread()
{
super(null);
}
protected void doJob() throws InterruptedException
{
folderTree.update();
}
}
}