001/* 002 * Copyright (c) 2004-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2015-08-24 22:47:39 +0000 (Mon, 24 Aug 2015) $' 007 * '$Revision: 33633 $' 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.srb; 031 032// Ptolemy packages 033import java.io.BufferedReader; 034import java.io.DataInputStream; 035import java.io.File; 036import java.io.FileOutputStream; 037import java.io.IOException; 038import java.io.OutputStream; 039import java.io.StringReader; 040import java.util.Iterator; 041import java.util.List; 042 043import edu.sdsc.grid.io.srb.SRBFileSystem; 044import ptolemy.actor.IOPort; 045import ptolemy.actor.NoTokenException; 046import ptolemy.actor.TypedAtomicActor; 047import ptolemy.actor.TypedIOPort; 048import ptolemy.data.BooleanToken; 049import ptolemy.data.ObjectToken; 050import ptolemy.data.StringToken; 051import ptolemy.data.expr.FileParameter; 052import ptolemy.data.expr.Parameter; 053import ptolemy.data.expr.SingletonParameter; 054import ptolemy.data.expr.StringParameter; 055import ptolemy.data.type.BaseType; 056import ptolemy.kernel.CompositeEntity; 057import ptolemy.kernel.util.Attribute; 058import ptolemy.kernel.util.IllegalActionException; 059import ptolemy.kernel.util.NameDuplicationException; 060import ptolemy.util.MessageHandler; 061 062////////////////////////////////////////////////////////////////////////// 063//// SRBProxyCommand 064/** 065 * <p> 066 * SProxyCommand is a Kepler Actor which has a functionality similar to the SRB 067 * command namely "Spcommand". Spcommand performs the remote execution of 068 * arbitrary commands (executables) installed in a specific predefined directory 069 * on the remote host. SProxyCommand actor executes proxy commands on the SRB. 070 * The following actor expects as input a reference to the SRB file system. This 071 * reference connection is obtained via the SRBConnect Actor in Kepler. <i>See 072 * SRBConnect and its documentation.</i> 073 * </p> 074 * <p> 075 * The file reference system is created with a unique SRB user account and with 076 * this connection reference as input the SProxyCommand actor is able to gain 077 * access to the SRB file space. Once an alive SRB file connection system has 078 * been established the actor gets the command port and parameters to be 079 * executed as input from the user.The arguments to the command are take in as 080 * input and implemented as a multi/input port to support more than one 081 * argument. It concatanates the inputs in all the channels. 082 * </p> 083 * <p> 084 * <B>Actor Input:</B> Accepts a reference to the SRB files system, command and 085 * arguments to be executed as well as the outputfile name (optional) 086 * </p> 087 * <p> 088 * <B>Actor Output:</B> Outputs the result of execution of the proxy command as 089 * well as an outputfilehandle (if the outfile path exists) 090 * 091 * </p> 092 * <p> 093 * The following actor accesses SRB file reference system and SRB file space 094 * with the SRB Jargon API provided. The JARGON is a pure API for developing 095 * programs with a data grid interface and I/O for SRB file systems. 096 * </p> 097 * <A href="http://www.sdsc.edu/srb"><I>Further information on SRB</I> </A> 098 * 099 * 100 @author Efrat Jaeger 101 * @version $Id: SRBProxyCommand.java 33633 2015-08-24 22:47:39Z crawl $ 102 */ 103 104public class SRBProxyCommand extends TypedAtomicActor { 105 106 /** 107 * Construct an actor with the given container and name. 108 * 109 * @param container 110 * The container. 111 * @param name 112 * The name of this actor. 113 * @exception IllegalActionException 114 * If the actor cannot be contained by the proposed 115 * container. 116 * @exception NameDuplicationException 117 * If the container already has an actor with this name. 118 */ 119 public SRBProxyCommand(CompositeEntity container, String name) 120 throws IllegalActionException, NameDuplicationException { 121 super(container, name); 122 123 SRBFileSystem = new TypedIOPort(this, "SRBFileSystem", true, false); 124 SRBFileSystem.setTypeEquals(BaseType.GENERAL); 125 new Attribute(SRBFileSystem, "_showName"); 126 127 commandParameter = new StringParameter(this, "commandParameter"); 128 commandParameter.setExpression("Please type your command here..."); 129 130 command = new TypedIOPort(this, "command", true, false); 131 command.setTypeEquals(BaseType.STRING); 132 new Attribute(command, "_showName"); 133 134 outputFile = new FileParameter(this, "outputFile"); 135 // Construct input ports. 136 arguments = new TypedIOPort(this, "arguments", true, false); 137 arguments.setMultiport(true); 138 arguments.setTypeEquals(BaseType.STRING); 139 new Attribute(arguments, "_showName"); 140 141 outputFileName = new TypedIOPort(this, "outputFileName", true, false); 142 outputFileName.setTypeEquals(BaseType.STRING); 143 new Attribute(outputFileName, "_showName"); 144 145 output = new TypedIOPort(this, "output", false, true); 146 output.setTypeEquals(BaseType.STRING); 147 new Attribute(output, "_showName"); 148 149 outfileHandle = new TypedIOPort(this, "outfileHandle", false, true); 150 outfileHandle.setTypeEquals(BaseType.STRING); 151 new Attribute(outfileHandle, "_showName"); 152 153 outputLineByLine = new Parameter(this, "outputLineByLine", 154 new BooleanToken(false)); 155 outputLineByLine.setTypeEquals(BaseType.BOOLEAN); 156 157 hasTrigger = new Parameter(this, "hasTrigger", new BooleanToken(false)); 158 hasTrigger.setTypeEquals(BaseType.BOOLEAN); 159 160 trigger = new TypedIOPort(this, "trigger", true, false); 161 hide = new SingletonParameter(trigger, "_hide"); 162 hide.setToken(BooleanToken.TRUE); 163 164 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"0\" y=\"0\" " 165 + "width=\"60\" height=\"40\" " + "style=\"fill:white\"/>\n" 166 + "<text x=\"4\" y=\"25\" " 167 + "style=\"font-size:16; fill:blue; font-family:SansSerif\">" 168 + "[SRB]</text>\n" + "<text x=\"45\" y=\"27\" " 169 + "style=\"font-size:20; fill:blue; font-family:SansSerif\">" 170 + "$</text>\n" + "</svg>\n"); 171 172 } // constructor 173 174 // //////////////// Public ports and parameters /////////////////////// 175 176 public SingletonParameter hide; 177 178 /** 179 * pointer to the SRB file system. 180 */ 181 public TypedIOPort SRBFileSystem; 182 183 /** 184 * command port to be executed. 185 */ 186 public TypedIOPort command; 187 188 /** 189 * command parameter to be executed. 190 */ 191 public StringParameter commandParameter; 192 193 /** 194 * Filled in if the user wants the command to output to a file. 195 */ 196 public FileParameter outputFile; 197 198 /** 199 * The output file name is set by previous processes. 200 */ 201 public TypedIOPort outputFileName; 202 203 /** 204 * The arguments to the command. Implemented as a multi/input port to 205 * support more than one argument. It concatanates the inputs in all the 206 * channels. 207 */ 208 public TypedIOPort arguments; 209 210 /** 211 * The trigger port. 212 */ 213 public TypedIOPort trigger; 214 215 /** 216 * The output file path, if exists. 217 */ 218 public TypedIOPort outfileHandle; 219 /** 220 * The result stream of the command. 221 */ 222 public TypedIOPort output; 223 // ** exitCode will be 1 if the command executes successfully. 224 // */ 225 // public TypedIOPort exitCode; 226 /** 227 * If selected, broadcasts the output of the command line by line. 228 */ 229 public Parameter outputLineByLine; 230 231 /** 232 * Unhide the trigger port when this parameter is true. This Parameter is 233 * type of boolean. NOTE: in fact, user can use the port configuration 234 * window to hide or unhide a port. This paremeter is here to provide a more 235 * intuitive interface for this actor. 236 */ 237 public Parameter hasTrigger; 238 239 // ///////////////////////////////////////////////////////////////// 240 // // public methods //// 241 242 /** 243 * If the specified attribute is <i>showTriggerPort</i>, then get the value 244 * of it and re-render the trigger port. If it is true, show the trigger 245 * port; if it is false, hide the trigger port. 246 * 247 * @param attribute 248 * The attribute that has changed. 249 * @exception IllegalActionException. 250 */ 251 public void attributeChanged(Attribute attribute) 252 throws IllegalActionException { 253 if (attribute == hasTrigger) { 254 _triggerFlag = ((BooleanToken) hasTrigger.getToken()) 255 .booleanValue(); 256 _debug("<TRIGGER_FLAG>" + _triggerFlag + "</TRIGGER_FLAG>"); 257 if (_triggerFlag) { 258 hide.setToken(BooleanToken.FALSE); 259 } else { 260 List inPortList = this.inputPortList(); 261 Iterator ports = inPortList.iterator(); 262 while (ports.hasNext()) { 263 IOPort p = (IOPort) ports.next(); 264 if (p.isInput()) { 265 try { 266 if (p.getName().equals("trigger")) { 267 // new Attribute(trigger, "_hideName"); 268 // p.setContainer(null); 269 hide.setToken(BooleanToken.TRUE); 270 } 271 } catch (Exception e) { 272 throw new IllegalActionException(this, e 273 .getMessage()); 274 } 275 } 276 }// while 277 }// else 278 } else { 279 super.attributeChanged(attribute); 280 } 281 } 282 283 /** 284 * Sends a proxy command to be executed on SRB. 285 * 286 * @exception IllegalActionException 287 * If there is no director. 288 */ 289 public void fire() throws IllegalActionException { 290 291 if (_triggerFlag) { 292 List inPortList = this.inputPortList(); 293 Iterator ports = inPortList.iterator(); 294 while (ports.hasNext()) { 295 IOPort p = (IOPort) ports.next(); 296 if (p.getName().equals("trigger")) { 297 if (p.getWidth() > 0) { 298 for (int i = 0; i < p.getWidth(); i++) { 299 p.get(0); 300 } 301 } 302 } 303 } 304 } 305 // make sure there is an alive connection. 306 try { 307 srbFileSystem.getHost(); 308 } catch (Exception ex) { // connection was closed. 309 srbFileSystem = null; 310 ObjectToken SRBConOT = null; 311 try { // try to get a new connection in case the previous one has 312 // terminated. 313 SRBConOT = (ObjectToken) SRBFileSystem.get(0); 314 } catch (NoTokenException ntex) { 315 } 316 if (SRBConOT != null) { 317 srbFileSystem = (SRBFileSystem) SRBConOT.getValue(); 318 } 319 } 320 if (srbFileSystem == null) { 321 throw new IllegalActionException(this, 322 "No SRB connection available in actor " + this.getName() 323 + "."); 324 } 325 326 _lineFlag = ((BooleanToken) outputLineByLine.getToken()).booleanValue(); 327 _debug("<TRIGGER_FLAG>" + _lineFlag + "</TRIGGER_FLAG>"); 328 329 if (command.getWidth() > 0) { 330 commandParameter.setExpression(((StringToken) command.get(0)) 331 .stringValue()); 332 } 333 334 _commandStr = ((StringToken) commandParameter.getToken()).stringValue(); 335 336 String argString = ""; 337 int i = 0; 338 int width = arguments.getWidth(); 339 for (i = 0; i < width; i++) { 340 if (arguments.hasToken(i)) { 341 String argument = ((StringToken) arguments.get(i)) 342 .stringValue(); 343 _debug("arguments(i) = " + argument); 344 345 while (argument.indexOf("\\\"") != -1) { 346 int ind = argument.indexOf("\\\""); 347 argument = argument.substring(0, ind) 348 + argument.substring(ind + 1, argument.length()); 349 _debug(argument); 350 } 351 argString += argument + " "; 352 _debug("argString = " + argString); 353 } 354 } 355 356 StringBuffer outBuff = new StringBuffer(""); 357 DataInputStream inStream = null; 358 OutputStream out = null; 359 byte[] bytesRead = new byte[20000]; 360 ; 361 int nBytesRead; 362 String outFilePath = ""; 363 try { 364 if (outputFileName.getWidth() > 0) { 365 String outFileName = ((StringToken) outputFileName.get(0)) 366 .stringValue(); 367 outputFile.setExpression(outFileName); 368 } 369 // opening output file stream 370 if (!outputFile.getExpression().equals("")) { 371 outFilePath = outputFile.asURL().toString(); 372 File outFile = outputFile.asFile(); 373 File parent = outFile.getParentFile(); 374 if (!parent.exists()) { 375 if (!MessageHandler.yesNoQuestion("OK to create directory " 376 + parent.getAbsolutePath() + "?")) { 377 srbFileSystem = SRBUtil.closeConnection(srbFileSystem); 378 throw new IllegalActionException(this, 379 "Please select another output directory name."); 380 } 381 } 382 383 parent.mkdirs(); 384 if (outFile.exists()) { 385 if (!MessageHandler.yesNoQuestion("OK to overwrite " 386 + outFilePath + "?")) { 387 srbFileSystem = SRBUtil.closeConnection(srbFileSystem); 388 throw new IllegalActionException(this, 389 "Please select another output file name."); 390 } 391 } 392 393 out = new FileOutputStream(outFile); 394 } 395 396 // Executing the proxy command. 397 try { 398 inStream = (DataInputStream) srbFileSystem.executeProxyCommand( 399 _commandStr, argString); 400 } catch (IOException ioex) { 401 srbFileSystem = SRBUtil.closeConnection(srbFileSystem); 402 ioex.printStackTrace(); 403 throw new IllegalActionException(this, 404 "Failed to execute SRB proxy command " + _commandStr 405 + "in actor " + this.getName() + ": " 406 + ioex.getMessage() + "."); 407 } 408 409 // processing the result. 410 nBytesRead = inStream.read(bytesRead); 411 while (nBytesRead > 0) { 412 // if there is a specified file, write to it. 413 if (out != null) { 414 out.write(bytesRead, 0, nBytesRead); 415 } 416 // append binary result to a string buffer. 417 outBuff.append(new String(bytesRead, 0, nBytesRead)); 418 nBytesRead = inStream.read(bytesRead); 419 } 420 if (out != null) 421 out.close(); 422 423 // process string result. 424 if (_lineFlag) { // output each line separately. 425 BufferedReader br = new BufferedReader(new StringReader(outBuff 426 .toString())); 427 String line; 428 while ((line = br.readLine()) != null) { 429 output.broadcast(new StringToken(line)); 430 } 431 // output the whole result string at once. 432 } else { 433 output.broadcast(new StringToken(outBuff.toString())); 434 } 435 } catch (IOException ioe) { 436 srbFileSystem = SRBUtil.closeConnection(srbFileSystem); 437 _debug("<IOException> when reading the input: " + ioe 438 + "</IOException>"); 439 throw new IllegalActionException(this, 440 "IOException when reading the input: " + ioe); 441 } 442 443 // output out file handle if exists. 444 if (!outFilePath.equals("")) { 445 outfileHandle.broadcast(new StringToken(outFilePath)); 446 } 447 } 448 449 /** 450 * Initialize the srb file system to null. 451 */ 452 public void initialize() throws IllegalActionException { 453 super.initialize(); 454 srbFileSystem = null; 455 } 456 457 /** 458 * Disconnect from SRB. 459 */ 460 public void wrapup() { 461 srbFileSystem = SRBUtil.closeConnection(srbFileSystem); 462 } 463 464 // //////////////////////////////////////////////////////////////////// 465 // // private variables //// 466 467 /** 468 * Command to be executed. 469 */ 470 private String _commandStr = ""; 471 472 /** 473 * Indicator to output each line separately. 474 */ 475 private boolean _lineFlag = false; 476 477 /** 478 * Has trigger indicator 479 */ 480 private boolean _triggerFlag = false; 481 // private int _charsToSkip = 6; 482 483 /** 484 * An srb file system variable. 485 */ 486 private SRBFileSystem srbFileSystem = null; 487}