/*
* Copyright 2010-2015 Institut Pasteur.
*
* This file is part of Icy.
*
* Icy 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.
*
* Icy 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 Icy. If not, see <http://www.gnu.org/licenses/>.
*/
package icy.workspace;
import icy.file.FileUtil;
import icy.gui.dialog.ConfirmDialog;
import icy.gui.frame.progress.FailedAnnounceFrame;
import icy.gui.frame.progress.ProgressFrame;
import icy.gui.frame.progress.SuccessfullAnnounceFrame;
import icy.main.Icy;
import icy.network.NetworkUtil;
import icy.plugin.PluginDescriptor;
import icy.plugin.PluginInstaller;
import icy.plugin.PluginLoader;
import icy.preferences.WorkspaceLocalPreferences;
import icy.system.thread.ThreadUtil;
import icy.util.StringUtil;
import icy.workspace.Workspace.TaskDefinition.BandDefinition.ItemDefinition;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.List;
import javax.swing.event.EventListenerList;
/**
* @author Stephane
*/
public class WorkspaceInstaller implements Runnable
{
public static interface WorkspaceInstallerListener extends EventListener
{
public void workspaceInstalled(WorkspaceInstallerEvent e);
public void workspaceRemoved(WorkspaceInstallerEvent e);
}
public static class WorkspaceInstallerEvent
{
private final Workspace workspace;
private final boolean successed;
public WorkspaceInstallerEvent(Workspace workspace, boolean successed)
{
super();
this.workspace = workspace;
this.successed = successed;
}
/**
* @return the workspace
*/
public Workspace getWorkspace()
{
return workspace;
}
/**
* @return the success
*/
public boolean getSuccessed()
{
return successed;
}
}
private static class WorkspaceInstallInfo
{
final Workspace workspace;
final boolean showConfirm;
public WorkspaceInstallInfo(Workspace workspace, boolean showConfirm)
{
super();
this.workspace = workspace;
this.showConfirm = showConfirm;
}
}
/**
* static class
*/
private static final WorkspaceInstaller instance = new WorkspaceInstaller();
/**
* workspace to install FIFO
*/
private final List<WorkspaceInstallInfo> installFIFO;
/**
* workspace to delete FIFO
*/
private final List<WorkspaceInstallInfo> removeFIFO;
/**
* listeners
*/
private final EventListenerList listeners;
/**
* internals
*/
private Workspace installingWorkspace;
private Workspace desinstallingWorkspace;
private boolean installing;
private boolean deinstalling;
/**
* static class
*/
private WorkspaceInstaller()
{
super();
installFIFO = new ArrayList<WorkspaceInstallInfo>();
removeFIFO = new ArrayList<WorkspaceInstallInfo>();
listeners = new EventListenerList();
installingWorkspace = null;
desinstallingWorkspace = null;
installing = false;
deinstalling = false;
// launch installer thread
new Thread(this, "Workspace installer").start();
}
/**
* install a workspace (asynchronous)
*/
public static void install(Workspace workspace, boolean showConfirm)
{
if (workspace != null)
{
if (!NetworkUtil.hasInternetAccess())
{
final String text = "Cannot install '" + workspace.getName()
+ "' workspace : you are not connected to Internet.";
if (Icy.getMainInterface().isHeadLess())
System.err.println(text);
else
new FailedAnnounceFrame(text, 10);
return;
}
synchronized (instance.installFIFO)
{
instance.installFIFO.add(new WorkspaceInstallInfo(workspace, showConfirm));
}
}
}
/**
* return true if WorkspaceInstaller is processing
*/
public static boolean isProcessing()
{
return isInstalling() || isDesinstalling();
}
/**
* return true if WorkspaceInstaller is installing workspace(s)
*/
public static boolean isInstalling()
{
return (!instance.installFIFO.isEmpty()) || instance.installing;
}
/**
* return true if 'workspace' is in the install FIFO
*/
public static boolean isWaitingForInstall(Workspace workspace)
{
final String workspaceName = workspace.getName();
synchronized (instance.installFIFO)
{
for (WorkspaceInstallInfo info : instance.installFIFO)
if (workspaceName.equals(info.workspace.getName()))
return true;
}
return false;
}
/**
* return the current installed workspace (null if none)
*/
public static Workspace getCurrentInstallingWorkspace()
{
return instance.installingWorkspace;
}
/**
* return true if specified workspace is currently being installed or will be installed
*/
public static boolean isInstallingWorkspace(Workspace workspace)
{
if (instance.installingWorkspace != null)
{
if (instance.installingWorkspace.getName().equals(workspace.getName()))
return true;
}
return isWaitingForInstall(workspace);
}
/**
* uninstall a workspace (asynchronous)
*/
public static void desinstall(Workspace workspace, boolean showConfirm)
{
if (workspace != null)
{
synchronized (instance.removeFIFO)
{
instance.removeFIFO.add(new WorkspaceInstallInfo(workspace, showConfirm));
}
}
}
/**
* return true if WorkspaceInstaller is desinstalling workspace(s)
*/
public static boolean isDesinstalling()
{
return (!instance.removeFIFO.isEmpty()) || instance.deinstalling;
}
/**
* return true if 'workspace' is in the remove FIFO
*/
public static boolean isWaitingForDesinstall(Workspace workspace)
{
final String workspaceName = workspace.getName();
synchronized (instance.removeFIFO)
{
for (WorkspaceInstallInfo info : instance.removeFIFO)
if (workspaceName.equals(info.workspace.getName()))
return true;
}
return false;
}
/**
* return true if specified workspace is currently being desinstalled or will be desinstalled
*/
public static boolean isDesinstallingWorkspace(Workspace workspace)
{
if (instance.desinstallingWorkspace != null)
{
if (instance.desinstallingWorkspace.getName().equals(workspace.getName()))
return true;
}
return isWaitingForDesinstall(workspace);
}
@Override
public void run()
{
while (!Thread.interrupted())
{
boolean empty;
boolean result;
WorkspaceInstallInfo installInfo = null;
// process installations
empty = installFIFO.isEmpty();
if (!empty)
{
installing = true;
try
{
while (!empty)
{
synchronized (installFIFO)
{
installInfo = installFIFO.remove(0);
empty = installFIFO.isEmpty();
}
// don't install if the workspace is already installed
if (!WorkspaceLoader.isLoaded(installInfo.workspace))
{
result = installInternal(installInfo);
// process on workspace installation
installed(installInfo.workspace, result);
}
synchronized (installFIFO)
{
}
}
}
finally
{
installing = false;
}
}
// process deletions
empty = removeFIFO.isEmpty();
if (!empty)
{
deinstalling = true;
try
{
while (!empty)
{
synchronized (removeFIFO)
{
installInfo = removeFIFO.remove(0);
empty = removeFIFO.isEmpty();
}
result = desinstallInternal(installInfo);
// process on workspace deletion
desinstalled(installInfo.workspace, result);
}
}
finally
{
deinstalling = false;
}
}
ThreadUtil.sleep(200);
}
}
private boolean deleteWorkspace(Workspace workspace)
{
if (!FileUtil.delete(workspace.getLocalFilename(), false))
System.err.println("deleteWorkspace : Can't delete " + workspace.getLocalFilename());
// reload workspace list
WorkspaceLoader.reload();
return true;
}
/**
* Return local plugins of specified workspace
*/
private ArrayList<PluginDescriptor> getLocalPlugins(Workspace workspace)
{
final ArrayList<PluginDescriptor> result = new ArrayList<PluginDescriptor>();
for (ItemDefinition item : workspace.getAllItems())
{
if (!item.isSeparator())
{
final PluginDescriptor plugin = PluginLoader.getPlugin(item.getClassName());
// plugin found
if (plugin != null)
{
// add all its dependences
PluginInstaller.getLocalDependenciesOf(result, plugin);
// the add the plugin itselft
PluginDescriptor.addToList(result, plugin);
}
}
}
return result;
}
/**
* Return independent plugins of workspace (so they can be deleted)
*/
private ArrayList<PluginDescriptor> getIndependentPlugins(Workspace workspace)
{
// get plugins of specified workspace
final ArrayList<PluginDescriptor> result = getLocalPlugins(workspace);
final ArrayList<PluginDescriptor> others = new ArrayList<PluginDescriptor>();
// get plugins of all others workspaces
for (Workspace ws : WorkspaceLoader.getWorkspaces())
// we can use name as id here
if (!StringUtil.equals(ws.getName(), workspace.getName()))
others.addAll(getLocalPlugins(ws));
for (PluginDescriptor plugin : others)
{
for (int i = result.size() - 1; i >= 0; i--)
{
final PluginDescriptor depPlug = result.get(i);
// have a dependence, remove from list...
if (plugin.equals(depPlug) || plugin.requires(depPlug))
result.remove(i);
}
}
return result;
}
private boolean installInternal(WorkspaceInstallInfo installInfo)
{
final Workspace workspace = installInfo.workspace;
final boolean showConfirm = installInfo.showConfirm;
// installation start
installingWorkspace = workspace;
try
{
ProgressFrame taskFrame = null;
int result = 0;
final String workspaceName = workspace.getName();
if (showConfirm && !Icy.getMainInterface().isHeadLess())
taskFrame = new ProgressFrame("installing workspace '" + workspaceName + "'...");
try
{
// install workspace (actually install dependent plugins)
result = workspace.install(taskFrame);
if (result > 0)
{
if (taskFrame != null)
taskFrame.setMessage("saving workspace '" + workspaceName + "'...");
// save workspace locally
workspace.save();
if (taskFrame != null)
taskFrame.setMessage("reloading workspaces list...");
// reload workspace list
WorkspaceLoader.reload();
}
}
finally
{
if (taskFrame != null)
taskFrame.close();
}
final String resMess = "Workspace '" + workspaceName + "' installation";
if (showConfirm && !Icy.getMainInterface().isHeadLess())
{
switch (result)
{
default:
new FailedAnnounceFrame(resMess + " failed !");
break;
case 1:
new SuccessfullAnnounceFrame(resMess + " succeed !", 10);
break;
case 2:
new SuccessfullAnnounceFrame(resMess + " succeed but some plugins cannot be installed.", 10);
break;
}
}
else
{
switch (result)
{
default:
System.err.println(resMess + " failed !");
break;
case 1:
System.out.println(resMess + " succeed !");
break;
case 2:
System.out.println(resMess + " partially succeed (some plugins cannot be installed) !");
break;
}
}
return result > 0;
}
finally
{
// installation end
installingWorkspace = null;
}
}
private boolean desinstallInternal(WorkspaceInstallInfo installInfo)
{
final Workspace workspace = installInfo.workspace;
final boolean showConfirm = installInfo.showConfirm;
// desinstall start
desinstallingWorkspace = workspace;
try
{
final ArrayList<PluginDescriptor> independentPlugins = new ArrayList<PluginDescriptor>();
final String workspaceDesc = workspace.getName();
final boolean deletePlugin;
final boolean result;
ProgressFrame taskFrame = null;
if (showConfirm)
{
String message = "<html>Do you want to also remove the associated plugins ?</html>";
deletePlugin = ConfirmDialog.confirm(message);
}
else
deletePlugin = true;
if (deletePlugin)
{
if (showConfirm && !Icy.getMainInterface().isHeadLess())
taskFrame = new ProgressFrame("checking plugins dependences...");
try
{
independentPlugins.addAll(getIndependentPlugins(workspace));
}
finally
{
if (taskFrame != null)
taskFrame.close();
}
}
if (showConfirm)
taskFrame = new ProgressFrame("removing workspace '" + workspaceDesc + "'...");
try
{
// remove workspace independent plugins
for (PluginDescriptor plugin : independentPlugins)
if (plugin.isInstalled())
PluginInstaller.desinstall(plugin, false, false);
// wait for plugins desintallation
PluginInstaller.waitDesinstall();
// delete workspace
result = deleteWorkspace(workspace);
}
finally
{
if (taskFrame != null)
taskFrame.close();
}
final String resMess = "Workspace '" + workspaceDesc + "' remove";
if (showConfirm && !Icy.getMainInterface().isHeadLess())
{
if (result)
new SuccessfullAnnounceFrame(resMess + " succeed !", 10);
else
new FailedAnnounceFrame(resMess + " failed !");
}
else
{
if (result)
System.out.println(resMess + " succeed !");
else
System.err.println(resMess + " failed !");
}
return result;
}
finally
{
// desintall end
desinstallingWorkspace = null;
}
}
/**
* process on workspace install
*/
private void installed(Workspace workspace, boolean result)
{
if (result)
{
// enable the installed workspace by default
WorkspaceLocalPreferences.setWorkspaceEnable(workspace.getName(), true);
// show an announcement for restart
Icy.announceRestart();
}
fireInstalledEvent(new WorkspaceInstallerEvent(workspace, result));
}
/**
* process on workspace remove
*/
private void desinstalled(Workspace workspace, boolean result)
{
if (result)
// show an announcement for restart
Icy.announceRestart();
fireRemovedEvent(new WorkspaceInstallerEvent(workspace, result));
}
/**
* Add a listener
*
* @param listener
*/
public static void addListener(WorkspaceInstallerListener listener)
{
synchronized (instance.listeners)
{
instance.listeners.add(WorkspaceInstallerListener.class, listener);
}
}
/**
* Remove a listener
*
* @param listener
*/
public static void removeListener(WorkspaceInstallerListener listener)
{
synchronized (instance.listeners)
{
instance.listeners.remove(WorkspaceInstallerListener.class, listener);
}
}
/**
* fire workspace installed event
*/
private void fireInstalledEvent(WorkspaceInstallerEvent e)
{
for (WorkspaceInstallerListener listener : listeners.getListeners(WorkspaceInstallerListener.class))
listener.workspaceInstalled(e);
}
/**
* fire workspace removed event
*/
private void fireRemovedEvent(WorkspaceInstallerEvent e)
{
for (WorkspaceInstallerListener listener : listeners.getListeners(WorkspaceInstallerListener.class))
listener.workspaceRemoved(e);
}
}