View Javadoc
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 }