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