1   /*
2    *  Gate.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, 31/07/98
12   *
13   *  $Id: Gate.java,v 1.49 2002/05/20 10:30:44 valyt Exp $
14   */
15  
16  package gate;
17  
18  import java.util.*;
19  import java.net.*;
20  import java.io.*;
21  
22  import gate.util.*;
23  import gate.creole.*;
24  import gate.config.*;
25  import gate.event.*;
26  
27  /** The class is responsible for initialising the GATE libraries, and
28    * providing access to singleton utility objects, such as the GATE class
29    * loader, CREOLE register and so on.
30    */
31  public class Gate implements GateConstants
32  {
33    /** Debug flag */
34    private static final boolean DEBUG = false;
35  
36    /**
37     *  The default StringBuffer size, it seems that we need longer string
38     *  than the StringBuffer class default because of the high number of
39     *  buffer expansions
40     *  */
41    public static final int STRINGBUFFER_SIZE = 1024;
42  
43    /**
44     *  The default size to be used for Hashtable, HashMap and HashSet.
45     *  The defualt is 11 and it leads to big memory usage. Having a default
46     *  load factor of 0.75, table of size 4 can take 3 elements before being
47     *  re-hashed - a values that seems to be optimal for most of the cases.
48     *  */
49    public static final int HASH_STH_SIZE = 4;
50  
51  
52    /**
53     *  The database schema owner (GATEADMIN is default)
54     *  this one should not be hardcoded but set in the
55     *  XML initialization files
56     *
57     *  */
58    public static final String DB_OWNER = "gateadmin";
59  
60  
61    /** The list of builtin URLs to search for CREOLE resources. */
62    private static String builtinCreoleDirectoryUrls[] = {
63      // "http://derwent.dcs.shef.ac.uk/gate.ac.uk/creole/"
64  
65      // this has been moved to initCreoleRegister and made relative to
66      // the base URL returned by getUrl()
67      // "http://gate.ac.uk/creole/"
68    };
69  
70  
71    /** The GATE URI used to interpret custom GATE tags*/
72    public static final String URI = "http://www.gate.ac.uk";
73  
74    /** Minimum version of JDK we support */
75    protected static final String MIN_JDK_VERSION = "1.3";
76  
77    /** Get the minimum supported version of the JDK */
78    public static String getMinJdkVersion() { return MIN_JDK_VERSION; }
79  
80    /** Initialisation - must be called by all clients before using
81      * any other parts of the library. Also initialises the CREOLE
82      * register and reads config data (<TT>gate.xml</TT> files).
83      * @see #initCreoleRegister
84      */
85    public static void init() throws GateException {
86  
87      // register the URL handler  for the "gate://" URLs
88      System.setProperty(
89        "java.protocol.handler.pkgs",
90        System.getProperty("java.protocol.handler.pkgs")
91          + "|" + "gate.util.protocols"
92      );
93  
94      System.setProperty("javax.xml.parsers.SAXParserFactory",
95                               "org.apache.xerces.jaxp.SAXParserFactoryImpl");
96  
97      //initialise the symbols generator
98      lastSym = 0;
99  
100     // create class loader and creole register if they're null
101     if(classLoader == null)
102       classLoader = new GateClassLoader();
103     if(creoleRegister == null)
104       creoleRegister = new CreoleRegisterImpl();
105     // init the creole register
106     initCreoleRegister();
107     // init the data store register
108     initDataStoreRegister();
109     // read gate.xml files; this must come before creole register
110     // initialisation in order for the CREOLE-DIR elements to have and effect
111     initConfigData();
112     // the creoleRegister acts as a proxy for datastore related events
113     dataStoreRegister.addCreoleListener(creoleRegister);
114 
115     // some of the events are actually fired by the {@link gate.Factory}
116     Factory.addCreoleListener(creoleRegister);
117 
118     // check we have a useable JDK
119     if(System.getProperty("java.version").compareTo(MIN_JDK_VERSION) < 0) {
120       throw new GateException(
121         "GATE requires JDK " + MIN_JDK_VERSION + " or newer"
122       );
123     }
124 
125     //register Lucene as a IR search engine
126     try{
127       registerIREngine("gate.creole.ir.lucene.LuceneIREngine");
128     }catch(ClassNotFoundException cnfe){
129       throw new GateRuntimeException(cnfe.toString());
130     }
131   } // init()
132 
133   /** Initialise the CREOLE register. */
134   public static void initCreoleRegister() throws GateException {
135 
136     // register the builtin CREOLE directories
137     for(int i=0; i<builtinCreoleDirectoryUrls.length; i++)
138       try {
139         creoleRegister.addDirectory(
140           new URL(builtinCreoleDirectoryUrls[i])
141         );
142       } catch(MalformedURLException e) {
143         throw new GateException(e);
144       }
145 
146 /*
147 We'll have to think about this. Right now it points to the creole inside the
148 jar/classpath so it's the same as registerBuiltins
149 */
150 //    // add the GATE base URL creole directory
151 //    creoleRegister.addDirectory(Gate.getUrl("creole/"));
152 //    creoleRegister.registerDirectories();
153 
154     // register the resources that are actually in gate.jar
155     creoleRegister.registerBuiltins();
156   } // initCreoleRegister
157 
158   /** Initialise the DataStore register. */
159   public static void initDataStoreRegister() {
160     dataStoreRegister = new DataStoreRegister();
161   } // initDataStoreRegister()
162 
163   /**
164    * Reads config data (<TT>gate.xml</TT> files). There are three
165    * sorts of these files:
166    * <UL>
167    * <LI>
168    * The builtin file from GATE's resources - this is read first.
169    * <LI>
170    * A site-wide init file given as a command-line argument or as a
171    * <TT>gate.config</TT> property - this is read second.
172    * <LI>
173    * The user's file from their home directory - this is read last.
174    * </UL>
175    * Settings from files read after some settings have already been
176    * made will simply overwrite the previous settings.
177    */
178   public static void initConfigData() throws GateException {
179     ConfigDataProcessor configProcessor = new ConfigDataProcessor();
180 
181     // url of the builtin config data (for error messages)
182     URL configUrl =
183       Gate.getClassLoader().getResource("gate/resources/" + GATE_DOT_XML);
184 
185     // open a stream to the builtin config data file and parse it
186     InputStream configStream = null;
187     try {
188       configStream = Files.getGateResourceAsStream(GATE_DOT_XML);
189     } catch(IOException e) {
190       throw new GateException(
191         "Couldn't open builtin config data file: " + configUrl + " " + e
192       );
193     }
194     configProcessor.parseConfigFile(configStream, configUrl);
195 
196     // parse any command-line initialisation file
197     File siteConfigFile = Gate.getSiteConfigFile();
198     if(siteConfigFile != null) {
199       try {
200         configUrl = siteConfigFile.toURL();
201         configStream = new FileInputStream(Gate.getSiteConfigFile());
202       } catch(IOException e) {
203         throw new GateException(
204           "Couldn't open site config data file: " + configUrl + " " + e
205         );
206       }
207       configProcessor.parseConfigFile(configStream, configUrl);
208     }
209 
210     // parse the user's config file (if it exists)
211     String userConfigName = getUserConfigFileName();
212     File userConfigFile = null;
213     URL userConfigUrl = null;
214     if(DEBUG) { Out.prln("loading user config from " + userConfigName); }
215     configStream = null;
216     boolean userConfigExists = true;
217     try {
218       userConfigFile = new File(userConfigName);
219       configStream = new FileInputStream(userConfigFile);
220       userConfigUrl = userConfigFile.toURL();
221     } catch(IOException e) {
222       userConfigExists = false;
223     }
224     if(userConfigExists)
225       configProcessor.parseConfigFile(configStream, userConfigUrl);
226 
227     // remember the init-time config options
228     originalUserConfig.putAll(userConfig);
229 
230     if(DEBUG) {
231       Out.prln(
232         "user config loaded; DBCONFIG=" + DataStoreRegister.getConfigData()
233       );
234     }
235   } // initConfigData()
236 
237   /**
238    * Attempts to guess the Unicode font for the platform.
239    */
240   public static String guessUnicodeFont(){
241     //guess the Unicode font for the platform
242     String[] fontNames = java.awt.GraphicsEnvironment.
243                          getLocalGraphicsEnvironment().
244                          getAvailableFontFamilyNames();
245     String unicodeFontName = null;
246     for(int i = 0; i < fontNames.length; i++){
247       if(fontNames[i].equalsIgnoreCase("Arial Unicode MS")){
248         unicodeFontName = fontNames[i];
249         break;
250       }
251       if(fontNames[i].toLowerCase().indexOf("unicode") != -1){
252         unicodeFontName = fontNames[i];
253       }
254     }//for(int i = 0; i < fontNames.length; i++)
255     return unicodeFontName;
256   }
257 
258   /** Get a URL that points to either an HTTP server or a file system
259     * that contains GATE files (such as test cases). The following locations
260     * are tried in sequence:
261     * <UL>
262     * <LI>
263     * <TT>http://derwent.dcs.shef.ac.uk/gate.ac.uk/</TT>, a Sheffield-internal
264     * development server (the gate.ac.uk affix is a copy of the file system
265     * present on GATE's main public server - see next item);
266     * <LI>
267     * <TT>http://gate.ac.uk/</TT>, GATE's main public server;
268     * <LI>
269     * <TT>http://localhost/gate.ac.uk/</TT>, a Web server running on the
270     * local machine;
271     * <LI>
272     * the local file system where the binaries for the
273     * current invocation of GATE are stored.
274     * </UL>
275     * In each case we assume that a Web server will be running on port 80,
276     * and that if we can open a socket to that port then the server is
277     * running. (This is a bit of a strong assumption, but this URL is used
278     * largely by the test suite, so we're not betting anything too critical
279     * on it.)
280     * <P>
281     * Note that the value returned will only be calculated when the existing
282     * value recorded by this class is null (which will be the case when
283     * neither setUrlBase nor getUrlBase have been called, or if
284     * setUrlBase(null) has been called).
285     */
286   public static URL getUrl() throws GateException {
287     if(urlBase != null) return urlBase;
288 
289     try {
290 
291        // if we're assuming a net connection, try network servers
292       if(isNetConnected()) {
293         if(
294           tryNetServer("gate-internal.dcs.shef.ac.uk", 80, "/") ||
295    //       tryNetServer("derwent.dcs.shef.ac.uk", 80, "/gate.ac.uk/") ||
296           tryNetServer("gate.ac.uk", 80, "/")
297         ) {
298             if(DEBUG) Out.prln("getUrl() returned " + urlBase);
299             return urlBase;
300         }
301       } // if isNetConnected() ...
302 
303       // no network servers; try for a local host web server.
304       // we use InetAddress to get host name instead of using "localhost" coz
305       // badly configured Windoze IP sometimes doesn't resolve the latter
306       if(
307         isLocalWebServer() &&
308         tryNetServer(
309           InetAddress.getLocalHost().getHostName(), 80, "/gate.ac.uk/"
310         )
311       ) {
312         if(DEBUG) Out.prln("getUrlBase() returned " + urlBase);
313         return urlBase;
314       }
315 
316       // try the local file system
317       tryFileSystem();
318 
319     } catch(MalformedURLException e) {
320       throw new GateException("Bad URL, getUrlBase(): " + urlBase + ": " + e);
321     } catch(UnknownHostException e) {
322       throw new GateException("No host, getUrlBase(): " + urlBase + ": " + e);
323     }
324 
325     // return value will be based on the file system, or null
326     if(DEBUG) Out.prln("getUrlBase() returned " + urlBase);
327     return urlBase;
328   } // getUrl()
329 
330   /** Get a URL that points to either an HTTP server or a file system
331     * that contains GATE files (such as test cases).
332     * Calls <TT>getUrl()</TT> then adds the <TT>path</TT> parameter to
333     * the result.
334     * @param path a path to add to the base URL.
335     * @see #getUrl()
336     */
337   public static URL getUrl(String path) throws GateException {
338     getUrl();
339     if(urlBase == null)
340       return null;
341 
342     URL newUrl = null;
343     try {
344       newUrl = new URL(urlBase, path);
345     } catch(MalformedURLException e) {
346       throw new GateException("Bad URL, getUrl( " + path + "): " + e);
347     }
348 
349     if(DEBUG) Out.prln("getUrl(" + path + ") returned " + newUrl);
350     return newUrl;
351   } // getUrl(path)
352 
353   /** Flag controlling whether we should try to access the net, e.g. when
354     * setting up a base URL.
355     */
356   private static boolean netConnected = true;
357 
358   private static int lastSym;
359 
360   /**
361    * A list of names of classes that implement {@link gate.creole.ir.IREngine}
362    * that will be used as information retrieval engines.
363    */
364   private static Set registeredIREngines = new HashSet();
365 
366   /**
367    * Registers a new IR engine. The class named should implement
368    * {@link gate.creole.ir.IREngine}.
369    * @param className the fully qualified name of the class to be registered
370    * @throws GateException if the class does not implement the
371    * {@link gate.creole.ir.IREngine} interface.
372    * @throws ClassNotFoundException if the named class cannot be found.
373    */
374   public static void registerIREngine(String className)
375     throws GateException, ClassNotFoundException{
376     Class aClass = Class.forName(className);
377     if(gate.creole.ir.IREngine.class.isAssignableFrom(aClass)){
378       registeredIREngines.add(className);
379     }else{
380       throw new GateException(className + " does not implement the " +
381                               gate.creole.ir.IREngine.class.getName() +
382                               " interface!");
383     }
384   }
385 
386   /**
387    * Unregisters a previously registered IR engine.
388    * @param className the name of the class to be removed from the list of
389    * registered IR engines.
390    * @return true if the class was found and removed.
391    */
392   public static boolean unregisterIREngine(String className){
393     return registeredIREngines.remove(className);
394   }
395 
396   /**
397    * Gets the set of registered IR engines.
398    * @return an unmodifiable {@link java.util.Set} value.
399    */
400   public static Set getRegisteredIREngines(){
401     return Collections.unmodifiableSet(registeredIREngines);
402   }
403 
404   /** Should we assume we're connected to the net? */
405   public static boolean isNetConnected() { return netConnected; }
406 
407   /**
408    * Tell GATE whether to assume we're connected to the net. Has to be
409    * called <B>before</B> {@link #init()}.
410    */
411   public static void setNetConnected(boolean b) { netConnected = b; }
412 
413   /**
414    * Flag controlling whether we should try to access a web server on
415    * localhost, e.g. when setting up a base URL. Has to be
416    * called <B>before</B> {@link #init()}.
417    */
418   private static boolean localWebServer = true;
419 
420   /** Should we assume there's a local web server? */
421   public static boolean isLocalWebServer() { return localWebServer; }
422 
423   /** Tell GATE whether to assume there's a local web server. */
424   public static void setLocalWebServer(boolean b) { localWebServer = b; }
425 
426   /** Try to contact a network server. When sucessfull sets urlBase to an HTTP
427     * URL for the server.
428     * @param hostName the name of the host to try and connect to
429     * @param serverPort the port to try and connect to
430     * @param path a path to append to the URL when we make a successfull
431     * connection. E.g. for host xyz, port 80, path /thing, the resultant URL
432     * would be <TT>http://xyz:80/thing</TT>.
433     */
434   public static boolean tryNetServer(
435     String hostName, int serverPort, String path
436   ) throws MalformedURLException {
437     Socket socket = null;
438     if(DEBUG)
439       Out.prln(
440         "tryNetServer(hostName=" + hostName + ", serverPort=" + serverPort +
441         ", path=" + path +")"
442       );
443 
444     // is the host listening at the port?
445     try{
446       URL url = new URL("http://" + hostName + ":" + serverPort + "/");
447       URLConnection uConn =  url.openConnection();
448       HttpURLConnection huConn = null;
449       if(uConn instanceof HttpURLConnection)
450         huConn = (HttpURLConnection)uConn;
451       if(huConn.getResponseCode() == -1) return false;
452     } catch (IOException e){
453       return false;
454     }
455 
456 //    if(socket != null) {
457       urlBase = new URL("http", hostName, serverPort, path);
458       return true;
459 //    }
460 
461 //    return false;
462   } // tryNetServer()
463 
464   /** Try to find GATE files in the local file system */
465   protected static boolean tryFileSystem() throws MalformedURLException {
466     String urlBaseName = locateGateFiles();
467     if(DEBUG) Out.prln("tryFileSystem: " + urlBaseName);
468 
469     urlBase = new URL(urlBaseName + "gate/resources/gate.ac.uk/");
470     return urlBase == null;
471   } // tryFileSystem()
472 
473   /**
474    * Find the location of the GATE binaries (and resources) in the
475    * local file system.
476    */
477   public static String locateGateFiles() {
478     String aGateResourceName = "gate/resources/creole/creole.xml";
479     URL resourcesUrl = Gate.getClassLoader().getResource(aGateResourceName);
480 
481     StringBuffer basePath = new StringBuffer(resourcesUrl.toExternalForm());
482     String urlBaseName =
483       basePath.substring(0, basePath.length() - aGateResourceName.length());
484 
485     return urlBaseName;
486   } // locateGateFiles
487 
488   /**
489    * Checks whether a particular class is a Gate defined type
490    */
491   public static boolean isGateType(String classname){
492     boolean res = getCreoleRegister().containsKey(classname);
493     if(!res){
494       try{
495         Class aClass = Class.forName(classname);
496         res = Resource.class.isAssignableFrom(aClass) ||
497               Controller.class.isAssignableFrom(aClass) ||
498               DataStore.class.isAssignableFrom(aClass);
499       }catch(ClassNotFoundException cnfe){}
500     }
501     return res;
502   }
503 
504   /** Returns the value for the HIDDEN attribute of a feature map */
505   static public boolean getHiddenAttribute(FeatureMap fm){
506     if(fm == null) return false;
507     Object value = fm.get("gate.HIDDEN");
508     return value != null &&
509            value instanceof String &&
510            ((String)value).equals("true");
511   }
512 
513   /** Sets the value for the HIDDEN attribute of a feature map */
514   static public void setHiddenAttribute(FeatureMap fm, boolean hidden){
515     if(hidden){
516       fm.put("gate.HIDDEN", "true");
517     }else{
518       fm.remove("gate.HIDDEN");
519     }
520   }
521 
522 
523   /** Registers a {@link gate.event.CreoleListener} with the Gate system
524     */
525   public static synchronized void addCreoleListener(CreoleListener l){
526     creoleRegister.addCreoleListener(l);
527   } // addCreoleListener
528 
529   /** Set the URL base for GATE files, e.g. <TT>http://gate.ac.uk/</TT>. */
530   public static void setUrlBase(URL urlBase) { Gate.urlBase = urlBase; }
531 
532   /** The URL base for GATE files, e.g. <TT>http://gate.ac.uk/</TT>. */
533   private static URL urlBase = null;
534 
535   /** Class loader used e.g. for loading CREOLE modules, of compiling
536     * JAPE rule RHSs.
537     */
538   private static GateClassLoader classLoader = null;
539 
540   /** Get the GATE class loader. */
541   public static GateClassLoader getClassLoader() { return classLoader; }
542 
543   /** The CREOLE register. */
544   private static CreoleRegister creoleRegister = null;
545 
546   /** Get the CREOLE register. */
547   public static CreoleRegister getCreoleRegister() { return creoleRegister; }
548 
549   /** The DataStore register */
550   private static DataStoreRegister dataStoreRegister = null;
551 
552   /**
553    * The current executable under execution.
554    */
555   private static gate.Executable currentExecutable;
556 
557   /** Get the DataStore register. */
558   public static DataStoreRegister getDataStoreRegister() {
559     return dataStoreRegister;
560   } // getDataStoreRegister
561 
562   /**
563    * Sets the {@link Executable} currently under execution.
564    * At a given time there can be only one executable set. After the executable
565    * has finished its execution this value should be set back to null.
566    * An attempt to set the executable while this value is not null will result
567    * in the method call waiting until the old executable is set to null.
568    */
569   public synchronized static void setExecutable(gate.Executable executable) {
570     if(executable == null) currentExecutable = executable;
571     else{
572       while(getExecutable() != null){
573         try{
574           Thread.currentThread().sleep(200);
575         }catch(InterruptedException ie){
576           throw new LuckyException(ie.toString());
577         }
578       }
579       currentExecutable = executable;
580     }
581   } // setExecutable
582 
583   /**
584    * Returns the curently set executable.
585    * {@see setExecutable()}
586    */
587   public synchronized static gate.Executable getExecutable() {
588     return currentExecutable;
589   } // getExecutable
590 
591 
592   /**
593    * Returns a new unique string
594    */
595   public synchronized static String genSym() {
596     StringBuffer buff = new StringBuffer(Integer.toHexString(lastSym++).
597                                          toUpperCase());
598     for(int i = buff.length(); i <= 4; i++) buff.insert(0, '0');
599     return buff.toString();
600   } // genSym
601 
602   /** GATE development environment configuration data (stored in gate.xml). */
603   private static OptionsMap userConfig = new OptionsMap();
604 
605   /**
606    * This map stores the init-time config data in case we need it later.
607    * GATE development environment configuration data (stored in gate.xml).
608    */
609   private static OptionsMap originalUserConfig = new OptionsMap();
610 
611   /** Name of the XML element for GATE development environment config data. */
612   private static String userConfigElement = "GATECONFIG";
613 
614   /**
615    * Gate the name of the XML element for GATE development environment
616    * config data.
617    */
618   public static String getUserConfigElement() { return userConfigElement; }
619 
620   /**
621    * Get the site config file (generally set during command-line processing
622    * or as a <TT>gate.config</TT> property).
623    * If the config is null, this method checks the <TT>gate.config</TT>
624    * property and uses it if non-null.
625    */
626   public static File getSiteConfigFile() {
627     if(siteConfigFile == null) {
628       String gateConfigProperty = System.getProperty(GATE_CONFIG_PROPERTY);
629       if(gateConfigProperty != null)
630         siteConfigFile = new File(gateConfigProperty);
631     }
632     return siteConfigFile;
633   } // getSiteConfigFile
634 
635   /** Set the site config file (e.g. during command-line processing). */
636   public static void setSiteConfigFile(File siteConfigFile) {
637     Gate.siteConfigFile = siteConfigFile;
638   } // setSiteConfigFile
639 
640   /** Site config file */
641   private static File siteConfigFile;
642 
643   /** Shorthand for local newline */
644   private static String nl = Strings.getNl();
645 
646   /** An empty config data file. */
647   private static String emptyConfigFile =
648     "<?xml version=\"1.0\"?>" + nl +
649     "<!-- " + GATE_DOT_XML + ": GATE configuration data -->" + nl +
650     "<GATE>" + nl +
651     "" + nl +
652     "<!-- NOTE: the next element may be overwritten by the GUI!!! -->" + nl +
653     "<" + userConfigElement + "/>" + nl +
654     "" + nl +
655     "</GATE>" + nl;
656 
657   /**
658    * Get an empty config file. <B>NOTE:</B> this method is intended only
659    * for use by the test suite.
660    */
661   public static String getEmptyConfigFile() { return emptyConfigFile; }
662 
663   /**
664    * Get the GATE development environment configuration data
665    * (initialised from <TT>gate.xml</TT>).
666    */
667   public static OptionsMap getUserConfig() { return userConfig; }
668 
669   /**
670    * Get the original, initialisation-time,
671    * GATE development environment configuration data
672    * (initialised from <TT>gate.xml</TT>).
673    */
674   public static OptionsMap getOriginalUserConfig() {
675     return originalUserConfig;
676   } // getOriginalUserConfig
677 
678   /**
679    * Update the GATE development environment configuration data in the
680    * user's <TT>gate.xml</TT> file (create one if it doesn't exist).
681    */
682   public static void writeUserConfig() throws GateException {
683     // the user's config file
684     String configFileName = getUserConfigFileName();
685     File configFile = new File(configFileName);
686 
687     // create if not there, then update
688     try {
689       // if the file doesn't exist, create one with an empty GATECONFIG
690       if(! configFile.exists()) {
691         FileWriter writer = new FileWriter(configFile);
692         writer.write(emptyConfigFile);
693         writer.close();
694       }
695 
696       // update the config element of the file
697       Files.updateXmlElement(
698         new File(configFileName), userConfigElement, userConfig
699       );
700 
701     } catch(IOException e) {
702       throw new GateException(
703         "problem writing user " + GATE_DOT_XML + ": " + nl + e.toString()
704       );
705     }
706   } // writeUserConfig
707 
708   /**
709    * Get the name of the user's <TT>gate.xml</TT> config file (this
710    * doesn't guarantee that file exists!).
711    */
712   public static String getUserConfigFileName() {
713     String filePrefix = "";
714     if(runningOnUnix()) filePrefix = ".";
715 
716     String userConfigName =
717       System.getProperty("user.home") + Strings.getFileSep() +
718       filePrefix + GATE_DOT_XML;
719     return userConfigName;
720   } // getUserConfigFileName
721 
722   /**
723    * Get the name of the user's <TT>gate.ser</TT> session state file (this
724    * doesn't guarantee that file exists!).
725    */
726   public static String getUserSessionFileName() {
727     String filePrefix = "";
728     if(runningOnUnix()) filePrefix = ".";
729 
730     String userSessionName =
731       System.getProperty("user.home") + Strings.getFileSep() +
732       filePrefix + GATE_DOT_SER;
733     return userSessionName;
734   } // getUserSessionFileName
735 
736   /**
737    * This method tries to guess if we are on a UNIX system. It does this
738    * by checking the value of <TT>System.getProperty("file.separator")</TT>;
739    * if this is "/" it concludes we are on UNIX. <B>This is obviously not
740    * a very good idea in the general case, so nothing much should be made
741    * to depend on this method (e.g. just naming of config file
742    * <TT>.gate.xml</TT> as opposed to <TT>gate.xml</TT>)</B>.
743    */
744   public static boolean runningOnUnix() {
745     return Strings.getFileSep().equals("/");
746   } // runningOnUnix
747 
748   /** Flag for SLUG GUI start instead of standart GATE GUI. */
749   private static boolean slugGui = false;
750 
751   /** Should we start SLUG GUI. */
752   public static boolean isSlugGui() { return slugGui; }
753 
754   /** Tell GATE whether to start SLUG GUI. */
755   public static void setSlugGui(boolean b) { slugGui = b; }
756 
757 } // class Gate
758