JAL-3321 Last pieces of the getdown-launcher.jar upgrade puzzle
[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.ext.so.SequenceOntology;
24 import jalview.gui.AlignFrame;
25 import jalview.gui.Desktop;
26 import jalview.gui.PromptUserConfig;
27 import jalview.io.AppletFormatAdapter;
28 import jalview.io.BioJsHTMLOutput;
29 import jalview.io.DataSourceType;
30 import jalview.io.FileFormat;
31 import jalview.io.FileFormatException;
32 import jalview.io.FileFormatI;
33 import jalview.io.FileLoader;
34 import jalview.io.HtmlSvgOutput;
35 import jalview.io.IdentifyFile;
36 import jalview.io.NewickFile;
37 import jalview.io.gff.SequenceOntologyFactory;
38 import jalview.schemes.ColourSchemeI;
39 import jalview.schemes.ColourSchemeProperty;
40 import jalview.util.MessageManager;
41 import jalview.util.Platform;
42 import jalview.ws.jws2.Jws2Discoverer;
43
44 import java.io.BufferedReader;
45 import java.io.File;
46 import java.io.FileOutputStream;
47 import java.io.IOException;
48 import java.io.InputStreamReader;
49 import java.io.OutputStreamWriter;
50 import java.io.PrintWriter;
51 import java.net.MalformedURLException;
52 import java.net.URI;
53 import java.net.URISyntaxException;
54 import java.net.URL;
55 import java.security.AllPermission;
56 import java.security.CodeSource;
57 import java.security.PermissionCollection;
58 import java.security.Permissions;
59 import java.security.Policy;
60 import java.util.HashMap;
61 import java.util.Map;
62 import java.util.Vector;
63
64 import javax.swing.LookAndFeel;
65 import javax.swing.UIManager;
66
67 import com.threerings.getdown.util.LaunchUtil;
68
69 import groovy.lang.Binding;
70 import groovy.util.GroovyScriptEngine;
71
72 /**
73  * Main class for Jalview Application <br>
74  * <br>
75  * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
76  * jalview.bin.Jalview
77  * 
78  * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
79  * jalview.bin.Jalview jalview.bin.Jalview
80  * 
81  * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
82  * embellish '*' to e.g. '*.jar')
83  * 
84  * @author $author$
85  * @version $Revision$
86  */
87 public class Jalview
88 {
89         /*
90          * singleton instance of this class
91          */
92         private static Jalview instance;
93
94         private Desktop desktop;
95
96         public static AlignFrame currentAlignFrame;
97
98         static {
99                 // grab all the rights we can the JVM
100                 Policy.setPolicy(new Policy() {
101                         @Override
102                         public PermissionCollection getPermissions(CodeSource codesource) {
103                                 Permissions perms = new Permissions();
104                                 perms.add(new AllPermission());
105                                 return (perms);
106                         }
107
108                         @Override
109                         public void refresh() {
110                         }
111                 });
112         }
113
114         /**
115          * keep track of feature fetching tasks.
116          * 
117          * @author JimP
118          * 
119          */
120         class FeatureFetcher {
121                 /*
122                  * TODO: generalise to track all jalview events to orchestrate batch processing
123                  * events.
124                  */
125
126                 private int queued = 0;
127
128                 private int running = 0;
129
130                 public FeatureFetcher() {
131
132                 }
133
134                 public void addFetcher(final AlignFrame af, final Vector<String> dasSources) {
135                         final long id = System.currentTimeMillis();
136                         queued++;
137                         final FeatureFetcher us = this;
138                         new Thread(new Runnable() {
139
140                                 @Override
141                                 public void run() {
142                                         synchronized (us) {
143                                                 queued--;
144                                                 running++;
145                                         }
146
147                                         af.setProgressBar(MessageManager.getString("status.das_features_being_retrived"), id);
148                                         af.featureSettings_actionPerformed(null);
149                                         af.setProgressBar(null, id);
150                                         synchronized (us) {
151                                                 running--;
152                                         }
153                                 }
154                         }).start();
155                 }
156
157                 public synchronized boolean allFinished() {
158                         return queued == 0 && running == 0;
159                 }
160
161         }
162
163         public static Jalview getInstance() {
164                 return instance;
165         }
166
167         /**
168          * main class for Jalview application
169          * 
170          * @param args open <em>filename</em>
171          */
172         public static void main(String[] args) {
173                 instance = new Jalview();
174                 instance.doMain(args);
175         }
176
177         /**
178          * @param args
179          */
180         void doMain(String[] args) {
181                 System.setSecurityManager(null);
182                 System.out.println("Java version: " + System.getProperty("java.version"));
183                 System.out.println(System.getProperty("os.arch") + " " + System.getProperty("os.name") + " "
184                                 + System.getProperty("os.version"));
185                 // report Jalview version
186                 Cache.loadBuildProperties(true);
187
188                 ArgsParser aparser = new ArgsParser(args);
189                 boolean headless = false;
190
191                 if (aparser.contains("help") || aparser.contains("h")) {
192                         showUsage();
193                         System.exit(0);
194                 }
195                 if (aparser.contains("nodisplay") || aparser.contains("nogui") || aparser.contains("headless")) {
196                         System.setProperty("java.awt.headless", "true");
197                         headless = true;
198                 }
199                 String usrPropsFile = aparser.getValue("props");
200                 Cache.loadProperties(usrPropsFile); // must do this before
201                 if (usrPropsFile != null) {
202                         System.out.println("CMD [-props " + usrPropsFile + "] executed successfully!");
203                 }
204
205                 // anything else!
206
207                 final String jabawsUrl = aparser.getValue("jabaws");
208                 if (jabawsUrl != null) {
209                         try {
210                                 Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
211                                 System.out.println("CMD [-jabaws " + jabawsUrl + "] executed successfully!");
212                         } catch (MalformedURLException e) {
213                                 System.err.println("Invalid jabaws parameter: " + jabawsUrl + " ignored");
214                         }
215                 }
216
217                 String defs = aparser.getValue("setprop");
218                 while (defs != null) {
219                         int p = defs.indexOf('=');
220                         if (p == -1) {
221                                 System.err.println("Ignoring invalid setprop argument : " + defs);
222                         } else {
223                                 System.out.println("Executing setprop argument: " + defs);
224                                 // DISABLED FOR SECURITY REASONS
225                                 // TODO: add a property to allow properties to be overriden by cli args
226                                 // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
227                         }
228                         defs = aparser.getValue("setprop");
229                 }
230                 if (System.getProperty("java.awt.headless") != null && System.getProperty("java.awt.headless").equals("true")) {
231                         headless = true;
232                 }
233                 System.setProperty("http.agent", "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
234                 try {
235                         Cache.initLogger();
236                 } catch (NoClassDefFoundError error) {
237                         error.printStackTrace();
238                         System.out.println("\nEssential logging libraries not found."
239                                         + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
240                         System.exit(0);
241                 }
242
243                 desktop = null;
244
245                 try {
246                         UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
247                 } catch (Exception ex) {
248                         System.err.println("Unexpected Look and Feel Exception");
249                         ex.printStackTrace();
250                 }
251                 if (Platform.isAMac()) {
252
253                         LookAndFeel lookAndFeel = ch.randelshofer.quaqua.QuaquaManager.getLookAndFeel();
254                         System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Jalview");
255                         System.setProperty("apple.laf.useScreenMenuBar", "true");
256                         if (lookAndFeel != null) {
257                                 try {
258                                         UIManager.setLookAndFeel(lookAndFeel);
259                                 } catch (Throwable e) {
260                                         System.err.println("Failed to set QuaQua look and feel: " + e.toString());
261                                 }
262                         }
263                         if (lookAndFeel == null || !(lookAndFeel.getClass().isAssignableFrom(UIManager.getLookAndFeel().getClass()))
264                                         || !UIManager.getLookAndFeel().getClass().toString().toLowerCase().contains("quaqua")) {
265                                 try {
266                                         System.err.println(
267                                                         "Quaqua LaF not available on this plaform. Using VAqua(4).\nSee https://issues.jalview.org/browse/JAL-2976");
268                                         UIManager.setLookAndFeel("org.violetlib.aqua.AquaLookAndFeel");
269                                 } catch (Throwable e) {
270                                         System.err.println("Failed to reset look and feel: " + e.toString());
271                                 }
272                         }
273                 }
274
275                 /*
276                  * configure 'full' SO model if preferences say to, else use the default (SO
277                  * Lite)
278                  */
279                 if (Cache.getDefault("USE_FULL_SO", false)) {
280                         SequenceOntologyFactory.setInstance(new SequenceOntology());
281                 }
282
283                 if (!headless) {
284                         desktop = new Desktop();
285                         desktop.setInBatchMode(true); // indicate we are starting up
286
287                         try {
288                                 JalviewTaskbar.setTaskbar(this);
289                         } catch (Exception e) {
290                                 System.out.println("Cannot set Taskbar");
291                                 // e.printStackTrace();
292                         } catch (Throwable t) {
293                                 System.out.println("Cannot set Taskbar");
294                                 // t.printStackTrace();
295                         }
296
297                         desktop.setVisible(true);
298                         desktop.startServiceDiscovery();
299                         if (!aparser.contains("nousagestats")) {
300                                 startUsageStats(desktop);
301                         } else {
302                                 System.err.println("CMD [-nousagestats] executed successfully!");
303                         }
304
305                         if (!aparser.contains("noquestionnaire")) {
306                                 String url = aparser.getValue("questionnaire");
307                                 if (url != null) {
308                                         // Start the desktop questionnaire prompter with the specified
309                                         // questionnaire
310                                         Cache.log.debug("Starting questionnaire url at " + url);
311                                         desktop.checkForQuestionnaire(url);
312                                         System.out.println("CMD questionnaire[-" + url + "] executed successfully!");
313                                 } else {
314                                         if (Cache.getProperty("NOQUESTIONNAIRES") == null) {
315                                                 // Start the desktop questionnaire prompter with the specified
316                                                 // questionnaire
317                                                 // String defurl =
318                                                 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
319                                                 // //
320                                                 String defurl = "http://www.jalview.org/cgi-bin/questionnaire.pl";
321                                                 Cache.log.debug("Starting questionnaire with default url: " + defurl);
322                                                 desktop.checkForQuestionnaire(defurl);
323                                         }
324                                 }
325                         } else {
326                                 System.err.println("CMD [-noquestionnaire] executed successfully!");
327                         }
328
329                         if (!aparser.contains("nonews")) {
330                                 desktop.checkForNews();
331                         }
332
333                         BioJsHTMLOutput.updateBioJS();
334                 }
335
336                 // Move any new getdown-launcher-new.jar into place over old
337                 // getdown-launcher.jar
338                 String appdirString = System.getProperty("getdownappdir");
339                 if (appdirString != null && appdirString.length() > 0) {
340                         final File appdir = new File(appdirString);
341                         new Thread() {
342                                 @Override
343                                 public void run() {
344                                         LaunchUtil.upgradeGetdown(new File(appdir, "getdown-launcher-old.jar"),
345                                                         new File(appdir, "getdown-launcher.jar"), new File(appdir, "getdown-launcher-new.jar"));
346                                 }
347                         }.start();
348                 }
349
350                 String file = null, data = null;
351                 FileFormatI format = null;
352                 DataSourceType protocol = null;
353                 FileLoader fileLoader = new FileLoader(!headless);
354
355                 String groovyscript = null; // script to execute after all loading is
356                 // completed one way or another
357                 // extract groovy argument and execute if necessary
358                 groovyscript = aparser.getValue("groovy", true);
359                 file = aparser.getValue("open", true);
360
361                 if (file == null && desktop == null) {
362                         System.out.println("No files to open!");
363                         System.exit(1);
364                 }
365                 String vamsasImport = aparser.getValue("vdoc");
366                 String vamsasSession = aparser.getValue("vsess");
367                 if (vamsasImport != null || vamsasSession != null) {
368                         if (desktop == null || headless) {
369                                 System.out.println("Headless vamsas sessions not yet supported. Sorry.");
370                                 System.exit(1);
371                         }
372                         // if we have a file, start a new session and import it.
373                         boolean inSession = false;
374                         if (vamsasImport != null) {
375                                 try {
376                                         DataSourceType viprotocol = AppletFormatAdapter.checkProtocol(vamsasImport);
377                                         if (viprotocol == DataSourceType.FILE) {
378                                                 inSession = desktop.vamsasImport(new File(vamsasImport));
379                                         } else if (viprotocol == DataSourceType.URL) {
380                                                 inSession = desktop.vamsasImport(new URL(vamsasImport));
381                                         }
382
383                                 } catch (Exception e) {
384                                         System.err.println("Exeption when importing " + vamsasImport + " as a vamsas document.");
385                                         e.printStackTrace();
386                                 }
387                                 if (!inSession) {
388                                         System.err.println("Failed to import " + vamsasImport + " as a vamsas document.");
389                                 } else {
390                                         System.out.println("Imported Successfully into new session "
391                                                         + desktop.getVamsasApplication().getCurrentSession());
392                                 }
393                         }
394                         if (vamsasSession != null) {
395                                 if (vamsasImport != null) {
396                                         // close the newly imported session and import the Jalview specific
397                                         // remnants into the new session later on.
398                                         desktop.vamsasStop_actionPerformed(null);
399                                 }
400                                 // now join the new session
401                                 try {
402                                         if (desktop.joinVamsasSession(vamsasSession)) {
403                                                 System.out.println("Successfully joined vamsas session " + vamsasSession);
404                                         } else {
405                                                 System.err.println("WARNING: Failed to join vamsas session " + vamsasSession);
406                                         }
407                                 } catch (Exception e) {
408                                         System.err.println("ERROR: Failed to join vamsas session " + vamsasSession);
409                                         e.printStackTrace();
410                                 }
411                                 if (vamsasImport != null) {
412                                         // the Jalview specific remnants can now be imported into the new
413                                         // session at the user's leisure.
414                                         Cache.log.info("Skipping Push for import of data into existing vamsas session."); // TODO:
415                                         // enable
416                                         // this
417                                         // when
418                                         // debugged
419                                         // desktop.getVamsasApplication().push_update();
420                                 }
421                         }
422                 }
423                 long progress = -1;
424                 // Finally, deal with the remaining input data.
425                 if (file != null) {
426                         if (!headless) {
427                                 desktop.setProgressBar(MessageManager.getString("status.processing_commandline_args"),
428                                                 progress = System.currentTimeMillis());
429                         }
430                         System.out.println("CMD [-open " + file + "] executed successfully!");
431
432                         if (!file.startsWith("http://")) {
433                                 if (!(new File(file)).exists()) {
434                                         System.out.println("Can't find " + file);
435                                         if (headless) {
436                                                 System.exit(1);
437                                         }
438                                 }
439                         }
440
441                         protocol = AppletFormatAdapter.checkProtocol(file);
442
443                         try {
444                                 format = new IdentifyFile().identify(file, protocol);
445                         } catch (FileFormatException e1) {
446                                 // TODO ?
447                         }
448
449                         AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol, format);
450                         if (af == null) {
451                                 System.out.println("error");
452                         } else {
453                                 setCurrentAlignFrame(af);
454                                 data = aparser.getValue("colour", true);
455                                 if (data != null) {
456                                         data.replaceAll("%20", " ");
457
458                                         ColourSchemeI cs = ColourSchemeProperty.getColourScheme(af.getViewport(),
459                                                         af.getViewport().getAlignment(), data);
460
461                                         if (cs != null) {
462                                                 System.out.println("CMD [-color " + data + "] executed successfully!");
463                                         }
464                                         af.changeColour(cs);
465                                 }
466
467                                 // Must maintain ability to use the groups flag
468                                 data = aparser.getValue("groups", true);
469                                 if (data != null) {
470                                         af.parseFeaturesFile(data, AppletFormatAdapter.checkProtocol(data));
471                                         // System.out.println("Added " + data);
472                                         System.out.println("CMD groups[-" + data + "]  executed successfully!");
473                                 }
474                                 data = aparser.getValue("features", true);
475                                 if (data != null) {
476                                         af.parseFeaturesFile(data, AppletFormatAdapter.checkProtocol(data));
477                                         // System.out.println("Added " + data);
478                                         System.out.println("CMD [-features " + data + "]  executed successfully!");
479                                 }
480
481                                 data = aparser.getValue("annotations", true);
482                                 if (data != null) {
483                                         af.loadJalviewDataFile(data, null, null, null);
484                                         // System.out.println("Added " + data);
485                                         System.out.println("CMD [-annotations " + data + "] executed successfully!");
486                                 }
487                                 // set or clear the sortbytree flag.
488                                 if (aparser.contains("sortbytree")) {
489                                         af.getViewport().setSortByTree(true);
490                                         if (af.getViewport().getSortByTree()) {
491                                                 System.out.println("CMD [-sortbytree] executed successfully!");
492                                         }
493                                 }
494                                 if (aparser.contains("no-annotation")) {
495                                         af.getViewport().setShowAnnotation(false);
496                                         if (!af.getViewport().isShowAnnotation()) {
497                                                 System.out.println("CMD no-annotation executed successfully!");
498                                         }
499                                 }
500                                 if (aparser.contains("nosortbytree")) {
501                                         af.getViewport().setSortByTree(false);
502                                         if (!af.getViewport().getSortByTree()) {
503                                                 System.out.println("CMD [-nosortbytree] executed successfully!");
504                                         }
505                                 }
506                                 data = aparser.getValue("tree", true);
507                                 if (data != null) {
508                                         try {
509                                                 System.out.println("CMD [-tree " + data + "] executed successfully!");
510                                                 NewickFile nf = new NewickFile(data, AppletFormatAdapter.checkProtocol(data));
511                                                 af.getViewport().setCurrentTree(af.showNewickTree(nf, data).getTree());
512                                         } catch (IOException ex) {
513                                                 System.err.println("Couldn't add tree " + data);
514                                                 ex.printStackTrace(System.err);
515                                         }
516                                 }
517                                 // TODO - load PDB structure(s) to alignment JAL-629
518                                 // (associate with identical sequence in alignment, or a specified
519                                 // sequence)
520                                 if (groovyscript != null) {
521                                         // Execute the groovy script after we've done all the rendering stuff
522                                         // and before any images or figures are generated.
523                                         System.out.println("Executing script " + groovyscript);
524                                         executeGroovyScript(groovyscript, af);
525                                         System.out.println("CMD groovy[" + groovyscript + "] executed successfully!");
526                                         groovyscript = null;
527                                 }
528                                 String imageName = "unnamed.png";
529                                 while (aparser.getSize() > 1) {
530                                         String outputFormat = aparser.nextValue();
531                                         file = aparser.nextValue();
532
533                                         if (outputFormat.equalsIgnoreCase("png")) {
534                                                 af.createPNG(new File(file));
535                                                 imageName = (new File(file)).getName();
536                                                 System.out.println("Creating PNG image: " + file);
537                                                 continue;
538                                         } else if (outputFormat.equalsIgnoreCase("svg")) {
539                                                 File imageFile = new File(file);
540                                                 imageName = imageFile.getName();
541                                                 af.createSVG(imageFile);
542                                                 System.out.println("Creating SVG image: " + file);
543                                                 continue;
544                                         } else if (outputFormat.equalsIgnoreCase("html")) {
545                                                 File imageFile = new File(file);
546                                                 imageName = imageFile.getName();
547                                                 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
548                                                 htmlSVG.exportHTML(file);
549
550                                                 System.out.println("Creating HTML image: " + file);
551                                                 continue;
552                                         } else if (outputFormat.equalsIgnoreCase("biojsmsa")) {
553                                                 if (file == null) {
554                                                         System.err.println("The output html file must not be null");
555                                                         return;
556                                                 }
557                                                 try {
558                                                         BioJsHTMLOutput.refreshVersionInfo(BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
559                                                 } catch (URISyntaxException e) {
560                                                         e.printStackTrace();
561                                                 }
562                                                 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
563                                                 bjs.exportHTML(file);
564                                                 System.out.println("Creating BioJS MSA Viwer HTML file: " + file);
565                                                 continue;
566                                         } else if (outputFormat.equalsIgnoreCase("imgMap")) {
567                                                 af.createImageMap(new File(file), imageName);
568                                                 System.out.println("Creating image map: " + file);
569                                                 continue;
570                                         } else if (outputFormat.equalsIgnoreCase("eps")) {
571                                                 File outputFile = new File(file);
572                                                 System.out.println("Creating EPS file: " + outputFile.getAbsolutePath());
573                                                 af.createEPS(outputFile);
574                                                 continue;
575                                         }
576
577                                         if (af.saveAlignment(file, format)) {
578                                                 System.out.println("Written alignment in " + format + " format to " + file);
579                                         } else {
580                                                 System.out.println("Error writing file " + file + " in " + format + " format!!");
581                                         }
582
583                                 }
584
585                                 while (aparser.getSize() > 0) {
586                                         System.out.println("Unknown arg: " + aparser.nextValue());
587                                 }
588                         }
589                 }
590                 AlignFrame startUpAlframe = null;
591                 // We'll only open the default file if the desktop is visible.
592                 // And the user
593                 // ////////////////////
594
595                 if (!headless && file == null && vamsasImport == null
596                                 && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true)) {
597                         file = jalview.bin.Cache.getDefault("STARTUP_FILE",
598                                         jalview.bin.Cache.getDefault("www.jalview.org", "http://www.jalview.org")
599                                                         + "/examples/exampleFile_2_7.jar");
600                         if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")) {
601                                 // hardwire upgrade of the startup file
602                                 file.replace("_2_3.jar", "_2_7.jar");
603                                 // and remove the stale setting
604                                 jalview.bin.Cache.removeProperty("STARTUP_FILE");
605                         }
606
607                         protocol = DataSourceType.FILE;
608
609                         if (file.indexOf("http:") > -1) {
610                                 protocol = DataSourceType.URL;
611                         }
612
613                         if (file.endsWith(".jar")) {
614                                 format = FileFormat.Jalview;
615                         } else {
616                                 try {
617                                         format = new IdentifyFile().identify(file, protocol);
618                                 } catch (FileFormatException e) {
619                                         // TODO what?
620                                 }
621                         }
622
623                         startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol, format);
624                         // extract groovy arguments before anything else.
625                 }
626
627                 // Once all other stuff is done, execute any groovy scripts (in order)
628                 if (groovyscript != null) {
629                         if (Cache.groovyJarsPresent()) {
630                                 System.out.println("Executing script " + groovyscript);
631                                 executeGroovyScript(groovyscript, startUpAlframe);
632                         } else {
633                                 System.err.println("Sorry. Groovy Support is not available, so ignoring the provided groovy script "
634                                                 + groovyscript);
635                         }
636                 }
637                 // and finally, turn off batch mode indicator - if the desktop still exists
638                 if (desktop != null) {
639                         if (progress != -1) {
640                                 desktop.setProgressBar(null, progress);
641                         }
642                         desktop.setInBatchMode(false);
643                 }
644         }
645
646         private static void showUsage() {
647                 System.out.println("Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
648                                 + "-nodisplay\tRun Jalview without User Interface.\n"
649                                 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
650                                 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
651                                 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
652                                 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
653                                 + "-features FILE\tUse the given file to mark features on the alignment.\n"
654                                 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
655                                 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
656                                 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
657                                 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
658                                 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
659                                 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
660                                 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
661                                 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
662                                 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
663                                 + "-png FILE\tCreate PNG image FILE from alignment.\n"
664                                 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
665                                 + "-html FILE\tCreate HTML file from alignment.\n"
666                                 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
667                                 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
668                                 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
669                                 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
670                                 + "-noquestionnaire\tTurn off questionnaire check.\n" + "-nonews\tTurn off check for Jalview news.\n"
671                                 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
672                                 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
673                                 // +
674                                 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
675                                 // after all other properties files have been read\n\t
676                                 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
677                                 // passed in correctly)"
678                                 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
679                                 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
680                                 // +
681                                 // "-vdoc vamsas-document\tImport vamsas document into new
682                                 // session or join existing session with same URN\n"
683                                 // + "-vses vamsas-session\tJoin session with given URN\n"
684                                 + "-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"
685                                 + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
686         }
687
688         private static void startUsageStats(final Desktop desktop) {
689                 /**
690                  * start a User Config prompt asking if we can log usage statistics.
691                  */
692                 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop, "USAGESTATS", "Jalview Usage Statistics",
693                                 "Do you want to help make Jalview better by enabling "
694                                                 + "the collection of usage statistics with Google Analytics ?"
695                                                 + "\n\n(you can enable or disable usage tracking in the preferences)",
696                                 new Runnable() {
697                                         @Override
698                                         public void run() {
699                                                 Cache.log.debug("Initialising googletracker for usage stats.");
700                                                 Cache.initGoogleTracker();
701                                                 Cache.log.debug("Tracking enabled.");
702                                         }
703                                 }, new Runnable() {
704                                         @Override
705                                         public void run() {
706                                                 Cache.log.debug("Not enabling Google Tracking.");
707                                         }
708                                 }, null, true);
709                 desktop.addDialogThread(prompter);
710         }
711
712         /**
713          * Locate the given string as a file and pass it to the groovy interpreter.
714          * 
715          * @param groovyscript   the script to execute
716          * @param jalviewContext the Jalview Desktop object passed in to the groovy
717          *                       binding as the 'Jalview' object.
718          */
719         private void executeGroovyScript(String groovyscript, AlignFrame af) {
720                 /**
721                  * for scripts contained in files
722                  */
723                 File tfile = null;
724                 /**
725                  * script's URI
726                  */
727                 URL sfile = null;
728                 if (groovyscript.trim().equals("STDIN")) {
729                         // read from stdin into a tempfile and execute it
730                         try {
731                                 tfile = File.createTempFile("jalview", "groovy");
732                                 PrintWriter outfile = new PrintWriter(new OutputStreamWriter(new FileOutputStream(tfile)));
733                                 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
734                                 String line = null;
735                                 while ((line = br.readLine()) != null) {
736                                         outfile.write(line + "\n");
737                                 }
738                                 br.close();
739                                 outfile.flush();
740                                 outfile.close();
741
742                         } catch (Exception ex) {
743                                 System.err.println("Failed to read from STDIN into tempfile "
744                                                 + ((tfile == null) ? "(tempfile wasn't created)" : tfile.toString()));
745                                 ex.printStackTrace();
746                                 return;
747                         }
748                         try {
749                                 sfile = tfile.toURI().toURL();
750                         } catch (Exception x) {
751                                 System.err.println(
752                                                 "Unexpected Malformed URL Exception for temporary file created from STDIN: " + tfile.toURI());
753                                 x.printStackTrace();
754                                 return;
755                         }
756                 } else {
757                         try {
758                                 sfile = new URI(groovyscript).toURL();
759                         } catch (Exception x) {
760                                 tfile = new File(groovyscript);
761                                 if (!tfile.exists()) {
762                                         System.err.println("File '" + groovyscript + "' does not exist.");
763                                         return;
764                                 }
765                                 if (!tfile.canRead()) {
766                                         System.err.println("File '" + groovyscript + "' cannot be read.");
767                                         return;
768                                 }
769                                 if (tfile.length() < 1) {
770                                         System.err.println("File '" + groovyscript + "' is empty.");
771                                         return;
772                                 }
773                                 try {
774                                         sfile = tfile.getAbsoluteFile().toURI().toURL();
775                                 } catch (Exception ex) {
776                                         System.err.println("Failed to create a file URL for " + tfile.getAbsoluteFile());
777                                         return;
778                                 }
779                         }
780                 }
781                 try {
782                         Map<String, java.lang.Object> vbinding = new HashMap<>();
783                         vbinding.put("Jalview", this);
784                         if (af != null) {
785                                 vbinding.put("currentAlFrame", af);
786                         }
787                         Binding gbinding = new Binding(vbinding);
788                         GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
789                         gse.run(sfile.toString(), gbinding);
790                         if ("STDIN".equals(groovyscript)) {
791                                 // delete temp file that we made -
792                                 // only if it was successfully executed
793                                 tfile.delete();
794                         }
795                 } catch (Exception e) {
796                         System.err.println("Exception Whilst trying to execute file " + sfile + " as a groovy script.");
797                         e.printStackTrace(System.err);
798
799                 }
800         }
801
802         public static boolean isHeadlessMode() {
803                 String isheadless = System.getProperty("java.awt.headless");
804                 if (isheadless != null && isheadless.equalsIgnoreCase("true")) {
805                         return true;
806                 }
807                 return false;
808         }
809
810         public AlignFrame[] getAlignFrames() {
811                 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() } : Desktop.getAlignFrames();
812
813         }
814
815         /**
816          * Quit method delegates to Desktop.quit - unless running in headless mode when
817          * it just ends the JVM
818          */
819         public void quit() {
820                 if (desktop != null) {
821                         desktop.quit();
822                 } else {
823                         System.exit(0);
824                 }
825         }
826
827         public static AlignFrame getCurrentAlignFrame() {
828                 return Jalview.currentAlignFrame;
829         }
830
831         public static void setCurrentAlignFrame(AlignFrame currentAlignFrame) {
832                 Jalview.currentAlignFrame = currentAlignFrame;
833         }
834 }