Jalview-JS/JAL-3253-applet additional static final preferences
[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
514     // script to execute after all loading is
515     // completed one way or another
516     // extract groovy argument and execute if necessary
517     String groovyscript = (isJS ? null
518             : aparser.getValue(ArgsParser.GROOVY, true));
519     String file = aparser.getValue(ArgsParser.OPEN, true);
520     String file2 = (isJavaAppletTag ? aparser.getAppletValue("file2", null)
521             : null);
522     String fileFormat = (isJavaAppletTag
523             ? aparser.getAppletValue("format", null)
524             : null);
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)
537     {
538       if (!headless)
539       {
540         desktop.setProgressBar(
541                 MessageManager
542                         .getString("status.processing_commandline_args"),
543                 progress = System.currentTimeMillis());
544       }
545
546       if (!isJS)
547       /**
548        * ignore in JavaScript -- can't just check file existence - could load
549        * it?
550        * 
551        * @j2sIgnore
552        */
553       {
554         if (!file.startsWith("http://") && !file.startsWith("https://"))
555         // BH 2019 added https check for Java
556         {
557           if (!(new File(file)).exists())
558           {
559             System.out.println("Can't find " + file);
560             if (headless)
561             {
562               System.exit(1);
563             }
564           }
565         }
566       }
567
568       protocol = AppletFormatAdapter.checkProtocol(file);
569
570       try
571       {
572         format = (isJavaAppletTag && fileFormat != null
573                 ? FileFormats.getInstance().forName(fileFormat)
574                 : null);
575         if (format == null)
576         {
577           format = new IdentifyFile().identify(file, protocol);
578         }
579       } catch (FileFormatException e1)
580       {
581         // TODO ?
582       }
583
584       AlignFrame af = new FileLoader(!headless).loadFileWaitTillLoaded(file,
585               protocol,
586               format);
587       if (af == null)
588       {
589         System.out.println("error");
590       }
591       else
592       {
593         System.out
594                 .println("CMD [-open " + file + "] executed successfully!");
595         if (file2 != null)
596         {
597           protocol = AppletFormatAdapter.checkProtocol(file2);
598           try
599           {
600             format = new IdentifyFile().identify(file2, protocol);
601           } catch (FileFormatException e1)
602           {
603             // TODO ?
604           }
605           AlignFrame af2 = new FileLoader(!headless).loadFileWaitTillLoaded(
606                   file2,
607                   protocol, format);
608           if (af2 == null)
609           {
610             System.out.println("error");
611           }
612           else
613           {
614             AlignViewport.openLinkedAlignmentAs(af,
615                     af.getViewport().getAlignment(),
616                     af2.getViewport().getAlignment(), "",
617                     AlignViewport.SPLIT_FRAME);
618           }
619         }
620
621         setCurrentAlignFrame(af);
622
623         // TODO: file2 How to implement file2 for the applet spit screen?
624
625         String data = aparser.getValue(ArgsParser.COLOUR, true);
626         if (data != null)
627         {
628           data.replaceAll("%20", " ");
629
630           ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
631                   af.getViewport(), af.getViewport().getAlignment(), data);
632
633           if (cs != null)
634           {
635             System.out.println(
636                     "CMD [-color " + data + "] executed successfully!");
637           }
638           af.changeColour(cs);
639         }
640
641         // Must maintain ability to use the groups flag
642         data = aparser.getValue(ArgsParser.GROUPS, true);
643         if (data != null)
644         {
645           af.parseFeaturesFile(data,
646                   AppletFormatAdapter.checkProtocol(data));
647           // System.out.println("Added " + data);
648           System.out.println(
649                   "CMD groups[-" + data + "]  executed successfully!");
650         }
651         data = aparser.getValue(ArgsParser.FEATURES, true);
652         if (data != null)
653         {
654           af.parseFeaturesFile(data,
655                   AppletFormatAdapter.checkProtocol(data));
656           // System.out.println("Added " + data);
657           System.out.println(
658                   "CMD [-features " + data + "]  executed successfully!");
659         }
660
661         data = aparser.getValue(ArgsParser.ANNOTATIONS, true);
662         if (data != null)
663         {
664           af.loadJalviewDataFile(data, null, null, null);
665           // System.out.println("Added " + data);
666           System.out.println(
667                   "CMD [-annotations " + data + "] executed successfully!");
668         }
669         // set or clear the sortbytree flag.
670         if (aparser.contains(ArgsParser.SORTBYTREE))
671         {
672           af.getViewport().setSortByTree(true);
673           if (af.getViewport().getSortByTree())
674           {
675             System.out.println("CMD [-sortbytree] executed successfully!");
676           }
677         }
678         if (aparser.contains(ArgsParser.NOANNOTATION)
679                 || aparser.contains(ArgsParser.NOANNOTATION2))
680         {
681           af.getViewport().setShowAnnotation(false);
682           if (!af.getViewport().isShowAnnotation())
683           {
684             System.out.println("CMD no-annotation executed successfully!");
685           }
686         }
687         if (aparser.contains(ArgsParser.NOSORTBYTREE))
688         {
689           af.getViewport().setSortByTree(false);
690           if (!af.getViewport().getSortByTree())
691           {
692             System.out
693                     .println("CMD [-nosortbytree] executed successfully!");
694           }
695         }
696         data = aparser.getValue(ArgsParser.TREE, true);
697         if (data != null)
698         {
699           try
700           {
701             System.out.println(
702                     "CMD [-tree " + data + "] executed successfully!");
703             NewickFile nf = new NewickFile(data,
704                     AppletFormatAdapter.checkProtocol(data));
705             af.getViewport()
706                     .setCurrentTree(af.showNewickTree(nf, data).getTree());
707           } catch (IOException ex)
708           {
709             System.err.println("Couldn't add tree " + data);
710             ex.printStackTrace(System.err);
711           }
712         }
713         // TODO - load PDB structure(s) to alignment JAL-629
714         // (associate with identical sequence in alignment, or a specified
715         // sequence)
716         if (isJavaAppletTag)
717         {
718           loadAppletParams(aparser, af);
719         }
720         else if (!isJS)
721         /**
722          * Java only
723          * 
724          * @j2sIgnore
725          */
726         {
727           if (groovyscript != null)
728           {
729             // Execute the groovy script after we've done all the rendering
730             // stuff
731             // and before any images or figures are generated.
732             System.out.println("Executing script " + groovyscript);
733             executeGroovyScript(groovyscript, af);
734             System.out.println("CMD groovy[" + groovyscript
735                     + "] executed successfully!");
736             groovyscript = null;
737           }
738           checkOutputFile(aparser, af, format);
739           while (aparser.getSize() > 0)
740           {
741             System.out.println("Unknown arg: " + aparser.nextValue());
742           }
743         }
744       }
745     }
746     AlignFrame startUpAlframe = null;
747     // We'll only open the default file if the desktop is visible.
748     // And the user
749     // ////////////////////
750
751     if (!isJS && !headless && file == null && !haveImport
752             && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true))
753     /**
754      * Java only
755      * 
756      * @j2sIgnore
757      */
758     {
759       file = jalview.bin.Cache.getDefault("STARTUP_FILE",
760               jalview.bin.Cache.getDefault("www.jalview.org",
761                       "http://www.jalview.org")
762                       + "/examples/exampleFile_2_7.jar");
763       if (file.equals(
764               "http://www.jalview.org/examples/exampleFile_2_3.jar"))
765       {
766         // hardwire upgrade of the startup file
767         file.replace("_2_3.jar", "_2_7.jar");
768         // and remove the stale setting
769         jalview.bin.Cache.removeProperty("STARTUP_FILE");
770       }
771
772       protocol = DataSourceType.FILE;
773
774       if (file.indexOf("http:") > -1)
775       {
776         protocol = DataSourceType.URL;
777       }
778
779       if (file.endsWith(".jar"))
780       {
781         format = FileFormat.Jalview;
782       }
783       else
784       {
785         try
786         {
787           format = new IdentifyFile().identify(file, protocol);
788         } catch (FileFormatException e)
789         {
790           // TODO what?
791         }
792       }
793
794       startUpAlframe = new FileLoader(!headless)
795               .loadFileWaitTillLoaded(file, protocol,
796               format);
797       // extract groovy arguments before anything else.
798     }
799
800     // Once all other stuff is done, execute any groovy scripts (in order)
801     if (groovyscript != null)
802     {
803       if (Cache.groovyJarsPresent())
804       {
805         System.out.println("Executing script " + groovyscript);
806         executeGroovyScript(groovyscript, startUpAlframe);
807       }
808       else
809       {
810         System.err.println(
811                 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
812                         + groovyscript);
813       }
814     }
815     // and finally, turn off batch mode indicator - if the desktop still exists
816     if (desktop != null)
817     {
818       if (progress != -1)
819       {
820         desktop.setProgressBar(null, progress);
821       }
822       desktop.setInBatchMode(false);
823     }
824   }
825
826   private boolean checkStartVamas(ArgsParser aparser)
827   {
828     String vamsasImport = aparser.getValue(ArgsParser.VDOC);
829     String vamsasSession = aparser.getValue(ArgsParser.VSESS);
830     if (vamsasImport == null && vamsasSession == null)
831     {
832       return false;
833     }
834     if (desktop == null || headless)
835     {
836       System.out.println(
837               "Headless vamsas sessions not yet supported. Sorry.");
838       System.exit(1);
839     }
840     boolean haveImport = (vamsasImport != null);
841     if (haveImport)
842     {
843       // if we have a file, start a new session and import it.
844       boolean inSession = false;
845       try
846       {
847         DataSourceType viprotocol = AppletFormatAdapter
848                 .checkProtocol(vamsasImport);
849         if (viprotocol == DataSourceType.FILE)
850         {
851           inSession = desktop.vamsasImport(new File(vamsasImport));
852         }
853         else if (viprotocol == DataSourceType.URL)
854         {
855           inSession = desktop.vamsasImport(new URL(vamsasImport));
856         }
857
858       } catch (Exception e)
859       {
860         System.err.println("Exeption when importing " + vamsasImport
861                 + " as a vamsas document.");
862         e.printStackTrace();
863       }
864       if (!inSession)
865       {
866         System.err.println("Failed to import " + vamsasImport
867                 + " as a vamsas document.");
868       }
869       else
870       {
871         System.out.println("Imported Successfully into new session "
872                 + desktop.getVamsasApplication().getCurrentSession());
873       }
874     }
875     if (vamsasSession != null)
876     {
877       if (vamsasImport != null)
878       {
879         // close the newly imported session and import the Jalview specific
880         // remnants into the new session later on.
881         desktop.vamsasStop_actionPerformed(null);
882       }
883       // now join the new session
884       try
885       {
886         if (desktop.joinVamsasSession(vamsasSession))
887         {
888           System.out.println(
889                   "Successfully joined vamsas session " + vamsasSession);
890         }
891         else
892         {
893           System.err.println("WARNING: Failed to join vamsas session "
894                   + vamsasSession);
895         }
896       } catch (Exception e)
897       {
898         System.err.println(
899                 "ERROR: Failed to join vamsas session " + vamsasSession);
900         e.printStackTrace();
901       }
902       if (vamsasImport != null)
903       {
904         // the Jalview specific remnants can now be imported into the new
905         // session at the user's leisure.
906         Cache.log.info(
907                 "Skipping Push for import of data into existing vamsas session."); // TODO:
908         // enable
909         // this
910         // when
911         // debugged
912         // desktop.getVamsasApplication().push_update();
913       }
914     }
915     return haveImport;
916   }
917
918   private void checkOutputFile(ArgsParser aparser, AlignFrame af,
919           FileFormatI format)
920   {
921     String imageName = "unnamed.png";
922     while (aparser.getSize() > 1)
923     {
924       // PNG filename
925       // SVG filename
926       // HTML filename
927       // biojsmsa filename
928       String outputFormat = aparser.nextValue();
929       String file = aparser.nextValue();
930       if (outputFormat.equalsIgnoreCase("png"))
931       {
932         af.createPNG(new File(file));
933         imageName = (new File(file)).getName();
934         System.out.println("Creating PNG image: " + file);
935         continue;
936       }
937       else if (outputFormat.equalsIgnoreCase("svg"))
938       {
939         File imageFile = new File(file);
940         imageName = imageFile.getName();
941         af.createSVG(imageFile);
942         System.out.println("Creating SVG image: " + file);
943         continue;
944       }
945       else if (outputFormat.equalsIgnoreCase("html"))
946       {
947         File imageFile = new File(file);
948         imageName = imageFile.getName();
949         HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
950         htmlSVG.exportHTML(file);
951
952         System.out.println("Creating HTML image: " + file);
953         continue;
954       }
955       else if (outputFormat.equalsIgnoreCase("biojsmsa"))
956       {
957         if (file == null)
958         {
959           System.err.println("The output html file must not be null");
960           return;
961         }
962         try
963         {
964           BioJsHTMLOutput.refreshVersionInfo(
965                   BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
966         } catch (URISyntaxException e)
967         {
968           e.printStackTrace();
969         }
970         BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
971         bjs.exportHTML(file);
972         System.out.println("Creating BioJS MSA Viwer HTML file: " + file);
973         continue;
974       }
975       else if (outputFormat.equalsIgnoreCase("imgMap"))
976       {
977         af.createImageMap(new File(file), imageName);
978         System.out.println("Creating image map: " + file);
979         continue;
980       }
981       else if (outputFormat.equalsIgnoreCase("eps"))
982       {
983         File outputFile = new File(file);
984         System.out.println(
985                 "Creating EPS file: " + outputFile.getAbsolutePath());
986         af.createEPS(outputFile);
987         continue;
988       }
989
990       af.saveAlignment(file, format);
991       if (af.isSaveAlignmentSuccessful())
992       {
993         System.out.println(
994                 "Written alignment in " + format + " format to " + file);
995       }
996       else
997       {
998         System.out.println("Error writing file " + file + " in " + format
999                 + " format!!");
1000       }
1001
1002     }
1003   }
1004
1005   private static void showUsage()
1006   {
1007     System.out.println(
1008             "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1009                     + "-nodisplay\tRun Jalview without User Interface.\n"
1010                     + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1011                     + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1012                     + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1013                     + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1014                     + "-features FILE\tUse the given file to mark features on the alignment.\n"
1015                     + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1016                     + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1017                     + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1018                     + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1019                     + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1020                     + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1021                     + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1022                     + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1023                     + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1024                     + "-png FILE\tCreate PNG image FILE from alignment.\n"
1025                     + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1026                     + "-html FILE\tCreate HTML file from alignment.\n"
1027                     + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1028                     + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1029                     + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1030                     + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1031                     + "-noquestionnaire\tTurn off questionnaire check.\n"
1032                     + "-nonews\tTurn off check for Jalview news.\n"
1033                     + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1034                     + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1035                     // +
1036                     // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1037                     // after all other properties files have been read\n\t
1038                     // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1039                     // passed in correctly)"
1040                     + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1041                     + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1042                     // +
1043                     // "-vdoc vamsas-document\tImport vamsas document into new
1044                     // session or join existing session with same URN\n"
1045                     // + "-vses vamsas-session\tJoin session with given URN\n"
1046                     + "-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"
1047                     + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
1048   }
1049
1050   private static void startUsageStats(final Desktop desktop)
1051   {
1052     /**
1053      * start a User Config prompt asking if we can log usage statistics.
1054      */
1055     PromptUserConfig prompter = new PromptUserConfig(
1056             Desktop.getDesktopPane(), "USAGESTATS",
1057             "Jalview Usage Statistics",
1058             "Do you want to help make Jalview better by enabling "
1059                     + "the collection of usage statistics with Google Analytics ?"
1060                     + "\n\n(you can enable or disable usage tracking in the preferences)",
1061             new Runnable()
1062             {
1063               @Override
1064               public void run()
1065               {
1066                 Cache.log.debug(
1067                         "Initialising googletracker for usage stats.");
1068                 Cache.initGoogleTracker();
1069                 Cache.log.debug("Tracking enabled.");
1070               }
1071             }, new Runnable()
1072             {
1073               @Override
1074               public void run()
1075               {
1076                 Cache.log.debug("Not enabling Google Tracking.");
1077               }
1078             }, null, true);
1079     desktop.addDialogThread(prompter);
1080   }
1081
1082   /**
1083    * Locate the given string as a file and pass it to the groovy interpreter.
1084    * 
1085    * @param groovyscript
1086    *          the script to execute
1087    * @param jalviewContext
1088    *          the Jalview Desktop object passed in to the groovy binding as the
1089    *          'Jalview' object.
1090    */
1091   private void executeGroovyScript(String groovyscript, AlignFrame af)
1092   {
1093     /**
1094      * for scripts contained in files
1095      */
1096     File tfile = null;
1097     /**
1098      * script's URI
1099      */
1100     URL sfile = null;
1101     if (groovyscript.trim().equals("STDIN"))
1102     {
1103       // read from stdin into a tempfile and execute it
1104       try
1105       {
1106         tfile = File.createTempFile("jalview", "groovy");
1107         PrintWriter outfile = new PrintWriter(
1108                 new OutputStreamWriter(new FileOutputStream(tfile)));
1109         BufferedReader br = new BufferedReader(
1110                 new InputStreamReader(System.in));
1111         String line = null;
1112         while ((line = br.readLine()) != null)
1113         {
1114           outfile.write(line + "\n");
1115         }
1116         br.close();
1117         outfile.flush();
1118         outfile.close();
1119
1120       } catch (Exception ex)
1121       {
1122         System.err.println("Failed to read from STDIN into tempfile "
1123                 + ((tfile == null) ? "(tempfile wasn't created)"
1124                         : tfile.toString()));
1125         ex.printStackTrace();
1126         return;
1127       }
1128       try
1129       {
1130         sfile = tfile.toURI().toURL();
1131       } catch (Exception x)
1132       {
1133         System.err.println(
1134                 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1135                         + tfile.toURI());
1136         x.printStackTrace();
1137         return;
1138       }
1139     }
1140     else
1141     {
1142       try
1143       {
1144         sfile = new URI(groovyscript).toURL();
1145       } catch (Exception x)
1146       {
1147         tfile = new File(groovyscript);
1148         if (!tfile.exists())
1149         {
1150           System.err.println("File '" + groovyscript + "' does not exist.");
1151           return;
1152         }
1153         if (!tfile.canRead())
1154         {
1155           System.err.println("File '" + groovyscript + "' cannot be read.");
1156           return;
1157         }
1158         if (tfile.length() < 1)
1159         {
1160           System.err.println("File '" + groovyscript + "' is empty.");
1161           return;
1162         }
1163         try
1164         {
1165           sfile = tfile.getAbsoluteFile().toURI().toURL();
1166         } catch (Exception ex)
1167         {
1168           System.err.println("Failed to create a file URL for "
1169                   + tfile.getAbsoluteFile());
1170           return;
1171         }
1172       }
1173     }
1174     try
1175     {
1176       Map<String, Object> vbinding = new HashMap<>();
1177       vbinding.put("Jalview", this);
1178       if (af != null)
1179       {
1180         vbinding.put("currentAlFrame", af);
1181       }
1182       Binding gbinding = new Binding(vbinding);
1183       GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1184       gse.run(sfile.toString(), gbinding);
1185       if ("STDIN".equals(groovyscript))
1186       {
1187         // delete temp file that we made -
1188         // only if it was successfully executed
1189         tfile.delete();
1190       }
1191     } catch (Exception e)
1192     {
1193       System.err.println("Exception Whilst trying to execute file " + sfile
1194               + " as a groovy script.");
1195       e.printStackTrace(System.err);
1196
1197     }
1198   }
1199
1200   public AlignFrame[] getAlignFrames()
1201   {
1202     return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1203             : Desktop.getAlignFrames();
1204
1205   }
1206
1207   /**
1208    * Quit method delegates to Desktop.quit - unless running in headless mode
1209    * when it just ends the JVM
1210    */
1211   public void quit()
1212   {
1213     if (desktop != null)
1214     {
1215       desktop.quit();
1216     }
1217     else
1218     {
1219       System.exit(0);
1220     }
1221   }
1222
1223   /**
1224    * Get the SwingJS applet ID and combine that with the frameType
1225    * 
1226    * @param frameType
1227    *          "alignment", "desktop", etc., or null
1228    * @return
1229    */
1230   public static String getAppID(String frameType)
1231   {
1232     String id = Cache.getProperty("Info.j2sAppletID");
1233     if (id == null)
1234     {
1235       id = "jalview";
1236     }
1237     return id + (frameType == null ? "" : "-" + frameType);
1238   }
1239
1240   /**
1241    * Handle all JalviewLite applet parameters
1242    * 
1243    * @param aparser
1244    * @param af
1245    */
1246   private void loadAppletParams(ArgsParser aparser, AlignFrame af)
1247   {
1248     JalviewApp app = new JalviewApp()
1249     {
1250
1251       private boolean alignPDBStructures; // From JalviewLite; not implemented
1252
1253       @Override
1254       public String getParameter(String name)
1255       {
1256         return aparser.getAppletValue(name, null);
1257       }
1258
1259       @Override
1260       public boolean getDefaultParameter(String name, boolean def)
1261       {
1262         String stn;
1263         return ((stn = getParameter(name)) == null ? def
1264                 : "true".equalsIgnoreCase(stn));
1265       }
1266
1267       /**
1268        * Get the applet-like document base even though this is an application.
1269        */
1270       @Override
1271       public URL getDocumentBase()
1272       {
1273         return Platform.getDocumentBase();
1274       }
1275
1276       /**
1277        * Get the applet-like code base even though this is an application.
1278        */
1279       @Override
1280       public URL getCodeBase()
1281       {
1282         return Platform.getCodeBase();
1283       }
1284
1285       @Override
1286       public AlignViewportI getViewport()
1287       {
1288         return af.getViewport();
1289       }
1290
1291       /**
1292        * features
1293        * 
1294        */
1295       @Override
1296       public boolean parseFeaturesFile(String filename,
1297               DataSourceType protocol)
1298       {
1299         return af.parseFeaturesFile(filename, protocol);
1300       }
1301
1302       /**
1303        * scorefile
1304        * 
1305        */
1306       @Override
1307       public boolean loadScoreFile(String sScoreFile) throws IOException
1308       {
1309         af.loadJalviewDataFile(sScoreFile, null, null, null);
1310         return true;
1311       }
1312
1313       /**
1314        * annotations, jpredfile, jnetfile
1315        * 
1316        */
1317       @Override
1318       public void updateForAnnotations()
1319       {
1320         af.updateForAnnotations();
1321       }
1322
1323       @Override
1324       public void loadTree(NewickFile fin, String treeFile)
1325               throws IOException
1326       {
1327         // n/a -- already done by standard Jalview command line processing
1328       }
1329
1330       @Override
1331       public void setAlignPdbStructures(boolean defaultParameter)
1332       {
1333         alignPDBStructures = true;
1334       }
1335
1336       @Override
1337       public void newStructureView(PDBEntry pdb, SequenceI[] seqs,
1338               String[] chains, DataSourceType protocol)
1339       {
1340         StructureViewer.launchStructureViewer(af.alignPanel, pdb, seqs);
1341       }
1342
1343       @Override
1344       public void setFeatureGroupState(String[] groups, boolean state)
1345       {
1346         af.setFeatureGroupState(groups, state);
1347       }
1348
1349       @Override
1350       public void alignedStructureView(PDBEntry[] pdb, SequenceI[][] seqs,
1351               String[][] chains, String[] protocols)
1352       {
1353         System.err.println(
1354                 "Jalview applet interface alignedStructureView not implemented");
1355       }
1356
1357       @Override
1358       public void newFeatureSettings()
1359       {
1360         System.err.println(
1361                 "Jalview applet interface newFeatureSettings not implemented");
1362       }
1363
1364     };
1365
1366     new JalviewAppLoader(true).load(app);
1367   }
1368
1369 }