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