1 package com.github.celldynamics.quimp.plugin; 2 3 import java.io.File; 4 5 import com.github.celldynamics.quimp.QParams; 6 import com.github.celldynamics.quimp.QuimpException; 7 import com.github.celldynamics.quimp.QuimpException.MessageSinkTypes; 8 import com.github.celldynamics.quimp.filesystem.FileExtensions; 9 import com.github.celldynamics.quimp.filesystem.QconfLoader; 10 11 /** 12 * Template of plugin focused at processing QCONF/paQP files. 13 * 14 * <p>This type of plugin opens QCONF/paQP file immediately after run, process it and returns 15 * results. User interface is not directly supported here unless you override {@link #executer()}. 16 * For UI plugins use {@link AbstractPluginTemplate}. If {@link AbstractPluginOptions#paramFile} is 17 * not null and not empty, it will be used, otherwise template displays file dialog. 18 * 19 * <p>Following workflow specified in {@link AbstractPluginBase}, this implementation calls 20 * {@link #loadFile(String)} from {@link #executer()}. If default constructor 21 * {@link #AbstractPluginQconf(String, AbstractPluginOptions, String)} is called from constructor in 22 * implementing class and any additional configuration is needed before plugin executes (that 23 * typically should go after calling super (this) constructor) that configuration can be added in 24 * overridden {@link #loadFile(String)} method before calling super#loadFile. 25 * 26 * @author p.baniukiewicz 27 * @see AbstractPluginBase 28 */ 29 public abstract class AbstractPluginQconf extends AbstractPluginBase { 30 31 /** 32 * Loaded configuration file. 33 */ 34 protected QconfLoader qconfLoader; // main object representing loaded configuration file 35 36 /** 37 * Extension of file plugin asks for after execution in IJ mode. 38 */ 39 protected String fileExt = FileExtensions.newConfigFileExt; 40 41 /** 42 * This default constructor must be overridden in concrete class. It is called by IJ when plugin 43 * instance is created. A concrete instance of {@link AbstractPluginOptions} class should be 44 * created there and then passed to {@link #AbstractPluginQconf(AbstractPluginOptions,String)}. 45 */ 46 protected AbstractPluginQconf() { 47 super(); 48 } 49 50 /** 51 * Default constructor. 52 * 53 * <p>Set api call to false and assign provided options to object. 54 * 55 * @param options Reference to plugin configuration container. 56 * @param pluginName name of the plugin that will be displayed in Macro Recorder 57 */ 58 protected AbstractPluginQconf(AbstractPluginOptions options, String pluginName) { 59 super(options, pluginName); 60 } 61 62 /** 63 * Constructor that allows to provide own parameters. 64 * 65 * <p>Intended to run from API. Set {@link #apiCall} to true and {@link #errorSink} to 66 * {@link MessageSinkTypes#CONSOLE}. 67 * {@link AbstractPluginOptions} is initialised from specified string and assigned to this 68 * instance. 69 * 70 * <p>It loads QCONF.paQP file specified in {@link AbstractPluginOptions#paramFile}. If file is 71 * not specified it shows load file window. 72 * 73 * @param argString parameters string like that passed in macro. If it is empty string or null 74 * constructor exits before deserialisation. 75 * @param options Reference to plugin configuration container. 76 * @param pluginName name of the plugin that will be displayed in Macro Recorder 77 * @throws QuimpPluginException on any error in plugin execution. 78 * @see #loadFile(String) 79 */ 80 protected AbstractPluginQconf(String argString, AbstractPluginOptions options, String pluginName) 81 throws QuimpPluginException { 82 super(argString, options, pluginName); 83 try { 84 loadFile(this.options.paramFile); // load configuration file and verify it 85 } catch (QuimpPluginException qe) { 86 throw qe; 87 } catch (Exception qe) { 88 throw new QuimpPluginException(qe); 89 } 90 } 91 92 /* 93 * (non-Javadoc) 94 * 95 * @see com.github.celldynamics.quimp.plugin.AbstractPluginBase#executer() 96 */ 97 @Override 98 protected void executer() throws QuimpException { 99 loadFile(options.paramFile); 100 // FIXME It should call either runFromPaqp or validate();runFromQconf(); here 101 } 102 103 /** 104 * Load specified configuration file and execute plugin depending on file type. 105 * 106 * <p>This method executes only once, if {@link #getQconfLoader()} is null. Should be overridden 107 * if there is any additional configuration needed before execution. 108 * 109 * <p>If file is QCONF then {@link #runFromQconf()} is executed, if it is paQP then 110 * {@link #runFromPaqp()}. Validate loaded QCONF file by {@link #validate()}. 111 * 112 * @param paramFile path to the file. It can be null or empty string to allow user pick the file. 113 * 114 * @throws QuimpException When configuration file could not be loaded or it does not meet 115 * requirements. 116 * @see #validate() 117 */ 118 protected void loadFile(String paramFile) throws QuimpException { 119 File pf; 120 if (paramFile == null || paramFile.isEmpty()) { 121 pf = null; 122 } else { 123 pf = new File(paramFile); 124 } 125 if (qconfLoader == null || qconfLoader.getQp() == null) { 126 // load new file 127 qconfLoader = new QconfLoader(pf, fileExt); 128 if (qconfLoader.getQp() == null) { 129 // not loaded (cancelled) 130 throw new QuimpPluginException("Cancelled", MessageSinkTypes.MESSAGE, true); 131 } 132 if (qconfLoader.isFileLoaded() == QParams.QUIMP_11) { // old path 133 runFromPaqp(); 134 } else if (qconfLoader.isFileLoaded() == QParams.NEW_QUIMP) { // new path 135 validate(); 136 runFromQconf(); 137 } else { 138 qconfLoader = null; // failed load or checking 139 throw new QuimpPluginException( 140 "QconfLoader returned unsupported version of QuimP or error."); 141 } 142 } 143 } 144 145 /** 146 * Override this method to pass your own validation of QCONF structure. 147 * 148 * @throws QuimpException if file can not be validated. 149 */ 150 protected void validate() throws QuimpException { 151 qconfLoader.getBOA(); 152 } 153 154 /** 155 * Return {@link QconfLoader} object. 156 * 157 * @return the qconfLoader 158 */ 159 public QconfLoader getQconfLoader() { 160 return qconfLoader; 161 } 162 163 /** 164 * Remove loaded QCONF file and allows to load new one. 165 * 166 * <p>Note that file can be processed once, therefore next call of {@link #run(String)} wil do 167 * nothing unless {@link #unload()} is used. 168 * 169 * @see AbstractPluginQconf#loadFile(String) 170 */ 171 public final void unload() { 172 qconfLoader = null; 173 } 174 175 /** 176 * Called if loaded file is QCONF. 177 * 178 * <p>This method expects that {@link #qconfLoader} is already set up ({@link #run(String)}. In 179 * macro or IJ mode exceptions will be handled in place and displayed as IJERROR or GUI message. 180 * For API call (only if initialised by 181 * {@link #AbstractPluginQconf(String, AbstractPluginOptions, String)}) 182 * exceptions are re-thrown. 183 * 184 * @throws QuimpException on error 185 */ 186 protected abstract void runFromQconf() throws QuimpException; 187 188 /** 189 * Called if loaded file is paQP. 190 * 191 * <p>This method expects that {@link #qconfLoader} is already set up ({@link #run(String)}. In 192 * macro or IJ mode exceptions will be handled in place and displayed as IJERROR or GUI message. 193 * For API call (only if initialised by 194 * {@link #AbstractPluginQconf(String, AbstractPluginOptions, String)}) 195 * exceptions are re-thrown. 196 * 197 * @throws QuimpException on error 198 */ 199 protected abstract void runFromPaqp() throws QuimpException; 200 201 }