001/* 002 * Copyright (c) 2003-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2015-08-24 22:48:48 +0000 (Mon, 24 Aug 2015) $' 007 * '$Revision: 33634 $' 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 030//implements WmsdActor, which allows Kepler to control the wmsd system (in wmsd.jar at time of writing), which submits Encyclopedia of Life (EOL) tasks via APST system. 031//EOL uses the Grid to predict 3D protein structures on entire genomes from homologous experimentally solved structures in support of rational drug design, ultimately in support of the pharmaceutical industry 032//This extremely CPU-intensive process is considered "embarrassingly parallel" and thus an excellent application for the computational grid. 033//Modeled protein structures are stored in an on-line, Internet accessible database. 034//See more about the Encyclopedia of Life project at SDSC at http://eol.sdsc.edu 035 036package org.eol; 037 038import java.sql.Connection; 039import java.util.ArrayList; 040 041import org.geon.DBConnectionToken; 042 043import edu.sdsc.eol.EolLog; 044import edu.sdsc.eol.Wmsd; 045import ptolemy.actor.TypedAtomicActor; 046import ptolemy.actor.TypedIOPort; 047import ptolemy.data.BooleanToken; 048import ptolemy.data.StringToken; 049import ptolemy.data.expr.FileParameter; 050import ptolemy.data.expr.Parameter; 051import ptolemy.data.expr.StringParameter; 052import ptolemy.data.type.BaseType; 053import ptolemy.kernel.CompositeEntity; 054import ptolemy.kernel.util.IllegalActionException; 055import ptolemy.kernel.util.NameDuplicationException; 056 057/** 058 * Description of the Class 059 */ 060public class WmsdActor extends TypedAtomicActor { 061 /** 062 * Construct an actor with the given container and name. 063 * 064 * @param container 065 * The container. 066 * @param name 067 * The name of this actor. 068 * @exception IllegalActionException 069 * If the actor cannot be contained by the proposed 070 * container. 071 * @exception NameDuplicationException 072 * If the container already has an actor with this name. 073 * @since 074 */ 075 076 // inputs 077 public TypedIOPort dbcon = new TypedIOPort(this, "dbcon", true, false); // wmsd 078 079 // bookkeeping 080 // database 081 082 public TypedIOPort categoryDatabaseName = new TypedIOPort(this, 083 "categoryDatabaseName", true, false); 084 085 public TypedIOPort sourceLabel = new TypedIOPort(this, "sourceLabel", true, 086 false); 087 088 // outputs 089 public TypedIOPort trigger = new TypedIOPort(this, "trigger", false, true); 090 091 public TypedIOPort output_log = new TypedIOPort(this, "output_log", false, 092 true); 093 094 public Parameter createDB = new Parameter(this, "CREATE_DB", 095 new BooleanToken(false)); 096 097 public Parameter init_apstd = new Parameter(this, "INIT_APSTD", 098 new BooleanToken(false)); 099 100 public Parameter dbPrefix = new StringParameter(this, "DB_PREFIX"); 101 102 public Parameter apstdHostColonPort = new StringParameter(this, 103 "APSTD_HOST_COLON_PORT"); 104 105 public FileParameter tmp_dir = new FileParameter(this, "TMP_DIR"); 106 107 public Parameter scp_user = new StringParameter(this, "SCP_USER"); 108 109 public Parameter scp_server = new StringParameter(this, "SCP_SERVER"); // Null 110 111 // OK 112 113 public Parameter scp_invoke_string = new StringParameter(this, 114 "SCP_INVOKE_STRING"); 115 116 public FileParameter resource_xml_file_name = new FileParameter(this, 117 "RESOURCE_XML_FILE_NAME"); 118 119 public FileParameter application_xml_file_name = new FileParameter(this, 120 "APPLICATION_XML_FILE_NAME"); 121 122 public Parameter enough_tasks = new Parameter(this, "ENOUGH_TASKS"); 123 124 public Parameter tasks_per_update = new Parameter(this, "TASKS_PER_UPDATE"); 125 126 // Until the DBconnect actor is fixed, when we won't need these anymore. 127 public Parameter db_jdbc_connection_string = new StringParameter(this, 128 "DB_JDBC_CONNECTION_STRING"); 129 130 public Parameter db_username = new StringParameter(this, "DB_USERNAME"); 131 132 public Parameter db_password = new StringParameter(this, "DB_PASSWORD"); 133 134 private String DB_PREFIX; 135 136 private String APSTD_HOST_COLON_PORT, TMP_DIR, SCP_USER, SCP_SERVER, 137 SCP_INVOKE_STRING; 138 139 private String RESOURCE_XML_FILE_NAME, APPLICATION_XML_FILE_NAME, 140 TASKS_PER_UPDATE, ENOUGH_TASKS; 141 142 // Only needed if DBconnection input isn't provided, which happened during 143 // testing because DBconnection was broken, or at least configuration 144 // was broken. 145 146 private String DB_JDBC_CONNECTION_STRING, DB_USERNAME, DB_PASSWORD; 147 148 public WmsdActor(CompositeEntity container, String name) 149 throws NameDuplicationException, IllegalActionException { 150 151 super(container, name); 152 153 // make these booleans radio buttons 154 createDB.setTypeEquals(BaseType.BOOLEAN); 155 attributeChanged(createDB); 156 157 init_apstd.setTypeEquals(BaseType.BOOLEAN); 158 attributeChanged(init_apstd); 159 160 enough_tasks.setTypeEquals(BaseType.INT); 161 attributeChanged(enough_tasks); 162 163 tasks_per_update.setTypeEquals(BaseType.INT); 164 attributeChanged(tasks_per_update); 165 166 dbcon.setTypeEquals(DBConnectionToken.DBCONNECTION); 167 168 categoryDatabaseName.setTypeEquals(BaseType.STRING); 169 sourceLabel.setTypeEquals(BaseType.STRING); 170 171 trigger.setTypeEquals(BaseType.STRING); 172 output_log.setTypeEquals(BaseType.STRING); 173 174 } 175 176 /** 177 * initialize 178 * 179 * @throws IllegalActionException 180 */ 181 public void initialize() throws IllegalActionException { 182 // WGK: this is the way others do it, but one can imagine 183 // an object that acts as an array encapsulating Parameter, 184 // private String, and string descriptor, and a loop here. 185 // More elegant, less verbose, less prone to bugs. 186 187 DB_JDBC_CONNECTION_STRING = dequoteAndLog(db_jdbc_connection_string, 188 "DB_JDBC_CONNECTION_STRING"); 189 DB_USERNAME = dequoteAndLog(db_username, "DB_USERNAME"); 190 DB_PASSWORD = dequoteAndLog(db_password, "DB_PASSWORD"); 191 DB_PREFIX = dequoteAndLog(dbPrefix, "DB_PREFIX"); 192 APSTD_HOST_COLON_PORT = dequoteAndLog(apstdHostColonPort, 193 "APSTD_HOST_COLON_PORT"); 194 SCP_USER = dequoteAndLog(scp_user, "SCP_USER"); 195 SCP_SERVER = dequoteAndLog(scp_server, "SCP_SERVER"); 196 SCP_INVOKE_STRING = dequoteAndLog(scp_invoke_string, 197 "SCP_INVOKE_STRING"); 198 199 if (resource_xml_file_name.getToken() != null) { 200 RESOURCE_XML_FILE_NAME = resource_xml_file_name.asFile().toString(); 201 writeLogLn("RESOURCE_XML_FILE_NAME: " + RESOURCE_XML_FILE_NAME); 202 } 203 204 if (application_xml_file_name.getToken() != null) { 205 APPLICATION_XML_FILE_NAME = application_xml_file_name.asFile() 206 .toString(); 207 writeLogLn("APPLICATION_XML_FILE_NAME: " 208 + APPLICATION_XML_FILE_NAME); 209 } 210 211 if (tmp_dir.getToken() != null) { 212 TMP_DIR = tmp_dir.asFile().toString(); 213 writeLogLn("TMP_DIR: " + TMP_DIR); 214 } 215 216 if (enough_tasks.getToken() != null) { 217 // Integer type. 218 ENOUGH_TASKS = enough_tasks.getToken().toString(); 219 writeLogLn("ENOUGH_TASKS: " + ENOUGH_TASKS); 220 } 221 222 if (tasks_per_update.getToken() != null) { 223 // Integer type. 224 TASKS_PER_UPDATE = tasks_per_update.getToken().toString(); 225 writeLogLn("TASKS_PER_UPDATE: " + TASKS_PER_UPDATE); 226 } 227 228 if (DB_PREFIX == null || TMP_DIR == null || SCP_USER == null 229 || RESOURCE_XML_FILE_NAME == null 230 || APPLICATION_XML_FILE_NAME == null 231 || SCP_INVOKE_STRING == null || APSTD_HOST_COLON_PORT == null) { 232 throw new IllegalActionException( 233 "The parameters CREATE_DB, DB_PREFIX, APSTD_HOST_COLON_PORT " 234 + "TMP_DIR, SCP_USER, SCP_INVOKE_STRING, INIT_APSTD must have valid values. CREATE_DB specifies whether to create bookkeeping database tables must be TRUE or FALSE." 235 + "DB_PREFIX gives the wmsd bookkeeping database table prefixes." 236 + "APST_HOST_COLON_PORT is gives the host and port (separated by a colon)" 237 + "where an apstd is listening. (Typically localhost:6660). SCP_INVOKE_STRING provides the local path and command arguments (e.g. identity file) that will be used to start scp. SCP_USER gives the username to be used to scp/ssh login on the apstd host. SCP_SERVER, optional, gives the SCP server when it is different from the apstd connection (due to, say, ssh port forwarding as a result of a firewall.) INIT_APSTD must be TRUE or FALSE, and specifies whether to clear the Apstd and load in the resource file. TMP_DIR gives the name of a temporary directory on the local machine (required)." 238 + "RESOURCE_XML_FILE_NAME must be set to the local location of the XML computation resources file in APSTD format. APPLICATION_XML_FILE_NAME species in the XML file (in WMSD pseudo-Apstd task format) that gives the per-protein and per-genome tasks to be submitted, with variable substitution. ENOUGH_TASKS (optional) specifies the maximum number of tasks apst is allowed to run at any given time --- set larger than cpus in the cluster. TASKS_PER_UPDATE (optional) specifies the max submitted to apstd at any given time. Please provide these values and re-execute."); 239 } 240 241 } 242 243 /** 244 * @return Description of the Returned Value 245 * @exception IllegalActionException 246 * Description of Exception 247 * @since 248 */ 249 public boolean prefire() throws IllegalActionException { 250 return super.prefire(); 251 } 252 253 /** 254 * Send a random number with a uniform distribution to the output. This 255 * number is only changed in the prefire() method, so it will remain 256 * constant throughout an iteration. 257 * 258 * @exception IllegalActionException 259 * If there is no director. 260 * @since 261 */ 262 public void fire() throws IllegalActionException { 263 writeLogLn("firing Wmsd Actor"); 264 super.fire(); 265 266 // convert inputs to string types 267 268 String categoryDatabaseNameStr = ((StringToken) categoryDatabaseName 269 .get(0)).stringValue(); 270 String sourceLabelStr = ((StringToken) sourceLabel.get(0)) 271 .stringValue(); 272 273 ArrayList atemp = new ArrayList(); 274 275 // String createDbOption = "--create_db"; 276 277 String[] argsTemp = { "--resources", RESOURCE_XML_FILE_NAME, 278 "--applications", APPLICATION_XML_FILE_NAME, "--apstcontact", 279 APSTD_HOST_COLON_PORT, "--category", categoryDatabaseNameStr, 280 "--source", sourceLabelStr, "--dbprefix", DB_PREFIX, 281 "--tmpdir", TMP_DIR, "--scp_user", SCP_USER, 282 "--scp_invoke_string", SCP_INVOKE_STRING, }; 283 // convert to ArrayList because Java doesn't support dynamic array sizes 284 for (int i = 0; i < argsTemp.length; i++) { 285 atemp.add(argsTemp[i]); 286 } 287 288 if (((BooleanToken) createDB.getToken()).booleanValue() == true) { 289 // we've already tested that this is either true or false. 290 // if it is true, the default value above is used. 291 atemp.add("--create_db"); 292 } 293 294 if (((BooleanToken) init_apstd.getToken()).booleanValue() == true) { 295 // we've already tested that this is either true or false. 296 // if it is true, the default value above is used. 297 atemp.add("--init_apstd"); 298 } 299 300 if (SCP_SERVER != null && !SCP_SERVER.equals("")) { 301 atemp.add("--scp_server"); 302 atemp.add(SCP_SERVER); 303 } 304 305 if (ENOUGH_TASKS != null) { 306 ENOUGH_TASKS = (new Integer(ENOUGH_TASKS)).toString(); // make sure 307 // integer 308 // value. 309 atemp.add("--enough_tasks"); 310 atemp.add(ENOUGH_TASKS); 311 } 312 313 if (TASKS_PER_UPDATE != null) { 314 TASKS_PER_UPDATE = (new Integer(TASKS_PER_UPDATE)).toString(); // make 315 // sure 316 // integer 317 // value. 318 atemp.add("--tasks_per_update"); 319 atemp.add(TASKS_PER_UPDATE); 320 } 321 322 try { 323 Wmsd wm = null; 324 if (dbcon.numberOfSources() > 0 && dbcon.hasToken(0)) { 325 String[] args = (String[]) atemp.toArray(new String[atemp 326 .size()]); 327 328 DBConnectionToken _dbcon = (DBConnectionToken) dbcon.get(0); 329 Connection _con; 330 try { 331 _con = _dbcon.getValue(); 332 333 } catch (Exception e) { 334 throw new IllegalActionException(this, e, 335 "CONNECTION FAILURE"); 336 } 337 338 wm = new Wmsd(args, _con); 339 340 } else { 341 // DB connect broken, user putting in db parameters manually. 342 // :-( 343 // this stuff will be eliminated once DBconnect actor is again 344 // working reliably. 345 346 if (DB_JDBC_CONNECTION_STRING == null || DB_USERNAME == null 347 || DB_PASSWORD == null) { 348 throw new IllegalActionException( 349 "In the absence of an DBconnect input, DB_JDBC_CONNECTION_STRING, DB_USERNAME, DB_PASSWORD must not be null but provide the db connection parameters for the Wmsd bookkeeping database."); 350 } 351 atemp.add("--dbhost"); 352 atemp.add(DB_JDBC_CONNECTION_STRING); 353 atemp.add("--dbuser"); 354 atemp.add(DB_USERNAME); 355 atemp.add("--dbpassword"); 356 atemp.add(DB_PASSWORD); 357 358 String[] args = (String[]) atemp.toArray(new String[atemp 359 .size()]); 360 wm = new Wmsd(args); 361 } 362 wm.run(); 363 364 } catch (Exception e) { 365 e.printStackTrace(); 366 throw new IllegalActionException("Unexpected error: " 367 + e.getMessage()); 368 } 369 370 copyToLog(EolLog.getAndClearOutData()); 371 broadcastToLog(); 372 373 trigger.broadcast(new StringToken(categoryDatabaseNameStr)); 374 writeLogLn("Wmsd Actor done"); 375 376 } 377 378 private void writeLogLn(String msg) { 379 System.out.println(msg); 380 copyToLog(msg + "\n"); 381 } 382 383 private String logString = null; 384 385 private void copyToLog(String msg) { 386 if (logString == null) { 387 logString = new String(); 388 } 389 logString += msg; 390 } 391 392 private void broadcastToLog() { 393 if (logString != null) { 394 try { 395 output_log.broadcast(new StringToken(logString)); 396 } catch (IllegalActionException e) { 397 e.printStackTrace(); 398 } 399 } 400 } 401 402 private String dequote(String mystring) { 403 return (mystring.substring(1, mystring.length() - 1)); 404 } 405 406 private String dequoteAndLog(String mystring, String name) { 407 mystring = dequote(mystring); 408 writeLogLn(name + ": " + mystring); 409 return (mystring); 410 } 411 412 private String dequoteAndLog(Parameter myparm, String name) 413 throws IllegalActionException { 414 if (myparm.getToken() != null) { 415 // only fix and print if not equal to null. 416 String mystring = ((StringToken) myparm.getToken()).toString(); 417 return (dequoteAndLog(mystring, name)); 418 } 419 return (null); 420 } 421 422}