package com.limegroup.gnutella.gui;
import com.limegroup.gnutella.bugs.BugManager;
import com.limegroup.gnutella.RouterService;
import com.limegroup.gnutella.gui.notify.NotifyUserProxy;
import com.limegroup.gnutella.settings.SettingsHandler;
/**
* This class provides the "shutdown" method that should be
* the only method for closing the application for production
* (non_testing) code. This method makes sure that all of
* the necessary classes are notified that the virtual machine
* is about to be exited.
*/
final class Finalizer {
/** Stores the connection status before a shutdown
* operation is initiated.
*/
private static boolean _wasConnected;
/** Stores whether a shutdown operation has been
* initiated.
*/
private static boolean _shutdownImminent;
/** Indicates whether file uploads are complete.
*/
private static boolean _uploadsComplete;
/** Indicates whether file downloads are complete.
*/
private static boolean _downloadsComplete;
/**
* An update command to execute upon shutdown, if any.
*/
private static volatile String _updateCommand;
/**
* Suppress the default constructor to ensure that this class can never
* be constructed.
*/
private Finalizer() {}
/** Indicates whether the application is waiting to
* shutdown.
* @return true if the application is waiting to
* shutdown, false otherwise
*/
static boolean isShutdownImminent() {
return _shutdownImminent;
}
/**
* Exits the virtual machine, making calls to save
* any necessary settings and to perform any
* necessary cleanups.
* @param toExecute a string to try to execute after shutting down.
*/
static void shutdown() {
GUIMediator.applyWindowSettings();
GUIMediator.setAppVisible(false);
new ShutdownWindow().setVisible(true);
// remove any user notification icons
NotifyUserProxy.instance().removeNotify();
// Do shutdown stuff in another thread.
// We don't want to lockup the event thread
// (which this was called on).
final String toExecute = _updateCommand;
Thread shutdown = new Thread("Shutdown Thread") {
public void run() {
try {
BugManager.instance().shutdown();
RouterService router = GUIMediator.instance().getRouter();
if (router != null)
RouterService.shutdown(toExecute);
// if the router does not exist, we still need
// to write out the properties.
else
SettingsHandler.save();
System.exit(0);
} catch(Throwable t) {
t.printStackTrace();
System.exit(0);
}
}
};
shutdown.start();
}
static void flagUpdate(String toExecute) {
_updateCommand = toExecute;
}
/** Exits the virtual machine, making calls to save
* any necessary settings and to perform any
* necessary cleanups, after all incoming and
* outgoing transfers are complete.
*/
static void shutdownAfterTransfers() {
if (isShutdownImminent())
return;
_shutdownImminent = true;
_wasConnected = RouterService.isConnected();
RouterService.setIsShuttingDown(true);
if (_wasConnected)
RouterService.disconnect();
if (transfersComplete())
GUIMediator.shutdown();
}
/** Cancels a pending shutdown operation.
*/
public static void cancelShutdown() {
_shutdownImminent = false;
_uploadsComplete = false;
_downloadsComplete = false;
if (_wasConnected) {
RouterService.connect();
}
RouterService.setIsShuttingDown(false);
}
/** Notifies the <tt>Finalizer</tt> that all
* downloads have been completed.
*/
static void setDownloadsComplete() {
_downloadsComplete = true;
checkForShutdown();
}
/** Notifies the <tt>Finalizer</tt> that all uploads
* have been completed.
*/
static void setUploadsComplete() {
_uploadsComplete = true;
checkForShutdown();
}
/** Indicates whether all incoming and outgoing
* transfers have completed at the time this method
* is called.
* @return true if all transfers have been
* completed, false otherwise.
*/
private static boolean transfersComplete() {
RouterService router = GUIMediator.instance().getRouter();
if (router == null)
return true;
if (RouterService.getNumDownloads() == 0)
_downloadsComplete = true;
if (RouterService.getNumUploads() == 0)
_uploadsComplete = true;
return _uploadsComplete & _downloadsComplete;
}
/** Attempts to shutdown the application. This
* method does nothing if all file transfers are
* not yet complete.
*/
private static void checkForShutdown() {
if(_shutdownImminent && _uploadsComplete && _downloadsComplete) {
GUIMediator.shutdown();
}
}
/**
* Adds the specified <tt>Finalizable</tt> instance to the list of
* classes to notify prior to shutdown.
*
* @param fin the <tt>Finalizable</tt> instance to register
*/
static void addFinalizeListener(final FinalizeListener fin) {
Thread t = new Thread("FinalizeItem") {
public void run() {
fin.doFinalize();
}
};
RouterService.addShutdownItem(t);
}
}