bae40cac24fc154a50a3fc7c952a69eb326902a0
[jalview.git] / src / jalview / bin / Cache.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3  * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.bin;
20
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
44  * on startup </li>
45  * <li>DISCOVERY_URLS - comma separated list of Discovery Service endpoints.
46  * </li>
47  * <li>SCREEN_WIDTH </li>
48  * <li>SCREEN_HEIGHT </li>
49  * <li>SCREEN_Y=285 </li>
50  * <li>SCREEN_X=371 </li>
51  * <li>SHOW_FULLSCREEN boolean </li>
52  * <li>FONT_NAME java font name for alignment text display </li>
53  * <li>FONT_SIZE size of displayed alignment text </li>
54  * <li>FONT_STYLE style of font displayed (sequence labels are always italic)
55  * </li>
56  * <li>GAP_SYMBOL character to treat as gap symbol (usually -,.,' ') </li>
57  * <li>LAST_DIRECTORY last directory for browsing alignment </li>
58  * <li>USER_DEFINED_COLOURS list of user defined colour scheme files </li>
59  * <li>SHOW_FULL_ID show id with '/start-end' numbers appended </li>
60  * <li>SHOW_IDENTITY show percentage identity annotation </li>
61  * <li>SHOW_QUALITY show alignment quality annotation </li>
62  * <li>SHOW_ANNOTATIONS show alignment annotation rows </li>
63  * <li>SHOW_CONSERVATION show alignment conservation annotation </li>
64  * <li>CENTRE_COLUMN_LABELS centre the labels at each column in a displayed
65  * annotation row </li>
66  * <li>DEFAULT_COLOUR default colour scheme to apply for a new alignment </li>
67  * <li>DEFAULT_FILE_FORMAT file format used to save </li>
68  * <li>STARTUP_FILE file loaded on startup (may be a fully qualified url) </li>
69  * <li>SHOW_STARTUP_FILE flag to control loading of startup file </li>
70  * <li>VERSION the version of the jalview build </li>
71  * <li>BUILD_DATE date of this build </li>
72  * <li>LATEST_VERSION the latest jalview version advertised on the
73  * www.jalview.org </li>
74  * <li>PIR_MODELLER boolean indicating if PIR files are written with MODELLER
75  * descriptions </li>
76  * <li>(FASTA,MSF,PILEUP,CLUSTAL,BLC,PIR,PFAM)_JVSUFFIX boolean for adding jv
77  * suffix to file </li>
78  * <li>RECENT_URL list of recently retrieved URLs </li>
79  * <li>RECENT_FILE list of recently opened files </li>
80  * <li>USE_PROXY flag for whether a http proxy is to be used </li>
81  * <li>PROXY_SERVER the proxy </li>
82  * <li>PROXY_PORT </li>
83  * <li>NOQUESTIONNAIRES true to prevent jalview from checking the questionnaire
84  * service </li>
85  * <li>QUESTIONNAIRE last questionnaire:responder id string from questionnaire
86  * service </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
92  * </li>
93  * <li>PAD_GAPS boolean </li>
94  * <li>ID_ITALICS boolean </li>
95  * <li>SHOW_JV_SUFFIX </li>
96  * <li>WRAP_ALIGNMENT </li>
97  * <li>EPS_RENDERING (Prompt each time|Lineart|Text) default for EPS rendering
98  * style check </li>
99  * <li>SORT_ALIGNMENT (No sort|Id|Pairwise Identity) </li>
100  * <li>SEQUENCE_LINKS list of name|URL pairs for opening a url with
101  * $SEQUENCE_ID$ </li>
102  * <li>DAS_REGISTRY_URL the registry to query </li>
103  * <li>DEFAULT_BROWSER for unix </li>
104  * <li>DAS_ACTIVE_SOURCE list of active sources </li>
105  * <li>SHOW_MEMUSAGE boolean show memory usage and warning indicator on desktop
106  * (false) </li>
107  * <li>SHOW_NPFEATS_TOOLTIP (true) show non-positional features in the Sequence ID tooltip</li>
108  * <li>SHOW_DBREFS_TOOLTIP (true) show Database Cross References in the Sequence ID tooltip</li>
109  * <li> </li>
110  * 
111  * </ul>
112  * 
113  * @author $author$
114  * @version $Revision$
115  */
116 public class Cache
117 {
118   /**
119    * property giving log4j level for CASTOR loggers
120    */
121   public static final String CASTORLOGLEVEL = "logs.Castor.level";
122
123   /**
124    * property giving log4j level for AXIS loggers
125    */
126   public static final String AXISLOGLEVEL = "logs.Axis.level";
127
128   /**
129    * property giving log4j level for Jalview Log
130    */
131   public static final String JALVIEWLOGLEVEL = "logs.Jalview.level";
132
133   public static final String DAS_LOCAL_SOURCE = "DAS_LOCAL_SOURCE";
134
135   public static final String DAS_REGISTRY_URL = "DAS_REGISTRY_URL";
136
137   public static final String DAS_ACTIVE_SOURCE = "DAS_ACTIVE_SOURCE";
138
139   /**
140    * Initialises the Jalview Application Log
141    */
142   public static Logger log;
143
144   /** Jalview Properties */
145   public static Properties applicationProperties = new Properties();
146
147   /** Default file is ~/.jalview_properties */
148   static String propertiesFile;
149
150   public static void initLogger()
151   {
152     try
153     {
154       ConsoleAppender ap = new ConsoleAppender(new SimpleLayout(),
155               "System.err");
156       ap.setName("JalviewLogger");
157       org.apache.log4j.Logger.getRootLogger().addAppender(ap); // catch all for
158                                                                 // log output
159       Logger laxis = Logger.getLogger("org.apache.axis");
160       Logger lcastor = Logger.getLogger("org.exolab.castor");
161       jalview.bin.Cache.log = Logger.getLogger("jalview.bin.Jalview");
162
163       laxis.setLevel(Level.toLevel(Cache.getDefault("logs.Axis.Level",
164               Level.INFO.toString())));
165       lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
166               Level.INFO.toString())));
167       lcastor = Logger.getLogger("org.exolab.castor.xml");
168       lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
169               Level.INFO.toString())));
170       // lcastor = Logger.getLogger("org.exolab.castor.xml.Marshaller");
171       // lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
172       // Level.INFO.toString())));
173       jalview.bin.Cache.log.setLevel(Level.toLevel(Cache.getDefault(
174               "logs.Jalview.level", Level.INFO.toString())));
175       // laxis.addAppender(ap);
176       // lcastor.addAppender(ap);
177       // jalview.bin.Cache.log.addAppender(ap);
178       // Tell the user that debug is enabled
179       jalview.bin.Cache.log.debug("Jalview Debugging Output Follows.");
180     } catch (Exception ex)
181     {
182       System.err.println("Problems initializing the log4j system\n");
183       ex.printStackTrace(System.err);
184     }
185   }
186
187   /** Called when Jalview is started */
188   public static void loadProperties(String propsFile)
189   {
190     propertiesFile = propsFile;
191     if (propsFile == null)
192     {
193       propertiesFile = System.getProperty("user.home") + File.separatorChar
194               + ".jalview_properties";
195     }
196
197     try
198     {
199       FileInputStream fis = new FileInputStream(propertiesFile);
200       applicationProperties.load(fis);
201       applicationProperties.remove("LATEST_VERSION");
202       applicationProperties.remove("VERSION");
203       fis.close();
204     } catch (Exception ex)
205     {
206       System.out.println("Error reading properties file: " + ex);
207     }
208
209     if (getDefault("USE_PROXY", false))
210     {
211       System.out.println("Using proxyServer: "
212               + getDefault("PROXY_SERVER", null) + " proxyPort: "
213               + getDefault("PROXY_PORT", null));
214       System
215               .setProperty("http.proxyHost", getDefault("PROXY_SERVER",
216                       null));
217       System.setProperty("http.proxyPort", getDefault("PROXY_PORT", null));
218     }
219
220     // FIND THE VERSION NUMBER AND BUILD DATE FROM jalview.jar
221     // MUST FOLLOW READING OF LOCAL PROPERTIES FILE AS THE
222     // VERSION MAY HAVE CHANGED SINCE LAST USING JALVIEW
223     try
224     {
225       String buildDetails = "jar:".concat(Cache.class.getProtectionDomain()
226               .getCodeSource().getLocation().toString().concat(
227                       "!/.build_properties"));
228
229       java.net.URL localJarFileURL = new java.net.URL(buildDetails);
230
231       InputStream in = localJarFileURL.openStream();
232       applicationProperties.load(in);
233       in.close();
234     } catch (Exception ex)
235     {
236       System.out.println("Error reading build details: " + ex);
237       applicationProperties.remove("VERSION");
238     }
239
240     String jnlpVersion = System.getProperty("jalview.version");
241     String codeVersion = getProperty("VERSION");
242
243     if (codeVersion == null)
244     {
245       // THIS SHOULD ONLY BE THE CASE WHEN TESTING!!
246       codeVersion = "Test";
247       jnlpVersion = "Test";
248     }
249
250     System.out.println("Jalview Version: " + codeVersion);
251
252     // jnlpVersion will be null if we're using InstallAnywhere
253     // Dont do this check if running in headless mode
254     if (jnlpVersion == null
255             && (System.getProperty("java.awt.headless") == null || System
256                     .getProperty("java.awt.headless").equals("false")))
257     {
258
259       class VersionChecker extends Thread
260       {
261         public void run()
262         {
263           String orgtimeout = System
264                   .getProperty("sun.net.client.defaultConnectTimeout");
265           if (orgtimeout == null)
266           {
267             orgtimeout = "30";
268             System.out.println("# INFO: Setting default net timeout to "
269                     + orgtimeout + " seconds.");
270           }
271           String jnlpVersion = null;
272           try
273           {
274             System.setProperty("sun.net.client.defaultConnectTimeout",
275                     "5000");
276             java.net.URL url = new java.net.URL(
277                     "http://www.jalview.org/webstart/jalview.jnlp");
278             BufferedReader in = new BufferedReader(new InputStreamReader(
279                     url.openStream()));
280             String line = null;
281             while ((line = in.readLine()) != null)
282             {
283               if (line.indexOf("jalview.version") == -1)
284               {
285                 continue;
286               }
287
288               line = line.substring(line.indexOf("value=") + 7);
289               line = line.substring(0, line.lastIndexOf("\""));
290               jnlpVersion = line;
291               break;
292             }
293           } catch (Exception ex)
294           {
295             System.out
296                     .println("Non-fatal exceptions when checking version at www.jalview.org :");
297             System.out.println(ex);
298             jnlpVersion = getProperty("VERSION");
299           }
300           System.setProperty("sun.net.client.defaultConnectTimeout",
301                   orgtimeout);
302
303           setProperty("LATEST_VERSION", jnlpVersion);
304         }
305       }
306
307       VersionChecker vc = new VersionChecker();
308       vc.start();
309     }
310     else
311     {
312       if (jnlpVersion != null)
313       {
314         setProperty("LATEST_VERSION", jnlpVersion);
315       }
316       else
317       {
318         applicationProperties.remove("LATEST_VERSION");
319       }
320     }
321
322     setProperty("VERSION", codeVersion);
323
324     // LOAD USERDEFINED COLOURS
325     jalview.gui.UserDefinedColours
326             .initUserColourSchemes(getProperty("USER_DEFINED_COLOURS"));
327     jalview.io.PIRFile.useModellerOutput = Cache.getDefault("PIR_MODELLER",
328             false);
329   }
330
331   /**
332    * Gets Jalview application property of given key. Returns null if key not
333    * found
334    * 
335    * @param key
336    *                Name of property
337    * 
338    * @return Property value
339    */
340   public static String getProperty(String key)
341   {
342     return applicationProperties.getProperty(key);
343   }
344
345   /**
346    * These methods are used when checking if the saved preference is different
347    * to the default setting
348    */
349
350   public static boolean getDefault(String property, boolean def)
351   {
352     String string = getProperty(property);
353     if (string != null)
354     {
355       def = Boolean.valueOf(string).booleanValue();
356     }
357
358     return def;
359   }
360
361   /**
362    * These methods are used when checking if the saved preference is different
363    * to the default setting
364    */
365   public static String getDefault(String property, String def)
366   {
367     String string = getProperty(property);
368     if (string != null)
369     {
370       return string;
371     }
372
373     return def;
374   }
375
376   /**
377    * Stores property in the file "HOME_DIR/.jalview_properties"
378    * 
379    * @param key
380    *                Name of object
381    * @param obj
382    *                String value of property
383    * 
384    * @return String value of property
385    */
386   public static String setProperty(String key, String obj)
387   {
388     try
389     {
390       FileOutputStream out = new FileOutputStream(propertiesFile);
391       applicationProperties.setProperty(key, obj);
392       applicationProperties.store(out, "---JalviewX Properties File---");
393       out.close();
394     } catch (Exception ex)
395     {
396       System.out.println("Error setting property: " + key + " " + obj
397               + "\n" + ex);
398     }
399     return obj;
400   }
401
402   public static void saveProperties()
403   {
404     try
405     {
406       FileOutputStream out = new FileOutputStream(propertiesFile);
407       applicationProperties.store(out, "---JalviewX Properties File---");
408       out.close();
409     } catch (Exception ex)
410     {
411       System.out.println("Error saving properties: " + ex);
412     }
413   }
414
415   /**
416    * internal vamsas class discovery state
417    */
418   private static int vamsasJarsArePresent = -1;
419
420   /**
421    * Searches for vamsas client classes on class path.
422    * 
423    * @return true if vamsas client is present on classpath
424    */
425   public static boolean vamsasJarsPresent()
426   {
427     if (vamsasJarsArePresent == -1)
428     {
429       try
430       {
431         if (jalview.jbgui.GDesktop.class.getClassLoader().loadClass(
432                 "uk.ac.vamsas.client.VorbaId") != null)
433         {
434           jalview.bin.Cache.log
435                   .debug("Found Vamsas Classes (uk.ac..vamsas.client.VorbaId can be loaded)");
436           vamsasJarsArePresent = 1;
437           Logger lvclient = Logger.getLogger("uk.ac.vamsas");
438           lvclient.setLevel(Level.toLevel(Cache.getDefault(
439                   "logs.Vamsas.Level", Level.INFO.toString())));
440
441           lvclient.addAppender(log.getAppender("JalviewLogger"));
442           // Tell the user that debug is enabled
443           lvclient.debug("Jalview Vamsas Client Debugging Output Follows.");
444         }
445       } catch (Exception e)
446       {
447         vamsasJarsArePresent = 0;
448         jalview.bin.Cache.log.debug("Vamsas Classes are not present");
449       }
450     }
451     return (vamsasJarsArePresent > 0);
452   }
453
454   /**
455    * internal vamsas class discovery state
456    */
457   private static int groovyJarsArePresent = -1;
458
459   /**
460    * Searches for vamsas client classes on class path.
461    * 
462    * @return true if vamsas client is present on classpath
463    */
464   public static boolean groovyJarsPresent()
465   {
466     if (groovyJarsArePresent == -1)
467     {
468       try
469       {
470         if (Cache.class.getClassLoader().loadClass(
471                 "groovy.lang.GroovyObject") != null)
472         {
473           jalview.bin.Cache.log
474                   .debug("Found Groovy (groovy.lang.GroovyObject can be loaded)");
475           groovyJarsArePresent = 1;
476           Logger lgclient = Logger.getLogger("groovy");
477           lgclient.setLevel(Level.toLevel(Cache.getDefault(
478                   "logs.Groovy.Level", Level.INFO.toString())));
479
480           lgclient.addAppender(log.getAppender("JalviewLogger"));
481           // Tell the user that debug is enabled
482           lgclient.debug("Jalview Groovy Client Debugging Output Follows.");
483         }
484       } catch (Exception e)
485       {
486         groovyJarsArePresent = 0;
487         jalview.bin.Cache.log.debug("Groovy Classes are not present");
488       }
489     }
490     return (groovyJarsArePresent > 0);
491   }
492
493   /**
494    * generate Das1Sources from the local das source list
495    * @return Vector of Das1Sources
496    */
497   public static Vector getLocalDasSources()
498   {
499     Vector localSources = new Vector();
500     String local = jalview.bin.Cache.getProperty("DAS_LOCAL_SOURCE");
501     if (local != null)
502     {
503       StringTokenizer st = new StringTokenizer(local, "\t");
504       while (st.hasMoreTokens())
505       {
506         String token = st.nextToken();
507         int bar = token.indexOf("|");
508         Das1Source source = new Das1Source();
509         source.setUrl(token.substring(bar + 1));
510         if (source.getUrl().startsWith("sequence:"))
511         {
512           source.setUrl(source.getUrl().substring(9));
513           // this source also serves sequences as well as features
514           source.setCapabilities(new String[] { "sequence", "features"});
515         } else {
516           // default is that all user added sources serve features
517           source.setCapabilities(new String[] { "features"}); 
518         }
519
520         source.setNickname(token.substring(0, bar));
521
522         localSources.addElement(source);
523       }
524     }
525     return localSources;
526   }
527
528 }