1 package com.github.celldynamics.quimp.plugin; 2 3 import com.github.celldynamics.quimp.QuimpException; 4 import com.github.celldynamics.quimp.QuimpException.MessageSinkTypes; 5 import com.github.celldynamics.quimp.registration.Registration; 6 7 import ij.IJ; 8 import ij.plugin.PlugIn; 9 10 /** 11 * Base template of QuimP (legacy Fiji compatible) plugins. 12 * 13 * <p>This template provides template of {@link #run(String)} method specified in 14 * {@link PlugIn#run(String)} interface that detects context of caller by testing if there is valid 15 * parameter string specified and then sets proper {@link AbstractOptionsParser#errorSink} and 16 * {@link AbstractOptionsParser#apiCall}. Thus depending on context plugin will report errors in 17 * correct place. Using {@link #run(String)} errors can be directed to {@link MessageSinkTypes#GUI} 18 * or {@link MessageSinkTypes#IJERROR}. For having them in {@link MessageSinkTypes#CONSOLE} override 19 * {@link #executer()} or use other method for executing plugin. 20 * 21 * @author p.baniukiewicz 22 * @see QuimpException#handleException(java.awt.Frame, String) 23 */ 24 public abstract class AbstractPluginBase extends AbstractOptionsParser implements IQuimpPlugin { 25 26 /** 27 * Name of the plugin that will be displayed in Macro Recorder. 28 */ 29 private String pluginName = ""; 30 31 /** 32 * This default constructor must be overridden in concrete class. It is called by IJ when plugin 33 * instance is created. A concrete instance of {@link AbstractPluginOptions} class should be 34 * created there and then passed to 35 * {@link AbstractOptionsParser#AbstractOptionsParser(AbstractPluginOptions)}. One needs to call 36 * {@link #setPluginName(String)} here as well. 37 */ 38 public AbstractPluginBase() { 39 super(); 40 } 41 42 /** 43 * Default constructor. 44 * 45 * <p>Set api call to false and assign provided options to object. 46 * 47 * @param options Reference to plugin configuration container. 48 * @param pluginName name of the plugin that will be displayed in Macro Recorder 49 */ 50 public AbstractPluginBase(AbstractPluginOptions options, String pluginName) { 51 super(options); 52 setPluginName(pluginName); 53 } 54 55 /** 56 * Constructor that allows to provide own parameter string. 57 * 58 * <p>Intended to run from API. Set {@link #apiCall} to true and {@link #errorSink} to 59 * {@link MessageSinkTypes#CONSOLE}. 60 * {@link AbstractPluginOptions} is initialised from specified string and assigned to this 61 * instance. 62 * 63 * @param argString parameters string like that passed in macro. If it is empty string or null 64 * constructor exits before deserialisation. 65 * @param options Reference to plugin configuration container. 66 * @param pluginName name of the plugin that will be displayed in Macro Recorder 67 * @throws QuimpPluginException on any error in plugin execution. 68 */ 69 public AbstractPluginBase(String argString, AbstractPluginOptions options, String pluginName) 70 throws QuimpPluginException { 71 super(argString, options); 72 setPluginName(pluginName); 73 } 74 75 /** 76 * Called on plugin run by ImageJ or from API. 77 * 78 * <p>Overrides {@link PlugIn#run(String)}. If input string is null or empty it sets 79 * {@link AbstractOptionsParser#errorSink} to 80 * {@link MessageSinkTypes#GUI}. Note that {@link AbstractOptionsParser#apiCall} is set by 81 * choosing proper constructor. Then it tries to parse specified parameter string, if it succeeds, 82 * {@link AbstractOptionsParser#options} is set and deserialised and {@link #executer()} method is 83 * executed. If parsing fails, {@link #showUi(boolean)} is called with option true. If there is 84 * parsable string {@link AbstractOptionsParser#errorSink} is set to 85 * {@link MessageSinkTypes#IJERROR} 86 * 87 * <p>Finally, macro string is published to ImageJ that represents current state of 88 * {@link AbstractOptionsParser#options}. 89 * 90 * <p>All exceptions thrown by plugin logic (from {@link #executer()}) are handled here depending 91 * on {@link AbstractOptionsParser#errorSink} value. 92 * 93 * @see AbstractOptionsParser#parseArgumentString(String) 94 */ 95 @Override 96 public void run(String arg) { 97 if (arg == null || arg.isEmpty()) { 98 errorSink = MessageSinkTypes.GUI; // no parameters - assume menu call 99 } else { 100 errorSink = MessageSinkTypes.IJERROR; // parameters available - macro call 101 } 102 // validate registered user 103 new Registration(IJ.getInstance(), "QuimP Registration"); 104 try { 105 if (parseArgumentString(arg)) { // process options passed to this method 106 IJ.showStatus(pluginName); 107 executer(); 108 IJ.log(pluginName + " complete"); 109 IJ.showStatus("Finished"); 110 } else { 111 showUi(true); 112 } 113 114 } catch (QuimpException qe) { 115 qe.setMessageSinkType(errorSink); 116 qe.handleException(IJ.getInstance(), this.getClass().getSimpleName()); 117 } catch (Exception e) { // catch all exceptions here 118 logger.debug(e.getMessage(), e); 119 logger.error("Problem with running plugin: " + e.getMessage() + " (" + e.toString() + ")"); 120 } finally { 121 publishMacroString(pluginName); 122 } 123 } 124 125 /** 126 * Open plugin UI. 127 * 128 * <p>Executed if {@link #run(String)} could not parse parameters. 129 * 130 * @param val true to show UI 131 * @throws Exception on any error. Handled by {@link #run(String)} 132 */ 133 public abstract void showUi(boolean val) throws Exception; 134 135 /** 136 * Executed if {@link #run(String)} got parsable parameter string. 137 * 138 * @throws QuimpException on any error. Exception is handled depending on 139 * {@link AbstractOptionsParser#errorSink} set by {@link #run(String)} 140 */ 141 protected abstract void executer() throws QuimpException; 142 143 /** 144 * Set plugin name, should be that recognisable by IJ, usually plugins.config. 145 * 146 * @param pluginName the pluginName to set 147 */ 148 public void setPluginName(String pluginName) { 149 this.pluginName = pluginName; 150 } 151 152 }