001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.plugin; 020 021import icy.main.Icy; 022import icy.plugin.abstract_.Plugin; 023import icy.plugin.interface_.PluginImageAnalysis; 024import icy.plugin.interface_.PluginNoEDTConstructor; 025import icy.plugin.interface_.PluginStartAsThread; 026import icy.plugin.interface_.PluginThreaded; 027import icy.system.IcyExceptionHandler; 028import icy.system.audit.Audit; 029import icy.system.thread.ThreadUtil; 030import icy.util.ClassUtil; 031 032import java.util.concurrent.Callable; 033 034/** 035 * This class launch plugins and register them to the main application.<br> 036 * The launch can be in a decicated thread or in the EDT. 037 * 038 * @author Fabrice de Chaumont & Stephane 039 */ 040public class PluginLauncher 041{ 042 protected static class PluginExecutor implements Callable<Boolean>, Runnable 043 { 044 final Plugin plugin; 045 046 public PluginExecutor(Plugin plugin) 047 { 048 super(); 049 050 this.plugin = plugin; 051 } 052 053 @Override 054 public Boolean call() throws Exception 055 { 056 // some plugins (as EzPlug) do not respect the PluginActionable convention (run() method 057 // contains all the process) 058 // so we can't yet use this bloc of code 059 060 // if (plugin instanceof PluginActionable) 061 // ((PluginActionable) plugin).run(); 062 // // keep backward compatibility 063 // else if (plugin instanceof PluginImageAnalysis) 064 // ((PluginImageAnalysis) plugin).compute(); 065 066 // keep backward compatibility 067 if (plugin instanceof PluginImageAnalysis) 068 ((PluginImageAnalysis) plugin).compute(); 069 070 return Boolean.TRUE; 071 } 072 073 @Override 074 public void run() 075 { 076 try 077 { 078 call(); 079 } 080 catch (Throwable t) 081 { 082 IcyExceptionHandler.handleException(plugin.getDescriptor(), t, true); 083 } 084 } 085 } 086 087 /** 088 * Executes the specified plugin.<br> 089 * If the specified plugin implements {@link PluginThreaded} then the plugin will be executed in 090 * a separate thread and the method will return before completion.<br> 091 * In other case the plugin is executed on the EDT by using {@link ThreadUtil#invokeNow(Callable)} and so method 092 * return after completion. 093 * 094 * @throws InterruptedException 095 * if the current thread was interrupted while waiting for execution on EDT. 096 * @throws Exception 097 * if the computation threw an exception (only when plugin is executed on EDT). 098 */ 099 private static void internalExecute(final Plugin plugin) throws Exception 100 { 101 if (plugin instanceof PluginThreaded) 102 { 103 // headless mode --> command line direct execution 104 if (Icy.getMainInterface().isHeadLess()) 105 ((PluginThreaded) plugin).run(); 106 else 107 new Thread((PluginThreaded) plugin, plugin.getName()).start(); 108 } 109 else 110 { 111 final PluginExecutor executor = new PluginExecutor(plugin); 112 113 // headless mode --> command line direct execution 114 if (Icy.getMainInterface().isHeadLess()) 115 executor.call(); 116 // keep backward compatibility 117 else if (plugin instanceof PluginStartAsThread) 118 new Thread(executor, plugin.getName()).start(); 119 // direct launch in EDT now (no thread creation) 120 else 121 ThreadUtil.invokeNow((Callable<Boolean>) executor); 122 } 123 } 124 125 /** 126 * Creates a new instance of the specified plugin and returns it.<br> 127 * 128 * @param plugin 129 * descriptor of the plugin we want to create an instance for 130 * @param register 131 * if we want to register the plugin in the active plugin list 132 * @see #startSafe(PluginDescriptor) 133 */ 134 public static Plugin create(final PluginDescriptor plugin, boolean register) throws Exception 135 { 136 final Class<? extends Plugin> clazz = plugin.getPluginClass(); 137 final Plugin result; 138 139 // use the special PluginNoEDTConstructor interface or headless mode ? 140 if (ClassUtil.isSubClass(clazz, PluginNoEDTConstructor.class) || Icy.getMainInterface().isHeadLess()) 141 result = clazz.newInstance(); 142 else 143 { 144 // create the plugin instance on the EDT 145 result = ThreadUtil.invokeNow(new Callable<Plugin>() 146 { 147 @Override 148 public Plugin call() throws Exception 149 { 150 return clazz.newInstance(); 151 } 152 }); 153 } 154 155 // register plugin 156 if (register) 157 Icy.getMainInterface().registerPlugin(result); 158 159 return result; 160 } 161 162 /** 163 * Creates a new instance of the specified plugin and returns it.<br> 164 * The plugin is automatically registered to the list of active plugins. 165 * 166 * @param plugin 167 * descriptor of the plugin we want to create an instance for 168 * @see #startSafe(PluginDescriptor) 169 */ 170 public static Plugin create(final PluginDescriptor plugin) throws Exception 171 { 172 return create(plugin, true); 173 } 174 175 /** 176 * Starts the specified plugin (catched exception version).<br> 177 * Returns the plugin instance (only meaningful for {@link PluginThreaded} plugin) or <code>null</code> if an error 178 * occurred. 179 * 180 * @param plugin 181 * descriptor of the plugin we want to start 182 * @see #startSafe(PluginDescriptor) 183 */ 184 public static Plugin start(PluginDescriptor plugin) 185 { 186 final Plugin result; 187 188 try 189 { 190 try 191 { 192 // create plugin instance 193 result = create(plugin); 194 } 195 catch (IllegalAccessException e) 196 { 197 System.err.println("Cannot start plugin " + plugin.getName() + " :"); 198 System.err.println(e.getMessage()); 199 return null; 200 } 201 catch (InstantiationException e) 202 { 203 System.err.println("Cannot start plugin " + plugin.getName() + " :"); 204 System.err.println(e.getMessage()); 205 return null; 206 } 207 208 // audit 209 Audit.pluginLaunched(result); 210 // execute plugin 211 if (result instanceof PluginImageAnalysis) 212 internalExecute(result); 213 214 return result; 215 } 216 catch (InterruptedException e) 217 { 218 // we just ignore interruption 219 } 220 catch (Throwable t) 221 { 222 IcyExceptionHandler.handleException(plugin, t, true); 223 } 224 225 return null; 226 } 227 228 /** 229 * @deprecated Use {@link #start(PluginDescriptor)} instead.<br> 230 * You can retrieve a {@link PluginDescriptor} from the class name by using 231 * {@link PluginLoader#getPlugin(String)} method. 232 */ 233 @Deprecated 234 public static Plugin start(String pluginClassName) 235 { 236 final PluginDescriptor plugin = PluginLoader.getPlugin(pluginClassName); 237 238 if (plugin != null) 239 return start(plugin); 240 241 return null; 242 } 243 244 /** 245 * Same as {@link #start(PluginDescriptor)} except it throws {@link Exception} on error 246 * so user can handle them. 247 * 248 * @param plugin 249 * descriptor of the plugin we want to start 250 * compatibility) 251 * @throws InterruptedException 252 * if the current thread was interrupted while waiting for execution on EDT. 253 * @throws Exception 254 * if the computation threw an exception (only when plugin is executed on EDT). 255 */ 256 public static Plugin startSafe(PluginDescriptor plugin) throws Exception 257 { 258 final Plugin result; 259 260 // create plugin instance 261 result = create(plugin); 262 263 // audit 264 Audit.pluginLaunched(result); 265 // execute plugin 266 if (result instanceof PluginImageAnalysis) 267 internalExecute(result); 268 269 return result; 270 } 271 272 /** 273 * @deprecated Use {@link #startSafe(PluginDescriptor)} instead.<br> 274 * You can retrieve a {@link PluginDescriptor} from the class name by using 275 * {@link PluginLoader#getPlugin(String)} method. 276 */ 277 @Deprecated 278 public static Plugin startSafe(String pluginClassName) throws Exception 279 { 280 final PluginDescriptor plugin = PluginLoader.getPlugin(pluginClassName); 281 282 if (plugin != null) 283 return startSafe(plugin); 284 285 return null; 286 } 287 288 /** 289 * @deprecated Use {@link #start(PluginDescriptor)} instead. 290 */ 291 @Deprecated 292 public synchronized static void launch(PluginDescriptor descriptor) 293 { 294 start(descriptor); 295 } 296}