001/* 002 * Copyright (c) 2008-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2016-04-21 05:45:00 +0000 (Thu, 21 Apr 2016) $' 007 * '$Revision: 34479 $' 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.kepler; 031 032import java.io.File; 033import java.io.FileReader; 034import java.io.IOException; 035import java.lang.reflect.InvocationTargetException; 036import java.lang.reflect.Method; 037import java.net.URISyntaxException; 038import java.net.URL; 039import java.util.ArrayList; 040import java.util.Arrays; 041import java.util.Collection; 042import java.util.Enumeration; 043import java.util.Hashtable; 044import java.util.Iterator; 045import java.util.LinkedList; 046import java.util.List; 047import java.util.ResourceBundle; 048import java.util.StringTokenizer; 049 050import javax.swing.UIManager; 051 052import org.apache.commons.lang.exception.ExceptionUtils; 053import org.apache.commons.logging.Log; 054import org.apache.commons.logging.LogFactory; 055import org.apache.tools.ant.Project; 056import org.kepler.build.MakeKars; 057import org.kepler.build.modules.Module; 058import org.kepler.build.modules.ModuleTree; 059import org.kepler.build.project.ProjectLocator; 060import org.kepler.build.project.RepositoryLocations; 061import org.kepler.configuration.ConfigurationManager; 062import org.kepler.configuration.ConfigurationProperty; 063import org.kepler.gui.SplashWindow; 064import org.kepler.loader.PermissionManager; 065import org.kepler.loader.SystemPropertyLoader; 066import org.kepler.loader.util.Screenshot; 067import org.kepler.module.ModuleHSQLManager; 068import org.kepler.module.ModuleInitializer; 069import org.kepler.modulemanager.gui.patch.PatchChecker; 070import org.kepler.moml.NamedObjId; 071import org.kepler.sms.util.OntologyConfiguration; 072import org.kepler.util.DotKeplerManager; 073import org.kepler.util.FileUtil; 074import org.kepler.util.RunnableExecutionQueue; 075import org.kepler.util.ShutdownListener; 076import org.kepler.util.ShutdownNotifier; 077import org.kepler.util.StatusListener; 078import org.kepler.util.StatusNotifier; 079 080import ptolemy.actor.injection.ActorModuleInitializer.Initializer; 081import ptolemy.actor.injection.PtolemyInjector; 082import ptolemy.actor.injection.PtolemyModule; 083import ptolemy.kernel.util.IllegalActionException; 084import ptolemy.moml.filter.BackwardCompatibility; 085import ptolemy.util.FileUtilities; 086import ptolemy.vergil.VergilApplication; 087 088/** 089 * A class to initialize the build system, then start the Kepler GUI or execute 090 * workflows from the command line. In the latter case, command line arguments 091 * specify different run time configurations. 092 * 093 * @author Chad Berkely, Daniel Crawl, David Welker 094 * @version $Id: Kepler.java 34479 2016-04-21 05:45:00Z crawl $ 095 */ 096 097public class Kepler { 098 099 public static void restart() { 100 main(_args); 101 } 102 103 public static void main(String[] args) { 104 105 // print status updates to stdout 106 StatusNotifier.addStatusListener(new StatusListener() { 107 @Override 108 public void log(String message) { 109 System.out.println(message); 110 } 111 }); 112 113 //System.out.println("java.library.path = " + System.getProperty("java.library.path")); 114 115 // log4j uses the first log4j.properties file found on the classpath. 116 // since kepler's classpath is complicated, it is not always obvious 117 // which log4j.properties is used; it may be hidden in a jar file. 118 // this prints the log4j.properties file found on the classpath. 119 File log4jFile = FileUtilities.nameToFile("$CLASSPATH/log4j.properties", null); 120 if(log4jFile == null) { 121 System.out.println("log4j.properties not found in CLASSPATH."); 122 } else { 123 System.out.println("log4j.properties found in CLASSPATH: " + log4jFile); 124 } 125 126 127 // run command line arguments module initializers to set command 128 // line arguments specific to modules. 129 try { 130 _initializeCommandLineArguments(); 131 } catch (Exception e) { 132 System.out.println("Error initializing module command line arguments: " + e.getMessage()); 133 return; 134 } 135 136 // Save the args in case they are needed later. 137 // long startTime = System.currentTimeMillis(); 138 _args = args; 139 CommandLineArgs.store(args); 140 List<String> argList = Arrays.asList(args); 141 142 // parse the command line arguments 143 if(!parseArgs(args)) { 144 // an error occurred, so exit. 145 return; 146 } 147 148 // set the repository location from the module manager configuration file. 149 RepositoryLocations 150 .setReleaseLocation(org.kepler.modulemanager.RepositoryLocations 151 .getReleaseLocation()); 152 153 ModuleTree.init(); 154 155 // use headless mode if kepler is running without a gui. 156 // this is necessary since the DISPLAY environment variable 157 // may be set to an incorrect value, and by default java does 158 // not use headless mode if DISPLAY is set. 159 if(!_runWithGui) { 160 System.setProperty("java.awt.headless", "true"); 161 } else if(UIManager.getLookAndFeel().getName().startsWith("Mac OS")) { 162 System.setProperty("apple.laf.useScreenMenuBar", "true"); 163 System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Kepler"); 164 } 165 166 167 /* Do not check for patches if running workflows from the command 168 * line since this can occur many times and checking slows down 169 * startup time. 170 171 // if we are executing a workflow from the command line, check now for 172 // patches. 173 if(_action == Action.RunKAR || _action == Action.RunWf) { 174 // if we are running headless, do not display a dialog if patches 175 // are available 176 if (!_runWithGui || _displayRedirectOutputPath != null) { 177 PatchChecker.check(true); 178 } else { 179 PatchChecker.check(false); 180 } 181 // show the splash if the Kepler UI is starting 182 } else*/ 183 if(_action == Action.Kepler && _showSplash) { 184 _showSplash(); 185 } 186 187 ShutdownNotifier.addShutdownListener(new Shutdown()); 188 try { 189 190 setJavaPropertiesAndCopyModuleDirectories(); 191 192 // System.out.println("os: " + System.getProperty("os.name")); 193 String OSName = System.getProperty("os.name"); 194 195 // Hashtable properties = getProject().getProperties(); 196 ModuleTree moduleTree = ModuleTree.instance(); 197 198 String classpath = System.getProperty("java.class.path"); 199 String[] classpathItems = classpath.split(File.pathSeparator); 200 201 for (Module module : moduleTree) { 202 203 // XXX since Module dir variables can be wrong, utilizing classpath 204 // to determine module location on disk. Use below line instead when 205 // that's fixed. 206 //File osextension = new File(module.getModuleInfoDir() + File.separator + "osextension.txt"); 207 File osextension = null; 208 String sought = File.separator + module.getName() + File.separator; 209 for (String path: classpathItems){ 210 // must check each match since parent path could possibly have a module name 211 // in it (don't break on first): 212 if (path.contains(sought)){ 213 int lastIndex = path.lastIndexOf(sought); 214 String p = path.substring(0, lastIndex); 215 p = p.concat(sought + "module-info" + 216 File.separator + "osextension.txt"); 217 osextension = new File(p); 218 if (osextension.exists()){ 219 break; 220 } 221 } 222 } 223 if (osextension == null || !osextension.exists()){ 224 continue; 225 } 226 227 if(_isDebugging) { 228 log.debug("Found OS Extension file: " 229 + osextension.getAbsolutePath()); 230 } 231 Hashtable<String, String> properties = readOSExtensionFile(osextension); 232 Enumeration<String> keys = properties.keys(); 233 while (keys.hasMoreElements()) { 234 String extClass = keys.nextElement(); 235 String os = properties.get(extClass); 236 if (OSName.trim().equals(os.trim())) { 237 // if we're in an OS that an extension 238 // needs to be loaded for attempt to load 239 // the OSExtension via reflection 240 // and run the addOSExtension method 241 242 Class<?> c = Class.forName(extClass); 243 try { 244 OSExtension extension = (OSExtension) c 245 .newInstance(); 246 extension.addOSExtensions(); 247 if(_isDebugging) { 248 log.debug("loading OS extensions for OS " 249 + os + " with class " + extClass); 250 } 251 } catch (ClassCastException cce) { 252 // System.out.println(extClass + 253 // " is not an instance of OSExtension"); 254 } 255 } 256 } 257 } 258 259 Project project = new Project(); 260 File projDir = ProjectLocator.getProjectDir(); 261 project.setBaseDir(projDir); 262 263 // set the ProjectLocator ant project if it's not already set. 264 // this prevents ProjectLocator.getAntProject() from returning null 265 if(ProjectLocator.getAntProject() == null) { 266 ProjectLocator.setAntProject(project); 267 } 268 269 //_setOntologyIndexFile(); 270 271 272 if (!argList.contains("-runwf")) { 273 // Allow developers to turn off MakeKars by creating 274 // a file called "skipMakeKars" in the project root 275 File skipMakeKars = new File(projDir, "skipMakeKars"); 276 if (!skipMakeKars.exists()) { 277 MakeKars kar = new MakeKars(); 278 kar.setProject(project); 279 kar.init(); 280 kar.run(); 281 } 282 } 283 284 PermissionManager.makeNativeLibsExecutable(); 285 // CreateIntroFileTask createIntroFileTask = new 286 // CreateIntroFileTask(); 287 // createIntroFileTask.execute(); 288 289 } catch (URISyntaxException e) { 290 e.printStackTrace(); 291 } catch (IOException e) { 292 e.printStackTrace(); 293 } catch (Exception e) { 294 e.printStackTrace(); 295 } 296 297 int rc = runApplication(); 298 299 if(rc != 0) { 300 System.exit(rc); 301 } 302 303 // System.exit(0); 304 305 // long endTime = System.currentTimeMillis(); 306 // System.out.println( (endTime-startTime)/1000.0 ); 307 308 309 RunnableExecutionQueue.execute(); 310 311 } 312 313 public static void setOntologyIndexFile() { 314 OntologyConfiguration oc = OntologyConfiguration.instance(); 315 File f = FileUtil 316 .getHighestRankedFile("configs/ptolemy/configs/kepler/ontologies/ontology_catalog.xml"); 317 oc.setIndexFile(f); 318 oc.initialize(); 319 } 320 321 /** 322 * Parse the command line arguments and run the appropriate application. 323 * @return If true, no error occurred parsing the arguments. 324 */ 325 public static boolean parseArgs(String[] args) { 326 327 try { 328 // parse the switches and remaining arguments 329 for (int i = 0; i < args.length; i++) { 330 if (args[i].equals("-runwf")) { 331 _action = Action.RunWf; 332 } else if (args[i].equals("-runkar")) { 333 _action = Action.RunKAR; 334 } else if (args[i].equals("-nogui")) { 335 _assertRunWF(args[i]); 336 _runWithGui = false; 337 } else if (args[i].equals("-nocache")) { 338 _assertRunWF(args[i]); 339 _runWithCache = false; 340 } else if (args[i].equals("-nosplash")) { 341 _showSplash = false; 342 } else if (args[i].equals("-noexit")) { 343 _runThenExitNoGui = false; 344 } else if (args[i].equals("-gui")) { 345 _assertRunWF(args[i]); 346 _runWithGui = true; 347 } else if (args[i].equals("-cache")) { 348 _assertRunWF(args[i]); 349 _runWithCache = true; 350 } else if (args[i].equals("-vergil")) { 351 _action = Action.Vergil; 352 } else if (args[i].equals("-createActorXML")) { 353 _action = Action.CreateActorXML; 354 _runWithGui = false; 355 } else if (args[i].equals("-hsql")) { 356 if(_action != Action.Kepler) { 357 throw new IllegalArgumentException("ERROR: -hsql may not be used with " + 358 _action.getArg()); 359 } 360 361 i++; 362 if(i == args.length) { 363 throw new IllegalArgumentException("ERROR: must specify -hsql start or -hsql stop."); 364 } 365 366 if(args[i].equals("start")) { 367 _action = Action.HSQLStart; 368 } else if(args[i].equals("stop")) { 369 _action = Action.HSQLStop; 370 } else { 371 throw new IllegalArgumentException("ERROR: must specify -hsql start or -hsql stop."); 372 } 373 } else if (args[i].equals("-force")) { 374 _forceOpen = true; 375 } else if (args[i].equals("-noilwc")) { 376 NamedObjId.incrementLSIDOnWorkflowChange(false); 377 } else if (args[i].equals("-updateActorDocs")) { 378 _action = Action.UpdateActorDocs; 379 _runWithGui = false; 380 } else if (args[i].equals("-h") || args[i].equals("-help")) { 381 _showHelp(); 382 return false; 383 } 384 // NOTE: -redirectdisplay is kept for backwards-compatibility 385 else if(args[i].equals("-redirectgui") || args[i].equals("-redirectdisplay")){ 386 _assertRunWF(args[i]); 387 _runWithGui = false; 388 if (i >= args.length) { 389 throw new IllegalArgumentException("ERROR: cannot set " 390 + "redirectgui argument because no redirect dir for display actors is " 391 + "given."); 392 } 393 _displayRedirectOutputPath = new String(args[++i]); 394 if (!(new File(_displayRedirectOutputPath)).isDirectory()){ 395 throw new IllegalArgumentException("ERROR: cannot set " 396 + "redirectdisplay argument because the argument after '-redirectdisplay' is not a directory."); 397 } 398 } else if(args[i].equals("-screenshot")) { 399 _action = Action.MakeScreenShot; 400 i++; 401 _parseScreenShotArgs(args, i); 402 } else { 403 404 boolean foundParser = false; 405 for(CommandLineArgument arg: CommandLineArgument.getAll()) { 406 // see if we've already parsed it. 407 if(!arg.wasParsed()) { 408 int next = arg.parseRemainingArgs(args, i); 409 if(next >= 0) { 410 foundParser = true; 411 if(arg.isAction()) { 412 _action = Action.RunCustomAction; 413 _customActionClass = arg.getActionClass(); 414 _customActionMethod = arg.getActionMethod(); 415 } 416 // i is next - 1 since the for loop increments i. 417 i = next - 1; 418 // see if there are any more arguments left. 419 if(i >= args.length) { 420 break; 421 } 422 } 423 } 424 } 425 426 if(!foundParser) { 427 _applicationArgsList.add(args[i]); 428 } 429 } 430 } 431 } catch (IllegalArgumentException e) { 432 System.out.print(e.getMessage()); 433 return false; 434 } 435 436 return true; 437 438 } 439 440 /** Parse the command-line arguments for creating screenshots of workflows. 441 * @param args an array of command-line arguments 442 * @param i the index into command-line arguments array that points to the 443 * argument after "-screenshot" 444 */ 445 private static void _parseScreenShotArgs(String[] args, int i) { 446 447 // command-line usage for screenshots is: 448 // 449 // kepler -screenshot [-type png | jpg | gif] [-force] 450 // [-o output [output2 ...] | -odir directory] 451 // workflow.xml [workflow2.xml ...]"); 452 453 454 while(i < args.length) { 455 456 if(args[i].equals("-type")) { 457 i++; 458 if(i == args.length) { 459 throw new IllegalArgumentException("ERROR: must specify screen shot image type with -type argument."); 460 } 461 _screenShotType = args[i]; 462 } else if(args[i].equals("-force")) { 463 _screenShotForce = true; 464 } else if(args[i].equals("-odir")) { 465 if(_screenShotOutputs != null) { 466 throw new IllegalArgumentException("ERROR: cannot specify both -dir and -o with -screenshot."); 467 } 468 469 i++; 470 if(i == args.length) { 471 throw new IllegalArgumentException("ERROR: must specify output directory with -dir."); 472 } 473 474 _screenShotOutputDir = args[i]; 475 476 } else if(args[i].equals("-o")) { 477 if(_screenShotOutputDir != null) { 478 throw new IllegalArgumentException("ERROR: cannot specify both -dir and -o with -screenshot."); 479 } 480 481 i++; 482 if(i == args.length) { 483 throw new IllegalArgumentException("ERROR: must specify at least one output name with -o."); 484 } 485 486 _screenShotOutputs = new LinkedList<String>(); 487 while(i < args.length && !args[i].startsWith("-") && 488 // make sure it is not a workflow 489 !args[i].toLowerCase().endsWith(".xml") && 490 !args[i].toLowerCase().endsWith(".kar")) { 491 _screenShotOutputs.add(args[i]); 492 i++; 493 } 494 // decrement i since it will be incremented again before 495 // the loop restarts. 496 i--; 497 498 } else { 499 String name = args[i]; 500 File file = new File(name); 501 if(!file.exists()) { 502 throw new IllegalArgumentException("ERROR: workflow " + name + " does not exist."); 503 } 504 _screenShotWorkflows.add(name); 505 } 506 507 i++; 508 } 509 510 if(_screenShotWorkflows.isEmpty()) { 511 throw new IllegalArgumentException("ERROR: must specify at least one workflow with -screenshot."); 512 } 513 } 514 515 /** Run the appropriate application based on command line arguments. 516 * @return Returns 0 if success, 1 if there was an error. 517 */ 518 public static int runApplication() { 519 520 try { 521 522 if(_runWithCache) { 523 setOntologyIndexFile(); 524 } 525 526 // see if we're running the gui editor 527 if (_action == Action.Kepler) { 528 addActorModule("org/kepler/ActorModuleDefault"); 529 initialize(); 530 _applicationArgsList.addFirst("-kepler"); 531 String[] loadArgs = _applicationArgsList.toArray(new String[0]); 532 if(_showSplash) { 533 VergilApplication.main(loadArgs); 534 SplashWindow.disposeSplash(); 535 StatusNotifier.clearStatusListeners(); 536 } else { 537 VergilApplication.main(loadArgs); 538 } 539 540 // check for patches now that the UI has started. 541 PatchChecker.check(false); 542 543 } else if (_action == Action.Vergil) { 544 addActorModule("org/kepler/ActorModuleDefault"); 545 String[] loadArgs = _applicationArgsList.toArray(new String[0]); 546 VergilApplication.main(loadArgs); 547 } else if (_action == Action.RunWf || _action == Action.RunKAR) { 548 final String className = "org.kepler.KeplerConfigurationApplication"; 549 550 // if we are running a workflow from the cmd line and have 551 // the gui enabled, the program does not quit until the user 552 // enters control-c. 553 if(_runWithGui) { 554 _mustManuallyQuit = true; 555 } 556 addActorModule("org/kepler/ActorModuleDefault"); 557 if (_runWithGui && _runWithCache) { 558 _applicationArgsList.addFirst("-run"); 559 _applicationArgsList.addFirst("ptolemy/configs/kepler/ConfigGUIAndCache.xml"); 560 } else if (_runWithGui && !_runWithCache) { 561 _applicationArgsList.addFirst("-run"); 562 _applicationArgsList.addFirst("ptolemy/configs/kepler/ConfigGUINoCache.xml"); 563 } else if (!_runWithGui && _runWithCache) { 564 String spec; 565 if (_displayRedirectOutputPath != null){ 566 //add display redirection filter 567 BackwardCompatibility.addFilter(new au.edu.jcu.kepler.hydrant.DisplayRedirectFilter(_displayRedirectOutputPath)); 568 addActorModule("org/kepler/ActorModuleBatch"); 569 spec = "ptolemy/configs/kepler/ConfigRedirectGUIWithCache.xml"; 570 } else { 571 spec = "ptolemy/configs/kepler/ConfigNoGUIWithCache.xml"; 572 } 573 if(_runThenExitNoGui) { 574 _applicationArgsList.addFirst("-runThenExit"); 575 } 576 _applicationArgsList.addFirst(spec); 577 // ConfigurationApplication.readConfiguration(ConfigurationApplication.specToURL(spec)); 578 } else { // if(!gui && !cache) 579 String spec; 580 if (_displayRedirectOutputPath != null) 581 //enter into display redirection mode 582 { 583 BackwardCompatibility.addFilter( 584 new au.edu.jcu.kepler.hydrant.DisplayRedirectFilter(_displayRedirectOutputPath)); 585 addActorModule("org/kepler/ActorModuleBatch"); 586// DisplayRediectClassChanges.classChanges(); 587// BackwardCompatibility.addFilter(new DisplayRedirectFilter(outputPath)); 588 spec = "ptolemy/configs/kepler/ConfigRedirectGUINoCache.xml"; 589 590 } else { 591 spec = "ptolemy/configs/kepler/ConfigNoGUINoCache.xml"; 592 } 593 if(_runThenExitNoGui) { 594 _applicationArgsList.addFirst("-runThenExit"); 595 } 596 _applicationArgsList.addFirst(spec); 597// else{ 598// className = "ptolemy.moml.MoMLCommandLineApplication"; 599// } 600 } 601 602 if (className != null) { 603 // initialize and run the class. 604 String[] loadArgs = _applicationArgsList.toArray(new String[0]); 605 load(className, loadArgs); 606 } 607 } else if (_action == Action.CreateActorXML) { 608 String[] loadArgs = _applicationArgsList.toArray(new String[0]); 609 load("org.kepler.loader.util.UpdateActorTreeFiles", "buildXMLs", loadArgs); 610 } else if (_action == Action.UpdateActorDocs) { 611 String[] loadArgs = _applicationArgsList.toArray(new String[0]); 612 load("org.kepler.loader.util.UpdateActorTreeFiles", "updateKarXMLDocsForFile", loadArgs); 613 } else if (_action == Action.HSQLStart) { 614 System.out.println("going to start hsql servers."); 615 _runHSQLServers(true); 616 } else if (_action == Action.HSQLStop) { 617 System.out.println("going to stop hsql servers."); 618 _runHSQLServers(false); 619 } else if (_action == Action.MakeScreenShot) { 620 initialize(); 621 Screenshot.makeScreenshot(_screenShotWorkflows, _screenShotType, _screenShotOutputs, 622 _screenShotOutputDir, _screenShotForce); 623 shutdown(); 624 // TODO: why is System.exit() necessary? 625 System.exit(0); 626 } else if(_action == Action.RunCustomAction) { 627 load(_customActionClass, _customActionMethod, null); 628 } else { 629 System.err.println("Unknown execution action: " + _action); 630 } 631 } catch (IllegalArgumentException e) { 632 System.out.print(e.getMessage()); 633 return 1; 634 } catch (Exception e) { 635 System.out.println(e.getClass() + ": " + e.getMessage()); 636 e.printStackTrace(); 637 return 1; 638 } 639 640 if(!_runWithGui && !_runThenExitNoGui) { 641 System.out.println("Ctrl-c to exit."); 642 } 643 644 return 0; 645 } 646 647 /** Show the splash screen and start the kepler GUI. */ 648 private static void _showSplash() { 649 try { 650 651 ConfigurationProperty commonProperty = ConfigurationManager 652 .getInstance().getProperty( 653 ConfigurationManager.getModule("common")); 654 ConfigurationProperty splashscreenProp = commonProperty 655 .getProperty("splash.image"); 656 String splashname = splashscreenProp.getValue(); 657 658 final URL splashURL = ClassLoader.getSystemClassLoader() 659 .getResource(splashname); 660 661 SplashWindow.splash(splashURL); 662 663 } catch (Exception ex) { 664 System.err.println("Failed to find splash screen image." 665 + "Ignoring, use the Java coffee cup"); 666 ex.printStackTrace(); 667 } 668 } 669 670 /** 671 * This method provides a generic loader. It first updates the classpath 672 * with all the jars in $KEPLER/lib/jar, and then uses reflection to invoke 673 * the method. NOTE: the method must be static. 674 */ 675 public static void load(String className, String methodName, String[] args) 676 throws IllegalActionException { 677 // sanity checks 678 if (className == null || className.equals("")) { 679 throw new IllegalActionException("Must supply class to load."); 680 } else if (methodName == null || methodName.equals("")) { 681 throw new IllegalActionException("Must supply method to invoke."); 682 } 683 684 try { 685 initialize(); 686 687 if (className.equals("ptolemy.actor.gui.PtExecuteApplication")) { 688 ptolemy.actor.gui.PtExecuteApplication application = new ptolemy.actor.gui.PtExecuteApplication( 689 args); 690 application.runModels(); 691 application.waitForFinish(); 692 } else if(className.equals("org.kepler.KeplerConfigurationApplication")) { 693 KeplerConfigurationApplication application = new KeplerConfigurationApplication(args); 694 application.waitForFinish(); 695 } else { 696 System.out.print("loading: " + className); 697 if(args != null) { 698 System.out.println(" args: "); 699 for (String arg : args) { 700 System.out.print(arg + " "); 701 } 702 } 703 System.out.println(); 704 705 // invoke the class's method 706 Class<?> cl = Class.forName(className); 707 Method mthd = cl.getMethod(methodName, String[].class); 708 System.out.println("invoking: " + className + "." + methodName); 709 mthd.invoke(null, new Object[] { args }); 710 } 711 712 if (_mustManuallyQuit) { 713 System.out.println("Done."); 714 System.out.println("Ctrl-c to exit."); 715 } 716 717 // clean up modules unless we ran KeplerConfigurationApplication 718 // since that class calls shutdown() after the models have been 719 // executed. 720 if(!className.equals("org.kepler.KeplerConfigurationApplication")) { 721 _initializeModules(false); 722 } 723 724 } catch (ClassNotFoundException e) { 725 throw new IllegalActionException("ERROR: could not find start-up class: " 726 + className); 727 } catch (NoSuchMethodException e) { 728 throw new IllegalActionException("ERROR: class " + className 729 + " does not have a method called " + methodName); 730 } catch (Throwable throwable) { 731 throw new IllegalActionException("Unable to start application: " + 732 ExceptionUtils.getStackTrace(throwable)); 733 } 734 } 735 736 /** Load classes and invoke "main" method. */ 737 public static void load(String className, String[] args) 738 throws IllegalActionException { 739 load(className, "main", args); 740 } 741 742 /** Perform initialization. */ 743 public static void initialize() throws Exception { 744 _initializeCommandLineArguments(); 745 if (!_haveInitialized) { 746 _initializeModules(true); 747 } 748 } 749 750 /** Perform module cleanup. */ 751 public static void shutdown() { 752 _initializeModules(false); 753 } 754 755 /** Returns true if -force was specified on the command line. */ 756 public static boolean getForceOpen() { 757 return _forceOpen; 758 } 759 760 /** Returns true if -nogui was specified on the command line. */ 761 public static boolean getRunWithGUI() { 762 return _runWithGui; 763 } 764 765 /** Set Kepler java properties and copy the module directories into KeplerData/. */ 766 public static void setJavaPropertiesAndCopyModuleDirectories() throws URISyntaxException, IOException { 767 768 StatusNotifier.log("Setting Java Properties."); 769 770 SystemPropertyLoader.load(); 771 System.setProperty("KEPLER", ProjectLocator.getProjectDir() 772 .getAbsolutePath()); 773 String persistentDir = DotKeplerManager.getInstance() 774 .getPersistentDirString(); 775 System.setProperty("KEPLERDATA", persistentDir); 776 777 String dotKepler = DotKeplerManager.getDotKeplerPath(); 778 System.setProperty(".kepler", dotKepler); 779 780 String keplerUserData = DotKeplerManager.getInstance() 781 .getPersistentUserDataDirString(); 782 System.setProperty("KEPLERUSERDATA", keplerUserData); 783 784 String personalModuleWorkflowDirStr = DotKeplerManager 785 .getInstance().getPersistentModuleWorkflowsDirString(); 786 String docDirStr = DotKeplerManager.getInstance() 787 .getPersistentDocumentationDirString(); 788 789 StatusNotifier.log("Copying Module Files."); 790 791 List<Module> modules = ModuleTree.instance().getModuleList(); 792 Iterator<Module> moduleItr = modules.iterator(); 793 while (moduleItr.hasNext()) { 794 Module m = moduleItr.next(); 795 File applicationModuleWorkflowsDir = m.getWorkflowsDir(); 796 File applicationModuleDocDir = m.getDocumentationDir(); 797 // we want the full name, use getName not getStemName: 798 File moduleWorkflowDir = new File(personalModuleWorkflowDirStr 799 + File.separator + m.getName()); 800 File personalModuleDocDir = new File(docDirStr + File.separator 801 + m.getName()); 802 803 System.setProperty(m.getStemName() + ".workflowdir", 804 moduleWorkflowDir.toString() + File.separator); 805 806 if (applicationModuleWorkflowsDir.exists()) { 807 FileUtil.copyDirectory(applicationModuleWorkflowsDir, 808 moduleWorkflowDir, false); 809 } else { 810 log.debug(m + " workflow dir does not exist."); 811 } 812 813 if (applicationModuleDocDir.exists()) { 814 if (!personalModuleDocDir.exists()) { 815 log.warn(personalModuleDocDir + " does not exist."); 816 log.warn("copy(" + applicationModuleDocDir + "," 817 + personalModuleDocDir + ")"); 818 FileUtil.copyDirectory(applicationModuleDocDir, 819 personalModuleDocDir, false); 820 } 821 } 822 823 } 824 } 825 826 /** Set the class and method to invoke instead of starting Kepler. */ 827 public static void setRunApplication(String className, String method) { 828 _action = Action.RunCustomAction; 829 _customActionClass = className; 830 _customActionMethod = method; 831 } 832 833 // //////////////////////////////////////////////////////////////////// 834 // // private methods //// 835 836 /** Make sure that -runwf was specified. */ 837 private static void _assertRunWF(String arg) 838 throws IllegalArgumentException { 839 if (_action != Action.RunWf && _action != Action.RunKAR) { 840 throw new IllegalArgumentException("ERROR: " + arg 841 + " may only be used with -runwf"); 842 } 843 } 844 845 /** Run Kepler startup or shutdown module intializers. */ 846 private static void _initializeModules(boolean start) { 847 _runModuleInitializers(start, 848 start ? "Initialize" : "Shutdown", 849 start ? "initializeModule" : "shutdownModule"); 850 851 // update whether we initialized or shut down. 852 _haveInitialized = start; 853 } 854 855 /** Initialize command line arguments. */ 856 private static void _initializeCommandLineArguments() { 857 if(!_haveInitializedCommandLineArguments) { 858 _runModuleInitializers(true, "CommandLineArguments", 859 "initializeCommandLineArguments"); 860 _haveInitializedCommandLineArguments = true; 861 } 862 } 863 864 /** Run any module initializers with specific class and method names. 865 * @param start If true, the modules are called starting from the bottom 866 * of the suite. 867 * @param className The name of the module initializer class to run. 868 * @param methodName The name of the method in the class to invoke. 869 */ 870 private static void _runModuleInitializers(boolean start, String className, String methodName) { 871 ModuleTree tree = ModuleTree.instance(); 872 873 Iterable<Module> moduleList = null; 874 875 // on startup, call initializers starting at lowest dependency, 876 // i.e., at the bottom of modules.txt. 877 // on shutdown, start at top of modules.txt 878 if(start) { 879 moduleList = tree.reverse(); 880 } else { 881 moduleList = tree; 882 } 883 884 for (Module module : moduleList) { 885 String name = module.getName(); 886 name = module.getStemName(); 887 888 // construct the class name 889 890 // dashes and periods are illegal characters in package names 891 name = name.replaceAll("-", ""); 892 name = name.replaceAll("\\.", ""); 893 String fullClassName = "org.kepler.module." + name + "." + className; 894 //System.out.println("looking for class: " + fullClassName); 895 896 try { 897 // attempt to find and instantiate it 898 Class<?> moduleClass = Class.forName(fullClassName); 899 900 // call the initializer 901 Object instance = moduleClass.newInstance(); 902 903 if (className.equals("Initialize")) { 904 StatusNotifier.log("Initializing Module: " + name + "."); 905 ((ModuleInitializer)instance).initializeModule(); 906 907 if(_isDebugging) { 908 log.debug("Ran additional initialization for module " 909 + name + " from class " + fullClassName); 910 } 911 } else { 912 Method method = moduleClass.getMethod(methodName); 913 method.invoke(instance); 914 } 915 916 } catch (ClassNotFoundException e) { 917 // it's not required that every module have an initializer. 918 // System.out.println("initializer class not found for " + 919 // module); 920 } catch (InstantiationException e) { 921 System.out.println("ERROR instantiating " + fullClassName + ": " 922 + e.getMessage()); 923 } catch (IllegalAccessException e) { 924 System.out.println(e.getMessage()); 925 } catch(NoSuchMethodException | InvocationTargetException e) { 926 System.out.println(e.getMessage()); 927 } 928 } 929 } 930 931 /** 932 * read the osextension.txt file and return a hashtable of the properties 933 * 934 * NOTE this method is duplicated in CompileModules.java. Change both if you 935 * change one. 936 */ 937 private static Hashtable<String, String> readOSExtensionFile(File f) 938 throws Exception { 939 // String newline = System.getProperty("line.separator"); 940 Hashtable<String, String> properties = new Hashtable<String, String>(); 941 FileReader fr = new FileReader(f); 942 StringBuffer sb = new StringBuffer(); 943 char[] c = new char[1024]; 944 int numread = fr.read(c, 0, 1024); 945 while (numread != -1) { 946 sb.append(c, 0, numread); 947 numread = fr.read(c, 0, 1024); 948 } 949 fr.close(); 950 951 String propertiesStr = sb.toString(); 952 // String[] props = propertiesStr.split(newline); 953 String[] props = propertiesStr.split(";"); 954 for (int i = 0; i < props.length; i++) { 955 String token1 = props[i]; 956 StringTokenizer st2 = new StringTokenizer(token1, ","); 957 String key = st2.nextToken(); 958 String val = st2.nextToken(); 959 properties.put(key, val); 960 } 961 962 return properties; 963 } 964 965 /** Start or stop any module HSQL servers. */ 966 private static void _runHSQLServers(boolean start) { 967 968 org.kepler.util.sql.HSQL.setForkServers(true); 969 970 ModuleTree tree = ModuleTree.instance(); 971 972 Iterable<Module> moduleList = null; 973 974 // if start, call at lowest dependency, i.e., at the bottom of modules.txt. 975 // if stop, call at top of modules.txt 976 if(start) { 977 moduleList = tree.reverse(); 978 } else { 979 moduleList = tree; 980 } 981 982 for (Module module : moduleList) { 983 String name = module.getName(); 984 name = module.getStemName(); 985 986 // construct the class name 987 if (name.indexOf("-") != -1) { // dashes are illegal characters in 988 // package names so we need to 989 // remove them 990 name = name.replaceAll("-", ""); 991 } 992 String fullClassName = "org.kepler.module." + name + ".HSQLManager"; 993 //System.out.println("looking for class: " + className); 994 995 try { 996 // attempt to find and instantiate it 997 Class<?> moduleClass = Class.forName(fullClassName); 998 ModuleHSQLManager manager = (ModuleHSQLManager) moduleClass.newInstance(); 999 1000 if (start) { 1001 manager.start(); 1002 } else { 1003 manager.stop(); 1004 } 1005 1006 } catch (ClassNotFoundException e) { 1007 // it's not required that every module have an hsql manager. 1008 } catch (InstantiationException e) { 1009 System.out.println("ERROR instantiating " + fullClassName + ": " 1010 + e.getMessage()); 1011 } catch (IllegalAccessException e) { 1012 System.out.println(e.getMessage()); 1013 } 1014 } 1015 } 1016 1017 /** Add the display related actor implementation information, different ActorModule properties 1018 * file specify different display implementation. 1019 * The two ActorModule files in Kepler are located at display-redirect/src/org/kepler/. 1020 * The ActorModule file in ptolemy is located at ptolemy/src/ptolemy/actor/. 1021 * More info can be found at ptolemy.actor.injection.ActorModuleInitializer 1022 */ 1023 private static void addActorModule(String bundleFile){ 1024 final ArrayList<PtolemyModule> actorModules = new ArrayList<PtolemyModule>(); 1025 actorModules.add(new PtolemyModule(ResourceBundle 1026 .getBundle(bundleFile))); 1027 Initializer _defaultInitializer = new Initializer() { 1028 @Override 1029 public void initialize() { 1030 PtolemyInjector.createInjector(actorModules); 1031 } 1032 }; 1033 ptolemy.actor.injection.ActorModuleInitializer.setInitializer(_defaultInitializer); 1034 } 1035 1036 /** Print usage and exit. */ 1037 private static void _showHelp() { 1038 System.out.println("USAGE:"); 1039 System.out.println(); 1040 System.out.println("To run the Kepler GUI:"); 1041 System.out.println("kepler [-nosplash] [workflow.xml | workflow.kar]"); 1042 System.out.println("-nosplash start without showing splash screen."); 1043 System.out.println(); 1044 System.out.println("To run the Ptolemy GUI:"); 1045 System.out.println("kepler -vergil [workflow.xml]"); 1046 System.out.println(); 1047 System.out.println("To run a workflow XML from the command line:"); 1048 System.out.println("kepler -runwf [-nogui | -redirectgui dir] [-nocache] [-noilwc] " 1049 + "[-paramFile file] [-param1 value1 ...] workflow.xml"); 1050 System.out.println("-nogui run without GUI support."); 1051 System.out.println("-nocache run without kepler cache."); 1052 System.out.println("-noilwc run without incrementing LSIDs when the workflow changes."); 1053 System.out.println("-noexit do not exit after execution when running with -nogui"); 1054 System.out.println("-paramFile file read parameters from file."); 1055 System.out.println("-redirectgui dir redirect the contents of GUI actors to the specified directory."); 1056 System.out.println(); 1057 System.out.println("To run a workflow KAR from the command line:"); 1058 System.out.println("kepler -runkar [-nogui | -redirectgui dir] [-force] [-paramFile file] [-param1 value1 ...] workflow.kar"); 1059 System.out.println("-force attempt to run ignoring missing module dependencies."); 1060 System.out.println("-nogui run without GUI support."); 1061 System.out.println("-paramFile file read parameters from file."); 1062 System.out.println("-redirectgui dir redirect the contents of GUI actors to the specified directory."); 1063 System.out.println(); 1064 System.out.println("To start or stop the HSQL database servers:"); 1065 System.out.println("kepler -hsql start"); 1066 System.out.println("kepler -hsql stop"); 1067 System.out.println(); 1068 System.out.println("To create a workflow screen shot:"); 1069 System.out.println("kepler -screenshot [-type png | jpg | gif] [-force] [-o output [output2 [...]] | -odir directory] workflow.xml [workflow2.xml [...]]"); 1070 System.out.println("-force if true, always create the screenshot."); 1071 System.out.println("-o output [output2 [...]] the output file name(s)."); 1072 System.out.println("-odir dir the output directory."); 1073 System.out.println("-type png|jpg|gif the image type."); 1074 System.out.println(); 1075 System.out.println("The following options are for actor developers:"); 1076 System.out.println(); 1077 System.out.println("To create XML file(s) describing an actor using either the source file or class name:"); 1078 System.out.println("kepler -createActorXML file1.java|class1 [file2.java|class2 ...]"); 1079 System.out.println(); 1080 System.out.println("To create the documentation for an item in the actor tree:"); 1081 System.out.println("kepler -updateActorDocs [-overwrite] file1.xml [file2.xml ...]"); 1082 System.out.println("-overwrite overwrite any existing documentation."); 1083 1084 Collection<CommandLineArgument> args = CommandLineArgument.getAll(); 1085 if(!args.isEmpty()) { 1086 System.out.println(); 1087 System.out.println("Additional command-line arguments:"); 1088 System.out.println(); 1089 for(CommandLineArgument arg: args) { 1090 System.out.println(arg.getUsage()); 1091 } 1092 } 1093 } 1094 1095 //////////////////////////////////////////////////////////////////// 1096 // private classes //// 1097 1098 /** A class that implements ShutdownListener. The class 1099 * org.kepler.Kepler cannot be used since it is never 1100 * instantiated. 1101 */ 1102 private static class Shutdown implements ShutdownListener 1103 { 1104 /** Perform any module cleanup tasks. */ 1105 @Override 1106 public void shutdown() { 1107 Kepler._initializeModules(false); 1108 } 1109 } 1110 1111 //////////////////////////////////////////////////////////////////// 1112 // private variables //// 1113 1114 /** The types of actions. */ 1115 private enum Action { 1116 Kepler(""), 1117 RunWf("-runwf"), 1118 RunKAR("-runkar"), 1119 CreateActorXML("-createActorXML"), 1120 Vergil("-vergil"), 1121 HSQLStart("-hsql"), 1122 HSQLStop("-hsql"), 1123 UpdateActorDocs("-updateActorDocs"), 1124 MakeScreenShot("-screenshot"), 1125 RunCustomAction(""); 1126 1127 Action(String arg) { 1128 _arg = arg; 1129 } 1130 1131 public String getArg() { 1132 return _arg; 1133 } 1134 1135 private String _arg; 1136 }; 1137 1138 /** The action to perform. By default, start kepler GUI. */ 1139 private static Action _action = Action.Kepler; 1140 1141 /** Boolean to see if we've initialized. */ 1142 private static boolean _haveInitialized = false; 1143 1144 /** A copy of the command line arguments. */ 1145 private static String[] _args; 1146 1147 /** Logging. */ 1148 private final static Log log = LogFactory.getLog(Kepler.class); 1149 1150 /** True if log level is set to DEBUG. */ 1151 private final static boolean _isDebugging = log.isDebugEnabled(); 1152 1153 /** If true, the program must be manually quit by the user. */ 1154 private static boolean _mustManuallyQuit = false; 1155 1156 /** If true, -nogui was specified on the command line. */ 1157 private static boolean _runWithGui = true; 1158 1159 /** If true, start the Kepler cache. If -nocache specified on 1160 * the command line, this is false. 1161 */ 1162 private static boolean _runWithCache = true; 1163 1164 /** If true, show the splash screen. */ 1165 private static boolean _showSplash = true; 1166 1167 /** The output path for redirectdisplay option. */ 1168 private static String _displayRedirectOutputPath = null; 1169 1170 /** If true, -force was specified on the command line. */ 1171 private static boolean _forceOpen = false; 1172 1173 private static LinkedList<String> _applicationArgsList = new LinkedList<String>(); 1174 1175 /** The image type for the screenshot.*/ 1176 private static String _screenShotType; 1177 1178 /** A set of output screenshot file names. */ 1179 private static List<String> _screenShotOutputs; 1180 1181 /** The output directory for screenshots. */ 1182 private static String _screenShotOutputDir; 1183 1184 /** If true, always create screenshots. Otherwise, screenshots are only taken if 1185 * either the screenshot image does not exist or is older than the workflow. 1186 */ 1187 private static boolean _screenShotForce = false; 1188 1189 /** A set of workflows to take screenshots of. */ 1190 private static List<String> _screenShotWorkflows = new LinkedList<String>(); 1191 1192 /** If true, then call System.exit() after running with no gui. */ 1193 private static boolean _runThenExitNoGui = true; 1194 1195 /** The class name containing _customActionMethod to run instead of starting Kepler. */ 1196 private static String _customActionClass; 1197 1198 /** The method in _customActionClass to run instead of starting Kepler. */ 1199 private static String _customActionMethod; 1200 1201 /** If true, command line arguments have been initialized. */ 1202 private static boolean _haveInitializedCommandLineArguments = false; 1203 1204}