001/* 002 * Copyright (c) 2004-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: welker $' 006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 007 * '$Revision: 24234 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.cipres.kepler; 031 032// ptolemy packages 033import java.util.Observable; 034import java.util.Observer; 035 036import javax.swing.JOptionPane; 037 038import org.cipres.helpers.GUIRun; 039 040import ptolemy.actor.CompositeActor; 041import ptolemy.actor.Manager; 042import ptolemy.actor.TypedAtomicActor; 043import ptolemy.actor.TypedIOPort; 044import ptolemy.data.IntToken; 045import ptolemy.data.StringToken; 046import ptolemy.data.expr.FileParameter; 047import ptolemy.data.expr.Parameter; 048import ptolemy.data.type.BaseType; 049import ptolemy.kernel.CompositeEntity; 050import ptolemy.kernel.util.IllegalActionException; 051import ptolemy.kernel.util.NameDuplicationException; 052import ptolemy.kernel.util.Nameable; 053 054////////////////////////////////////////////////////////////////////////// 055//// GUIRunCIPRes 056/** 057 * This actor calls external Cipres applications with GUIGen interfaces. 058 * 059 * The GUIRunCIPRes actor provides a template to invoke external Cipres 060 * applications. A set of parameters is configured in the actor to collect 061 * application related information. The value of these parameters will be fed to 062 * the GUIRun object when the actor fires. Thus the GUIRun object will invoke 063 * the corresponding application with those values, like the input/output file 064 * names and the working directory. After the execution, if the external program 065 * returns correctly, the standard output of the execution will be sent to the 066 * standard output file, the standard error will be sent to the standard error 067 * file, and the program output file name will be sent to the 068 * outputParameterValue port. 069 * 070 * The user can also set some words to be monitored in the standard output 071 * stream. The observer/observable design pattern is used here. The GUIRunCIPRes 072 * object is an observer. The GUIRun object is an observable. Whenever the 073 * GUIRun object find any of these monitored words in the standard output steam 074 * of the program execution, it will notify the GUIRunCIPRes objects to promote 075 * the user handling the issue. Usually the GUIRunCIPRes actor will stop the 076 * execution of the program. 077 * 078 * @author Zhijie Guan 079 * @version $Id: GUIRunCIPRes.java 24234 2010-05-06 05:21:26Z welker $ 080 */ 081 082public class GUIRunCIPRes extends TypedAtomicActor implements Observer { 083 084 /** 085 * Construct GUIRunCIPRes source with the given container and name. 086 * 087 * @param container 088 * The container. 089 * @param name 090 * The name of this actor. 091 * @exception IllegalActionException 092 * If the entity cannot be contained by the proposed 093 * container. 094 * @exception NameDuplicationException 095 * If the container already has an actor with this name. 096 */ 097 098 public GUIRunCIPRes(CompositeEntity container, String name) 099 throws NameDuplicationException, IllegalActionException { 100 super(container, name); 101 102 // initialize the standard output port 103 standardOutput = new TypedIOPort(this, "standardOutput", false, true); 104 standardOutput.setDisplayName("Standard Output"); 105 standardOutput.setTypeEquals(BaseType.STRING); 106 107 // initialize the standard error port 108 standardError = new TypedIOPort(this, "standardError", false, true); 109 standardError.setDisplayName("Standard Error"); 110 standardError.setTypeEquals(BaseType.STRING); 111 112 // initialize the exit code port 113 exitCode = new TypedIOPort(this, "exitCode", false, true); 114 exitCode.setDisplayName("Exit Code"); 115 exitCode.setTypeEquals(BaseType.STRING); 116 117 // parameters initialization 118 // output parameter value 119 outputParameterValue = new TypedIOPort(this, "outputParameterValue", 120 false, true); 121 outputParameterValue.setDisplayName("Parameter Value (Output)"); 122 outputParameterValue.setTypeEquals(BaseType.STRING); 123 124 // input parameter name 125 inputParameterName = new TypedIOPort(this, "inputParameterName", true, 126 false); 127 inputParameterName.setDisplayName("Input Parameter Name"); 128 inputParameterName.setTypeEquals(BaseType.STRING); 129 130 // input parameter value 131 inputParameterValue = new TypedIOPort(this, "inputParameterValue", 132 true, false); 133 inputParameterValue.setDisplayName("Input Parameter Value"); 134 inputParameterValue.setTypeEquals(BaseType.STRING); 135 136 // command name 137 command = new FileParameter(this, "command"); 138 command.setDisplayName("External Command"); 139 140 // GUIGen xml file name 141 uiXMLFile = new FileParameter(this, "uiXMLFile"); 142 uiXMLFile.setDisplayName("GUIGen XML File"); 143 144 // Standard output file 145 outputFile = new FileParameter(this, "outputFile"); 146 outputFile.setDisplayName("Standard Output File"); 147 148 // Standard error file 149 errorFile = new FileParameter(this, "errorFile"); 150 errorFile.setDisplayName("Standard Error File"); 151 152 // Working directory 153 workingDirectory = new Parameter(this, "workingDirectory", 154 new StringToken("")); 155 workingDirectory.setDisplayName("Working Direcotry"); 156 157 // parameter's name in the GUIRun. Usually it is "output" 158 parameterForOutput = new Parameter(this, "parameterForOutput", 159 new StringToken("")); 160 parameterForOutput.setDisplayName("Parameter to Output"); 161 162 // words to be monitored 163 monitoredErrorWords = new Parameter(this, "monitoredErrorWords", 164 new StringToken("")); 165 monitoredErrorWords.setDisplayName("Error Words to be Monitored"); 166 167 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"0\" y=\"0\" " 168 + "width=\"60\" height=\"20\" " + "style=\"fill:white\"/>\n" 169 + "</svg>\n"); 170 171 } 172 173 // ///////////////////////////////////////////////////////////////// 174 // // ports and parameters //// 175 176 /** 177 * The command path and name are defined in this parameter. 178 */ 179 public FileParameter command; 180 181 /** 182 * The GUIGen xml file's path and name are defined in this parameter. 183 */ 184 public FileParameter uiXMLFile; 185 186 /** 187 * The standard output file's path and name are defined in this parameter. 188 */ 189 public FileParameter outputFile; 190 191 /** 192 * The standard error file's path and name are defined in this parameter. 193 */ 194 public FileParameter errorFile; 195 196 /** 197 * The workfing directory of the external program is defined in this 198 * parameter. 199 */ 200 public Parameter workingDirectory; 201 202 /** 203 * The GUIRun parameter to be send out is defined in this parameter. Usually 204 * this GUIRun parameter is "outfile". 205 */ 206 public Parameter parameterForOutput; 207 208 /** 209 * The monitored words are defined in this parameter. 210 */ 211 public Parameter monitoredErrorWords; 212 213 /** 214 * The standard output stream of the execution is sent out through this 215 * port. 216 */ 217 public TypedIOPort standardOutput = null; 218 219 /** 220 * The standard error stream of the execution is sent out through this port. 221 */ 222 public TypedIOPort standardError = null; 223 224 /** 225 * The exit code of the execution is sent out through this port. 226 */ 227 public TypedIOPort exitCode = null; 228 229 /** 230 * The output parameter value, usually the name of the output file of the 231 * execution, is sent out throught this port. 232 */ 233 public TypedIOPort outputParameterValue = null; 234 235 /** 236 * The input parameter name (usually "infile") is sent through this port. 237 */ 238 public TypedIOPort inputParameterName = null; 239 240 /** 241 * The input parameter value (usually the name of the input file of the 242 * execution) is sent through this port. 243 */ 244 public TypedIOPort inputParameterValue = null; 245 246 // ///////////////////////////////////////////////////////////////// 247 // // functional variables //// 248 249 // ///////////////////////////////////////////////////////////////// 250 // // public methods //// 251 252 /** 253 * Invoke the external program by setting the parameters of the execution 254 * using GUIGen. The monitored words are being monitored during the 255 * execution. 256 * 257 * @exception IllegalActionException 258 * If it is thrown by the send() method sending out the 259 * token. 260 */ 261 public void fire() throws IllegalActionException { 262 if (inputParameterValue.hasToken(0) && inputParameterName.hasToken(0)) { 263 super.fire(); 264 try { 265 266 // get command 267 String commandFileName = ((StringToken) command.getToken()) 268 .stringValue(); 269 if (commandFileName.length() != 0) { 270 _grun.setCommand(commandFileName); 271 } else { 272 System.out.println("Command is not defined!"); 273 throw new IllegalActionException("Command is not defined"); 274 } 275 276 // get GUIGen xml file 277 String uiXMLFileName = ((StringToken) uiXMLFile.getToken()) 278 .stringValue(); 279 if (uiXMLFileName.length() != 0) { 280 _grun.setUIXMLFile(uiXMLFileName); 281 } 282 283 // get standard output file name 284 String outFileName = ((StringToken) outputFile.getToken()) 285 .stringValue(); 286 if (outFileName.length() != 0) { 287 _grun.setOutputFileName(outFileName); 288 } 289 290 // get standard error file name 291 String errorFileName = ((StringToken) errorFile.getToken()) 292 .stringValue(); 293 if (errorFileName.length() != 0) { 294 _grun.setErrorFileName(errorFileName); 295 } 296 297 // get the working directory 298 String workingDirName = ((StringToken) workingDirectory 299 .getToken()).stringValue(); 300 if (workingDirName.length() != 0) { 301 _grun.setWorkingDirectory(workingDirName); 302 } 303 304 // set the input file to the GUIRun object 305 _grun 306 .setArgumentValue(((StringToken) inputParameterName 307 .get(0)).stringValue(), 308 ((StringToken) inputParameterValue.get(0)) 309 .stringValue()); 310 311 // get arguments information with GUIGen interface 312 _grun.setArgumentsWithGUIGen(); 313 314 // Here we assume all the programs executed by GUIRunCIPRes must 315 // be finished to get the final results 316 // So the GUIRun is set to wait until the execution is finished 317 _grun.setWaitForExecution(true); 318 319 // check if the user set the monitored error words 320 String errorWords = ((StringToken) monitoredErrorWords 321 .getToken()).stringValue(); 322 if (errorWords.length() != 0) { 323 _grun.setMonitoredErrorWords(errorWords); 324 _grun.addObserver(this); // add this GUIRunCIPRes as an 325 // observer 326 } 327 328 _grun.execute(); // invoke the external program 329 330 String outputFileName = _grun 331 .getArgumentValue(((StringToken) parameterForOutput 332 .getToken()).stringValue()); 333 334 // call postExecutionProcess to process the output data after 335 // the execution 336 postExecutionProcess(outputFileName); 337 338 exitCode.send(0, new IntToken(_grun.getExitCode())); // send out 339 // the 340 // exit 341 // code 342 // token 343 344 if (_grun.getExitCode() != 0) { 345 _terminateWorkflow = true; // set the flag to terminate the 346 // workflow since errors are 347 // reported 348 } else { 349 // send out standard output/error and output file 350 standardOutput.send(0, new StringToken(_grun 351 .getStandardOutput())); 352 standardError.send(0, new StringToken(_grun 353 .getStandardError())); 354 355 outputParameterValue.send(0, 356 new StringToken(outputFileName)); 357 } 358 } catch (Exception e) { 359 e.printStackTrace(); 360 } 361 } 362 } 363 364 /** 365 * This function processes the output data after the execution. Usually 366 * subclasses of the GUIRunCIPRes class will implement this function. 367 * 368 * @param outputFileName 369 * is the output file name of the execution 370 */ 371 public void postExecutionProcess(String outputFileName) { 372 } 373 374 /** 375 * Observer function update guiRunObj is the GUIRun object that runs the 376 * program obj is the String message that GUIRun object send back. This 377 * string message is the standard output/error line that contains the 378 * monitored words 379 */ 380 public void update(Observable guiRunObj, Object obj) { 381 String outputMessage = (String) obj; 382 int stop = 0; // For default, we assume the execution should be stopped 383 // if any error appears 384 385 try { 386 // ask the user if we should abort the program execution 387 stop = JOptionPane.showConfirmDialog(null, // parent component 388 "The program execution reported the following error message.\n" 389 + // Message 390 "Would you like to stop the execution?\n" + // Message 391 outputMessage + "\n", // Error message for Standard 392 // output/error 393 "Error Reported", // Title 394 JOptionPane.YES_NO_OPTION, // Option type 395 JOptionPane.ERROR_MESSAGE); // Message type 396 } catch (Exception e) { 397 e.printStackTrace(); 398 } 399 400 if (stop == JOptionPane.YES_OPTION) { 401 ((GUIRun) guiRunObj).stopExecution(); // stop the execution 402 } 403 404 } 405 406 /** 407 * Post fire the actor. Return false to indicated that the process has 408 * finished. If it returns true, the process will continue indefinitely. 409 */ 410 public boolean postfire() throws IllegalActionException { 411 if (_terminateWorkflow) { // try to kill the execution 412 Nameable container = getContainer(); 413 if (container instanceof CompositeActor) { 414 Manager manager = ((CompositeActor) container).getManager(); 415 if (manager != null) { 416 manager.finish(); // stop the workflow 417 } else { 418 throw new IllegalActionException(this, 419 "Cannot terminate the workflow without a Manager"); 420 } 421 } else { 422 throw new IllegalActionException(this, 423 "Cannot terminate the workflow without a container that is a CompositeActor"); 424 } 425 } 426 return !_terminateWorkflow; 427 } 428 429 // ///////////////////////////////////////////////////////////////// 430 // // private variables //// 431 /** 432 * GUIRun object to invoke external programs. 433 */ 434 protected GUIRun _grun = new GUIRun("External Program"); 435 436 /** 437 * a flag to terminate the whole workflow if the execution of program got 438 * error messages 439 */ 440 private boolean _terminateWorkflow = false; 441}