/*
* 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.plugin;
import icy.main.Icy;
import icy.plugin.abstract_.Plugin;
import icy.plugin.interface_.PluginImageAnalysis;
import icy.plugin.interface_.PluginNoEDTConstructor;
import icy.plugin.interface_.PluginStartAsThread;
import icy.plugin.interface_.PluginThreaded;
import icy.system.IcyExceptionHandler;
import icy.system.audit.Audit;
import icy.system.thread.ThreadUtil;
import icy.util.ClassUtil;
import java.util.concurrent.Callable;
/**
* This class launch plugins and register them to the main application.<br>
* The launch can be in a decicated thread or in the EDT.
*
* @author Fabrice de Chaumont & Stephane
*/
public class PluginLauncher
{
protected static class PluginExecutor implements Callable<Boolean>, Runnable
{
final Plugin plugin;
public PluginExecutor(Plugin plugin)
{
super();
this.plugin = plugin;
}
@Override
public Boolean call() throws Exception
{
// some plugins (as EzPlug) do not respect the PluginActionable convention (run() method
// contains all the process)
// so we can't yet use this bloc of code
// if (plugin instanceof PluginActionable)
// ((PluginActionable) plugin).run();
// // keep backward compatibility
// else if (plugin instanceof PluginImageAnalysis)
// ((PluginImageAnalysis) plugin).compute();
// keep backward compatibility
if (plugin instanceof PluginImageAnalysis)
((PluginImageAnalysis) plugin).compute();
return Boolean.TRUE;
}
@Override
public void run()
{
try
{
call();
}
catch (Throwable t)
{
IcyExceptionHandler.handleException(plugin.getDescriptor(), t, true);
}
}
}
/**
* Executes the specified plugin.<br>
* If the specified plugin implements {@link PluginThreaded} then the plugin will be executed in
* a separate thread and the method will return before completion.<br>
* In other case the plugin is executed on the EDT by using {@link ThreadUtil#invokeNow(Callable)} and so method
* return after completion.
*
* @throws InterruptedException
* if the current thread was interrupted while waiting for execution on EDT.
* @throws Exception
* if the computation threw an exception (only when plugin is executed on EDT).
*/
private static void internalExecute(final Plugin plugin) throws Exception
{
if (plugin instanceof PluginThreaded)
{
// headless mode --> command line direct execution
if (Icy.getMainInterface().isHeadLess())
((PluginThreaded) plugin).run();
else
new Thread((PluginThreaded) plugin, plugin.getName()).start();
}
else
{
final PluginExecutor executor = new PluginExecutor(plugin);
// headless mode --> command line direct execution
if (Icy.getMainInterface().isHeadLess())
executor.call();
// keep backward compatibility
else if (plugin instanceof PluginStartAsThread)
new Thread(executor, plugin.getName()).start();
// direct launch in EDT now (no thread creation)
else
ThreadUtil.invokeNow((Callable<Boolean>) executor);
}
}
/**
* Creates a new instance of the specified plugin and returns it.<br>
*
* @param plugin
* descriptor of the plugin we want to create an instance for
* @param register
* if we want to register the plugin in the active plugin list
* @see #startSafe(PluginDescriptor)
*/
public static Plugin create(final PluginDescriptor plugin, boolean register) throws Exception
{
final Class<? extends Plugin> clazz = plugin.getPluginClass();
final Plugin result;
// use the special PluginNoEDTConstructor interface or headless mode ?
if (ClassUtil.isSubClass(clazz, PluginNoEDTConstructor.class) || Icy.getMainInterface().isHeadLess())
result = clazz.newInstance();
else
{
// create the plugin instance on the EDT
result = ThreadUtil.invokeNow(new Callable<Plugin>()
{
@Override
public Plugin call() throws Exception
{
return clazz.newInstance();
}
});
}
// register plugin
if (register)
Icy.getMainInterface().registerPlugin(result);
return result;
}
/**
* Creates a new instance of the specified plugin and returns it.<br>
* The plugin is automatically registered to the list of active plugins.
*
* @param plugin
* descriptor of the plugin we want to create an instance for
* @see #startSafe(PluginDescriptor)
*/
public static Plugin create(final PluginDescriptor plugin) throws Exception
{
return create(plugin, true);
}
/**
* Starts the specified plugin (catched exception version).<br>
* Returns the plugin instance (only meaningful for {@link PluginThreaded} plugin) or <code>null</code> if an error
* occurred.
*
* @param plugin
* descriptor of the plugin we want to start
* @see #startSafe(PluginDescriptor)
*/
public static Plugin start(PluginDescriptor plugin)
{
final Plugin result;
try
{
try
{
// create plugin instance
result = create(plugin);
}
catch (IllegalAccessException e)
{
System.err.println("Cannot start plugin " + plugin.getName() + " :");
System.err.println(e.getMessage());
return null;
}
catch (InstantiationException e)
{
System.err.println("Cannot start plugin " + plugin.getName() + " :");
System.err.println(e.getMessage());
return null;
}
// audit
Audit.pluginLaunched(result);
// execute plugin
if (result instanceof PluginImageAnalysis)
internalExecute(result);
return result;
}
catch (InterruptedException e)
{
// we just ignore interruption
}
catch (Throwable t)
{
IcyExceptionHandler.handleException(plugin, t, true);
}
return null;
}
/**
* @deprecated Use {@link #start(PluginDescriptor)} instead.<br>
* You can retrieve a {@link PluginDescriptor} from the class name by using
* {@link PluginLoader#getPlugin(String)} method.
*/
@Deprecated
public static Plugin start(String pluginClassName)
{
final PluginDescriptor plugin = PluginLoader.getPlugin(pluginClassName);
if (plugin != null)
return start(plugin);
return null;
}
/**
* Same as {@link #start(PluginDescriptor)} except it throws {@link Exception} on error
* so user can handle them.
*
* @param plugin
* descriptor of the plugin we want to start
* compatibility)
* @throws InterruptedException
* if the current thread was interrupted while waiting for execution on EDT.
* @throws Exception
* if the computation threw an exception (only when plugin is executed on EDT).
*/
public static Plugin startSafe(PluginDescriptor plugin) throws Exception
{
final Plugin result;
// create plugin instance
result = create(plugin);
// audit
Audit.pluginLaunched(result);
// execute plugin
if (result instanceof PluginImageAnalysis)
internalExecute(result);
return result;
}
/**
* @deprecated Use {@link #startSafe(PluginDescriptor)} instead.<br>
* You can retrieve a {@link PluginDescriptor} from the class name by using
* {@link PluginLoader#getPlugin(String)} method.
*/
@Deprecated
public static Plugin startSafe(String pluginClassName) throws Exception
{
final PluginDescriptor plugin = PluginLoader.getPlugin(pluginClassName);
if (plugin != null)
return startSafe(plugin);
return null;
}
/**
* @deprecated Use {@link #start(PluginDescriptor)} instead.
*/
@Deprecated
public synchronized static void launch(PluginDescriptor descriptor)
{
start(descriptor);
}
}