001/* 002 * Copyright (c) 2005-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.resurgence.actor; 031 032// Ptolemy packages 033import java.io.DataInputStream; 034import java.io.IOException; 035 036import org.sdm.spa.CommandLine; 037 038import ptolemy.actor.TypedIOPort; 039import ptolemy.data.BooleanToken; 040import ptolemy.data.IntToken; 041import ptolemy.data.LongToken; 042import ptolemy.data.StringToken; 043import ptolemy.data.Token; 044import ptolemy.data.expr.Parameter; 045import ptolemy.data.expr.StringParameter; 046import ptolemy.data.type.BaseType; 047import ptolemy.kernel.CompositeEntity; 048import ptolemy.kernel.util.Attribute; 049import ptolemy.kernel.util.IllegalActionException; 050import ptolemy.kernel.util.NameDuplicationException; 051import ptolemy.kernel.util.Settable; 052 053////////////////////////////////////////////////////////////////////////// 054//// StatusChecker 055/** 056 * FIXME: Add documents here. FIXME: Make it more generic... FIXME: If we 057 * decided to extend from CommandLine, then we should re-code CommandLine for 058 * code reuse. 059 * 060 * @author Yang Zhao 061 * @author Ilkay Altintas 062 * @author Wibke Sudholt, University and ETH Zurich, November 2004 063 * @version $Id: StatusChecker.java 24234 2010-05-06 05:21:26Z welker $ 064 */ 065 066public class StatusChecker extends CommandLine { 067 068 /** 069 * Construct a StatusChecker actor with the given container and name. 070 * 071 * @param container 072 * The container. 073 * @param name 074 * The name of this actor. 075 * @exception IllegalActionException 076 * If the actor cannot be contained by the proposed 077 * container. 078 * @exception NameDuplicationException 079 * If the container already has an actor with this name. 080 */ 081 public StatusChecker(CompositeEntity container, String name) 082 throws IllegalActionException, NameDuplicationException { 083 super(container, name); 084 085 iterationOutput = new TypedIOPort(this, "iterationOutput", false, true); 086 iterationOutput.setTypeEquals(BaseType.STRING); 087 new Attribute(iterationOutput, "_showName"); 088 089 // Hide the outputLineByLine parameter. 090 outputLineByLine.setVisibility(Settable.EXPERT); 091 092 sleepTime = new Parameter(this, "sleepTime", new LongToken(0)); 093 sleepTime.setTypeEquals(BaseType.LONG); 094 095 checkCondition = new StringParameter(this, "checkCondition"); 096 checkCondition.setTypeEquals(BaseType.STRING); 097 098 maxChecks = new Parameter(this, "maxChecks", new IntToken(1)); 099 maxChecks.setTypeEquals(BaseType.INT); 100 } 101 102 // ///////////////////////////////////////////////////////////////// 103 // // Public ports and parameters //// 104 105 /** 106 * The output in each iteration. 107 */ 108 public TypedIOPort iterationOutput; 109 110 /** 111 * The sleep time amount, in milliseconds, between two checks. This 112 * parameter must contain a LongToken. The default value of this parameter 113 * is 0, meaning that this actor will not sleep between checks. 114 */ 115 public Parameter sleepTime; 116 117 /** 118 * A regular expression for which to check in the output. 119 */ 120 public StringParameter checkCondition; 121 122 /** 123 * The max amount of checks. This parameter is type of int. The default 124 * value of this parameter is -1, meaning that this actor will keep on 125 * checking until the condition is satisfied. 126 */ 127 public Parameter maxChecks; 128 129 // ///////////////////////////////////////////////////////////////// 130 // // public methods //// 131 132 /** 133 * If the specified attribute is <i>sleepTime</i> or <i>maxChecks</i>, then 134 * get the value of them. 135 * 136 * @param attribute 137 * The attribute that has changed. 138 * @exception IllegalActionException. 139 */ 140 public void attributeChanged(Attribute attribute) 141 throws IllegalActionException { 142 // FIXME: should check whether the value is valid... 143 if (attribute == sleepTime) { 144 _sleepTime = ((LongToken) sleepTime.getToken()).longValue(); 145 } else if (attribute == maxChecks) { 146 _maxChecks = ((IntToken) maxChecks.getToken()).intValue(); 147 if (_maxChecks < 0) 148 _maxChecks = Integer.MAX_VALUE; 149 } else if (attribute == checkCondition) { 150 _condition = checkCondition.stringValue(); 151 } else { 152 super.attributeChanged(attribute); 153 } 154 } 155 156 /** 157 * ... Send the exitCode and outputFileHandle(optional) to the result port. 158 * 159 * @exception IllegalActionException 160 * If there is no director. 161 */ 162 public void fire() throws IllegalActionException { 163 164 _lineFlag = ((BooleanToken) outputLineByLine.getToken()).booleanValue(); 165 _debug("<TRIGGER_FLAG>" + _lineFlag + "</TRIGGER_FLAG>"); 166 // simply consume the trigger token if there is some. 167 if (trigger.getWidth() > 0) { 168 if (trigger.hasToken(0)) { 169 trigger.get(0); 170 _debug("consume the tokne at the trigger port."); 171 } 172 } 173 174 // Get the main command from the command parameter. 175 command.update(); 176 _commandStr = ((StringToken) command.getToken()).stringValue(); 177 _createCommand(); 178 179 int i = 0; 180 boolean isSatisfied = false; 181 String result = " "; 182 183 while (!isSatisfied && i < _maxChecks) { 184 result = _executeCommand(); 185 _debug("the execution result is : " + result); 186 if (result.matches(_condition)) 187 isSatisfied = true; 188 if (!_lineFlag) 189 iterationOutput.broadcast(new StringToken(result)); 190 i++; 191 try { 192 if (_debugging) 193 _debug(getName() + ": Wait for " + _sleepTime 194 + " milliseconds."); 195 Thread.sleep(_sleepTime); 196 } catch (InterruptedException e) { 197 // Ignore... 198 } 199 } 200 201 if (!_lineFlag) 202 output.broadcast(new StringToken(result)); 203 if (isSatisfied) { 204 exitCode.broadcast(new BooleanToken(true)); 205 } else { 206 exitCode.broadcast(new BooleanToken(false)); 207 } 208 } // end-of-fire 209 210 // FIXME: The reason I keep this method here is because the redefined 211 // private variable from the CommandLine actor. This should be changed... 212 public int getSystemProps() { 213 // Get OS name 214 String osName = System.getProperty("os.name"); 215 _debug("<OS>" + osName + "</OS>"); 216 if (osName.equals("Windows NT") || osName.equals("Windows XP") 217 || osName.equals("Windows 2000")) { 218 _commandArr[0] = "cmd.exe"; 219 _commandArr[1] = "/C"; 220 _charsToSkip = 6; 221 return 2; 222 } else if (osName.equals("Windows 95")) { 223 _commandArr[0] = "command.com"; 224 _commandArr[1] = "/C"; 225 _charsToSkip = 6; 226 return 2; 227 } else if (osName.equals("Linux")) { 228 _commandArr[0] = "/bin/sh"; 229 _commandArr[1] = "-c"; 230 _charsToSkip = 5; 231 return 2; 232 } else if (osName.equals("Mac OS X")) { 233 _commandArr[0] = "/bin/sh"; 234 _commandArr[1] = "-c"; 235 _charsToSkip = 5; 236 return 2; 237 } else { 238 return 0; 239 } 240 } // end-of-getSystemProps 241 242 private String _executeCommand() throws IllegalActionException { 243 int commandCount = getSystemProps(); 244 _commandArr[commandCount] = _commandStr; 245 _debug("<COMMAND>" + _commandArr[commandCount] + "</COMMAND>"); 246 // EXECUTION OF THE GENERATED COMMAND. 247 _debug("Executing the command..."); 248 try { 249 250 Runtime rt = Runtime.getRuntime(); 251 Process proc = rt.exec(_commandArr); 252 253 DataInputStream inStream = new DataInputStream(proc 254 .getInputStream()); 255 String result; // Temp for each line of output. 256 StringBuffer outBuff = new StringBuffer(""); 257 try { 258 while ((result = inStream.readLine()) != null) { 259 _debug(result); 260 if (_lineFlag) { 261 output.broadcast(new StringToken(result.toString())); 262 } else { 263 outBuff.append(result + "\n"); 264 } 265 } 266 return outBuff.toString(); 267 } catch (IOException ioe) { 268 throw new IllegalActionException(this, 269 "<IOException> when reading the input: " + ioe 270 + "</IOException>"); 271 } 272 } catch (Exception ex) { 273 throw new IllegalActionException(this, 274 "An exception occured when executing the command: " + ex); 275 } 276 } 277 278 private void _createCommand() throws IllegalActionException { 279 /* 280 * Consume the input file token if there's one. 281 */ 282 Token tokenFile = null; 283 String value = null; 284 try { 285 if (infileHandle.getWidth() > 0) { 286 if (infileHandle.hasToken(0)) { 287 tokenFile = infileHandle.get(0); 288 _debug("consume the tokne at the trigger port."); 289 } 290 } 291 292 if (tokenFile != null) { 293 value = new String(tokenFile.toString()); 294 _debug("infileHandle(i) = " + value); 295 value = value.substring(1, value.length() - 1); 296 _commandStr += " < " + value; 297 } 298 } catch (Exception ex) { 299 throw new IllegalActionException(this, "Input file is null."); 300 } 301 302 /* 303 * The arguments can only be accepted if there's no input file. So the 304 * "value" of the infile handle is checked here and arguments are 305 * consumed only if it is null. 306 */ 307 // if (value == null) { 308 /* 309 * Create the argument string. Consume data in all the channels an 310 * combine them. 311 */ 312 String argString = ""; 313 value = new String(""); 314 int i = 0; 315 int width = arguments.getWidth(); 316 for (i = 0; i < width; i++) { 317 if (arguments.hasToken(i)) { 318 Token tokenArg = arguments.get(i); 319 value = tokenArg.toString(); 320 _debug("arguments(i) = " + value); 321 value = value.substring(1, value.length() - 1); 322 323 while (value.indexOf("\\\"") != -1) { 324 int ind = value.indexOf("\\\""); 325 value = value.substring(0, ind) 326 + value.substring(ind + 1, value.length()); 327 _debug(value); 328 } 329 argString += value + " "; 330 _debug("argString = " + argString); 331 } 332 } 333 _commandStr += " " + argString; 334 // } 335 /* 336 * Get the output file path if there's one and add it to the command 337 * string. 338 */ 339 if (outputFile.asURL() == null) { 340 _debug("Output file is null."); 341 } else { 342 String outFilePath = outputFile.asURL().toString(); 343 if (outFilePath.startsWith("file:///")) { 344 if (_charsToSkip == 6) { 345 _charsToSkip = 8; 346 } else if (_charsToSkip == 5) { 347 _charsToSkip = 7; 348 } 349 } 350 outFilePath = outputFile.asURL().toString().substring(_charsToSkip); 351 _commandStr += " > " + outFilePath; 352 outfileHandle.broadcast(new StringToken(outFilePath)); 353 } 354 } 355 356 // //////////////////////////////////////////////////////////////////// 357 // // private variables //// 358 // The combined command to execute. 359 private String _commandStr = ""; 360 private String _commandArr[] = new String[3]; 361 private boolean _lineFlag = false; 362 private boolean _triggerFlag = false; 363 private int _charsToSkip = 6; 364 private long _sleepTime = 0; 365 private int _maxChecks = Integer.MAX_VALUE; 366 private String _condition = ".*"; 367 368} // end-of-class-StatusChecker