/* * 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); } }