JAL-2168 document '-nonews' parameter
[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       else
335       {
336         System.err.println("CMD [-noquestionnaire] executed successfully!");
337       }
338
339       if (!aparser.contains("nonews"))
340       {
341         desktop.checkForNews();
342       }
343
344       BioJsHTMLOutput.updateBioJS();
345     }
346
347     String file = null, protocol = null, format = null, data = null;
348     FileLoader fileLoader = new FileLoader(!headless);
349     Vector<String> getFeatures = null; // vector of das source nicknames to
350                                        // fetch
351     // features from
352     // loading is done.
353     String groovyscript = null; // script to execute after all loading is
354     // completed one way or another
355     // extract groovy argument and execute if necessary
356     groovyscript = aparser.getValue("groovy", true);
357     file = aparser.getValue("open", true);
358
359     if (file == null && desktop == null)
360     {
361       System.out.println("No files to open!");
362       System.exit(1);
363     }
364     String vamsasImport = aparser.getValue("vdoc");
365     String vamsasSession = aparser.getValue("vsess");
366     if (vamsasImport != null || vamsasSession != null)
367     {
368       if (desktop == null || headless)
369       {
370         System.out
371                 .println("Headless vamsas sessions not yet supported. Sorry.");
372         System.exit(1);
373       }
374       // if we have a file, start a new session and import it.
375       boolean inSession = false;
376       if (vamsasImport != null)
377       {
378         try
379         {
380           String viprotocol = AppletFormatAdapter
381                   .checkProtocol(vamsasImport);
382           if (viprotocol == jalview.io.FormatAdapter.FILE)
383           {
384             inSession = desktop.vamsasImport(new File(vamsasImport));
385           }
386           else if (viprotocol == FormatAdapter.URL)
387           {
388             inSession = desktop.vamsasImport(new URL(vamsasImport));
389           }
390
391         } catch (Exception e)
392         {
393           System.err.println("Exeption when importing " + vamsasImport
394                   + " as a vamsas document.");
395           e.printStackTrace();
396         }
397         if (!inSession)
398         {
399           System.err.println("Failed to import " + vamsasImport
400                   + " as a vamsas document.");
401         }
402         else
403         {
404           System.out.println("Imported Successfully into new session "
405                   + desktop.getVamsasApplication().getCurrentSession());
406         }
407       }
408       if (vamsasSession != null)
409       {
410         if (vamsasImport != null)
411         {
412           // close the newly imported session and import the Jalview specific
413           // remnants into the new session later on.
414           desktop.vamsasStop_actionPerformed(null);
415         }
416         // now join the new session
417         try
418         {
419           if (desktop.joinVamsasSession(vamsasSession))
420           {
421             System.out.println("Successfully joined vamsas session "
422                     + vamsasSession);
423           }
424           else
425           {
426             System.err.println("WARNING: Failed to join vamsas session "
427                     + vamsasSession);
428           }
429         } catch (Exception e)
430         {
431           System.err.println("ERROR: Failed to join vamsas session "
432                   + vamsasSession);
433           e.printStackTrace();
434         }
435         if (vamsasImport != null)
436         {
437           // the Jalview specific remnants can now be imported into the new
438           // session at the user's leisure.
439           Cache.log
440                   .info("Skipping Push for import of data into existing vamsas session."); // TODO:
441           // enable
442           // this
443           // when
444           // debugged
445           // desktop.getVamsasApplication().push_update();
446         }
447       }
448     }
449     long progress = -1;
450     // Finally, deal with the remaining input data.
451     if (file != null)
452     {
453       if (!headless)
454       {
455         desktop.setProgressBar(MessageManager
456                 .getString("status.processing_commandline_args"),
457                 progress = System.currentTimeMillis());
458       }
459       System.out.println("CMD [-open " + file + "] executed successfully!");
460
461       if (!file.startsWith("http://"))
462       {
463         if (!(new File(file)).exists())
464         {
465           System.out.println("Can't find " + file);
466           if (headless)
467           {
468             System.exit(1);
469           }
470         }
471       }
472
473       protocol = AppletFormatAdapter.checkProtocol(file);
474
475       format = new IdentifyFile().identify(file, protocol);
476
477       AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
478               format);
479       if (af == null)
480       {
481         System.out.println("error");
482       }
483       else
484       {
485         setCurrentAlignFrame(af);
486         data = aparser.getValue("colour", true);
487         if (data != null)
488         {
489           data.replaceAll("%20", " ");
490
491           ColourSchemeI cs = ColourSchemeProperty.getColour(af
492                   .getViewport().getAlignment(), data);
493
494           if (cs == null)
495           {
496             UserColourScheme ucs = new UserColourScheme("white");
497             ucs.parseAppletParameter(data);
498             cs = ucs;
499           }
500           else
501           {
502             System.out.println("CMD [-color " + data
503                     + "] executed successfully!");
504           }
505           af.changeColour(cs);
506         }
507
508         // Must maintain ability to use the groups flag
509         data = aparser.getValue("groups", true);
510         if (data != null)
511         {
512           af.parseFeaturesFile(data,
513                   AppletFormatAdapter.checkProtocol(data));
514           // System.out.println("Added " + data);
515           System.out.println("CMD groups[-" + data
516                   + "]  executed successfully!");
517         }
518         data = aparser.getValue("features", true);
519         if (data != null)
520         {
521           af.parseFeaturesFile(data,
522                   AppletFormatAdapter.checkProtocol(data));
523           // System.out.println("Added " + data);
524           System.out.println("CMD [-features " + data
525                   + "]  executed successfully!");
526         }
527
528         data = aparser.getValue("annotations", true);
529         if (data != null)
530         {
531           af.loadJalviewDataFile(data, null, null, null);
532           // System.out.println("Added " + data);
533           System.out.println("CMD [-annotations " + data
534                   + "] executed successfully!");
535         }
536         // set or clear the sortbytree flag.
537         if (aparser.contains("sortbytree"))
538         {
539           af.getViewport().setSortByTree(true);
540           if (af.getViewport().getSortByTree())
541           {
542             System.out.println("CMD [-sortbytree] executed successfully!");
543           }
544         }
545         if (aparser.contains("no-annotation"))
546         {
547           af.getViewport().setShowAnnotation(false);
548           if (!af.getViewport().isShowAnnotation())
549           {
550             System.out.println("CMD no-annotation executed successfully!");
551           }
552         }
553         if (aparser.contains("nosortbytree"))
554         {
555           af.getViewport().setSortByTree(false);
556           if (!af.getViewport().getSortByTree())
557           {
558             System.out
559                     .println("CMD [-nosortbytree] executed successfully!");
560           }
561         }
562         data = aparser.getValue("tree", true);
563         if (data != null)
564         {
565           jalview.io.NewickFile fin = null;
566           try
567           {
568             System.out.println("CMD [-tree " + data
569                     + "] executed successfully!");
570             fin = new NewickFile(data,
571                     AppletFormatAdapter.checkProtocol(data));
572             if (fin != null)
573             {
574               af.getViewport().setCurrentTree(
575                       af.ShowNewickTree(fin, data).getTree());
576             }
577           } catch (IOException ex)
578           {
579             System.err.println("Couldn't add tree " + data);
580             ex.printStackTrace(System.err);
581           }
582         }
583         // TODO - load PDB structure(s) to alignment JAL-629
584         // (associate with identical sequence in alignment, or a specified
585         // sequence)
586
587         getFeatures = checkDasArguments(aparser);
588         if (af != null && getFeatures != null)
589         {
590           FeatureFetcher ff = startFeatureFetching(getFeatures);
591           if (ff != null)
592           {
593             while (!ff.allFinished() || af.operationInProgress())
594             {
595               // wait around until fetching is finished.
596               try
597               {
598                 Thread.sleep(100);
599               } catch (Exception e)
600               {
601
602               }
603             }
604           }
605           getFeatures = null; // have retrieved features - forget them now.
606         }
607         if (groovyscript != null)
608         {
609           // Execute the groovy script after we've done all the rendering stuff
610           // and before any images or figures are generated.
611           System.out.println("Executing script " + groovyscript);
612           executeGroovyScript(groovyscript, af);
613           System.out.println("CMD groovy[" + groovyscript
614                   + "] executed successfully!");
615           groovyscript = null;
616         }
617         String imageName = "unnamed.png";
618         while (aparser.getSize() > 1)
619         {
620           format = aparser.nextValue();
621           file = aparser.nextValue();
622
623           if (format.equalsIgnoreCase("png"))
624           {
625             af.createPNG(new File(file));
626             imageName = (new File(file)).getName();
627             System.out.println("Creating PNG image: " + file);
628             continue;
629           }
630           else if (format.equalsIgnoreCase("svg"))
631           {
632             File imageFile = new File(file);
633             imageName = imageFile.getName();
634             af.createSVG(imageFile);
635             System.out.println("Creating SVG image: " + file);
636             continue;
637           }
638           else if (format.equalsIgnoreCase("html"))
639           {
640             File imageFile = new File(file);
641             imageName = imageFile.getName();
642             new HtmlSvgOutput(new File(file), af.alignPanel);
643             System.out.println("Creating HTML image: " + file);
644             continue;
645           }
646           else if (format.equalsIgnoreCase("imgMap"))
647           {
648             af.createImageMap(new File(file), imageName);
649             System.out.println("Creating image map: " + file);
650             continue;
651           }
652           else if (format.equalsIgnoreCase("eps"))
653           {
654             File outputFile = new File(file);
655             System.out.println("Creating EPS file: "
656                     + outputFile.getAbsolutePath());
657             af.createEPS(outputFile);
658             continue;
659           }
660
661           if (af.saveAlignment(file, format))
662           {
663             System.out.println("Written alignment in " + format
664                     + " format to " + file);
665           }
666           else
667           {
668             System.out.println("Error writing file " + file + " in "
669                     + format + " format!!");
670           }
671
672         }
673
674         while (aparser.getSize() > 0)
675         {
676           System.out.println("Unknown arg: " + aparser.nextValue());
677         }
678       }
679     }
680     AlignFrame startUpAlframe = null;
681     // We'll only open the default file if the desktop is visible.
682     // And the user
683     // ////////////////////
684
685     if (!headless && file == null && vamsasImport == null
686             && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true))
687     {
688       file = jalview.bin.Cache.getDefault(
689               "STARTUP_FILE",
690               jalview.bin.Cache.getDefault("www.jalview.org",
691                       "http://www.jalview.org")
692                       + "/examples/exampleFile_2_7.jar");
693       if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar"))
694       {
695         // hardwire upgrade of the startup file
696         file.replace("_2_3.jar", "_2_7.jar");
697         // and remove the stale setting
698         jalview.bin.Cache.removeProperty("STARTUP_FILE");
699       }
700
701       protocol = "File";
702
703       if (file.indexOf("http:") > -1)
704       {
705         protocol = "URL";
706       }
707
708       if (file.endsWith(".jar"))
709       {
710         format = "Jalview";
711       }
712       else
713       {
714         format = new IdentifyFile().identify(file, protocol);
715       }
716
717       startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
718               format);
719       getFeatures = checkDasArguments(aparser);
720       // extract groovy arguments before anything else.
721     }
722     // If the user has specified features to be retrieved,
723     // or a groovy script to be executed, do them if they
724     // haven't been done already
725     // fetch features for the default alignment
726     if (getFeatures != null)
727     {
728       if (startUpAlframe != null)
729       {
730         startFeatureFetching(getFeatures);
731       }
732     }
733     // Once all other stuff is done, execute any groovy scripts (in order)
734     if (groovyscript != null)
735     {
736       if (Cache.groovyJarsPresent())
737       {
738         System.out.println("Executing script " + groovyscript);
739         executeGroovyScript(groovyscript, startUpAlframe);
740       }
741       else
742       {
743         System.err
744                 .println("Sorry. Groovy Support is not available, so ignoring the provided groovy script "
745                         + groovyscript);
746       }
747     }
748     // and finally, turn off batch mode indicator - if the desktop still exists
749     if (desktop != null)
750     {
751       if (progress != -1)
752       {
753         desktop.setProgressBar(null, progress);
754       }
755       desktop.setInBatchMode(false);
756     }
757   }
758
759   private static void showUsage()
760   {
761     System.out
762             .println("Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
763                     + "-nodisplay\tRun Jalview without User Interface.\n"
764                     + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
765                     + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
766                     + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
767                     + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
768                     + "-features FILE\tUse the given file to mark features on the alignment.\n"
769                     + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
770                     + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
771                     + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
772                     + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
773                     + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
774                     + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
775                     + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
776                     + "-json FILE\tCreate alignment file FILE in JSON format.\n"
777                     + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
778                     + "-png FILE\tCreate PNG image FILE from alignment.\n"
779                     + "-svg FILE\tCreate SVG image FILE from alignment.\n"
780                     + "-html FILE\tCreate HTML file from alignment.\n"
781                     + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
782                     + "-eps FILE\tCreate EPS file FILE from alignment.\n"
783                     + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
784                     + "-noquestionnaire\tTurn off questionnaire check.\n"
785                     + "-nonews\tTurn off check for Jalview news.\n"
786                     + "-nousagestats\tTurn off google analytics tracking for this session.\n"
787                     + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
788                     // +
789                     // "-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)"
790                     + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
791                     + "-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"
792                     + "\t\t\tSources that also support the sequence command may be specified by prepending the URL with sequence:\n"
793                     + "\t\t\t e.g. sequence:http://localdas.somewhere.org/das/source)\n"
794                     + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
795                     // +
796                     // "-vdoc vamsas-document\tImport vamsas document into new session or join existing session with same URN\n"
797                     // + "-vses vamsas-session\tJoin session with given URN\n"
798                     + "-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"
799                     + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
800   }
801
802   private static void startUsageStats(final Desktop desktop)
803   {
804     /**
805      * start a User Config prompt asking if we can log usage statistics.
806      */
807     PromptUserConfig prompter = new PromptUserConfig(
808             Desktop.desktop,
809             "USAGESTATS",
810             "Jalview Usage Statistics",
811             "Do you want to help make Jalview better by enabling "
812                     + "the collection of usage statistics with Google Analytics ?"
813                     + "\n\n(you can enable or disable usage tracking in the preferences)",
814             new Runnable()
815             {
816               @Override
817               public void run()
818               {
819                 Cache.log
820                         .debug("Initialising googletracker for usage stats.");
821                 Cache.initGoogleTracker();
822                 Cache.log.debug("Tracking enabled.");
823               }
824             }, new Runnable()
825             {
826               @Override
827               public void run()
828               {
829                 Cache.log.debug("Not enabling Google Tracking.");
830               }
831             }, null, true);
832     desktop.addDialogThread(prompter);
833   }
834
835   /**
836    * Locate the given string as a file and pass it to the groovy interpreter.
837    * 
838    * @param groovyscript
839    *          the script to execute
840    * @param jalviewContext
841    *          the Jalview Desktop object passed in to the groovy binding as the
842    *          'Jalview' object.
843    */
844   private void executeGroovyScript(String groovyscript, AlignFrame af)
845   {
846     /**
847      * for scripts contained in files
848      */
849     File tfile = null;
850     /**
851      * script's URI
852      */
853     URL sfile = null;
854     if (groovyscript.trim().equals("STDIN"))
855     {
856       // read from stdin into a tempfile and execute it
857       try
858       {
859         tfile = File.createTempFile("jalview", "groovy");
860         PrintWriter outfile = new PrintWriter(new OutputStreamWriter(
861                 new FileOutputStream(tfile)));
862         BufferedReader br = new BufferedReader(new InputStreamReader(
863                 System.in));
864         String line = null;
865         while ((line = br.readLine()) != null)
866         {
867           outfile.write(line + "\n");
868         }
869         br.close();
870         outfile.flush();
871         outfile.close();
872
873       } catch (Exception ex)
874       {
875         System.err.println("Failed to read from STDIN into tempfile "
876                 + ((tfile == null) ? "(tempfile wasn't created)" : tfile
877                         .toString()));
878         ex.printStackTrace();
879         return;
880       }
881       try
882       {
883         sfile = tfile.toURI().toURL();
884       } catch (Exception x)
885       {
886         System.err
887                 .println("Unexpected Malformed URL Exception for temporary file created from STDIN: "
888                         + tfile.toURI());
889         x.printStackTrace();
890         return;
891       }
892     }
893     else
894     {
895       try
896       {
897         sfile = new URI(groovyscript).toURL();
898       } catch (Exception x)
899       {
900         tfile = new File(groovyscript);
901         if (!tfile.exists())
902         {
903           System.err.println("File '" + groovyscript + "' does not exist.");
904           return;
905         }
906         if (!tfile.canRead())
907         {
908           System.err.println("File '" + groovyscript + "' cannot be read.");
909           return;
910         }
911         if (tfile.length() < 1)
912         {
913           System.err.println("File '" + groovyscript + "' is empty.");
914           return;
915         }
916         try
917         {
918           sfile = tfile.getAbsoluteFile().toURI().toURL();
919         } catch (Exception ex)
920         {
921           System.err.println("Failed to create a file URL for "
922                   + tfile.getAbsoluteFile());
923           return;
924         }
925       }
926     }
927     try
928     {
929       Map<String, Object> vbinding = new HashMap<String, Object>();
930       vbinding.put("Jalview", this);
931       if (af != null)
932       {
933         vbinding.put("currentAlFrame", af);
934       }
935       Binding gbinding = new Binding(vbinding);
936       GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
937       gse.run(sfile.toString(), gbinding);
938       if ("STDIN".equals(groovyscript))
939       {
940         // delete temp file that we made -
941         // only if it was successfully executed
942         tfile.delete();
943       }
944     } catch (Exception e)
945     {
946       System.err.println("Exception Whilst trying to execute file " + sfile
947               + " as a groovy script.");
948       e.printStackTrace(System.err);
949
950     }
951   }
952
953   /**
954    * Check commandline for any das server definitions or any fetchfrom switches
955    * 
956    * @return vector of DAS source nicknames to retrieve from
957    */
958   private static Vector<String> checkDasArguments(ArgsParser aparser)
959   {
960     Vector<String> source = null;
961     String data;
962     String locsources = Cache.getProperty(Cache.DAS_LOCAL_SOURCE);
963     while ((data = aparser.getValue("dasserver", true)) != null)
964     {
965       String nickname = null;
966       String url = null;
967       int pos = data.indexOf('=');
968       // determine capabilities
969       if (pos > 0)
970       {
971         nickname = data.substring(0, pos);
972       }
973       url = data.substring(pos + 1);
974       if (url != null
975               && (url.startsWith("http:") || url
976                       .startsWith("sequence:http:")))
977       {
978         if (nickname == null)
979         {
980           nickname = url;
981         }
982         if (locsources == null)
983         {
984           locsources = "";
985         }
986         else
987         {
988           locsources += "\t";
989         }
990         locsources = locsources + nickname + "|" + url;
991         System.err
992                 .println("NOTE! dasserver parameter not yet really supported (got args of "
993                         + nickname + "|" + url);
994         if (source == null)
995         {
996           source = new Vector<String>();
997         }
998         source.addElement(nickname);
999       }
1000       System.out.println("CMD [-dasserver " + data
1001               + "] executed successfully!");
1002     } // loop until no more server entries are found.
1003     if (locsources != null && locsources.indexOf('|') > -1)
1004     {
1005       Cache.log.debug("Setting local source list in properties file to:\n"
1006               + locsources);
1007       Cache.setProperty(Cache.DAS_LOCAL_SOURCE, locsources);
1008     }
1009     while ((data = aparser.getValue("fetchfrom", true)) != null)
1010     {
1011       System.out.println("adding source '" + data + "'");
1012       if (source == null)
1013       {
1014         source = new Vector<String>();
1015       }
1016       source.addElement(data);
1017     }
1018     return source;
1019   }
1020
1021   /**
1022    * start a feature fetcher for every alignment frame
1023    * 
1024    * @param dasSources
1025    */
1026   private FeatureFetcher startFeatureFetching(
1027           final Vector<String> dasSources)
1028   {
1029     FeatureFetcher ff = new FeatureFetcher();
1030     AlignFrame afs[] = Desktop.getAlignFrames();
1031     if (afs == null || afs.length == 0)
1032     {
1033       return null;
1034     }
1035     for (int i = 0; i < afs.length; i++)
1036     {
1037       ff.addFetcher(afs[i], dasSources);
1038     }
1039     return ff;
1040   }
1041
1042   public static boolean isHeadlessMode()
1043   {
1044     String isheadless = System.getProperty("java.awt.headless");
1045     if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1046     {
1047       return true;
1048     }
1049     return false;
1050   }
1051
1052   public AlignFrame[] getAlignFrames()
1053   {
1054     return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1055             : Desktop.getAlignFrames();
1056
1057   }
1058
1059   /**
1060    * Quit method delegates to Desktop.quit - unless running in headless mode
1061    * when it just ends the JVM
1062    */
1063   public void quit()
1064   {
1065     if (desktop != null)
1066     {
1067       desktop.quit();
1068     }
1069     else
1070     {
1071       System.exit(0);
1072     }
1073   }
1074
1075   public static AlignFrame getCurrentAlignFrame()
1076   {
1077     return Jalview.currentAlignFrame;
1078   }
1079
1080   public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1081   {
1082     Jalview.currentAlignFrame = currentAlignFrame;
1083   }
1084 }