JAL-2168 skip news feed if parameter "-nonews" is supplied
[jalview.git] / src / jalview / bin / Jalview.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
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
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.bin;
22
23 import groovy.lang.Binding;
24 import groovy.util.GroovyScriptEngine;
25
26 import jalview.gui.AlignFrame;
27 import jalview.gui.Desktop;
28 import jalview.gui.PromptUserConfig;
29 import jalview.io.AppletFormatAdapter;
30 import jalview.io.BioJsHTMLOutput;
31 import jalview.io.FileLoader;
32 import jalview.io.FormatAdapter;
33 import jalview.io.HtmlSvgOutput;
34 import jalview.io.IdentifyFile;
35 import jalview.io.NewickFile;
36 import jalview.schemes.ColourSchemeI;
37 import jalview.schemes.ColourSchemeProperty;
38 import jalview.schemes.UserColourScheme;
39 import jalview.util.MessageManager;
40 import jalview.util.Platform;
41 import jalview.ws.jws2.Jws2Discoverer;
42
43 import java.io.BufferedReader;
44 import java.io.File;
45 import java.io.FileOutputStream;
46 import java.io.IOException;
47 import java.io.InputStreamReader;
48 import java.io.OutputStreamWriter;
49 import java.io.PrintWriter;
50 import java.net.MalformedURLException;
51 import java.net.URI;
52 import java.net.URL;
53 import java.security.AllPermission;
54 import java.security.CodeSource;
55 import java.security.PermissionCollection;
56 import java.security.Permissions;
57 import java.security.Policy;
58 import java.util.HashMap;
59 import java.util.Map;
60 import java.util.Vector;
61
62 import javax.swing.UIManager;
63
64 /**
65  * Main class for Jalview Application <br>
66  * <br>
67  * start with java -Djava.ext.dirs=$PATH_TO_LIB$ jalview.bin.Jalview
68  * 
69  * @author $author$
70  * @version $Revision$
71  */
72 public class Jalview
73 {
74   /*
75    * singleton instance of this class
76    */
77   private static Jalview instance;
78
79   private Desktop desktop;
80
81   public static AlignFrame currentAlignFrame;
82
83   static
84   {
85     // grab all the rights we can the JVM
86     Policy.setPolicy(new Policy()
87     {
88       @Override
89       public PermissionCollection getPermissions(CodeSource codesource)
90       {
91         Permissions perms = new Permissions();
92         perms.add(new AllPermission());
93         return (perms);
94       }
95
96       @Override
97       public void refresh()
98       {
99       }
100     });
101   }
102
103   /**
104    * keep track of feature fetching tasks.
105    * 
106    * @author JimP
107    * 
108    */
109   class FeatureFetcher
110   {
111     /*
112      * TODO: generalise to track all jalview events to orchestrate batch
113      * processing events.
114      */
115
116     private int queued = 0;
117
118     private int running = 0;
119
120     public FeatureFetcher()
121     {
122
123     }
124
125     public void addFetcher(final AlignFrame af,
126             final Vector<String> dasSources)
127     {
128       final long id = System.currentTimeMillis();
129       queued++;
130       final FeatureFetcher us = this;
131       new Thread(new Runnable()
132       {
133
134         @Override
135         public void run()
136         {
137           synchronized (us)
138           {
139             queued--;
140             running++;
141           }
142
143           af.setProgressBar(MessageManager
144                   .getString("status.das_features_being_retrived"), id);
145           af.featureSettings_actionPerformed(null);
146           af.featureSettings.fetchDasFeatures(dasSources, true);
147           af.setProgressBar(null, id);
148           synchronized (us)
149           {
150             running--;
151           }
152         }
153       }).start();
154     }
155
156     public synchronized boolean allFinished()
157     {
158       return queued == 0 && running == 0;
159     }
160
161   }
162
163   public static Jalview getInstance()
164   {
165     return instance;
166   }
167
168   /**
169    * main class for Jalview application
170    * 
171    * @param args
172    *          open <em>filename</em>
173    */
174   public static void main(String[] args)
175   {
176     instance = new Jalview();
177     instance.doMain(args);
178   }
179
180   /**
181    * @param args
182    */
183   void doMain(String[] args)
184   {
185     System.setSecurityManager(null);
186     System.out.println("Java version: "
187             + System.getProperty("java.version"));
188     System.out.println(System.getProperty("os.arch") + " "
189             + System.getProperty("os.name") + " "
190             + System.getProperty("os.version"));
191
192     ArgsParser aparser = new ArgsParser(args);
193     boolean headless = false;
194
195     if (aparser.contains("help") || aparser.contains("h"))
196     {
197       showUsage();
198       System.exit(0);
199     }
200     if (aparser.contains("nodisplay") || aparser.contains("nogui")
201             || aparser.contains("headless"))
202     {
203       System.setProperty("java.awt.headless", "true");
204       headless = true;
205     }
206     String usrPropsFile = aparser.getValue("props");
207     Cache.loadProperties(usrPropsFile); // must do this before
208     if (usrPropsFile != null)
209     {
210       System.out.println("CMD [-props " + usrPropsFile
211               + "] executed successfully!");
212     }
213
214     // anything else!
215
216     final String jabawsUrl = aparser.getValue("jabaws");
217     if (jabawsUrl != null)
218     {
219       try
220       {
221         Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
222         System.out.println("CMD [-jabaws " + jabawsUrl
223                 + "] executed successfully!");
224       } catch (MalformedURLException e)
225       {
226         System.err.println("Invalid jabaws parameter: " + jabawsUrl
227                 + " ignored");
228       }
229     }
230
231     String defs = aparser.getValue("setprop");
232     while (defs != null)
233     {
234       int p = defs.indexOf('=');
235       if (p == -1)
236       {
237         System.err.println("Ignoring invalid setprop argument : " + defs);
238       }
239       else
240       {
241         System.out.println("Executing setprop argument: " + defs);
242         // DISABLED FOR SECURITY REASONS
243         // TODO: add a property to allow properties to be overriden by cli args
244         // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
245       }
246       defs = aparser.getValue("setprop");
247     }
248     if (System.getProperty("java.awt.headless") != null
249             && System.getProperty("java.awt.headless").equals("true"))
250     {
251       headless = true;
252     }
253     System.setProperty("http.agent",
254             "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
255     try
256     {
257       Cache.initLogger();
258     } catch (NoClassDefFoundError error)
259     {
260       error.printStackTrace();
261       System.out
262               .println("\nEssential logging libraries not found."
263                       + "\nUse: java -Djava.ext.dirs=$PATH_TO_LIB$ jalview.bin.Jalview");
264       System.exit(0);
265     }
266
267     desktop = null;
268
269     try
270     {
271       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
272     } catch (Exception ex)
273     {
274     }
275     if (Platform.isAMac())
276     {
277       System.setProperty("com.apple.mrj.application.apple.menu.about.name",
278               "Jalview");
279       System.setProperty("apple.laf.useScreenMenuBar", "true");
280       try
281       {
282         UIManager.setLookAndFeel(ch.randelshofer.quaqua.QuaquaManager
283                 .getLookAndFeel());
284       } catch (Throwable e)
285       {
286         System.err.println("Failed to set QuaQua look and feel: "
287                 + e.toString());
288       }
289     }
290
291     if (!headless)
292     {
293       desktop = new Desktop();
294       desktop.setInBatchMode(true); // indicate we are starting up
295       desktop.setVisible(true);
296       desktop.startServiceDiscovery();
297       if (!aparser.contains("nousagestats"))
298       {
299         startUsageStats(desktop);
300       }
301       else
302       {
303         System.err.println("CMD [-nousagestats] executed successfully!");
304       }
305
306       if (!aparser.contains("noquestionnaire"))
307       {
308         String url = aparser.getValue("questionnaire");
309         if (url != null)
310         {
311           // Start the desktop questionnaire prompter with the specified
312           // questionnaire
313           Cache.log.debug("Starting questionnaire url at " + url);
314           desktop.checkForQuestionnaire(url);
315           System.out.println("CMD questionnaire[-" + url
316                   + "] executed successfully!");
317         }
318         else
319         {
320           if (Cache.getProperty("NOQUESTIONNAIRES") == null)
321           {
322             // Start the desktop questionnaire prompter with the specified
323             // questionnaire
324             // String defurl =
325             // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
326             // //
327             String defurl = "http://www.jalview.org/cgi-bin/questionnaire.pl";
328             Cache.log.debug("Starting questionnaire with default url: "
329                     + defurl);
330             desktop.checkForQuestionnaire(defurl);
331
332           }
333         }
334       }
335       else
336       {
337         System.err.println("CMD [-noquestionnaire] executed successfully!");
338       }
339       if (!aparser.contains("nonews"))
340       {
341         desktop.checkForNews();
342       }
343     }
344
345     if (!isHeadlessMode())
346     {
347       BioJsHTMLOutput.updateBioJS();
348     }
349
350     String file = null, protocol = null, format = null, data = null;
351     FileLoader fileLoader = new FileLoader(!headless);
352     Vector<String> getFeatures = null; // vector of das source nicknames to
353                                        // fetch
354     // features from
355     // loading is done.
356     String groovyscript = null; // script to execute after all loading is
357     // completed one way or another
358     // extract groovy argument and execute if necessary
359     groovyscript = aparser.getValue("groovy", true);
360     file = aparser.getValue("open", true);
361
362     if (file == null && desktop == null)
363     {
364       System.out.println("No files to open!");
365       System.exit(1);
366     }
367     String vamsasImport = aparser.getValue("vdoc");
368     String vamsasSession = aparser.getValue("vsess");
369     if (vamsasImport != null || vamsasSession != null)
370     {
371       if (desktop == null || headless)
372       {
373         System.out
374                 .println("Headless vamsas sessions not yet supported. Sorry.");
375         System.exit(1);
376       }
377       // if we have a file, start a new session and import it.
378       boolean inSession = false;
379       if (vamsasImport != null)
380       {
381         try
382         {
383           String viprotocol = AppletFormatAdapter
384                   .checkProtocol(vamsasImport);
385           if (viprotocol == jalview.io.FormatAdapter.FILE)
386           {
387             inSession = desktop.vamsasImport(new File(vamsasImport));
388           }
389           else if (viprotocol == FormatAdapter.URL)
390           {
391             inSession = desktop.vamsasImport(new URL(vamsasImport));
392           }
393
394         } catch (Exception e)
395         {
396           System.err.println("Exeption when importing " + vamsasImport
397                   + " as a vamsas document.");
398           e.printStackTrace();
399         }
400         if (!inSession)
401         {
402           System.err.println("Failed to import " + vamsasImport
403                   + " as a vamsas document.");
404         }
405         else
406         {
407           System.out.println("Imported Successfully into new session "
408                   + desktop.getVamsasApplication().getCurrentSession());
409         }
410       }
411       if (vamsasSession != null)
412       {
413         if (vamsasImport != null)
414         {
415           // close the newly imported session and import the Jalview specific
416           // remnants into the new session later on.
417           desktop.vamsasStop_actionPerformed(null);
418         }
419         // now join the new session
420         try
421         {
422           if (desktop.joinVamsasSession(vamsasSession))
423           {
424             System.out.println("Successfully joined vamsas session "
425                     + vamsasSession);
426           }
427           else
428           {
429             System.err.println("WARNING: Failed to join vamsas session "
430                     + vamsasSession);
431           }
432         } catch (Exception e)
433         {
434           System.err.println("ERROR: Failed to join vamsas session "
435                   + vamsasSession);
436           e.printStackTrace();
437         }
438         if (vamsasImport != null)
439         {
440           // the Jalview specific remnants can now be imported into the new
441           // session at the user's leisure.
442           Cache.log
443                   .info("Skipping Push for import of data into existing vamsas session."); // TODO:
444           // enable
445           // this
446           // when
447           // debugged
448           // desktop.getVamsasApplication().push_update();
449         }
450       }
451     }
452     long progress = -1;
453     // Finally, deal with the remaining input data.
454     if (file != null)
455     {
456       if (!headless)
457       {
458         desktop.setProgressBar(MessageManager
459                 .getString("status.processing_commandline_args"),
460                 progress = System.currentTimeMillis());
461       }
462       System.out.println("CMD [-open " + file + "] executed successfully!");
463
464       if (!file.startsWith("http://"))
465       {
466         if (!(new File(file)).exists())
467         {
468           System.out.println("Can't find " + file);
469           if (headless)
470           {
471             System.exit(1);
472           }
473         }
474       }
475
476       protocol = AppletFormatAdapter.checkProtocol(file);
477
478       format = new IdentifyFile().identify(file, protocol);
479
480       AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
481               format);
482       if (af == null)
483       {
484         System.out.println("error");
485       }
486       else
487       {
488         setCurrentAlignFrame(af);
489         data = aparser.getValue("colour", true);
490         if (data != null)
491         {
492           data.replaceAll("%20", " ");
493
494           ColourSchemeI cs = ColourSchemeProperty.getColour(af
495                   .getViewport().getAlignment(), data);
496
497           if (cs == null)
498           {
499             UserColourScheme ucs = new UserColourScheme("white");
500             ucs.parseAppletParameter(data);
501             cs = ucs;
502           }
503           else
504           {
505             System.out.println("CMD [-color " + data
506                     + "] executed successfully!");
507           }
508           af.changeColour(cs);
509         }
510
511         // Must maintain ability to use the groups flag
512         data = aparser.getValue("groups", true);
513         if (data != null)
514         {
515           af.parseFeaturesFile(data,
516                   AppletFormatAdapter.checkProtocol(data));
517           // System.out.println("Added " + data);
518           System.out.println("CMD groups[-" + data
519                   + "]  executed successfully!");
520         }
521         data = aparser.getValue("features", true);
522         if (data != null)
523         {
524           af.parseFeaturesFile(data,
525                   AppletFormatAdapter.checkProtocol(data));
526           // System.out.println("Added " + data);
527           System.out.println("CMD [-features " + data
528                   + "]  executed successfully!");
529         }
530
531         data = aparser.getValue("annotations", true);
532         if (data != null)
533         {
534           af.loadJalviewDataFile(data, null, null, null);
535           // System.out.println("Added " + data);
536           System.out.println("CMD [-annotations " + data
537                   + "] executed successfully!");
538         }
539         // set or clear the sortbytree flag.
540         if (aparser.contains("sortbytree"))
541         {
542           af.getViewport().setSortByTree(true);
543           if (af.getViewport().getSortByTree())
544           {
545             System.out.println("CMD [-sortbytree] executed successfully!");
546           }
547         }
548         if (aparser.contains("no-annotation"))
549         {
550           af.getViewport().setShowAnnotation(false);
551           if (!af.getViewport().isShowAnnotation())
552           {
553             System.out.println("CMD no-annotation executed successfully!");
554           }
555         }
556         if (aparser.contains("nosortbytree"))
557         {
558           af.getViewport().setSortByTree(false);
559           if (!af.getViewport().getSortByTree())
560           {
561             System.out
562                     .println("CMD [-nosortbytree] executed successfully!");
563           }
564         }
565         data = aparser.getValue("tree", true);
566         if (data != null)
567         {
568           jalview.io.NewickFile fin = null;
569           try
570           {
571             System.out.println("CMD [-tree " + data
572                     + "] executed successfully!");
573             fin = new NewickFile(data,
574                     AppletFormatAdapter.checkProtocol(data));
575             if (fin != null)
576             {
577               af.getViewport().setCurrentTree(
578                       af.ShowNewickTree(fin, data).getTree());
579             }
580           } catch (IOException ex)
581           {
582             System.err.println("Couldn't add tree " + data);
583             ex.printStackTrace(System.err);
584           }
585         }
586         // TODO - load PDB structure(s) to alignment JAL-629
587         // (associate with identical sequence in alignment, or a specified
588         // sequence)
589
590         getFeatures = checkDasArguments(aparser);
591         if (af != null && getFeatures != null)
592         {
593           FeatureFetcher ff = startFeatureFetching(getFeatures);
594           if (ff != null)
595           {
596             while (!ff.allFinished() || af.operationInProgress())
597             {
598               // wait around until fetching is finished.
599               try
600               {
601                 Thread.sleep(100);
602               } catch (Exception e)
603               {
604
605               }
606             }
607           }
608           getFeatures = null; // have retrieved features - forget them now.
609         }
610         if (groovyscript != null)
611         {
612           // Execute the groovy script after we've done all the rendering stuff
613           // and before any images or figures are generated.
614           System.out.println("Executing script " + groovyscript);
615           executeGroovyScript(groovyscript, af);
616           System.out.println("CMD groovy[" + groovyscript
617                   + "] executed successfully!");
618           groovyscript = null;
619         }
620         String imageName = "unnamed.png";
621         while (aparser.getSize() > 1)
622         {
623           format = aparser.nextValue();
624           file = aparser.nextValue();
625
626           if (format.equalsIgnoreCase("png"))
627           {
628             af.createPNG(new File(file));
629             imageName = (new File(file)).getName();
630             System.out.println("Creating PNG image: " + file);
631             continue;
632           }
633           else if (format.equalsIgnoreCase("svg"))
634           {
635             File imageFile = new File(file);
636             imageName = imageFile.getName();
637             af.createSVG(imageFile);
638             System.out.println("Creating SVG image: " + file);
639             continue;
640           }
641           else if (format.equalsIgnoreCase("html"))
642           {
643             File imageFile = new File(file);
644             imageName = imageFile.getName();
645             new HtmlSvgOutput(new File(file), af.alignPanel);
646             System.out.println("Creating HTML image: " + file);
647             continue;
648           }
649           else if (format.equalsIgnoreCase("imgMap"))
650           {
651             af.createImageMap(new File(file), imageName);
652             System.out.println("Creating image map: " + file);
653             continue;
654           }
655           else if (format.equalsIgnoreCase("eps"))
656           {
657             File outputFile = new File(file);
658             System.out.println("Creating EPS file: "
659                     + outputFile.getAbsolutePath());
660             af.createEPS(outputFile);
661             continue;
662           }
663
664           if (af.saveAlignment(file, format))
665           {
666             System.out.println("Written alignment in " + format
667                     + " format to " + file);
668           }
669           else
670           {
671             System.out.println("Error writing file " + file + " in "
672                     + format + " format!!");
673           }
674
675         }
676
677         while (aparser.getSize() > 0)
678         {
679           System.out.println("Unknown arg: " + aparser.nextValue());
680         }
681       }
682     }
683     AlignFrame startUpAlframe = null;
684     // We'll only open the default file if the desktop is visible.
685     // And the user
686     // ////////////////////
687
688     if (!headless && file == null && vamsasImport == null
689             && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true))
690     {
691       file = jalview.bin.Cache.getDefault(
692               "STARTUP_FILE",
693               jalview.bin.Cache.getDefault("www.jalview.org",
694                       "http://www.jalview.org")
695                       + "/examples/exampleFile_2_7.jar");
696       if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar"))
697       {
698         // hardwire upgrade of the startup file
699         file.replace("_2_3.jar", "_2_7.jar");
700         // and remove the stale setting
701         jalview.bin.Cache.removeProperty("STARTUP_FILE");
702       }
703
704       protocol = "File";
705
706       if (file.indexOf("http:") > -1)
707       {
708         protocol = "URL";
709       }
710
711       if (file.endsWith(".jar"))
712       {
713         format = "Jalview";
714       }
715       else
716       {
717         format = new IdentifyFile().identify(file, protocol);
718       }
719
720       startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
721               format);
722       getFeatures = checkDasArguments(aparser);
723       // extract groovy arguments before anything else.
724     }
725     // If the user has specified features to be retrieved,
726     // or a groovy script to be executed, do them if they
727     // haven't been done already
728     // fetch features for the default alignment
729     if (getFeatures != null)
730     {
731       if (startUpAlframe != null)
732       {
733         startFeatureFetching(getFeatures);
734       }
735     }
736     // Once all other stuff is done, execute any groovy scripts (in order)
737     if (groovyscript != null)
738     {
739       if (Cache.groovyJarsPresent())
740       {
741         System.out.println("Executing script " + groovyscript);
742         executeGroovyScript(groovyscript, startUpAlframe);
743       }
744       else
745       {
746         System.err
747                 .println("Sorry. Groovy Support is not available, so ignoring the provided groovy script "
748                         + groovyscript);
749       }
750     }
751     // and finally, turn off batch mode indicator - if the desktop still exists
752     if (desktop != null)
753     {
754       if (progress != -1)
755       {
756         desktop.setProgressBar(null, progress);
757       }
758       desktop.setInBatchMode(false);
759     }
760   }
761
762   private static void showUsage()
763   {
764     System.out
765             .println("Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
766                     + "-nodisplay\tRun Jalview without User Interface.\n"
767                     + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
768                     + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
769                     + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
770                     + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
771                     + "-features FILE\tUse the given file to mark features on the alignment.\n"
772                     + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
773                     + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
774                     + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
775                     + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
776                     + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
777                     + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
778                     + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
779                     + "-json FILE\tCreate alignment file FILE in JSON format.\n"
780                     + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
781                     + "-png FILE\tCreate PNG image FILE from alignment.\n"
782                     + "-svg FILE\tCreate SVG image FILE from alignment.\n"
783                     + "-html FILE\tCreate HTML file from alignment.\n"
784                     + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
785                     + "-eps FILE\tCreate EPS file FILE from alignment.\n"
786                     + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
787                     + "-noquestionnaire\tTurn off questionnaire check.\n"
788                     + "-nousagestats\tTurn off google analytics tracking for this session.\n"
789                     + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
790                     // +
791                     // "-setprop PROPERTY=VALUE\tSet the given Jalview property, after all other properties files have been read\n\t (quote the 'PROPERTY=VALUE' pair to ensure spaces are passed in correctly)"
792                     + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
793                     + "-dasserver nickname=URL\tAdd and enable a das server with given nickname\n\t\t\t(alphanumeric or underscores only) for retrieval of features for all alignments.\n"
794                     + "\t\t\tSources that also support the sequence command may be specified by prepending the URL with sequence:\n"
795                     + "\t\t\t e.g. sequence:http://localdas.somewhere.org/das/source)\n"
796                     + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
797                     // +
798                     // "-vdoc vamsas-document\tImport vamsas document into new session or join existing session with same URN\n"
799                     // + "-vses vamsas-session\tJoin session with given URN\n"
800                     + "-groovy FILE\tExecute groovy script in FILE, after all other arguments have been processed (if FILE is the text 'STDIN' then the file will be read from STDIN)\n"
801                     + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
802   }
803
804   private static void startUsageStats(final Desktop desktop)
805   {
806     /**
807      * start a User Config prompt asking if we can log usage statistics.
808      */
809     PromptUserConfig prompter = new PromptUserConfig(
810             Desktop.desktop,
811             "USAGESTATS",
812             "Jalview Usage Statistics",
813             "Do you want to help make Jalview better by enabling "
814                     + "the collection of usage statistics with Google Analytics ?"
815                     + "\n\n(you can enable or disable usage tracking in the preferences)",
816             new Runnable()
817             {
818               @Override
819               public void run()
820               {
821                 Cache.log
822                         .debug("Initialising googletracker for usage stats.");
823                 Cache.initGoogleTracker();
824                 Cache.log.debug("Tracking enabled.");
825               }
826             }, new Runnable()
827             {
828               @Override
829               public void run()
830               {
831                 Cache.log.debug("Not enabling Google Tracking.");
832               }
833             }, null, true);
834     desktop.addDialogThread(prompter);
835   }
836
837   /**
838    * Locate the given string as a file and pass it to the groovy interpreter.
839    * 
840    * @param groovyscript
841    *          the script to execute
842    * @param jalviewContext
843    *          the Jalview Desktop object passed in to the groovy binding as the
844    *          'Jalview' object.
845    */
846   private void executeGroovyScript(String groovyscript, AlignFrame af)
847   {
848     /**
849      * for scripts contained in files
850      */
851     File tfile = null;
852     /**
853      * script's URI
854      */
855     URL sfile = null;
856     if (groovyscript.trim().equals("STDIN"))
857     {
858       // read from stdin into a tempfile and execute it
859       try
860       {
861         tfile = File.createTempFile("jalview", "groovy");
862         PrintWriter outfile = new PrintWriter(new OutputStreamWriter(
863                 new FileOutputStream(tfile)));
864         BufferedReader br = new BufferedReader(new InputStreamReader(
865                 System.in));
866         String line = null;
867         while ((line = br.readLine()) != null)
868         {
869           outfile.write(line + "\n");
870         }
871         br.close();
872         outfile.flush();
873         outfile.close();
874
875       } catch (Exception ex)
876       {
877         System.err.println("Failed to read from STDIN into tempfile "
878                 + ((tfile == null) ? "(tempfile wasn't created)" : tfile
879                         .toString()));
880         ex.printStackTrace();
881         return;
882       }
883       try
884       {
885         sfile = tfile.toURI().toURL();
886       } catch (Exception x)
887       {
888         System.err
889                 .println("Unexpected Malformed URL Exception for temporary file created from STDIN: "
890                         + tfile.toURI());
891         x.printStackTrace();
892         return;
893       }
894     }
895     else
896     {
897       try
898       {
899         sfile = new URI(groovyscript).toURL();
900       } catch (Exception x)
901       {
902         tfile = new File(groovyscript);
903         if (!tfile.exists())
904         {
905           System.err.println("File '" + groovyscript + "' does not exist.");
906           return;
907         }
908         if (!tfile.canRead())
909         {
910           System.err.println("File '" + groovyscript + "' cannot be read.");
911           return;
912         }
913         if (tfile.length() < 1)
914         {
915           System.err.println("File '" + groovyscript + "' is empty.");
916           return;
917         }
918         try
919         {
920           sfile = tfile.getAbsoluteFile().toURI().toURL();
921         } catch (Exception ex)
922         {
923           System.err.println("Failed to create a file URL for "
924                   + tfile.getAbsoluteFile());
925           return;
926         }
927       }
928     }
929     try
930     {
931       Map<String, Object> vbinding = new HashMap<String, Object>();
932       vbinding.put("Jalview", this);
933       if (af != null)
934       {
935         vbinding.put("currentAlFrame", af);
936       }
937       Binding gbinding = new Binding(vbinding);
938       GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
939       gse.run(sfile.toString(), gbinding);
940       if ("STDIN".equals(groovyscript))
941       {
942         // delete temp file that we made -
943         // only if it was successfully executed
944         tfile.delete();
945       }
946     } catch (Exception e)
947     {
948       System.err.println("Exception Whilst trying to execute file " + sfile
949               + " as a groovy script.");
950       e.printStackTrace(System.err);
951
952     }
953   }
954
955   /**
956    * Check commandline for any das server definitions or any fetchfrom switches
957    * 
958    * @return vector of DAS source nicknames to retrieve from
959    */
960   private static Vector<String> checkDasArguments(ArgsParser aparser)
961   {
962     Vector<String> source = null;
963     String data;
964     String locsources = Cache.getProperty(Cache.DAS_LOCAL_SOURCE);
965     while ((data = aparser.getValue("dasserver", true)) != null)
966     {
967       String nickname = null;
968       String url = null;
969       int pos = data.indexOf('=');
970       // determine capabilities
971       if (pos > 0)
972       {
973         nickname = data.substring(0, pos);
974       }
975       url = data.substring(pos + 1);
976       if (url != null
977               && (url.startsWith("http:") || url
978                       .startsWith("sequence:http:")))
979       {
980         if (nickname == null)
981         {
982           nickname = url;
983         }
984         if (locsources == null)
985         {
986           locsources = "";
987         }
988         else
989         {
990           locsources += "\t";
991         }
992         locsources = locsources + nickname + "|" + url;
993         System.err
994                 .println("NOTE! dasserver parameter not yet really supported (got args of "
995                         + nickname + "|" + url);
996         if (source == null)
997         {
998           source = new Vector<String>();
999         }
1000         source.addElement(nickname);
1001       }
1002       System.out.println("CMD [-dasserver " + data
1003               + "] executed successfully!");
1004     } // loop until no more server entries are found.
1005     if (locsources != null && locsources.indexOf('|') > -1)
1006     {
1007       Cache.log.debug("Setting local source list in properties file to:\n"
1008               + locsources);
1009       Cache.setProperty(Cache.DAS_LOCAL_SOURCE, locsources);
1010     }
1011     while ((data = aparser.getValue("fetchfrom", true)) != null)
1012     {
1013       System.out.println("adding source '" + data + "'");
1014       if (source == null)
1015       {
1016         source = new Vector<String>();
1017       }
1018       source.addElement(data);
1019     }
1020     return source;
1021   }
1022
1023   /**
1024    * start a feature fetcher for every alignment frame
1025    * 
1026    * @param dasSources
1027    */
1028   private FeatureFetcher startFeatureFetching(
1029           final Vector<String> dasSources)
1030   {
1031     FeatureFetcher ff = new FeatureFetcher();
1032     AlignFrame afs[] = Desktop.getAlignFrames();
1033     if (afs == null || afs.length == 0)
1034     {
1035       return null;
1036     }
1037     for (int i = 0; i < afs.length; i++)
1038     {
1039       ff.addFetcher(afs[i], dasSources);
1040     }
1041     return ff;
1042   }
1043
1044   public static boolean isHeadlessMode()
1045   {
1046     String isheadless = System.getProperty("java.awt.headless");
1047     if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1048     {
1049       return true;
1050     }
1051     return false;
1052   }
1053
1054   public AlignFrame[] getAlignFrames()
1055   {
1056     return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1057             : Desktop.getAlignFrames();
1058
1059   }
1060
1061   /**
1062    * Quit method delegates to Desktop.quit - unless running in headless mode
1063    * when it just ends the JVM
1064    */
1065   public void quit()
1066   {
1067     if (desktop != null)
1068     {
1069       desktop.quit();
1070     }
1071     else
1072     {
1073       System.exit(0);
1074     }
1075   }
1076
1077   public static AlignFrame getCurrentAlignFrame()
1078   {
1079     return Jalview.currentAlignFrame;
1080   }
1081
1082   public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1083   {
1084     Jalview.currentAlignFrame = currentAlignFrame;
1085   }
1086 }