JAL-3253 preliminary static fixes for JavaScript part 3 of 3
[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 jalview.analysis.AlignmentSorter;
24 import jalview.analysis.scoremodels.ScoreModels;
25 import jalview.api.StructureSelectionManagerProvider;
26 import jalview.ext.ensembl.EnsemblInfo;
27 import jalview.ext.so.SequenceOntology;
28 import jalview.fts.service.pdb.PDBFTSRestClient;
29 import jalview.fts.service.uniprot.UniProtFTSRestClient;
30 import jalview.gui.AlignFrame;
31 import jalview.gui.Desktop;
32 import jalview.gui.PromptUserConfig;
33 import jalview.httpserver.HttpServer;
34 import jalview.io.AppletFormatAdapter;
35 import jalview.io.BioJsHTMLOutput;
36 import jalview.io.DataSourceType;
37 import jalview.io.FileFormat;
38 import jalview.io.FileFormatException;
39 import jalview.io.FileFormatI;
40 import jalview.io.FileLoader;
41 import jalview.io.HtmlSvgOutput;
42 import jalview.io.IdentifyFile;
43 import jalview.io.NewickFile;
44 import jalview.io.gff.SequenceOntologyFactory;
45 import jalview.io.gff.SequenceOntologyI;
46 import jalview.rest.RestHandler;
47 import jalview.schemes.ColourSchemeI;
48 import jalview.schemes.ColourSchemeProperty;
49 import jalview.structure.StructureImportSettings;
50 import jalview.structure.StructureSelectionManager;
51 import jalview.urls.IdOrgSettings;
52 import jalview.util.MessageManager;
53 import jalview.util.Platform;
54 import jalview.ws.SequenceFetcher;
55 import jalview.ws.jws1.Discoverer;
56 import jalview.ws.jws2.Jws2Discoverer;
57 import jalview.ws.jws2.jabaws2.Jws2InstanceFactory;
58 import jalview.ws.rest.RestClient;
59 import jalview.ws.sifts.SiftsSettings;
60
61 import java.awt.Color;
62 import java.io.BufferedReader;
63 import java.io.File;
64 import java.io.FileOutputStream;
65 import java.io.IOException;
66 import java.io.InputStreamReader;
67 import java.io.OutputStreamWriter;
68 import java.io.PrintWriter;
69 import java.net.MalformedURLException;
70 import java.net.URI;
71 import java.net.URISyntaxException;
72 import java.net.URL;
73 import java.security.AllPermission;
74 import java.security.CodeSource;
75 import java.security.PermissionCollection;
76 import java.security.Permissions;
77 import java.security.Policy;
78 import java.util.HashMap;
79 import java.util.IdentityHashMap;
80 import java.util.Map;
81 import java.util.Vector;
82 import java.util.logging.ConsoleHandler;
83 import java.util.logging.Level;
84 import java.util.logging.Logger;
85
86 import javax.swing.LookAndFeel;
87 import javax.swing.UIManager;
88
89 import groovy.lang.Binding;
90 import groovy.util.GroovyScriptEngine;
91
92 /**
93  * Main class for Jalview Application <br>
94  * <br>
95  * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
96  * jalview.bin.Jalview
97  * 
98  * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
99  * jalview.bin.Jalview jalview.bin.Jalview
100  * 
101  * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
102  * embellish '*' to e.g. '*.jar')
103  * 
104  * @author $author$
105  * @version $Revision$
106  */
107 public class Jalview
108 {
109   static
110   {
111     Platform.getURLCommandArguments();
112   }
113
114   private boolean headless;
115
116   public static boolean isHeadlessMode()
117   {
118     return getInstance().headless;
119   }
120
121   /**
122    * singleton instance of this class in Java only
123    */
124
125   private static Jalview instance;
126
127   public static Jalview getInstance()
128   {
129     Jalview j;
130     @SuppressWarnings("unused")
131     ThreadGroup g = Thread.currentThread().getThreadGroup();
132     /**
133      * @j2sNative j = g._jalviewInstance;
134      */
135     {
136       j = instance;
137     }
138     return j;
139   }
140
141   private static void setInstance(Jalview j)
142   {
143     @SuppressWarnings("unused")
144     ThreadGroup g = Thread.currentThread().getThreadGroup();
145     /**
146      * @j2sNative g._jalviewInstance = j;
147      */
148     {
149       instance = j;
150     }
151   }
152
153   private Desktop desktop;
154
155   private AlignFrame currentAlignFrame;
156
157   public static AlignFrame getCurrentAlignFrame()
158   {
159     return getInstance().currentAlignFrame;
160   }
161
162   public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
163   {
164     getInstance().currentAlignFrame = currentAlignFrame;
165   }
166
167   static
168   {
169     if (!Platform.isJS())
170     /**
171      * Java only
172      * 
173      * @j2sIgnore
174      */
175     {
176       // grab all the rights we can for the JVM
177       Policy.setPolicy(new Policy()
178       {
179         @Override
180         public PermissionCollection getPermissions(CodeSource codesource)
181         {
182           Permissions perms = new Permissions();
183           perms.add(new AllPermission());
184           return (perms);
185         }
186
187         @Override
188         public void refresh()
189         {
190         }
191       });
192     }
193   }
194
195   /**
196    * keep track of feature fetching tasks.
197    * 
198    * @author JimP
199    * 
200    */
201   class FeatureFetcher
202   {
203     /*
204      * TODO: generalise to track all jalview events to orchestrate batch
205      * processing events.
206      */
207
208     private int queued = 0;
209
210     private int running = 0;
211
212     public FeatureFetcher()
213     {
214
215     }
216
217     public void addFetcher(final AlignFrame af,
218             final Vector<String> dasSources)
219     {
220       final long id = System.currentTimeMillis();
221       queued++;
222       final FeatureFetcher us = this;
223       new Thread(new Runnable()
224       {
225
226         @Override
227         public void run()
228         {
229           synchronized (us)
230           {
231             queued--;
232             running++;
233           }
234
235           af.setProgressBar(MessageManager
236                   .getString("status.das_features_being_retrived"), id);
237           af.featureSettings_actionPerformed(null);
238           af.setProgressBar(null, id);
239           synchronized (us)
240           {
241             running--;
242           }
243         }
244       }).start();
245     }
246
247     public synchronized boolean allFinished()
248     {
249       return queued == 0 && running == 0;
250     }
251
252   }
253
254   /**
255    * main class for Jalview application
256    * 
257    * @param args
258    *          open <em>filename</em>
259    */
260   public static void main(String[] args)
261   {
262     // setLogging(); // BH - for event debugging in JavaScript
263     setInstance(new Jalview());
264     getInstance().doMain(args);
265   }
266
267   private static void logClass(String name)
268   {
269     // BH - for event debugging in JavaScript
270     ConsoleHandler consoleHandler = new ConsoleHandler();
271     consoleHandler.setLevel(Level.ALL);
272     Logger logger = Logger.getLogger(name);
273     logger.setLevel(Level.ALL);
274     logger.addHandler(consoleHandler);
275   }
276
277   @SuppressWarnings("unused")
278   private static void setLogging()
279   {
280
281     /**
282      * @j2sIgnore
283      * 
284      */
285     {
286       System.out.println("not in js");
287     }
288
289     // BH - for event debugging in JavaScript (Java mode only)
290     if (!Platform.isJS())
291     /**
292      * Java only
293      * 
294      * @j2sIgnore
295      */
296     {
297       Logger.getLogger("").setLevel(Level.ALL);
298       logClass("java.awt.EventDispatchThread");
299       logClass("java.awt.EventQueue");
300       logClass("java.awt.Component");
301       logClass("java.awt.focus.Component");
302       logClass("java.awt.focus.DefaultKeyboardFocusManager");
303     }
304
305   }
306
307   /**
308    * @param args
309    */
310   void doMain(String[] args)
311   {
312
313     if (!Platform.isJS())
314     {
315       System.setSecurityManager(null);
316     }
317
318     System.out
319             .println("Java version: " + System.getProperty("java.version"));
320     System.out.println(System.getProperty("os.arch") + " "
321             + System.getProperty("os.name") + " "
322             + System.getProperty("os.version"));
323
324     ArgsParser aparser = new ArgsParser(args);
325
326     String usrPropsFile = aparser.getValue(ArgsParser.PROPS);
327     Cache.loadProperties(usrPropsFile);
328     if (usrPropsFile != null)
329     {
330       System.out.println(
331               "CMD [-props " + usrPropsFile + "] executed successfully!");
332     }
333
334     if (!Platform.isJS())
335     /**
336      * Java only
337      * 
338      * @j2sIgnore
339      */
340     {
341       if (aparser.contains("help") || aparser.contains("h"))
342       {
343         showUsage();
344         System.exit(0);
345       }
346       if (aparser.contains(ArgsParser.NODISPLAY)
347               || aparser.contains(ArgsParser.NOGUI)
348               || aparser.contains(ArgsParser.HEADLESS)
349               || "true".equals(System.getProperty("java.awt.headless")))
350       {
351         headless = true;
352       }
353
354       // anything else!
355
356       final String jabawsUrl = aparser.getValue(ArgsParser.JABAWS);
357       if (jabawsUrl != null)
358       {
359         try
360         {
361           Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
362           System.out.println(
363                   "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
364         } catch (MalformedURLException e)
365         {
366           System.err.println(
367                   "Invalid jabaws parameter: " + jabawsUrl + " ignored");
368         }
369       }
370
371     }
372     // check for property setting
373     String defs = aparser.getValue(ArgsParser.SETPROP);
374     while (defs != null)
375     {
376       int p = defs.indexOf('=');
377       if (p == -1)
378       {
379         System.err.println("Ignoring invalid setprop argument : " + defs);
380       }
381       else
382       {
383         System.out.println("Executing setprop argument: " + defs);
384         if (Platform.isJS())
385         {
386           Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
387         }
388       }
389       defs = aparser.getValue(ArgsParser.SETPROP);
390     }
391     System.setProperty("http.agent",
392             "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
393     try
394     {
395       Cache.initLogger();
396     } catch (NoClassDefFoundError error)
397     {
398       error.printStackTrace();
399       System.out.println("\nEssential logging libraries not found."
400               + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
401       System.exit(0);
402     }
403
404     desktop = null;
405
406     try
407     {
408       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
409     } catch (Exception ex)
410     {
411       System.err.println("Unexpected Look and Feel Exception");
412       ex.printStackTrace();
413     }
414     if (Platform.isAMacAndNotJS())
415     {
416
417       LookAndFeel lookAndFeel = ch.randelshofer.quaqua.QuaquaManager
418               .getLookAndFeel();
419       System.setProperty("com.apple.mrj.application.apple.menu.about.name",
420               "Jalview");
421       System.setProperty("apple.laf.useScreenMenuBar", "true");
422       if (lookAndFeel != null)
423       {
424         try
425         {
426           UIManager.setLookAndFeel(lookAndFeel);
427         } catch (Throwable e)
428         {
429           System.err.println(
430                   "Failed to set QuaQua look and feel: " + e.toString());
431         }
432       }
433       if (lookAndFeel == null
434               || !(lookAndFeel.getClass().isAssignableFrom(
435                       UIManager.getLookAndFeel().getClass()))
436               || !UIManager.getLookAndFeel().getClass().toString()
437                       .toLowerCase().contains("quaqua"))
438       {
439         try
440         {
441           System.err.println(
442                   "Quaqua LaF not available on this plaform. Using VAqua(4).\nSee https://issues.jalview.org/browse/JAL-2976");
443           UIManager.setLookAndFeel("org.violetlib.aqua.AquaLookAndFeel");
444         } catch (Throwable e)
445         {
446           System.err.println(
447                   "Failed to reset look and feel: " + e.toString());
448         }
449       }
450     }
451
452     /*
453      * configure 'full' SO model if preferences say to, 
454      * else use the default (SO Lite)
455      */
456     if (Cache.getDefault("USE_FULL_SO", false))
457     {
458       SequenceOntologyFactory.setInstance(new SequenceOntology());
459     }
460
461     if (!headless)
462     {
463       desktop = new Desktop();
464       desktop.setInBatchMode(true); // indicate we are starting up
465       desktop.setVisible(true);
466
467       if (!Platform.isJS())
468       /**
469        * Java only
470        * 
471        * @j2sIgnore
472        */
473       {
474         desktop.startServiceDiscovery();
475         if (!aparser.contains(ArgsParser.NOUSAGESTATS))
476         {
477           startUsageStats(desktop);
478         }
479         else
480         {
481           System.err.println("CMD [-nousagestats] executed successfully!");
482         }
483
484         if (!aparser.contains(ArgsParser.NOQUESTIONNAIRE))
485         {
486           String url = aparser.getValue(ArgsParser.QUESTIONNAIRE);
487           if (url != null)
488           {
489             // Start the desktop questionnaire prompter with the specified
490             // questionnaire
491             Cache.log.debug("Starting questionnaire url at " + url);
492             desktop.checkForQuestionnaire(url);
493             System.out.println("CMD questionnaire[-" + url
494                     + "] executed successfully!");
495           }
496           else
497           {
498             if (Cache.getProperty("NOQUESTIONNAIRES") == null)
499             {
500               // Start the desktop questionnaire prompter with the specified
501               // questionnaire
502               // String defurl =
503               // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
504               // //
505               String defurl = "http://www.jalview.org/cgi-bin/questionnaire.pl";
506               Cache.log.debug(
507                       "Starting questionnaire with default url: " + defurl);
508               desktop.checkForQuestionnaire(defurl);
509             }
510           }
511         }
512         else
513         {
514           System.err
515                   .println("CMD [-noquestionnaire] executed successfully!");
516         }
517
518         if (!aparser.contains(ArgsParser.NONEWS))
519         {
520           desktop.checkForNews();
521         }
522
523         BioJsHTMLOutput.updateBioJS();
524       }
525     }
526
527     String data = null;
528     FileFormatI format = null;
529     DataSourceType protocol = null;
530     FileLoader fileLoader = new FileLoader(!headless);
531
532     // script to execute after all loading is
533     // completed one way or another
534     // extract groovy argument and execute if necessary
535     String groovyscript = aparser.getValue(ArgsParser.GROOVY, true);
536     String file = aparser.getValue(ArgsParser.OPEN, true);
537
538     if (file == null && desktop == null)
539     {
540       System.out.println("No files to open!");
541       System.exit(1);
542     }
543     String vamsasImport = aparser.getValue(ArgsParser.VDOC);
544     String vamsasSession = aparser.getValue(ArgsParser.VSESS);
545     if (vamsasImport != null || vamsasSession != null)
546     {
547       if (desktop == null || headless)
548       {
549         System.out.println(
550                 "Headless vamsas sessions not yet supported. Sorry.");
551         System.exit(1);
552       }
553       // if we have a file, start a new session and import it.
554       boolean inSession = false;
555       if (vamsasImport != null)
556       {
557         try
558         {
559           DataSourceType viprotocol = AppletFormatAdapter
560                   .checkProtocol(vamsasImport);
561           if (viprotocol == DataSourceType.FILE)
562           {
563             inSession = desktop.vamsasImport(new File(vamsasImport));
564           }
565           else if (viprotocol == DataSourceType.URL)
566           {
567             inSession = desktop.vamsasImport(new URL(vamsasImport));
568           }
569
570         } catch (Exception e)
571         {
572           System.err.println("Exeption when importing " + vamsasImport
573                   + " as a vamsas document.");
574           e.printStackTrace();
575         }
576         if (!inSession)
577         {
578           System.err.println("Failed to import " + vamsasImport
579                   + " as a vamsas document.");
580         }
581         else
582         {
583           System.out.println("Imported Successfully into new session "
584                   + desktop.getVamsasApplication().getCurrentSession());
585         }
586       }
587       if (vamsasSession != null)
588       {
589         if (vamsasImport != null)
590         {
591           // close the newly imported session and import the Jalview specific
592           // remnants into the new session later on.
593           desktop.vamsasStop_actionPerformed(null);
594         }
595         // now join the new session
596         try
597         {
598           if (desktop.joinVamsasSession(vamsasSession))
599           {
600             System.out.println(
601                     "Successfully joined vamsas session " + vamsasSession);
602           }
603           else
604           {
605             System.err.println("WARNING: Failed to join vamsas session "
606                     + vamsasSession);
607           }
608         } catch (Exception e)
609         {
610           System.err.println(
611                   "ERROR: Failed to join vamsas session " + vamsasSession);
612           e.printStackTrace();
613         }
614         if (vamsasImport != null)
615         {
616           // the Jalview specific remnants can now be imported into the new
617           // session at the user's leisure.
618           Cache.log.info(
619                   "Skipping Push for import of data into existing vamsas session."); // TODO:
620           // enable
621           // this
622           // when
623           // debugged
624           // desktop.getVamsasApplication().push_update();
625         }
626       }
627     }
628     long progress = -1;
629     // Finally, deal with the remaining input data.
630     if (file != null)
631     {
632       if (!headless)
633       {
634         desktop.setProgressBar(
635                 MessageManager
636                         .getString("status.processing_commandline_args"),
637                 progress = System.currentTimeMillis());
638       }
639       System.out.println("CMD [-open " + file + "] executed successfully!");
640
641       if (!Platform.isJS())
642       /**
643        * ignore in JavaScript -- can't just check file existence - could load
644        * it?
645        * 
646        * @j2sIgnore
647        */
648       {
649         if (!file.startsWith("http://") && !file.startsWith("https://"))
650         // BH 2019 added https check for Java
651         {
652           if (!(new File(file)).exists())
653           {
654             System.out.println("Can't find " + file);
655             if (headless)
656             {
657               System.exit(1);
658             }
659           }
660         }
661       }
662
663       protocol = AppletFormatAdapter.checkProtocol(file);
664
665       try
666       {
667         format = new IdentifyFile().identify(file, protocol);
668       } catch (FileFormatException e1)
669       {
670         // TODO ?
671       }
672
673       AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
674               format);
675       if (af == null)
676       {
677         System.out.println("error");
678       }
679       else
680       {
681         setCurrentAlignFrame(af);
682         data = aparser.getValue(ArgsParser.COLOUR, true);
683         if (data != null)
684         {
685           data.replaceAll("%20", " ");
686
687           ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
688                   af.getViewport(), af.getViewport().getAlignment(), data);
689
690           if (cs != null)
691           {
692             System.out.println(
693                     "CMD [-color " + data + "] executed successfully!");
694           }
695           af.changeColour(cs);
696         }
697
698         // Must maintain ability to use the groups flag
699         data = aparser.getValue(ArgsParser.GROUPS, true);
700         if (data != null)
701         {
702           af.parseFeaturesFile(data,
703                   AppletFormatAdapter.checkProtocol(data));
704           // System.out.println("Added " + data);
705           System.out.println(
706                   "CMD groups[-" + data + "]  executed successfully!");
707         }
708         data = aparser.getValue(ArgsParser.FEATURES, true);
709         if (data != null)
710         {
711           af.parseFeaturesFile(data,
712                   AppletFormatAdapter.checkProtocol(data));
713           // System.out.println("Added " + data);
714           System.out.println(
715                   "CMD [-features " + data + "]  executed successfully!");
716         }
717
718         data = aparser.getValue(ArgsParser.ANNOTATIONS, true);
719         if (data != null)
720         {
721           af.loadJalviewDataFile(data, null, null, null);
722           // System.out.println("Added " + data);
723           System.out.println(
724                   "CMD [-annotations " + data + "] executed successfully!");
725         }
726         // set or clear the sortbytree flag.
727         if (aparser.contains(ArgsParser.SORTBYTREE))
728         {
729           af.getViewport().setSortByTree(true);
730           if (af.getViewport().getSortByTree())
731           {
732             System.out.println("CMD [-sortbytree] executed successfully!");
733           }
734         }
735         if (aparser.contains(ArgsParser.NOANNOTATION)
736                 || aparser.contains(ArgsParser.NOANNOTATION2))
737         {
738           af.getViewport().setShowAnnotation(false);
739           if (!af.getViewport().isShowAnnotation())
740           {
741             System.out.println("CMD no-annotation executed successfully!");
742           }
743         }
744         if (aparser.contains(ArgsParser.NOSORTBYTREE))
745         {
746           af.getViewport().setSortByTree(false);
747           if (!af.getViewport().getSortByTree())
748           {
749             System.out
750                     .println("CMD [-nosortbytree] executed successfully!");
751           }
752         }
753         data = aparser.getValue(ArgsParser.TREE, true);
754         if (data != null)
755         {
756           try
757           {
758             System.out.println(
759                     "CMD [-tree " + data + "] executed successfully!");
760             NewickFile nf = new NewickFile(data,
761                     AppletFormatAdapter.checkProtocol(data));
762             af.getViewport()
763                     .setCurrentTree(af.showNewickTree(nf, data).getTree());
764           } catch (IOException ex)
765           {
766             System.err.println("Couldn't add tree " + data);
767             ex.printStackTrace(System.err);
768           }
769         }
770         // TODO - load PDB structure(s) to alignment JAL-629
771         // (associate with identical sequence in alignment, or a specified
772         // sequence)
773         if (groovyscript != null)
774         {
775           // Execute the groovy script after we've done all the rendering stuff
776           // and before any images or figures are generated.
777           System.out.println("Executing script " + groovyscript);
778           executeGroovyScript(groovyscript, af);
779           System.out.println("CMD groovy[" + groovyscript
780                   + "] executed successfully!");
781           groovyscript = null;
782         }
783         String imageName = "unnamed.png";
784         while (aparser.getSize() > 1)
785         {
786           // PNG filename
787           // SVG filename
788           // HTML filename
789           // biojsmsa filename
790           String outputFormat = aparser.nextValue();
791           file = aparser.nextValue();
792
793           if (outputFormat.equalsIgnoreCase("png"))
794           {
795             af.createPNG(new File(file));
796             imageName = (new File(file)).getName();
797             System.out.println("Creating PNG image: " + file);
798             continue;
799           }
800           else if (outputFormat.equalsIgnoreCase("svg"))
801           {
802             File imageFile = new File(file);
803             imageName = imageFile.getName();
804             af.createSVG(imageFile);
805             System.out.println("Creating SVG image: " + file);
806             continue;
807           }
808           else if (outputFormat.equalsIgnoreCase("html"))
809           {
810             File imageFile = new File(file);
811             imageName = imageFile.getName();
812             HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
813             htmlSVG.exportHTML(file);
814
815             System.out.println("Creating HTML image: " + file);
816             continue;
817           }
818           else if (outputFormat.equalsIgnoreCase("biojsmsa"))
819           {
820             if (file == null)
821             {
822               System.err.println("The output html file must not be null");
823               return;
824             }
825             try
826             {
827               BioJsHTMLOutput.refreshVersionInfo(
828                       BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
829             } catch (URISyntaxException e)
830             {
831               e.printStackTrace();
832             }
833             BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
834             bjs.exportHTML(file);
835             System.out
836                     .println("Creating BioJS MSA Viwer HTML file: " + file);
837             continue;
838           }
839           else if (outputFormat.equalsIgnoreCase("imgMap"))
840           {
841             af.createImageMap(new File(file), imageName);
842             System.out.println("Creating image map: " + file);
843             continue;
844           }
845           else if (outputFormat.equalsIgnoreCase("eps"))
846           {
847             File outputFile = new File(file);
848             System.out.println(
849                     "Creating EPS file: " + outputFile.getAbsolutePath());
850             af.createEPS(outputFile);
851             continue;
852           }
853
854           af.saveAlignment(file, format);
855           if (af.isSaveAlignmentSuccessful())
856           {
857             System.out.println("Written alignment in " + format
858                     + " format to " + file);
859           }
860           else
861           {
862             System.out.println("Error writing file " + file + " in "
863                     + format + " format!!");
864           }
865
866         }
867
868         while (aparser.getSize() > 0)
869         {
870           System.out.println("Unknown arg: " + aparser.nextValue());
871         }
872       }
873     }
874     AlignFrame startUpAlframe = null;
875     // We'll only open the default file if the desktop is visible.
876     // And the user
877     // ////////////////////
878
879     if (!Platform.isJS() && !headless && file == null
880             && vamsasImport == null
881             && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true))
882     /**
883      * Java only
884      * 
885      * @j2sIgnore
886      */
887     {
888       file = jalview.bin.Cache.getDefault("STARTUP_FILE",
889               jalview.bin.Cache.getDefault("www.jalview.org",
890                       "http://www.jalview.org")
891                       + "/examples/exampleFile_2_7.jar");
892       if (file.equals(
893               "http://www.jalview.org/examples/exampleFile_2_3.jar"))
894       {
895         // hardwire upgrade of the startup file
896         file.replace("_2_3.jar", "_2_7.jar");
897         // and remove the stale setting
898         jalview.bin.Cache.removeProperty("STARTUP_FILE");
899       }
900
901       protocol = DataSourceType.FILE;
902
903       if (file.indexOf("http:") > -1)
904       {
905         protocol = DataSourceType.URL;
906       }
907
908       if (file.endsWith(".jar"))
909       {
910         format = FileFormat.Jalview;
911       }
912       else
913       {
914         try
915         {
916           format = new IdentifyFile().identify(file, protocol);
917         } catch (FileFormatException e)
918         {
919           // TODO what?
920         }
921       }
922
923       startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
924               format);
925       // extract groovy arguments before anything else.
926     }
927
928     // Once all other stuff is done, execute any groovy scripts (in order)
929     if (groovyscript != null)
930     {
931       if (Cache.groovyJarsPresent())
932       {
933         System.out.println("Executing script " + groovyscript);
934         executeGroovyScript(groovyscript, startUpAlframe);
935       }
936       else
937       {
938         System.err.println(
939                 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
940                         + groovyscript);
941       }
942     }
943     // and finally, turn off batch mode indicator - if the desktop still exists
944     if (desktop != null)
945     {
946       if (progress != -1)
947       {
948         desktop.setProgressBar(null, progress);
949       }
950       desktop.setInBatchMode(false);
951     }
952   }
953
954   private static void showUsage()
955   {
956     System.out.println(
957             "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
958                     + "-nodisplay\tRun Jalview without User Interface.\n"
959                     + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
960                     + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
961                     + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
962                     + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
963                     + "-features FILE\tUse the given file to mark features on the alignment.\n"
964                     + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
965                     + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
966                     + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
967                     + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
968                     + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
969                     + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
970                     + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
971                     + "-json FILE\tCreate alignment file FILE in JSON format.\n"
972                     + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
973                     + "-png FILE\tCreate PNG image FILE from alignment.\n"
974                     + "-svg FILE\tCreate SVG image FILE from alignment.\n"
975                     + "-html FILE\tCreate HTML file from alignment.\n"
976                     + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
977                     + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
978                     + "-eps FILE\tCreate EPS file FILE from alignment.\n"
979                     + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
980                     + "-noquestionnaire\tTurn off questionnaire check.\n"
981                     + "-nonews\tTurn off check for Jalview news.\n"
982                     + "-nousagestats\tTurn off google analytics tracking for this session.\n"
983                     + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
984                     // +
985                     // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
986                     // after all other properties files have been read\n\t
987                     // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
988                     // passed in correctly)"
989                     + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
990                     + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
991                     // +
992                     // "-vdoc vamsas-document\tImport vamsas document into new
993                     // session or join existing session with same URN\n"
994                     // + "-vses vamsas-session\tJoin session with given URN\n"
995                     + "-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"
996                     + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
997   }
998
999   private static void startUsageStats(final Desktop desktop)
1000   {
1001     /**
1002      * start a User Config prompt asking if we can log usage statistics.
1003      */
1004     PromptUserConfig prompter = new PromptUserConfig(
1005             Desktop.getDesktopPane(), "USAGESTATS",
1006             "Jalview Usage Statistics",
1007             "Do you want to help make Jalview better by enabling "
1008                     + "the collection of usage statistics with Google Analytics ?"
1009                     + "\n\n(you can enable or disable usage tracking in the preferences)",
1010             new Runnable()
1011             {
1012               @Override
1013               public void run()
1014               {
1015                 Cache.log.debug(
1016                         "Initialising googletracker for usage stats.");
1017                 Cache.initGoogleTracker();
1018                 Cache.log.debug("Tracking enabled.");
1019               }
1020             }, new Runnable()
1021             {
1022               @Override
1023               public void run()
1024               {
1025                 Cache.log.debug("Not enabling Google Tracking.");
1026               }
1027             }, null, true);
1028     desktop.addDialogThread(prompter);
1029   }
1030
1031   /**
1032    * Locate the given string as a file and pass it to the groovy interpreter.
1033    * 
1034    * @param groovyscript
1035    *          the script to execute
1036    * @param jalviewContext
1037    *          the Jalview Desktop object passed in to the groovy binding as the
1038    *          'Jalview' object.
1039    */
1040   private void executeGroovyScript(String groovyscript, AlignFrame af)
1041   {
1042     /**
1043      * for scripts contained in files
1044      */
1045     File tfile = null;
1046     /**
1047      * script's URI
1048      */
1049     URL sfile = null;
1050     if (groovyscript.trim().equals("STDIN"))
1051     {
1052       // read from stdin into a tempfile and execute it
1053       try
1054       {
1055         tfile = File.createTempFile("jalview", "groovy");
1056         PrintWriter outfile = new PrintWriter(
1057                 new OutputStreamWriter(new FileOutputStream(tfile)));
1058         BufferedReader br = new BufferedReader(
1059                 new InputStreamReader(System.in));
1060         String line = null;
1061         while ((line = br.readLine()) != null)
1062         {
1063           outfile.write(line + "\n");
1064         }
1065         br.close();
1066         outfile.flush();
1067         outfile.close();
1068
1069       } catch (Exception ex)
1070       {
1071         System.err.println("Failed to read from STDIN into tempfile "
1072                 + ((tfile == null) ? "(tempfile wasn't created)"
1073                         : tfile.toString()));
1074         ex.printStackTrace();
1075         return;
1076       }
1077       try
1078       {
1079         sfile = tfile.toURI().toURL();
1080       } catch (Exception x)
1081       {
1082         System.err.println(
1083                 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1084                         + tfile.toURI());
1085         x.printStackTrace();
1086         return;
1087       }
1088     }
1089     else
1090     {
1091       try
1092       {
1093         sfile = new URI(groovyscript).toURL();
1094       } catch (Exception x)
1095       {
1096         tfile = new File(groovyscript);
1097         if (!tfile.exists())
1098         {
1099           System.err.println("File '" + groovyscript + "' does not exist.");
1100           return;
1101         }
1102         if (!tfile.canRead())
1103         {
1104           System.err.println("File '" + groovyscript + "' cannot be read.");
1105           return;
1106         }
1107         if (tfile.length() < 1)
1108         {
1109           System.err.println("File '" + groovyscript + "' is empty.");
1110           return;
1111         }
1112         try
1113         {
1114           sfile = tfile.getAbsoluteFile().toURI().toURL();
1115         } catch (Exception ex)
1116         {
1117           System.err.println("Failed to create a file URL for "
1118                   + tfile.getAbsoluteFile());
1119           return;
1120         }
1121       }
1122     }
1123     try
1124     {
1125       Map<String, Object> vbinding = new HashMap<>();
1126       vbinding.put("Jalview", this);
1127       if (af != null)
1128       {
1129         vbinding.put("currentAlFrame", af);
1130       }
1131       Binding gbinding = new Binding(vbinding);
1132       GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1133       gse.run(sfile.toString(), gbinding);
1134       if ("STDIN".equals(groovyscript))
1135       {
1136         // delete temp file that we made -
1137         // only if it was successfully executed
1138         tfile.delete();
1139       }
1140     } catch (Exception e)
1141     {
1142       System.err.println("Exception Whilst trying to execute file " + sfile
1143               + " as a groovy script.");
1144       e.printStackTrace(System.err);
1145
1146     }
1147   }
1148
1149   public AlignFrame[] getAlignFrames()
1150   {
1151     return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1152             : Desktop.getAlignFrames();
1153
1154   }
1155
1156   /**
1157    * Quit method delegates to Desktop.quit - unless running in headless mode
1158    * when it just ends the JVM
1159    */
1160   public void quit()
1161   {
1162     if (desktop != null)
1163     {
1164       desktop.quit();
1165     }
1166     else
1167     {
1168       System.exit(0);
1169     }
1170   }
1171
1172   // singleton instances
1173
1174   public Cache cache;
1175
1176   public AlignmentSorter alignmentSorter;
1177
1178   public EnsemblInfo ensemblInfo;
1179
1180   public HttpServer httpServer;
1181
1182   public IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> structureSelections;
1183
1184   public PDBFTSRestClient pdbFTSRestClient;
1185
1186   public RestHandler restHandler;
1187
1188   public ScoreModels scoreModels;
1189
1190   public SequenceFetcher sequenceFetcher;
1191
1192   public SequenceOntologyI sequenceOntology;
1193
1194   public UniProtFTSRestClient uniprotFTSRestClient;
1195
1196   public StructureSelectionManager nullProvider;
1197
1198   public Color[] rnaHelices = null;
1199
1200   public StructureImportSettings structureImportSettings;
1201
1202   public IdOrgSettings idOrgSettings;
1203
1204   public SiftsSettings siftsSettings;
1205
1206   public RestClient restClient;
1207
1208   public Jws2Discoverer j2s2discoverer;
1209
1210   public Jws2InstanceFactory jws2InstanceFactory;
1211
1212   public Discoverer discoverer;
1213
1214 }