Main.java
001 /*
002  *  Main.java
003  *
004  *  Copyright (c) 1995-2010, The University of Sheffield. See the file
005  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006  *
007  *  This file is part of GATE (see http://gate.ac.uk/), and is free
008  *  software, licenced under the GNU Library General Public License,
009  *  Version 2, June 1991 (in the distribution as file licence.html,
010  *  and also available at http://gate.ac.uk/gate/licence.html).
011  *
012  *  Hamish Cunningham, 1/Nov/00
013  *
014  *  $Id: Main.java 13613 2011-04-05 14:20:17Z valyt $
015  */
016 
017 package gate;
018 
019 import gate.gui.MainFrame;
020 import gate.gui.OptionsDialog;
021 import gate.gui.ShellSlacFrame;
022 import gate.gui.Splash;
023 import gate.gui.UserGroupEditor;
024 import gate.util.BomStrippingInputStreamReader;
025 import gate.util.CorpusBenchmarkTool;
026 import gate.util.Err;
027 import gate.util.Files;
028 import gate.util.GateException;
029 import gate.util.OptionsMap;
030 import gate.util.Out;
031 import gate.util.Strings;
032 import gnu.getopt.Getopt;
033 
034 import java.awt.Color;
035 import java.awt.Dimension;
036 import java.awt.Font;
037 import java.awt.GraphicsConfiguration;
038 import java.awt.GraphicsEnvironment;
039 import java.awt.GridBagConstraints;
040 import java.awt.GridBagLayout;
041 import java.awt.Insets;
042 import java.awt.Rectangle;
043 import java.awt.Toolkit;
044 import java.io.BufferedReader;
045 import java.io.File;
046 import java.io.IOException;
047 import java.io.InputStream;
048 import java.io.InputStreamReader;
049 import java.io.Reader;
050 import java.net.MalformedURLException;
051 import java.net.URL;
052 import java.util.ArrayList;
053 import java.util.HashMap;
054 import java.util.Iterator;
055 import java.util.List;
056 import java.util.Map;
057 
058 import javax.swing.JLabel;
059 import javax.swing.JOptionPane;
060 import javax.swing.JPanel;
061 import javax.swing.RepaintManager;
062 import javax.swing.SwingUtilities;
063 import javax.swing.UIManager;
064 
065 
066 /** Top-level entry point for the GATE command-line and GUI interfaces.
067   <P>
068   */
069 public class Main {
070 
071   /** Debug flag */
072   private static final boolean DEBUG = false;
073 
074   /** Status flag for normal exit. */
075   private static final int STATUS_NORMAL = 0;
076 
077   /** Status flag for error exit. */
078   private static final int STATUS_ERROR = 1;
079 
080   /** Main routine for GATE.
081     * Command-line arguments:
082     <UL>
083     <LI>
084     <B>-h</B> display a short help message
085     <LI>
086     <B>-d URL</B> define URL to be a location for CREOLE resoures
087     <LI>
088     <B>-i file</B> additional initialisation file (probably called
089     *   <TT>gate.xml</TT>). Used for site-wide initialisation by the
090     *   start-up scripts
091     <LI>
092     <B>-a</B> run the DB administration tool
093     </UL>
094     */
095   public static void main(String[] argsthrows GateException {
096     Main.annotatorArgsMap = null;
097     // check we have a useable JDK
098     if(
099       System.getProperty("java.version").compareTo(Gate.getMinJdkVersion())
100       0
101     ) {
102       throw new GateException(
103         "GATE requires JDK " + Gate.getMinJdkVersion() " or newer"
104       );
105     }
106 
107     // process command-line options
108     processArgs(args);
109 
110     // GATE builtins should be loaded from the jar (or classes dir), not
111     // from a web server (we load them over the web during testing to
112     // make sure that users can load their own that way)
113     Gate.setNetConnected(false);
114     Gate.setLocalWebServer(false);
115 
116 
117     // run the interface or do batch processing
118     if(batchMode) {
119       if(DEBUGOut.prln("running batch process");
120       batchProcess();
121     else if(dbAdminMode) {
122       if(DEBUGOut.prln("running dbAdmin");
123       dbAdmin();
124     else {
125       runGui();
126     }
127 //    Gate.setUseXMLSerialization(false);
128   // main
129 
130   /** Register any CREOLE URLs that we got on the command line */
131   private static void registerCreoleUrls() {
132     CreoleRegister reg = Gate.getCreoleRegister();
133     Iterator<URL> iter = pendingCreoleUrls.iterator();
134     while(iter.hasNext()) {
135       URL u = iter.next();
136       try {
137         reg.registerDirectories(u);
138       catch(GateException e) {
139         Err.prln("Couldn't register CREOLE directory: " + u);
140         Err.prln(e);
141         System.exit(STATUS_ERROR);
142       }
143     }
144   // registerCreoleUrls()
145 
146   /** Main Frame of the GUI; null when no GUI running */
147   private static MainFrame frame;
148 
149   /** The splash shown when Gate starts*/
150   private static Splash splash;
151 
152   /**
153    * Get the main frame of the GUI. If the GUI isn't running, it
154    * is started.
155    */
156   public static MainFrame getMainFrame() throws GateException {
157     if(frame == null)
158       runGui();
159     return frame;
160   // getMainFrame()
161 
162   /** Run the user interface. */
163   private static void runGui() throws GateException {
164     try {
165       Class rmClass =
166               Gate.class
167                       .getClassLoader()
168                       .loadClass(
169                               "org.jdesktop.swinghelper.debug.CheckThreadViolationRepaintManager");
170 
171       RepaintManager.setCurrentManager((RepaintManager)rmClass.getConstructor()
172               .newInstance());
173     catch(Exception e) {
174       // the debug classes from SwingHelper are not available
175     }
176 
177     Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
178     //show the splash
179     SwingUtilities.invokeLater(new Runnable(){
180       public void run(){
181         //build the Splash
182         JPanel splashBox = new JPanel();
183         splashBox.setLayout(new GridBagLayout());
184         splashBox.setBackground(Color.white);
185 
186         GridBagConstraints constraints = new GridBagConstraints();
187         constraints.insets = new Insets(2222);
188 
189         String splashName =
190           System.getProperty(GateConstants.APP_SPLASH_JAVA_PROPERTY_NAME);
191         if(splashName == null)
192           splashName = "splash";
193 
194         constraints.fill = GridBagConstraints.NONE;
195         constraints.anchor = GridBagConstraints.CENTER;
196         constraints.gridy = 1;
197         constraints.gridwidth = 1;
198         JLabel gifLbl = new JLabel(MainFrame.getIcon(splashName));
199         splashBox.add(gifLbl, constraints);
200         GraphicsConfiguration gc = GraphicsEnvironment.
201           getLocalGraphicsEnvironment().getDefaultScreenDevice().
202           getDefaultConfiguration();
203 
204         splash = new Splash(null, gc, splashBox);
205         splash.showSplash();
206       }
207     });
208 
209     // initialise the library and load user CREOLE directories
210     try{
211       Gate.init();
212     }catch(Throwable t){
213       int selection = JOptionPane.showOptionDialog(
214         null,
215         "Error during initialisation:\n" + t.toString() +
216         "\nDo you still want to start GATE?",
217         "GATE", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE,
218         null, new String[]{"Cancel""Start anyway"},
219         "Cancel");
220       if(selection != 1){
221         t.printStackTrace();
222         System.exit(1);
223       }
224     }
225 
226 
227     //create the main frame, show it and hide the splash
228     SwingUtilities.invokeLater(new Runnable(){
229       public void run(){
230         GraphicsConfiguration gc = GraphicsEnvironment.
231         getLocalGraphicsEnvironment().getDefaultScreenDevice().
232         getDefaultConfiguration();
233 
234         //this needs to run before any GUI component is constructed.
235         //the initial gate splash is exempted from this rule.
236         applyUserPreferences();
237 
238         //all the defaults tables have been updated; build the GUI
239         if(Gate.isSlugGui()) {
240           frame = new ShellSlacFrame();
241           if(DEBUGOut.prln("constructing SLUG GUI");
242         }
243         else {
244           frame = new MainFrame(gc);
245           if(DEBUGOut.prln("constructing GUI");
246         // if - SLUG
247 
248         // run the GUI
249         frame.setTitleChangable(true);
250         if(Gate.isSlugGui()) {
251           frame.setTitle("SLUG application");
252         }
253         else {
254           frame.setTitle(name + " " + version + " build " + build);
255         // if - SLUG
256 
257         // Set title from Java properties
258         String title =
259           System.getProperty(GateConstants.TITLE_JAVA_PROPERTY_NAME);
260         if(title != null) {
261           frame.setTitle(title);
262         // if
263         frame.setTitleChangable(false);
264 
265         // Set icon from Java properties
266         // iconName could be absolute or "gate:/img/..."
267         String iconName =
268           System.getProperty(GateConstants.APP_ICON_JAVA_PROPERTY_NAME);
269         if(iconName != null) {
270           try {
271             frame.setIconImage(Toolkit.getDefaultToolkit().getImage(
272                   new URL(iconName)));
273           catch(MalformedURLException mue){
274             mue.printStackTrace(Err.getPrintWriter());
275           }
276         // if
277 
278         // Validate frames that have preset sizes
279         frame.validate();
280 
281         // Center the window
282         Rectangle screenBounds = gc.getBounds();
283         Dimension screenSize = screenBounds.getSize();
284         Dimension frameSize = frame.getSize();
285         if (frameSize.height > screenSize.height) {
286           frameSize.height = screenSize.height;
287         }
288         if (frameSize.width > screenSize.width) {
289           frameSize.width = screenSize.width;
290         }
291         frame.setLocation((screenSize.width - frameSize.width2,
292                           (screenSize.height - frameSize.height2);
293 
294         frame.setVisible(true);
295         if(splash != null) {
296           splash.setVisible(false);
297           splash.dispose();
298         }
299 
300         if(!Gate.isSlugGui()) {
301           //load session if required and available;
302           //do everything from a new thread.
303           Runnable runnable = new Runnable(){
304             public void run(){
305               try{
306                 File sessionFile = Gate.getUserSessionFile();
307                 if(sessionFile.exists()){
308                   MainFrame.lockGUI("Loading saved session...");
309                   gate.util.persistence.PersistenceManager.loadObjectFromFile(sessionFile);
310                 }
311               }catch(Exception e){
312                 Err.prln("Failed to load session data:");
313                 e.printStackTrace(Err.getPrintWriter());
314               }finally{
315                 MainFrame.unlockGUI();
316               }
317             }
318           };
319           Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
320                                      runnable, "Session loader");
321           thread.setPriority(Thread.MIN_PRIORITY);
322           thread.start();
323         // if - when no SLUG GUI load session
324       }
325     });
326     registerCreoleUrls();
327   // runGui()
328 
329   /** Run the db admin interface. */
330   private static void dbAdmin() throws GateException {
331     try UserGroupEditor.main(null)catch(Exception e) {
332       throw new GateException(e);
333     }
334   // dbAdmin()
335 
336   /**
337    * Reads the user config data and applies the required settings.
338    * This must be called <b>after</b> {@link Gate#init()} but <b>before</b>
339    * any GUI components are created.
340    */
341   public static void applyUserPreferences(){
342     //look and feel
343     String lnfClassName = Gate.getUserConfig().
344                           getString(GateConstants.LOOK_AND_FEEL);
345     if(lnfClassName == null){
346       //if running on Linux, default to Metal rather than GTK because GTK LnF
347       //doesn't play nicely with most Gnome themes
348       if(System.getProperty("os.name").toLowerCase().indexOf("linux"!= -1){
349         //running on Linux
350         lnfClassName = UIManager.getCrossPlatformLookAndFeelClassName();
351       }else{
352         lnfClassName = UIManager.getSystemLookAndFeelClassName();
353       }
354       Gate.getUserConfig().put(GateConstants.LOOK_AND_FEEL, lnfClassName);
355     }
356     try {
357       UIManager.setLookAndFeel(lnfClassName);
358     catch(Exception e) {
359       System.err.print("Could not set your preferred Look and Feel. The error was:\n" +
360               e.toString() "\nReverting to using Java Look and Feel");
361       try {
362         UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
363       }catch(Exception e1) {
364         //we just can't catch a break here. Let's forget about look and feel.
365         System.err.print(
366                 "Could not set the cross-platform Look and Feel either. The error was:\n" +
367                 e1.toString() "\nGiving up on Look and Feel.");
368       }
369     }
370 
371     //read the user config data
372     OptionsMap userConfig = Gate.getUserConfig();
373 
374     //text font
375     Font font = userConfig.getFont(GateConstants.TEXT_COMPONENTS_FONT);
376     if(font == null){
377       String fontName = Gate.guessUnicodeFont();
378       if(fontName != null){
379         font = new Font(fontName, Font.PLAIN, 12);
380       }else{
381         font = UIManager.getFont("TextPane.font");
382       }
383     }
384 
385     if(font != null){
386       OptionsDialog.setTextComponentsFont(font);
387     }
388 
389     //menus font
390     font = userConfig.getFont(GateConstants.MENUS_FONT);
391     if(font == null){
392       String fontName = Gate.guessUnicodeFont();
393       if(fontName != null){
394         font = new Font(fontName, Font.PLAIN, 12);
395       }else{
396         font = UIManager.getFont("Menu.font");
397       }
398     }
399 
400     if(font != null){
401       OptionsDialog.setMenuComponentsFont(font);
402     }
403 
404     //other gui font
405     font = userConfig.getFont(GateConstants.OTHER_COMPONENTS_FONT);
406     if(font == null){
407       String fontName = Gate.guessUnicodeFont();
408       if(fontName != null){
409         font = new Font(fontName, Font.PLAIN, 12);
410       }else{
411         font = UIManager.getFont("Button.font");
412       }
413     }
414 
415     if(font != null){
416       OptionsDialog.setComponentsFont(font);
417     }
418 
419 
420   }
421 
422 
423 
424   // find out the version and build numbers
425   static {
426     // find out the version number
427     try {
428       InputStream ver = Files.getGateResourceAsStream("version.txt");
429       if (ver==null) {
430         throw new IOException();
431       }
432       BufferedReader reader = new BomStrippingInputStreamReader(ver, "UTF-8");
433       Main.version = reader.readLine();
434     catch(IOException ioe) {
435       Main.version = "6.1";
436     }
437 
438     // find out the build number
439     try{
440       InputStream build = Files.getGateResourceAsStream("build.txt");
441       if (build==null) {
442         throw new IOException();
443       }
444       BufferedReader reader = new BomStrippingInputStreamReader(build, "UTF-8");
445       Main.build = reader.readLine();
446     catch(IOException ioe) {
447       Main.build = "0000";
448     }
449   // static initializer finding build and version
450 
451 
452 /**
453 
454 <BR>
455 <B>Options processing: </B>
456 
457 <BR>
458 <TABLE>
459   <TR>
460     <TH ALIGN=left COLSPAN=15>
461     -a annotator arg(s)
462     </TH>
463     <TH ALIGN=left>
464     A CREOLE annotator to run on the collection, with zero or more
465     arguments. The set of such annotators will be run in the sequence
466     they appear in the arguments list. The arguments list must end with the
467     start of another option; otherwise add a "-" after the arguments to
468     terminate the list.
469     </TH>
470   </TR>
471   <TR>
472     <TH ALIGN=left COLSPAN=15>
473     -b
474     </TH>
475     <TH ALIGN=left>
476     Batch mode. Don't start the GUI, just process options and exit after
477     any actions (e.g. running annotators).
478     </TH>
479   </TR>
480   <TR>
481     <TH ALIGN=left COLSPAN=15>
482     -c collname
483     </TH>
484     <TH ALIGN=left>
485     Name of the collection to use. If the collection already exists then
486     it will be used as it stands, otherwise it will be created. See also
487     -f.
488     </TH>
489   </TR>
490   <TR>
491     <TH ALIGN=left COLSPAN=15>
492     -d
493     </TH>
494     <TH ALIGN=left>
495     Destroy the collection after use. (The default is to save it to
496     disk.)
497     </TH>
498   </TR>
499   <TR>
500     <TH ALIGN=left COLSPAN=15>
501     -f file(s)
502     </TH>
503     <TH ALIGN=left>
504     One or more files to create a collection with. If the collection
505     being used (see -c) already exists, these files are ignored.
506     Otherwise they are used to create the collection.
507     </TH>
508   </TR>
509   <TR>
510     <TH ALIGN=left COLSPAN=15>
511     -h
512     </TH>
513     <TH ALIGN=left>
514     Print a usage message and exit.
515     </TH>
516   </TR>
517   <TR>
518     <TH ALIGN=left COLSPAN=15>
519     -p creolepath
520     </TH>
521     <TH ALIGN=left>
522     Sets the search path for CREOLE modules.
523     </TH>
524   </TR>
525   <TR>
526     <TH ALIGN=left COLSPAN=15>
527     -v classname(s)
528     </TH>
529     <TH ALIGN=left>
530     Verbose: turns on debugging output. Takes zero or more class names
531     to debug.
532     </TH>
533   </TR>
534 </TABLE>
535 
536 */
537   /** Name of the collection we were asked to process. */
538   private static String collName;
539 
540   /** Search path for CREOLE modules. */
541   private static String creolePath;
542 
543   /** List of files we were asked to build a collection from. */
544   private static List fileNames = new ArrayList();
545 
546   /** List of annotators we were asked to run on the collection. */
547   private static List annotatorNames = new ArrayList();
548 
549   /** Map of annotator arguments. */
550   private static Map annotatorArgsMap = new HashMap();
551 
552   /** List of classes we were asked to debug. */
553   private static List debugNames = new ArrayList();
554 
555   /** Are we in batch mode? */
556   public static boolean batchMode = false;
557 
558   /** Are we in db admin mode? */
559   public static boolean dbAdminMode = false;
560 
561   /** Don't save collection after batch? */
562   private static boolean destroyColl = false;
563 
564   /** Verbose? */
565   private static boolean verbose = false;
566 
567   private static boolean runCorpusBenchmarkTool = false;
568 
569   public static String name = "GATE Developer";
570   public static String version;
571   public static String build;
572 
573   /** Process arguments and set up member fields appropriately.
574     * Will shut down the process (via System.exit) if there are
575     * incorrect arguments, or if the arguments ask for something
576     * simple like printing the help message.
577     */
578   public static void processArgs(String[] args) {
579 
580     Getopt g = new Getopt("GATE main", args, "hd:ei:asj");
581     int c;
582     while( (c = g.getopt()) != -)
583       switch(c) {
584         // -a
585         case 'a':
586           dbAdminMode = true;
587           break;
588         // -h
589         case 'h':
590           help();
591           usage();
592           System.exit(STATUS_NORMAL);
593           break;
594         // -d creole-dir
595         case 'd':
596           String urlString = g.getOptarg();
597           URL u = null;
598           try {
599             u = new URL(urlString);
600           catch(MalformedURLException e) {
601             Err.prln("Bad URL: " + urlString);
602             Err.prln(e);
603             System.exit(STATUS_ERROR);
604           }
605           pendingCreoleUrls.add(u);
606           Out.prln(
607             "CREOLE Directory " + urlString + " queued for registration"
608           );
609           break;
610         // -i gate.xml site-wide init file
611         case 'i':
612           String optionString = g.getOptarg();
613           URL u2 = null;
614           File f = new File(optionString);
615           try {
616             u2 = f.toURI().toURL();
617           catch(MalformedURLException e) {
618             Err.prln("Bad initialisation file: " + optionString);
619             Err.prln(e);
620             System.exit(STATUS_ERROR);
621           }
622           Gate.setSiteConfigFile(f);
623           if(DEBUG)
624             Out.prln(
625               "Initialisation file " + optionString +
626               " recorded for initialisation"
627             );
628           break;
629         // -e runs the CorpusBenchmarkTool (e for evaluate)
630         case 'e':
631           try {
632             CorpusBenchmarkTool.main(args);
633           catch (GateException ex) {
634             Out.prln("Error running the evaluation tool: " + ex.getMessage());
635             System.exit(-1);
636           }
637           break;
638         // -s runs the SLUG GUI
639         case 's':
640           Gate.setSlugGui(true);
641           break;
642 /*
643         // -c collname
644         case '-c':
645           collName = g.getOptarg();
646           break;
647 
648         // -b
649         case '-b':
650           batchMode = true;
651           break;
652 
653         // -a annotator(s)
654         case '-a':
655           if(++i == args.length) { usage(); return; }
656           String annotatorName = g.getOptarg();
657           annotatorNames.add(annotatorName);
658 // collect any args for the annotator
659           break;
660 
661         // -d
662         case '-d':
663           destroyColl = true;
664           break;
665 
666         // -f file(s)
667         case '-f':
668           while(++i < args.length)
669             if(args[i].toCharArray()[0] == '-') { // start of another option
670               i--;
671               break;
672             }
673             else
674               fileNames.add(args[i]);
675           break;
676 
677         // -p creolepath
678         case '-p':
679           if(++i < args.length)
680             creolePath = args[i];
681           else
682             { usage(); return; }
683           break;
684 
685         // -v classname(s)
686         case '-v':
687           verbose = true;
688           Debug.setDebug(true);
689           while(++i < args.length) {
690             if(args[i].toCharArray()[0] == '-') { // start of another option
691               i--;
692               break;
693             }
694             else
695               debugNames.add(args[i]);
696           } // while
697           break;
698 */
699 
700         case '?':
701           // leave the warning to getopt
702           System.exit(STATUS_ERROR);
703           break;
704 
705         default:
706           // shouldn't happen!
707           Err.prln("getopt() returned " + c + "\n");
708           System.exit(STATUS_ERROR);
709           break;
710       // getopt switch
711 
712   // processArgs()
713 
714   /** Run commands as a batch process. */
715   private static void batchProcess() throws GateException{
716     // initialise the library and load user CREOLE directories
717     Gate.init();
718     registerCreoleUrls();
719 
720 /*
721     // turn debugging on where requested
722     if(verbose) {
723       for(ArrayIterator i = debugNames.begin(); ! i.atEnd(); i.advance()) {
724         try { Debug.setDebug(Class.forName(((String) i.get())), true); }
725         catch(ClassNotFoundException e) {
726           System.err.println(
727             "can't debug class " + (String) i.get() + ": " + e.toString()
728           );
729         }
730       } // for
731     } // debugging on
732 
733     // collection: does it exist and can we open it?
734     if(collName == null) {
735       System.err.println("no collection name given");
736       usage();
737       return;
738     }
739     File collDir = new File(collName);
740     JdmCollection coll = null;
741     if(collDir.exists()) { // open collection
742       Debug.prnl("opening collection " + collName);
743       try {
744         coll = new JdmCollection(collName);
745       } catch (JdmException e) {
746         System.err.println(
747           "Couldn't open collection " + collName + " " + e.toString()
748         );
749         return;
750       }
751     } else { // create collection and add documents
752       Debug.prnl("creating collection " + collName);
753       JdmAttributeSequence attrs = new JdmAttributeSequence();
754       try {
755         coll = new JdmCollection(collName, attrs);
756       } catch (JdmException e) {
757         System.err.println(
758           "Couldn't create collection " + collName + " " + e.toString()
759         );
760         return;
761       }
762 
763       // add the documents to the collection
764       for(ArrayIterator i = fileNames.begin(); ! i.atEnd(); i.advance()) {
765         Debug.prnl("adding document " + (String) i.get());
766         try {
767           JdmDocument doc = coll.createDocument(
768             (String) i.get(),
769             null,
770             new JdmAnnotationSet(),
771             new JdmAttributeSequence()
772           );
773         } catch (JdmException e) {
774           System.err.println(
775              "Can't add document " + (String) i.get() + ": " + e.toString()
776           );
777         } // catch
778       } // for each filename
779     } // collection create
780 
781     // run the annotators on each document in the collection
782     // for each document
783     JdmDocument doc = null;
784     if(coll.length() > 0)
785       try{ doc = coll.firstDocument(); } catch(JdmException e) { }
786     for(int i = 0; i<coll.length(); i++) {
787       if(doc == null) continue; // first and next doc shouldn't throw excptns!
788 
789       // for each annotator
790       for(ArrayIterator j = annotatorNames.begin(); !j.atEnd(); j.advance()) {
791         String annotatorName = (String) j.get();
792         Debug.prnl(
793           "calling annotator " + annotatorName + " on doc " + doc.getId()
794         );
795 
796         // load the annotator class
797         Annotator annotator = null;
798         Class annotatorClass = null;
799         try {
800           // cheat and assume that all annotators are on CLASSPATH
801           annotatorClass = Class.forName(annotatorName);
802         } catch (Exception ex) {
803           System.err.println(
804             "Could load class for CREOLE object " + annotatorName + ": " +
805             ex.toString()
806           );
807           continue;
808         }
809 
810         // construct the annotator
811         try {
812           annotator = (Annotator) annotatorClass.newInstance();
813         } catch (Throwable ex) { // naughty chap
814           System.err.println(
815             "Could create instance of CREOLE object " + annotatorName + ": " +
816             ex.toString()
817           );
818           continue;
819         }
820 
821         // annotate this document
822         String[] args = (String[]) annotatorArgsMap.get(annotatorName);
823         if(args == null) args = new String[0];
824         annotator.annotate(doc, args);
825       } // for each annotator
826 
827       doc = null;
828       try { doc = coll.nextDocument(); } catch(JdmException e) { }
829     } // for each doc, annotate
830 
831     // save collection?
832     if(! destroyColl) {
833       Debug.prnl("saving the collection");
834       try {
835         coll.sync();
836       } catch (JdmException e) {
837         System.err.println(
838           "Can't save collection " + collName + ": " + e.toString()
839         );
840       }
841     } else {
842       Debug.prnl("destroying collection");
843       try { coll.destroy(); } catch(JdmException e) {
844         // if we didn't sync we can't destroy, but that's not an error
845       }
846     }
847 
848     Debug.prnl("done batch process");
849 */
850   // batchProcess()
851 
852   /** Display a usage message */
853   public static void usage() {
854     Out.prln(
855       "Usage: java gate.Main " +
856       "[ -h [-d CREOLE-URL]" +
857       ""
858     );
859   // usage()
860 
861   /** Display a help message */
862   public static void help() {
863     String nl = Strings.getNl();
864     Out.prln(
865       "For help on command-line options and other information " + nl +
866       "see the user manual in your GATE distribution or at " + nl +
867       "http://gate.ac.uk/userguide/"
868     );
869   // help()
870 
871   /** The list of pending URLs to add to the CREOLE register */
872   private static List<URL> pendingCreoleUrls = new ArrayList<URL>();
873 
874 // class Main