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