JAL-940 - removed legacy service options from preferences and noted deprecation in...
[jalview.git] / src / jalview / bin / Cache.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3  * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  * 
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.bin;
19
20 import java.awt.Color;
21 import java.io.*;
22 import java.util.*;
23
24 import org.apache.log4j.*;
25 import org.biojava.dasobert.dasregistry.Das1Source;
26
27 /**
28  * Stores and retrieves Jalview Application Properties Lists and fields within
29  * list entries are separated by '|' symbols unless otherwise stated (|) clauses
30  * are alternative values for a tag. <br>
31  * <br>
32  * Current properties include:
33  * <ul>
34  * <br>
35  * logs.Axis.Level - one of the stringified Levels for log4j controlling the
36  * logging level for axis (used for web services) <br>
37  * </li>
38  * <li>logs.Castor.Level - one of the stringified Levels for log4j controlling
39  * the logging level for castor (used for serialization) <br>
40  * </li>
41  * <li>logs.Jalview.Level - Cache.log stringified level. <br>
42  * </li>
43  * <li>SCREEN_WIDTH</li>
44  * <li>SCREEN_HEIGHT</li>
45  * <li>SCREEN_Y=285</li>
46  * <li>SCREEN_X=371</li>
47  * <li>SHOW_FULLSCREEN boolean</li>
48  * <li>FONT_NAME java font name for alignment text display</li>
49  * <li>FONT_SIZE size of displayed alignment text</li>
50  * <li>FONT_STYLE style of font displayed (sequence labels are always italic)</li>
51  * <li>GAP_SYMBOL character to treat as gap symbol (usually -,.,' ')</li>
52  * <li>LAST_DIRECTORY last directory for browsing alignment</li>
53  * <li>USER_DEFINED_COLOURS list of user defined colour scheme files</li>
54  * <li>SHOW_FULL_ID show id with '/start-end' numbers appended</li>
55  * <li>SHOW_IDENTITY show percentage identity annotation</li>
56  * <li>SHOW_QUALITY show alignment quality annotation</li>
57  * <li>SHOW_ANNOTATIONS show alignment annotation rows</li>
58  * <li>SHOW_CONSERVATION show alignment conservation annotation</li>
59  * <li>CENTRE_COLUMN_LABELS centre the labels at each column in a displayed
60  * annotation row</li>
61  * <li>DEFAULT_COLOUR default colour scheme to apply for a new alignment</li>
62  * <li>DEFAULT_FILE_FORMAT file format used to save</li>
63  * <li>STARTUP_FILE file loaded on startup (may be a fully qualified url)</li>
64  * <li>SHOW_STARTUP_FILE flag to control loading of startup file</li>
65  * <li>VERSION the version of the jalview build</li>
66  * <li>BUILD_DATE date of this build</li>
67  * <li>LATEST_VERSION the latest jalview version advertised on the
68  * www.jalview.org</li>
69  * <li>PIR_MODELLER boolean indicating if PIR files are written with MODELLER
70  * descriptions</li>
71  * <li>(FASTA,MSF,PILEUP,CLUSTAL,BLC,PIR,PFAM)_JVSUFFIX boolean for adding jv
72  * suffix to file</li>
73  * <li>RECENT_URL list of recently retrieved URLs</li>
74  * <li>RECENT_FILE list of recently opened files</li>
75  * <li>USE_PROXY flag for whether a http proxy is to be used</li>
76  * <li>PROXY_SERVER the proxy</li>
77  * <li>PROXY_PORT</li>
78  * <li>NOQUESTIONNAIRES true to prevent jalview from checking the questionnaire
79  * service</li>
80  * <li>QUESTIONNAIRE last questionnaire:responder id string from questionnaire
81  * service</li>
82  * <li>USAGESTATS (false - user prompted) Enable google analytics tracker for
83  * collecting usage statistics</li>
84  * <li>DAS_LOCAL_SOURCE list of local das sources</li>
85  * <li>SHOW_OVERVIEW boolean for overview window display</li>
86  * <li>ANTI_ALIAS boolean for smooth fonts</li>
87  * <li>RIGHT_ALIGN_IDS boolean</li>
88  * <li>AUTO_CALC_CONSENSUS boolean for automatic recalculation of consensus</li>
89  * <li>PAD_GAPS boolean</li>
90  * <li>ID_ITALICS boolean</li>
91  * <li>SHOW_JV_SUFFIX</li>
92  * <li>WRAP_ALIGNMENT</li>
93  * <li>EPS_RENDERING (Prompt each time|Lineart|Text) default for EPS rendering
94  * style check</li>
95  * <li>SORT_ALIGNMENT (No sort|Id|Pairwise Identity)</li>
96  * <li>SEQUENCE_LINKS list of name|URL pairs for opening a url with
97  * $SEQUENCE_ID$</li>
98  * <li>GROUP_LINKS list of name|URL[|&lt;separator&gt;] tuples - see
99  * jalview.utils.GroupURLLink for more info</li>
100  * <li>DAS_REGISTRY_URL the registry to query</li>
101  * <li>DEFAULT_BROWSER for unix</li>
102  * <li>DAS_ACTIVE_SOURCE list of active sources</li>
103  * <li>SHOW_MEMUSAGE boolean show memory usage and warning indicator on desktop
104  * (false)</li>
105  * <li>VERSION_CHECK (true) check for the latest release version from
106  * www.jalview.org (or the alias given by the www.jalview.org property)</li>
107  * <li>SHOW_NPFEATS_TOOLTIP (true) show non-positional features in the Sequence
108  * ID tooltip</li>
109  * <li>SHOW_DBREFS_TOOLTIP (true) show Database Cross References in the Sequence
110  * ID tooltip</li>
111  * <li>SHOW_UNCONSERVED (false) only render unconserved residues - conserved
112  * displayed as '.'</li>
113  * <li>SORT_BY_TREE (false) sort the current alignment view according to the
114  * order of a newly displayed tree</li>
115  * <li>DBFETCH_USEPICR (false) use PICR to recover valid DB references from
116  * sequence ID strings before attempting retrieval from any datasource</li>
117  * <li>SHOW_GROUP_CONSENSUS (false) Show consensus annotation for groups in the
118  * alignment.</li>
119  * <li>SHOW_GROUP_CONSERVATION (false) Show conservation annotation for groups
120  * in the alignment.</li>
121  * <li>SHOW_CONSENSUS_HISTOGRAM (false) Show consensus annotation row's
122  * histogram.</li>
123  * <li>SHOW_CONSENSUS_LOGO (false) Show consensus annotation row's sequence
124  * logo.</li>
125  * <li>FOLLOW_SELECTIONS (true) Controls whether a new alignment view should
126  * respond to selections made in other alignments containing the same sequences.
127  * </li>
128  * <li>SHOW_WSDISCOVERY_ERRORS (true) Controls if the web service URL discovery
129  * warning dialog box is displayed.</li>
130  * <li>ANNOTATIONCOLOUR_MIN (orange) Shade used for minimum value of annotation when shading by annotation</li>
131  * <li>ANNOTATIONCOLOUR_MAX (red) Shade used for maximum value of annotation when shading by annotation</li>
132  * <li>www.jalview.org (http://www.jalview.org) a property enabling all HTTP requests to be redirected to a mirror of http://www.jalview.org</li>
133  * 
134  * <li></li>
135  * 
136  * </ul>
137  * Deprecated settings:
138  * <ul>
139  *  * <li>DISCOVERY_START - Boolean - controls if discovery services are queried on
140  * startup (JWS1 services only)</li>
141  * <li>DISCOVERY_URLS - comma separated list of Discovery Service endpoints. (JWS1 services only)</li>
142  * <li>SHOW_JWS1_SERVICES (true) enable or disable the original Jalview 2 services in the desktop GUI
143  * </ul>
144  * @author $author$
145  * @version $Revision$
146  */
147 public class Cache
148 {
149   /**
150    * property giving log4j level for CASTOR loggers
151    */
152   public static final String CASTORLOGLEVEL = "logs.Castor.level";
153
154   /**
155    * property giving log4j level for AXIS loggers
156    */
157   public static final String AXISLOGLEVEL = "logs.Axis.level";
158
159   /**
160    * property giving log4j level for Jalview Log
161    */
162   public static final String JALVIEWLOGLEVEL = "logs.Jalview.level";
163
164   public static final String DAS_LOCAL_SOURCE = "DAS_LOCAL_SOURCE";
165
166   public static final String DAS_REGISTRY_URL = "DAS_REGISTRY_URL";
167
168   public static final String DAS_ACTIVE_SOURCE = "DAS_ACTIVE_SOURCE";
169
170   /**
171    * Initialises the Jalview Application Log
172    */
173   public static Logger log;
174
175   /** Jalview Properties */
176   public static Properties applicationProperties = new Properties();
177
178   /** Default file is ~/.jalview_properties */
179   static String propertiesFile;
180
181   private static boolean propsAreReadOnly=false;
182
183   public static void initLogger()
184   {
185     if (log != null)
186     {
187       return;
188     }
189     try
190     {
191       // TODO: redirect stdout and stderr here in order to grab the output of
192       // the log
193
194       ConsoleAppender ap = new ConsoleAppender(new SimpleLayout(),
195               "System.err");
196       ap.setName("JalviewLogger");
197       org.apache.log4j.Logger.getRootLogger().addAppender(ap); // catch all for
198       // log output
199       Logger laxis = Logger.getLogger("org.apache.axis");
200       Logger lcastor = Logger.getLogger("org.exolab.castor");
201       jalview.bin.Cache.log = Logger.getLogger("jalview.bin.Jalview");
202
203       laxis.setLevel(Level.toLevel(Cache.getDefault("logs.Axis.Level",
204               Level.INFO.toString())));
205       lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
206               Level.INFO.toString())));
207       lcastor = Logger.getLogger("org.exolab.castor.xml");
208       lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
209               Level.INFO.toString())));
210       // lcastor = Logger.getLogger("org.exolab.castor.xml.Marshaller");
211       // lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
212       // Level.INFO.toString())));
213       jalview.bin.Cache.log.setLevel(Level.toLevel(Cache.getDefault(
214               "logs.Jalview.level", Level.INFO.toString())));
215       // laxis.addAppender(ap);
216       // lcastor.addAppender(ap);
217       // jalview.bin.Cache.log.addAppender(ap);
218       // Tell the user that debug is enabled
219       jalview.bin.Cache.log.debug("Jalview Debugging Output Follows.");
220     } catch (Exception ex)
221     {
222       System.err.println("Problems initializing the log4j system\n");
223       ex.printStackTrace(System.err);
224     }
225   }
226
227   /** Called when Jalview is started */
228   public static void loadProperties(String propsFile)
229   {
230     propertiesFile = propsFile;
231     if (propsFile == null)
232     {
233       propertiesFile = System.getProperty("user.home") + File.separatorChar
234               + ".jalview_properties";
235     } else {
236       // don't corrupt the file we've been given.
237       propsAreReadOnly = true;
238     }
239
240     try
241     {
242       InputStream fis;
243       try
244       {
245         fis = new java.net.URL(propertiesFile).openStream();
246         System.out.println("Loading jalview properties from : "
247                 + propertiesFile);
248         System.out
249                 .println("Disabling Jalview writing to user's local properties file.");
250         propsAreReadOnly = true;
251
252       } catch (Exception ex)
253       {
254         fis = null;
255       }
256       if (fis == null)
257       {
258         fis = new FileInputStream(propertiesFile);
259       }
260       applicationProperties.load(fis);
261       applicationProperties.remove("LATEST_VERSION");
262       applicationProperties.remove("VERSION");
263       fis.close();
264     } catch (Exception ex)
265     {
266       System.out.println("Error reading properties file: " + ex);
267     }
268
269     if (getDefault("USE_PROXY", false))
270     {
271       System.out.println("Using proxyServer: "
272               + getDefault("PROXY_SERVER", null) + " proxyPort: "
273               + getDefault("PROXY_PORT", null));
274       System.setProperty("http.proxyHost", getDefault("PROXY_SERVER", null));
275       System.setProperty("http.proxyPort", getDefault("PROXY_PORT", null));
276     }
277
278     // FIND THE VERSION NUMBER AND BUILD DATE FROM jalview.jar
279     // MUST FOLLOW READING OF LOCAL PROPERTIES FILE AS THE
280     // VERSION MAY HAVE CHANGED SINCE LAST USING JALVIEW
281     try
282     {
283       String buildDetails = "jar:".concat(Cache.class.getProtectionDomain()
284               .getCodeSource().getLocation().toString()
285               .concat("!/.build_properties"));
286
287       java.net.URL localJarFileURL = new java.net.URL(buildDetails);
288
289       InputStream in = localJarFileURL.openStream();
290       applicationProperties.load(in);
291       in.close();
292     } catch (Exception ex)
293     {
294       System.out.println("Error reading build details: " + ex);
295       applicationProperties.remove("VERSION");
296     }
297
298     String jnlpVersion = System.getProperty("jalview.version");
299     String codeVersion = getProperty("VERSION");
300
301     if (codeVersion == null)
302     {
303       // THIS SHOULD ONLY BE THE CASE WHEN TESTING!!
304       codeVersion = "Test";
305       jnlpVersion = "Test";
306     }
307
308     System.out.println("Jalview Version: " + codeVersion);
309
310     // jnlpVersion will be null if we're using InstallAnywhere
311     // Dont do this check if running in headless mode
312     if (jnlpVersion == null
313             && getDefault("VERSION_CHECK", true)
314             && (System.getProperty("java.awt.headless") == null || System
315                     .getProperty("java.awt.headless").equals("false")))
316     {
317
318       class VersionChecker extends Thread
319       {
320         public void run()
321         {
322           String orgtimeout = System
323                   .getProperty("sun.net.client.defaultConnectTimeout");
324           if (orgtimeout == null)
325           {
326             orgtimeout = "30";
327             System.out.println("# INFO: Setting default net timeout to "
328                     + orgtimeout + " seconds.");
329           }
330           String jnlpVersion = null;
331           try
332           {
333             System.setProperty("sun.net.client.defaultConnectTimeout",
334                     "5000");
335             java.net.URL url = new java.net.URL(
336                     Cache.getDefault("www.jalview.org", "http://www.jalview.org")+"/webstart/jalview.jnlp");
337             BufferedReader in = new BufferedReader(new InputStreamReader(
338                     url.openStream()));
339             String line = null;
340             while ((line = in.readLine()) != null)
341             {
342               if (line.indexOf("jalview.version") == -1)
343               {
344                 continue;
345               }
346
347               line = line.substring(line.indexOf("value=") + 7);
348               line = line.substring(0, line.lastIndexOf("\""));
349               jnlpVersion = line;
350               break;
351             }
352           } catch (Exception ex)
353           {
354             System.out
355                     .println("Non-fatal exceptions when checking version at www.jalview.org :");
356             System.out.println(ex);
357             jnlpVersion = getProperty("VERSION");
358           }
359           System.setProperty("sun.net.client.defaultConnectTimeout",
360                   orgtimeout);
361
362           setProperty("LATEST_VERSION", jnlpVersion);
363         }
364       }
365
366       VersionChecker vc = new VersionChecker();
367       vc.start();
368     }
369     else
370     {
371       if (jnlpVersion != null)
372       {
373         setProperty("LATEST_VERSION", jnlpVersion);
374       }
375       else
376       {
377         applicationProperties.remove("LATEST_VERSION");
378       }
379     }
380
381     setProperty("VERSION", codeVersion);
382
383     // LOAD USERDEFINED COLOURS
384     jalview.gui.UserDefinedColours
385             .initUserColourSchemes(getProperty("USER_DEFINED_COLOURS"));
386     jalview.io.PIRFile.useModellerOutput = Cache.getDefault("PIR_MODELLER",
387             false);
388   }
389
390   /**
391    * Gets Jalview application property of given key. Returns null if key not
392    * found
393    * 
394    * @param key
395    *          Name of property
396    * 
397    * @return Property value
398    */
399   public static String getProperty(String key)
400   {
401     return applicationProperties.getProperty(key);
402   }
403
404   /**
405    * These methods are used when checking if the saved preference is different
406    * to the default setting
407    */
408
409   public static boolean getDefault(String property, boolean def)
410   {
411     String string = getProperty(property);
412     if (string != null)
413     {
414       def = Boolean.valueOf(string).booleanValue();
415     }
416
417     return def;
418   }
419
420   /**
421    * These methods are used when checking if the saved preference is different
422    * to the default setting
423    */
424   public static String getDefault(String property, String def)
425   {
426     String string = getProperty(property);
427     if (string != null)
428     {
429       return string;
430     }
431
432     return def;
433   }
434
435   /**
436    * Stores property in the file "HOME_DIR/.jalview_properties"
437    * 
438    * @param key
439    *          Name of object
440    * @param obj
441    *          String value of property
442    * 
443    * @return String value of property
444    */
445   public static String setProperty(String key, String obj)
446   {
447
448     try
449     {
450       applicationProperties.setProperty(key, obj);
451       if (!propsAreReadOnly)
452       {
453         FileOutputStream out = new FileOutputStream(propertiesFile);
454         applicationProperties.store(out, "---JalviewX Properties File---");
455         out.close();
456       }
457     } catch (Exception ex)
458     {
459       System.out.println("Error setting property: " + key + " " + obj
460               + "\n" + ex);
461     }
462     return obj;
463   }
464
465   /**
466    * remove the specified property from the jalview properties file
467    * 
468    * @param string
469    */
470   public static void removeProperty(String string)
471   {
472     applicationProperties.remove(string);
473     saveProperties();
474   }
475
476   /**
477    * save the properties to the jalview properties path
478    */
479   public static void saveProperties()
480   {
481     if (!propsAreReadOnly)
482     {
483       try
484       {
485         FileOutputStream out = new FileOutputStream(propertiesFile);
486         applicationProperties.store(out, "---JalviewX Properties File---");
487         out.close();
488       } catch (Exception ex)
489       {
490         System.out.println("Error saving properties: " + ex);
491       }
492     }
493   }
494
495   /**
496    * internal vamsas class discovery state
497    */
498   private static int vamsasJarsArePresent = -1;
499
500   /**
501    * Searches for vamsas client classes on class path.
502    * 
503    * @return true if vamsas client is present on classpath
504    */
505   public static boolean vamsasJarsPresent()
506   {
507     if (vamsasJarsArePresent == -1)
508     {
509       try
510       {
511         if (jalview.jbgui.GDesktop.class.getClassLoader().loadClass(
512                 "uk.ac.vamsas.client.VorbaId") != null)
513         {
514           jalview.bin.Cache.log
515                   .debug("Found Vamsas Classes (uk.ac..vamsas.client.VorbaId can be loaded)");
516           vamsasJarsArePresent = 1;
517           Logger lvclient = Logger.getLogger("uk.ac.vamsas");
518           lvclient.setLevel(Level.toLevel(Cache.getDefault(
519                   "logs.Vamsas.Level", Level.INFO.toString())));
520
521           lvclient.addAppender(log.getAppender("JalviewLogger"));
522           // Tell the user that debug is enabled
523           lvclient.debug("Jalview Vamsas Client Debugging Output Follows.");
524         }
525       } catch (Exception e)
526       {
527         vamsasJarsArePresent = 0;
528         jalview.bin.Cache.log.debug("Vamsas Classes are not present");
529       }
530     }
531     return (vamsasJarsArePresent > 0);
532   }
533
534   /**
535    * internal vamsas class discovery state
536    */
537   private static int groovyJarsArePresent = -1;
538
539   /**
540    * Searches for vamsas client classes on class path.
541    * 
542    * @return true if vamsas client is present on classpath
543    */
544   public static boolean groovyJarsPresent()
545   {
546     if (groovyJarsArePresent == -1)
547     {
548       try
549       {
550         if (Cache.class.getClassLoader().loadClass(
551                 "groovy.lang.GroovyObject") != null)
552         {
553           jalview.bin.Cache.log
554                   .debug("Found Groovy (groovy.lang.GroovyObject can be loaded)");
555           groovyJarsArePresent = 1;
556           Logger lgclient = Logger.getLogger("groovy");
557           lgclient.setLevel(Level.toLevel(Cache.getDefault(
558                   "logs.Groovy.Level", Level.INFO.toString())));
559
560           lgclient.addAppender(log.getAppender("JalviewLogger"));
561           // Tell the user that debug is enabled
562           lgclient.debug("Jalview Groovy Client Debugging Output Follows.");
563         }
564       } catch (Error e)
565       {
566         groovyJarsArePresent = 0;
567         jalview.bin.Cache.log.debug("Groovy Classes are not present", e);
568       } catch (Exception e)
569       {
570         groovyJarsArePresent = 0;
571         jalview.bin.Cache.log.debug("Groovy Classes are not present");
572       }
573     }
574     return (groovyJarsArePresent > 0);
575   }
576
577   /**
578    * generate Das1Sources from the local das source list
579    * 
580    * @return Vector of Das1Sources
581    */
582   public static Vector getLocalDasSources()
583   {
584     Vector localSources = new Vector();
585     String local = jalview.bin.Cache.getProperty("DAS_LOCAL_SOURCE");
586     if (local != null)
587     {
588       StringTokenizer st = new StringTokenizer(local, "\t");
589       while (st.hasMoreTokens())
590       {
591         String token = st.nextToken();
592         int bar = token.indexOf("|");
593         Das1Source source = new Das1Source();
594         source.setUrl(token.substring(bar + 1));
595         if (source.getUrl().startsWith("sequence:"))
596         {
597           source.setUrl(source.getUrl().substring(9));
598           // this source also serves sequences as well as features
599           source.setCapabilities(new String[]
600           { "sequence", "features" });
601         }
602         else
603         {
604           // default is that all user added sources serve features
605           source.setCapabilities(new String[]
606           { "features" });
607         }
608
609         source.setNickname(token.substring(0, bar));
610
611         localSources.addElement(source);
612       }
613     }
614     return localSources;
615   }
616
617   /**
618    * GA tracker object - actually JGoogleAnalyticsTracker null if tracking not
619    * enabled.
620    */
621   protected static Object tracker = null;
622
623   protected static Class trackerfocus = null;
624
625   protected static Class jgoogleanalyticstracker = null;
626
627   /**
628    * Initialise the google tracker if it is not done already.
629    */
630   public static void initGoogleTracker()
631   {
632     if (tracker == null)
633     {
634       if (jgoogleanalyticstracker == null)
635       {
636         // try to get the tracker class
637         try
638         {
639           jgoogleanalyticstracker = Cache.class
640                   .getClassLoader()
641                   .loadClass(
642                           "com.boxysystems.jgoogleanalytics.JGoogleAnalyticsTracker");
643           trackerfocus = Cache.class.getClassLoader().loadClass(
644                   "com.boxysystems.jgoogleanalytics.FocusPoint");
645         } catch (Exception e)
646         {
647           log.debug("com.boxysystems.jgoogleanalytics package is not present - tracking not enabled.");
648           tracker = null;
649           jgoogleanalyticstracker = null;
650           trackerfocus = null;
651           return;
652         }
653       }
654       // now initialise tracker
655       Exception re = null, ex = null;
656       Error err = null;
657       String vrs = "No Version Accessible";
658       try
659       {
660         // Google analytics tracking code for Library Finder
661         tracker = jgoogleanalyticstracker.getConstructor(new Class[]
662         { String.class, String.class, String.class }).newInstance(
663                 new Object[]
664                 {
665                     "Jalview Desktop",
666                     (vrs = jalview.bin.Cache.getProperty("VERSION")
667                             + "_"
668                             + jalview.bin.Cache.getDefault("BUILD_DATE",
669                                     "unknown")), "UA-9060947-1" });
670         jgoogleanalyticstracker.getMethod("trackAsynchronously",
671                 new Class[]
672                 { trackerfocus }).invoke(tracker, new Object[]
673         { trackerfocus.getConstructor(new Class[]
674         { String.class }).newInstance(new Object[]
675         { "Application Started." }) });
676       } catch (RuntimeException e)
677       {
678         re = e;
679       } catch (Exception e)
680       {
681         ex = e;
682       } catch (Error e)
683       {
684         err = e;
685       }
686       if (re != null || ex != null || err != null)
687       {
688         if (log != null)
689         {
690           if (re != null)
691             log.debug("Caught runtime exception in googletracker init:", re);
692           if (ex != null)
693             log.warn(
694                     "Failed to initialise GoogleTracker for Jalview Desktop with version "
695                             + vrs, ex);
696           if (err != null)
697             log.error(
698                     "Whilst initing GoogleTracker for Jalview Desktop version "
699                             + vrs, err);
700         }
701         else
702         {
703           if (re != null)
704           {
705             System.err
706                     .println("Debug: Caught runtime exception in googletracker init:"
707                             + vrs);
708             re.printStackTrace();
709           }
710           if (ex != null)
711           {
712             System.err
713                     .println("Warning:  Failed to initialise GoogleTracker for Jalview Desktop with version "
714                             + vrs);
715             ex.printStackTrace();
716           }
717
718           if (err != null)
719           {
720             System.err
721                     .println("ERROR: Whilst initing GoogleTracker for Jalview Desktop version "
722                             + vrs);
723             err.printStackTrace();
724           }
725         }
726       }
727       else
728       {
729         log.debug("Successfully initialised tracker.");
730       }
731     }
732   }
733
734   /**
735    * get the user's default colour if available
736    * @param property
737    * @param defcolour
738    * @return
739    */
740   public static Color getDefaultColour(String property, Color defcolour)
741   {
742     String colprop = getProperty(property);
743     if (colprop==null) {
744       return defcolour;
745     }
746     Color col = jalview.schemes.ColourSchemeProperty.getAWTColorFromName(colprop);
747     if (col==null)
748     {
749       try {
750         col = new jalview.schemes.UserColourScheme(colprop).findColour('A');
751       } catch (Exception ex)
752       {
753         log.warn("Couldn't parse '"+colprop+"' as a colour for "+property);
754         col=null;
755       }
756     }
757     return (col==null) ? defcolour: col;
758   }
759
760   /**
761    * store a colour as a Jalview user default property
762    * @param property
763    * @param colour     
764    */
765   public static void setColourProperty(String property, Color colour)
766   {
767     setProperty(property, jalview.util.Format
768           .getHexString(colour));
769   }
770 }