Main.java |
1 /* 2 * Main.java 3 * 4 * Copyright (c) 1998-2004, The University of Sheffield. 5 * 6 * This file is part of GATE (see http://gate.ac.uk/), and is free 7 * software, licenced under the GNU Library General Public License, 8 * Version 2, June 1991 (in the distribution as file licence.html, 9 * and also available at http://gate.ac.uk/gate/licence.html). 10 * 11 * Hamish Cunningham, 1/Nov/00 12 * 13 * $Id: Main.java,v 1.52 2004/09/30 11:37:36 valyt Exp $ 14 */ 15 16 package gate; 17 18 import java.awt.*; 19 import java.io.*; 20 import java.net.MalformedURLException; 21 import java.net.URL; 22 import java.util.*; 23 import java.util.List; 24 25 import javax.swing.*; 26 27 import gate.gui.*; 28 import gate.util.*; 29 30 import gnu.getopt.Getopt; 31 32 33 /** Top-level entry point for the GATE command-line and GUI interfaces. 34 * <P> 35 */ 36 public class Main { 37 38 /** Debug flag */ 39 private static final boolean DEBUG = false; 40 41 /** Status flag for normal exit. */ 42 private static final int STATUS_NORMAL = 0; 43 44 /** Status flag for error exit. */ 45 private static final int STATUS_ERROR = 1; 46 47 /** Main routine for GATE. 48 * Command-line arguments: 49 * <UL> 50 * <LI> 51 * <B>-h</B> display a short help message 52 * <LI> 53 * <B>-d URL</B> define URL to be a location for CREOLE resoures 54 * <LI> 55 * <B>-i file</B> additional initialisation file (probably called 56 * <TT>gate.xml</TT>). Used for site-wide initialisation by the 57 * start-up scripts 58 * <LI> 59 * <B>-a</B> run the DB administration tool 60 * </UL> 61 */ 62 public static void main(String[] args) throws GateException { 63 Main.annotatorArgsMap = null; 64 // check we have a useable JDK 65 if( 66 System.getProperty("java.version").compareTo(Gate.getMinJdkVersion()) 67 < 0 68 ) { 69 throw new GateException( 70 "GATE requires JDK " + Gate.getMinJdkVersion() + " or newer" 71 ); 72 } 73 74 // process command-line options 75 processArgs(args); 76 77 // GATE builtins should be loaded from the jar (or classes dir), not 78 // from a web server (we load them over the web during testing to 79 // make sure that users can load their own that way) 80 Gate.setNetConnected(false); 81 Gate.setLocalWebServer(false); 82 83 84 // run the interface or do batch processing 85 if(batchMode) { 86 if(DEBUG) Out.prln("running batch process"); 87 batchProcess(); 88 } else if(dbAdminMode) { 89 if(DEBUG) Out.prln("running dbAdmin"); 90 dbAdmin(); 91 } else { 92 runGui(); 93 } 94 } // main 95 96 /** Register any CREOLE URLs that we got on the command line */ 97 private static void registerCreoleUrls() { 98 CreoleRegister reg = Gate.getCreoleRegister(); 99 Iterator iter = pendingCreoleUrls.iterator(); 100 while(iter.hasNext()) { 101 URL u = (URL) iter.next(); 102 try { 103 reg.registerDirectories(u); 104 } catch(GateException e) { 105 Err.prln("Couldn't register CREOLE directory: " + u); 106 Err.prln(e); 107 System.exit(STATUS_ERROR); 108 } 109 } 110 } // registerCreoleUrls() 111 112 /** Main Frame of the GUI; null when no GUI running */ 113 private static MainFrame frame; 114 115 /** The splash shown when Gate starts*/ 116 private static Splash splash; 117 118 /** 119 * Get the main frame of the GUI. If the GUI isn't running, it 120 * is started. 121 */ 122 public static MainFrame getMainFrame() throws GateException { 123 if(frame == null) 124 runGui(); 125 return frame; 126 } // getMainFrame() 127 128 /** Run the user interface. */ 129 private static void runGui() throws GateException { 130 131 Thread.currentThread().setPriority(Thread.MIN_PRIORITY); 132 //show the splash 133 SwingUtilities.invokeLater(new Runnable(){ 134 public void run(){ 135 //build the Spash 136 JPanel splashBox = new JPanel(); 137 splashBox.setLayout(new BoxLayout(splashBox, BoxLayout.Y_AXIS)); 138 splashBox.setBackground(Color.white); 139 140 String splashName = 141 System.getProperty(GateConstants.APP_SPLASH_JAVA_PROPERTY_NAME); 142 if(splashName == null) { 143 splashName = "gateSplash.gif"; 144 } // if 145 146 JLabel gifLbl = new JLabel(new ImageIcon(Main.class.getResource( 147 "/gate/resources/img/"+splashName))); 148 Box box = new Box(BoxLayout.X_AXIS); 149 box.add(Box.createHorizontalGlue()); 150 box.add(gifLbl); 151 box.add(Box.createHorizontalGlue()); 152 splashBox.add(box); 153 gifLbl = new JLabel(new ImageIcon(Main.class.getResource( 154 "/gate/resources/img/gateHeader.gif"))); 155 box = new Box(BoxLayout.X_AXIS); 156 box.add(Box.createHorizontalGlue()); 157 box.add(gifLbl); 158 box.add(Box.createHorizontalGlue()); 159 splashBox.add(box); 160 splashBox.add(Box.createVerticalStrut(15)); 161 splash = new Splash(splashBox); 162 splash.showSplash(); 163 } 164 }); 165 166 // initialise the library and load user CREOLE directories 167 try{ 168 Gate.init(); 169 }catch(Throwable t){ 170 int selection = JOptionPane.showOptionDialog( 171 null, 172 "Error during initialisation:\n" + t.toString() + 173 "\nDo you still want to start GATE?", 174 "GATE", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, 175 null, new String[]{"Cancel", "Start anyway"}, 176 "Cancel"); 177 if(selection != 1){ 178 t.printStackTrace(); 179 System.exit(1); 180 } 181 } 182 183 184 //create the main frame, show it and hide the splash 185 SwingUtilities.invokeLater(new Runnable(){ 186 public void run(){ 187 //this needs to run before any GUI component is constructed. 188 //the initial gate splash is exempted from this rule. 189 applyUserPreferences(); 190 191 //all the defaults tables have been updated; build the GUI 192 if(Gate.isSlugGui()) { 193 frame = new ShellSlacFrame(); 194 if(DEBUG) Out.prln("constructing SLUG GUI"); 195 } 196 else { 197 frame = new MainFrame(); 198 if(DEBUG) Out.prln("constructing GUI"); 199 } // if - SLUG 200 201 // run the GUI 202 frame.setTitleChangable(true); 203 if(Gate.isSlugGui()) { 204 frame.setTitle("SLUG application"); 205 } 206 else { 207 frame.setTitle(name + " " + version + " build " + build); 208 } // if - SLUG 209 210 // Set title from Java properties 211 String title = 212 System.getProperty(GateConstants.TITLE_JAVA_PROPERTY_NAME); 213 if(title != null) { 214 frame.setTitle(title); 215 } // if 216 frame.setTitleChangable(false); 217 218 // Set icon from Java properties 219 // iconName could be absolute or "gate:/img/....gif" 220 String iconName = 221 System.getProperty(GateConstants.APP_ICON_JAVA_PROPERTY_NAME); 222 if(iconName != null) { 223 try { 224 frame.setIconImage(Toolkit.getDefaultToolkit().getImage( 225 new URL(iconName))); 226 } catch(MalformedURLException mue){ 227 mue.printStackTrace(Err.getPrintWriter()); 228 } 229 } // if 230 231 // Validate frames that have preset sizes 232 frame.validate(); 233 234 // Center the window 235 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 236 Dimension frameSize = frame.getSize(); 237 if (frameSize.height > screenSize.height) { 238 frameSize.height = screenSize.height; 239 } 240 if (frameSize.width > screenSize.width) { 241 frameSize.width = screenSize.width; 242 } 243 frame.setLocation((screenSize.width - frameSize.width) / 2, 244 (screenSize.height - frameSize.height) / 2); 245 246 frame.setVisible(true); 247 if(splash != null) splash.setVisible(false); 248 249 if(!Gate.isSlugGui()) { 250 //load session if required and available; 251 //do everything from a new thread. 252 Runnable runnable = new Runnable(){ 253 public void run(){ 254 try{ 255 File sessionFile = new File(Gate.getUserSessionFileName()); 256 if(sessionFile.exists()){ 257 MainFrame.lockGUI("Loading saved session..."); 258 gate.util.persistence.PersistenceManager.loadObjectFromFile(sessionFile); 259 } 260 }catch(Exception e){ 261 Err.prln("Failed to load session data:"); 262 e.printStackTrace(Err.getPrintWriter()); 263 }finally{ 264 MainFrame.unlockGUI(); 265 } 266 } 267 }; 268 Thread thread = new Thread(Thread.currentThread().getThreadGroup(), 269 runnable, "Session loader"); 270 thread.setPriority(Thread.MIN_PRIORITY); 271 thread.start(); 272 } // if - when no SLUG GUI load session 273 } 274 }); 275 registerCreoleUrls(); 276 } // runGui() 277 278 /** Run the db admin interface. */ 279 private static void dbAdmin() throws GateException { 280 try { UserGroupEditor.main(null); } catch(Exception e) { 281 throw new GateException(e); 282 } 283 } // dbAdmin() 284 285 /** 286 * Reads the user config data and applies the required settings. 287 */ 288 protected static void applyUserPreferences(){ 289 //look and feel 290 String lnfClassName = Gate.getUserConfig(). 291 getString(GateConstants.LOOK_AND_FEEL); 292 if(lnfClassName == null){ 293 lnfClassName = UIManager.getSystemLookAndFeelClassName(); 294 Gate.getUserConfig().put(GateConstants.LOOK_AND_FEEL, lnfClassName); 295 } 296 try { 297 UIManager.setLookAndFeel(lnfClassName); 298 } catch(Exception e) { 299 throw new gate.util.GateRuntimeException(e.toString()); 300 } 301 302 //read the user config data 303 OptionsMap userConfig = Gate.getUserConfig(); 304 305 //text font 306 Font font = userConfig.getFont(GateConstants.TEXT_COMPONENTS_FONT); 307 if(font == null){ 308 String fontName = Gate.guessUnicodeFont(); 309 if(fontName != null){ 310 font = new Font(fontName, Font.PLAIN, 12); 311 }else{ 312 font = UIManager.getFont("TextPane.font"); 313 } 314 } 315 316 if(font != null){ 317 OptionsDialog.setTextComponentsFont(font); 318 } 319 320 //menus font 321 font = userConfig.getFont(GateConstants.MENUS_FONT); 322 if(font == null){ 323 String fontName = Gate.guessUnicodeFont(); 324 if(fontName != null){ 325 font = new Font(fontName, Font.PLAIN, 12); 326 }else{ 327 font = UIManager.getFont("Menu.font"); 328 } 329 } 330 331 if(font != null){ 332 OptionsDialog.setMenuComponentsFont(font); 333 } 334 335 //other gui font 336 font = userConfig.getFont(GateConstants.OTHER_COMPONENTS_FONT); 337 if(font == null){ 338 String fontName = Gate.guessUnicodeFont(); 339 if(fontName != null){ 340 font = new Font(fontName, Font.PLAIN, 12); 341 }else{ 342 font = UIManager.getFont("Button.font"); 343 } 344 } 345 346 if(font != null){ 347 OptionsDialog.setComponentsFont(font); 348 } 349 350 351 } 352 353 354 355 // find out the version and build numbers 356 static { 357 // find out the version number 358 try { 359 InputStream ver = Files.getGateResourceAsStream("version.txt"); 360 if (ver==null) { 361 throw new IOException(); 362 } 363 BufferedReader reader = new BufferedReader(new InputStreamReader(ver, 364 "UTF-8")); 365 Main.version = reader.readLine(); 366 } catch(IOException ioe) { 367 Main.version = "3.0"; 368 } 369 370 // find out the build number 371 try{ 372 InputStream build = Files.getGateResourceAsStream("build.txt"); 373 if (build==null) { 374 throw new IOException(); 375 } 376 BufferedReader reader = new BufferedReader(new InputStreamReader(build, 377 "UTF-8")); 378 Main.build = reader.readLine(); 379 } catch(IOException ioe) { 380 Main.build = "0000"; 381 } 382 } // static initialiser finding build and version 383 384 385 /** 386 387 <BR> 388 <B>Options processing: </B> 389 390 <BR> 391 <TABLE> 392 <TR> 393 <TH ALIGN=left COLSPAN=15> 394 -a annotator arg(s) 395 </TH> 396 <TH ALIGN=left> 397 A CREOLE annotator to run on the collection, with zero or more 398 arguments. The set of such annotators will be run in the sequence 399 they appear in the arguments list. The arguments list must end with the 400 start of another option; otherwise add a "-" after the arguments to 401 terminate the list. 402 </TH> 403 </TR> 404 <TR> 405 <TH ALIGN=left COLSPAN=15> 406 -b 407 </TH> 408 <TH ALIGN=left> 409 Batch mode. Don't start the GUI, just process options and exit after 410 any actions (e.g. running annotators). 411 </TH> 412 </TR> 413 <TR> 414 <TH ALIGN=left COLSPAN=15> 415 -c collname 416 </TH> 417 <TH ALIGN=left> 418 Name of the collection to use. If the collection already exists then 419 it will be used as it stands, otherwise it will be created. See also 420 -f. 421 </TH> 422 </TR> 423 <TR> 424 <TH ALIGN=left COLSPAN=15> 425 -d 426 </TH> 427 <TH ALIGN=left> 428 Destroy the collection after use. (The default is to save it to 429 disk.) 430 </TH> 431 </TR> 432 <TR> 433 <TH ALIGN=left COLSPAN=15> 434 -f file(s) 435 </TH> 436 <TH ALIGN=left> 437 One or more files to create a collection with. If the collection 438 being used (see -c) already exists, these files are ignored. 439 Otherwise they are used to create the collection. 440 </TH> 441 </TR> 442 <TR> 443 <TH ALIGN=left COLSPAN=15> 444 -h 445 </TH> 446 <TH ALIGN=left> 447 Print a usage message and exit. 448 </TH> 449 </TR> 450 <TR> 451 <TH ALIGN=left COLSPAN=15> 452 -p creolepath 453 </TH> 454 <TH ALIGN=left> 455 Sets the search path for CREOLE modules. 456 </TH> 457 </TR> 458 <TR> 459 <TH ALIGN=left COLSPAN=15> 460 -v classname(s) 461 </TH> 462 <TH ALIGN=left> 463 Verbose: turns on debugging output. Takes zero or more class names 464 to debug. 465 </TH> 466 </TR> 467 </TABLE> 468 469 */ 470 /** Name of the collection we were asked to process. */ 471 private static String collName; 472 473 /** Search path for CREOLE modules. */ 474 private static String creolePath; 475 476 /** List of files we were asked to build a collection from. */ 477 private static List fileNames = new ArrayList(); 478 479 /** List of annotators we were asked to run on the collection. */ 480 private static List annotatorNames = new ArrayList(); 481 482 /** Map of annotator arguments. */ 483 private static Map annotatorArgsMap = new HashMap(); 484 485 /** List of classes we were asked to debug. */ 486 private static List debugNames = new ArrayList(); 487 488 /** Are we in batch mode? */ 489 public static boolean batchMode = false; 490 491 /** Are we in db admin mode? */ 492 public static boolean dbAdminMode = false; 493 494 /** Don't save collection after batch? */ 495 private static boolean destroyColl = false; 496 497 /** Verbose? */ 498 private static boolean verbose = false; 499 500 private static boolean runCorpusBenchmarkTool = false; 501 502 public static String name = "GATE"; 503 public static String version; 504 public static String build; 505 506 /** Process arguments and set up member fields appropriately. 507 * Will shut down the process (via System.exit) if there are 508 * incorrect arguments, or if the arguments ask for something 509 * simple like printing the help message. 510 */ 511 public static void processArgs(String[] args) { 512 513 Getopt g = new Getopt("GATE main", args, "hd:ei:asj"); 514 int c; 515 while( (c = g.getopt()) != -1 ) 516 switch(c) { 517 // -a 518 case 'a': 519 dbAdminMode = true; 520 break; 521 // -h 522 case 'h': 523 help(); 524 usage(); 525 System.exit(STATUS_NORMAL); 526 break; 527 // -d creole-dir 528 case 'd': 529 String urlString = g.getOptarg(); 530 URL u = null; 531 try { 532 u = new URL(urlString); 533 } catch(MalformedURLException e) { 534 Err.prln("Bad URL: " + urlString); 535 Err.prln(e); 536 System.exit(STATUS_ERROR); 537 } 538 pendingCreoleUrls.add(u); 539 Out.prln( 540 "CREOLE Directory " + urlString + " queued for registration" 541 ); 542 break; 543 // -i gate.xml site-wide init file 544 case 'i': 545 String optionString = g.getOptarg(); 546 URL u2 = null; 547 File f = new File(optionString); 548 try { 549 u2 = f.toURL(); 550 } catch(MalformedURLException e) { 551 Err.prln("Bad initialisation file: " + optionString); 552 Err.prln(e); 553 System.exit(STATUS_ERROR); 554 } 555 Gate.setSiteConfigFile(f); 556 if(DEBUG) 557 Out.prln( 558 "Initialisation file " + optionString + 559 " recorded for initialisation" 560 ); 561 break; 562 // -e runs the CorpusBenchmarkTool (e for evaluate) 563 case 'e': 564 try { 565 CorpusBenchmarkTool.main(args); 566 } catch (GateException ex) { 567 Out.prln("Error running the evaluation tool: " + ex.getMessage()); 568 System.exit(-1); 569 } 570 break; 571 // -s runs the SLUG GUI 572 case 's': 573 Gate.setSlugGui(true); 574 break; 575 // -j enable Jape Debugger 576 case 'j': 577 Gate.setEnableJapeDebug(true); 578 break; 579 580 581 582 /* 583 // -c collname 584 case '-c': 585 collName = g.getOptarg(); 586 break; 587 588 // -b 589 case '-b': 590 batchMode = true; 591 break; 592 593 // -a annotator(s) 594 case '-a': 595 if(++i == args.length) { usage(); return; } 596 String annotatorName = g.getOptarg(); 597 annotatorNames.add(annotatorName); 598 // collect any args for the annotator 599 break; 600 601 // -d 602 case '-d': 603 destroyColl = true; 604 break; 605 606 // -f file(s) 607 case '-f': 608 while(++i < args.length) 609 if(args[i].toCharArray()[0] == '-') { // start of another option 610 i--; 611 break; 612 } 613 else 614 fileNames.add(args[i]); 615 break; 616 617 // -p creolepath 618 case '-p': 619 if(++i < args.length) 620 creolePath = args[i]; 621 else 622 { usage(); return; } 623 break; 624 625 // -v classname(s) 626 case '-v': 627 verbose = true; 628 Debug.setDebug(true); 629 while(++i < args.length) { 630 if(args[i].toCharArray()[0] == '-') { // start of another option 631 i--; 632 break; 633 } 634 else 635 debugNames.add(args[i]); 636 } // while 637 break; 638 */ 639 640 case '?': 641 // leave the warning to getopt 642 System.exit(STATUS_ERROR); 643 break; 644 645 default: 646 // shouldn't happen! 647 Err.prln("getopt() returned " + c + "\n"); 648 System.exit(STATUS_ERROR); 649 break; 650 } // getopt switch 651 652 } // processArgs() 653 654 /** Run commands as a batch process. */ 655 private static void batchProcess() throws GateException{ 656 // initialise the library and load user CREOLE directories 657 Gate.init(); 658 registerCreoleUrls(); 659 660 /* 661 // turn debugging on where requested 662 if(verbose) { 663 for(ArrayIterator i = debugNames.begin(); ! i.atEnd(); i.advance()) { 664 try { Debug.setDebug(Class.forName(((String) i.get())), true); } 665 catch(ClassNotFoundException e) { 666 System.err.println( 667 "can't debug class " + (String) i.get() + ": " + e.toString() 668 ); 669 } 670 } // for 671 } // debugging on 672 673 // collection: does it exist and can we open it? 674 if(collName == null) { 675 System.err.println("no collection name given"); 676 usage(); 677 return; 678 } 679 File collDir = new File(collName); 680 JdmCollection coll = null; 681 if(collDir.exists()) { // open collection 682 Debug.prnl("opening collection " + collName); 683 try { 684 coll = new JdmCollection(collName); 685 } catch (JdmException e) { 686 System.err.println( 687 "Couldn't open collection " + collName + " " + e.toString() 688 ); 689 return; 690 } 691 } else { // create collection and add documents 692 Debug.prnl("creating collection " + collName); 693 JdmAttributeSequence attrs = new JdmAttributeSequence(); 694 try { 695 coll = new JdmCollection(collName, attrs); 696 } catch (JdmException e) { 697 System.err.println( 698 "Couldn't create collection " + collName + " " + e.toString() 699 ); 700 return; 701 } 702 703 // add the documents to the collection 704 for(ArrayIterator i = fileNames.begin(); ! i.atEnd(); i.advance()) { 705 Debug.prnl("adding document " + (String) i.get()); 706 try { 707 JdmDocument doc = coll.createDocument( 708 (String) i.get(), 709 null, 710 new JdmAnnotationSet(), 711 new JdmAttributeSequence() 712 ); 713 } catch (JdmException e) { 714 System.err.println( 715 "Can't add document " + (String) i.get() + ": " + e.toString() 716 ); 717 } // catch 718 } // for each filename 719 } // collection create 720 721 // run the annotators on each document in the collection 722 // for each document 723 JdmDocument doc = null; 724 if(coll.length() > 0) 725 try{ doc = coll.firstDocument(); } catch(JdmException e) { } 726 for(int i = 0; i<coll.length(); i++) { 727 if(doc == null) continue; // first and next doc shouldn't throw excptns! 728 729 // for each annotator 730 for(ArrayIterator j = annotatorNames.begin(); !j.atEnd(); j.advance()) { 731 String annotatorName = (String) j.get(); 732 Debug.prnl( 733 "calling annotator " + annotatorName + " on doc " + doc.getId() 734 ); 735 736 // load the annotator class 737 Annotator annotator = null; 738 Class annotatorClass = null; 739 try { 740 // cheat and assume that all annotators are on CLASSPATH 741 annotatorClass = Class.forName(annotatorName); 742 } catch (Exception ex) { 743 System.err.println( 744 "Could load class for CREOLE object " + annotatorName + ": " + 745 ex.toString() 746 ); 747 continue; 748 } 749 750 // construct the annotator 751 try { 752 annotator = (Annotator) annotatorClass.newInstance(); 753 } catch (Throwable ex) { // naughty chap 754 System.err.println( 755 "Could create instance of CREOLE object " + annotatorName + ": " + 756 ex.toString() 757 ); 758 continue; 759 } 760 761 // annotate this document 762 String[] args = (String[]) annotatorArgsMap.get(annotatorName); 763 if(args == null) args = new String[0]; 764 annotator.annotate(doc, args); 765 } // for each annotator 766 767 doc = null; 768 try { doc = coll.nextDocument(); } catch(JdmException e) { } 769 } // for each doc, annotate 770 771 // save collection? 772 if(! destroyColl) { 773 Debug.prnl("saving the collection"); 774 try { 775 coll.sync(); 776 } catch (JdmException e) { 777 System.err.println( 778 "Can't save collection " + collName + ": " + e.toString() 779 ); 780 } 781 } else { 782 Debug.prnl("destroying collection"); 783 try { coll.destroy(); } catch(JdmException e) { 784 // if we didn't sync we can't destroy, but that's not an error 785 } 786 } 787 788 Debug.prnl("done batch process"); 789 */ 790 } // batchProcess() 791 792 /** Display a usage message */ 793 public static void usage() { 794 Out.prln( 795 "Usage: java gate.Main " + 796 "[ -h [-d CREOLE-URL]" + 797 "" 798 ); 799 } // usage() 800 801 /** Display a help message */ 802 public static void help() { 803 String nl = Strings.getNl(); 804 Out.prln( 805 "For help on command-line options and other information " + nl + 806 "see the user manual in your GATE distribution or at " + nl + 807 "http://gate.ac.uk/sale/tao/" 808 ); 809 } // help() 810 811 /** The list of pending URLs to add to the CREOLE register */ 812 private static List pendingCreoleUrls = new ArrayList(); 813 814 } // class Main 815