Merge: 497958b 68dcaa7
[jalview.git] / src / jalview / bin / Jalview.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 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.gui.AlignFrame;
24 import jalview.gui.Desktop;
25 import jalview.io.HtmlSvgOutput;
26 import jalview.util.MessageManager;
27 import jalview.util.Platform;
28 import jalview.ws.jws2.Jws2Discoverer;
29
30 import java.awt.event.ActionEvent;
31 import java.awt.event.ActionListener;
32 import java.io.BufferedReader;
33 import java.io.File;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.OutputStreamWriter;
37 import java.io.PrintWriter;
38 import java.lang.reflect.Constructor;
39 import java.net.MalformedURLException;
40 import java.net.URI;
41 import java.net.URL;
42 import java.net.URLDecoder;
43 import java.security.AllPermission;
44 import java.security.CodeSource;
45 import java.security.PermissionCollection;
46 import java.security.Permissions;
47 import java.security.Policy;
48 import java.util.Hashtable;
49 import java.util.Map;
50 import java.util.Vector;
51
52 import javax.swing.UIManager;
53
54 /**
55  * Main class for Jalview Application <br>
56  * <br>
57  * start with java -Djava.ext.dirs=$PATH_TO_LIB$ jalview.bin.Jalview
58  * 
59  * @author $author$
60  * @version $Revision$
61  */
62 public class Jalview
63 {
64   static
65   {
66     // grab all the rights we can the JVM
67     Policy.setPolicy(new Policy()
68     {
69       public PermissionCollection getPermissions(CodeSource codesource)
70       {
71         Permissions perms = new Permissions();
72         perms.add(new AllPermission());
73         return (perms);
74       }
75
76       public void refresh()
77       {
78       }
79     });
80   }
81
82   /**
83    * main class for Jalview application
84    * 
85    * @param args
86    *          open <em>filename</em>
87    */
88   public static void main(String[] args)
89   {
90     System.out.println("Java version: "
91             + System.getProperty("java.version"));
92     System.out.println(System.getProperty("os.arch") + " "
93             + System.getProperty("os.name") + " "
94             + System.getProperty("os.version"));
95     if (new Platform().isAMac())
96     {
97       System.setProperty("com.apple.mrj.application.apple.menu.about.name",
98               "Jalview");
99       System.setProperty("apple.laf.useScreenMenuBar", "true");
100     }
101
102     ArgsParser aparser = new ArgsParser(args);
103     boolean headless = false;
104
105     if (aparser.contains("help") || aparser.contains("h"))
106     {
107       showUsage();
108       System.exit(0);
109     }
110     if (aparser.contains("nodisplay") || aparser.contains("nogui")
111             || aparser.contains("headless"))
112     {
113       System.setProperty("java.awt.headless", "true");
114       headless = true;
115     }
116     Cache.loadProperties(aparser.getValue("props")); // must do this before
117     // anything else!
118
119     final String jabawsUrl = aparser.getValue("jabaws");
120     if (jabawsUrl != null)
121     {
122       try
123       {
124         Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
125       } catch (MalformedURLException e)
126       {
127         System.err.println("Invalid jabaws parameter: " + jabawsUrl
128                 + " ignored");
129       }
130     }
131
132     String defs = aparser.getValue("setprop");
133     while (defs != null)
134     {
135       int p = defs.indexOf('=');
136       if (p == -1)
137       {
138         System.err.println("Ignoring invalid setprop argument : " + defs);
139       }
140       else
141       {
142         System.out.println("Executing setprop argument: " + defs);
143         // DISABLED FOR SECURITY REASONS
144         // TODO: add a property to allow properties to be overriden by cli args
145         // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
146       }
147       defs = aparser.getValue("setprop");
148     }
149     if (System.getProperty("java.awt.headless") != null
150             && System.getProperty("java.awt.headless").equals("true"))
151     {
152       headless = true;
153     }
154     System.setProperty("http.agent",
155             "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
156     try
157     {
158       Cache.initLogger();
159     } catch (java.lang.NoClassDefFoundError error)
160     {
161       error.printStackTrace();
162       System.out
163               .println("\nEssential logging libraries not found."
164                       + "\nUse: java -Djava.ext.dirs=$PATH_TO_LIB$ jalview.bin.Jalview");
165       System.exit(0);
166     }
167
168     Desktop desktop = null;
169
170     try
171     {
172       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
173     } catch (Exception ex)
174     {
175     }
176
177     if (!headless)
178     {
179       desktop = new Desktop();
180       desktop.setInBatchMode(true); // indicate we are starting up
181       desktop.setVisible(true);
182       desktop.startServiceDiscovery();
183       if (!aparser.contains("nousagestats"))
184       {
185         startUsageStats(desktop);
186       }
187       if (!aparser.contains("noquestionnaire"))
188       {
189         String url = aparser.getValue("questionnaire");
190         if (url != null)
191         {
192           // Start the desktop questionnaire prompter with the specified
193           // questionnaire
194           Cache.log.debug("Starting questionnaire url at " + url);
195           desktop.checkForQuestionnaire(url);
196         }
197         else
198         {
199           if (Cache.getProperty("NOQUESTIONNAIRES") == null)
200           {
201             // Start the desktop questionnaire prompter with the specified
202             // questionnaire
203             // String defurl =
204             // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
205             // //
206             String defurl = "http://www.jalview.org/cgi-bin/questionnaire.pl";
207             Cache.log.debug("Starting questionnaire with default url: "
208                     + defurl);
209             desktop.checkForQuestionnaire(defurl);
210
211           }
212         }
213       }
214       desktop.checkForNews();
215     }
216
217     String file = null, protocol = null, format = null, data = null;
218     jalview.io.FileLoader fileLoader = new jalview.io.FileLoader();
219     Vector getFeatures = null; // vector of das source nicknames to fetch
220     // features from
221     // loading is done.
222     String groovyscript = null; // script to execute after all loading is
223     // completed one way or another
224     // extract groovy argument and execute if necessary
225     groovyscript = aparser.getValue("groovy", true);
226     file = aparser.getValue("open", true);
227
228     if (file == null && desktop == null)
229     {
230       System.out.println("No files to open!");
231       System.exit(1);
232     }
233     String vamsasImport = aparser.getValue("vdoc"), vamsasSession = aparser
234             .getValue("vsess");
235     if (vamsasImport != null || vamsasSession != null)
236     {
237       if (desktop == null || headless)
238       {
239         System.out
240                 .println("Headless vamsas sessions not yet supported. Sorry.");
241         System.exit(1);
242       }
243       // if we have a file, start a new session and import it.
244       boolean inSession = false;
245       if (vamsasImport != null)
246       {
247         try
248         {
249           String viprotocol = jalview.io.AppletFormatAdapter
250                   .checkProtocol(vamsasImport);
251           if (viprotocol == jalview.io.FormatAdapter.FILE)
252           {
253             inSession = desktop.vamsasImport(new File(vamsasImport));
254           }
255           else if (viprotocol == jalview.io.FormatAdapter.URL)
256           {
257             inSession = desktop.vamsasImport(new URL(vamsasImport));
258           }
259
260         } catch (Exception e)
261         {
262           System.err.println("Exeption when importing " + vamsasImport
263                   + " as a vamsas document.");
264           e.printStackTrace();
265         }
266         if (!inSession)
267         {
268           System.err.println("Failed to import " + vamsasImport
269                   + " as a vamsas document.");
270         }
271         else
272         {
273           System.out.println("Imported Successfully into new session "
274                   + desktop.getVamsasApplication().getCurrentSession());
275         }
276       }
277       if (vamsasSession != null)
278       {
279         if (vamsasImport != null)
280         {
281           // close the newly imported session and import the Jalview specific
282           // remnants into the new session later on.
283           desktop.vamsasStop_actionPerformed(null);
284         }
285         // now join the new session
286         try
287         {
288           if (desktop.joinVamsasSession(vamsasSession))
289           {
290             System.out.println("Successfully joined vamsas session "
291                     + vamsasSession);
292           }
293           else
294           {
295             System.err.println("WARNING: Failed to join vamsas session "
296                     + vamsasSession);
297           }
298         } catch (Exception e)
299         {
300           System.err.println("ERROR: Failed to join vamsas session "
301                   + vamsasSession);
302           e.printStackTrace();
303         }
304         if (vamsasImport != null)
305         {
306           // the Jalview specific remnants can now be imported into the new
307           // session at the user's leisure.
308           Cache.log
309                   .info("Skipping Push for import of data into existing vamsas session."); // TODO:
310           // enable
311           // this
312           // when
313           // debugged
314           // desktop.getVamsasApplication().push_update();
315         }
316       }
317     }
318     long progress = -1;
319     // Finally, deal with the remaining input data.
320     if (file != null)
321     {
322       if (!headless)
323       {
324         desktop.setProgressBar(MessageManager.getString("status.processing_commandline_args"),
325                 progress = System.currentTimeMillis());
326       }
327       System.out.println("Opening file: " + file);
328
329       if (!file.startsWith("http://"))
330       {
331         if (!(new java.io.File(file)).exists())
332         {
333           System.out.println("Can't find " + file);
334           if (headless)
335           {
336             System.exit(1);
337           }
338         }
339       }
340
341       protocol = jalview.io.AppletFormatAdapter.checkProtocol(file);
342
343       format = new jalview.io.IdentifyFile().Identify(file, protocol);
344
345       AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
346               format);
347       if (af == null)
348       {
349         System.out.println("error");
350       }
351       else
352       {
353
354         data = aparser.getValue("colour", true);
355         if (data != null)
356         {
357           data.replaceAll("%20", " ");
358
359           jalview.schemes.ColourSchemeI cs = jalview.schemes.ColourSchemeProperty
360                   .getColour(af.getViewport().getAlignment(), data);
361
362           if (cs == null)
363           {
364             jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
365                     "white");
366             ucs.parseAppletParameter(data);
367             cs = ucs;
368           }
369
370           System.out.println("colour is " + data);
371           af.changeColour(cs);
372         }
373
374         // Must maintain ability to use the groups flag
375         data = aparser.getValue("groups", true);
376         if (data != null)
377         {
378           af.parseFeaturesFile(data,
379                   jalview.io.AppletFormatAdapter.checkProtocol(data));
380           System.out.println("Added " + data);
381         }
382         data = aparser.getValue("features", true);
383         if (data != null)
384         {
385           af.parseFeaturesFile(data,
386                   jalview.io.AppletFormatAdapter.checkProtocol(data));
387           System.out.println("Added " + data);
388         }
389
390         data = aparser.getValue("annotations", true);
391         if (data != null)
392         {
393           af.loadJalviewDataFile(data, null, null, null);
394           System.out.println("Added " + data);
395         }
396         // set or clear the sortbytree flag.
397         if (aparser.contains("sortbytree"))
398         {
399           af.getViewport().setSortByTree(true);
400         }
401         if (aparser.contains("no-annotation"))
402         {
403           af.getViewport().setShowAnnotation(false);
404         }
405         if (aparser.contains("nosortbytree"))
406         {
407           af.getViewport().setSortByTree(false);
408         }
409         data = aparser.getValue("tree", true);
410         if (data != null)
411         {
412           jalview.io.NewickFile fin = null;
413           try
414           {
415             fin = new jalview.io.NewickFile(data,
416                     jalview.io.AppletFormatAdapter.checkProtocol(data));
417             if (fin != null)
418             {
419               af.getViewport().setCurrentTree(
420                       af.ShowNewickTree(fin, data).getTree());
421               System.out.println("Added tree " + data);
422             }
423           } catch (IOException ex)
424           {
425             System.err.println("Couldn't add tree " + data);
426             ex.printStackTrace(System.err);
427           }
428         }
429         // TODO - load PDB structure(s) to alignment JAL-629
430         // (associate with identical sequence in alignment, or a specified
431         // sequence)
432
433         getFeatures = checkDasArguments(aparser);
434         if (af != null && getFeatures != null)
435         {
436           FeatureFetcher ff = startFeatureFetching(getFeatures);
437           if (ff != null)
438           {
439             while (!ff.allFinished() || af.operationInProgress())
440             {
441               // wait around until fetching is finished.
442               try
443               {
444                 Thread.sleep(100);
445               } catch (Exception e)
446               {
447
448               }
449             }
450           }
451           getFeatures = null; // have retrieved features - forget them now.
452         }
453         if (groovyscript != null)
454         {
455           // Execute the groovy script after we've done all the rendering stuff
456           // and before any images or figures are generated.
457           if (jalview.bin.Cache.groovyJarsPresent())
458           {
459             System.out.println("Executing script " + groovyscript);
460             executeGroovyScript(groovyscript, new Object[]
461             { desktop, af });
462           }
463           else
464           {
465             System.err
466                     .println("Sorry. Groovy Support is not available, so ignoring the provided groovy script "
467                             + groovyscript);
468           }
469           groovyscript = null;
470         }
471         String imageName = "unnamed.png";
472         while (aparser.getSize() > 1)
473         {
474           format = aparser.nextValue();
475           file = aparser.nextValue();
476
477           if (format.equalsIgnoreCase("png"))
478           {
479             af.createPNG(new java.io.File(file));
480             imageName = (new java.io.File(file)).getName();
481             System.out.println("Creating PNG image: " + file);
482             continue;
483           }
484           else if (format.equalsIgnoreCase("svg"))
485           {
486             File imageFile = new java.io.File(file);
487             imageName = imageFile.getName();
488             af.createSVG(imageFile);
489             System.out.println("Creating SVG image: " + file);
490             continue;
491           }
492           else if (format.equalsIgnoreCase("html"))
493           {
494             File imageFile = new java.io.File(file);
495             imageName = imageFile.getName();
496             new HtmlSvgOutput(new java.io.File(file), af.alignPanel);
497             System.out.println("Creating HTML image: " + file);
498             continue;
499           }
500           else if (format.equalsIgnoreCase("imgMap"))
501           {
502             af.createImageMap(new java.io.File(file), imageName);
503             System.out.println("Creating image map: " + file);
504             continue;
505           }
506           else if (format.equalsIgnoreCase("eps"))
507           {
508             System.out.println("Creating EPS file: " + file);
509             af.createEPS(new java.io.File(file));
510             continue;
511           }
512
513           if (af.saveAlignment(file, format))
514           {
515             System.out.println("Written alignment in " + format
516                     + " format to " + file);
517           }
518           else
519           {
520             System.out.println("Error writing file " + file + " in "
521                     + format + " format!!");
522           }
523
524         }
525
526         while (aparser.getSize() > 0)
527         {
528           System.out.println("Unknown arg: " + aparser.nextValue());
529         }
530       }
531     }
532     AlignFrame startUpAlframe = null;
533     // We'll only open the default file if the desktop is visible.
534     // And the user
535     // ////////////////////
536
537     if (!headless && file == null && vamsasImport == null
538             && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true))
539     {
540       file = jalview.bin.Cache.getDefault(
541               "STARTUP_FILE",
542               jalview.bin.Cache.getDefault("www.jalview.org",
543                       "http://www.jalview.org")
544                       + "/examples/exampleFile_2_7.jar");
545       if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar"))
546       {
547         // hardwire upgrade of the startup file
548         file.replace("_2_3.jar", "_2_7.jar");
549         // and remove the stale setting
550         jalview.bin.Cache.removeProperty("STARTUP_FILE");
551       }
552
553       protocol = "File";
554
555       if (file.indexOf("http:") > -1)
556       {
557         protocol = "URL";
558       }
559
560       if (file.endsWith(".jar"))
561       {
562         format = "Jalview";
563       }
564       else
565       {
566         format = new jalview.io.IdentifyFile().Identify(file, protocol);
567       }
568
569       startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
570               format);
571       getFeatures = checkDasArguments(aparser);
572       // extract groovy arguments before anything else.
573     }
574     // If the user has specified features to be retrieved,
575     // or a groovy script to be executed, do them if they
576     // haven't been done already
577     // fetch features for the default alignment
578     if (getFeatures != null)
579     {
580       if (startUpAlframe != null)
581       {
582         startFeatureFetching(getFeatures);
583       }
584     }
585     // Once all other stuff is done, execute any groovy scripts (in order)
586     if (groovyscript != null)
587     {
588       if (jalview.bin.Cache.groovyJarsPresent())
589       {
590         System.out.println("Executing script " + groovyscript);
591         executeGroovyScript(groovyscript, new Object[]
592         { desktop, startUpAlframe });
593       }
594       else
595       {
596         System.err
597                 .println("Sorry. Groovy Support is not available, so ignoring the provided groovy script "
598                         + groovyscript);
599       }
600     }
601     // and finally, turn off batch mode indicator - if the desktop still exists
602     if (desktop != null)
603     {
604       if (progress != -1)
605       {
606         desktop.setProgressBar(null, progress);
607       }
608       desktop.setInBatchMode(false);
609     }
610   }
611
612   private static void showUsage()
613   {
614     System.out
615             .println("Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
616                     + "-nodisplay\tRun Jalview without User Interface.\n"
617                     + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
618                     + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
619                     + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
620                     + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
621                     + "-features FILE\tUse the given file to mark features on the alignment.\n"
622                     + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
623                     + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
624                     + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
625                     + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
626                     + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
627                     + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
628                     + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
629                     + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
630                     + "-png FILE\tCreate PNG image FILE from alignment.\n"
631                     + "-svg FILE\tCreate SVG image FILE from alignment.\n"
632                     + "-html FILE\tCreate HTML file from alignment.\n"
633                     + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
634                     + "-eps FILE\tCreate EPS file FILE from alignment.\n"
635                     + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
636                     + "-noquestionnaire\tTurn off questionnaire check.\n"
637                     + "-nousagestats\tTurn off google analytics tracking for this session.\n"
638                     + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
639                     // +
640                     // "-setprop PROPERTY=VALUE\tSet the given Jalview property, after all other properties files have been read\n\t (quote the 'PROPERTY=VALUE' pair to ensure spaces are passed in correctly)"
641                     + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
642                     + "-dasserver nickname=URL\tAdd and enable a das server with given nickname\n\t\t\t(alphanumeric or underscores only) for retrieval of features for all alignments.\n"
643                     + "\t\t\tSources that also support the sequence command may be specified by prepending the URL with sequence:\n"
644                     + "\t\t\t e.g. sequence:http://localdas.somewhere.org/das/source)\n"
645                     + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
646                     // +
647                     // "-vdoc vamsas-document\tImport vamsas document into new session or join existing session with same URN\n"
648                     // + "-vses vamsas-session\tJoin session with given URN\n"
649                     + "-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"
650                     + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
651   }
652
653   private static void startUsageStats(final Desktop desktop)
654   {
655     /**
656      * start a User Config prompt asking if we can log usage statistics.
657      */
658     jalview.gui.PromptUserConfig prompter = new jalview.gui.PromptUserConfig(
659             desktop.desktop,
660             "USAGESTATS",
661             "Jalview Usage Statistics",
662             "Do you want to help make Jalview better by enabling "
663                     + "the collection of usage statistics with Google Analytics ?"
664                     + "\n\n(you can enable or disable usage tracking in the preferences)",
665             new Runnable()
666             {
667               public void run()
668               {
669                 Cache.log
670                         .debug("Initialising googletracker for usage stats.");
671                 Cache.initGoogleTracker();
672                 Cache.log.debug("Tracking enabled.");
673               }
674             }, new Runnable()
675             {
676               public void run()
677               {
678                 Cache.log.debug("Not enabling Google Tracking.");
679               }
680             }, null, true);
681     desktop.addDialogThread(prompter);
682   }
683
684   /**
685    * Locate the given string as a file and pass it to the groovy interpreter.
686    * 
687    * @param groovyscript
688    *          the script to execute
689    * @param jalviewContext
690    *          the Jalview Desktop object passed in to the groovy binding as the
691    *          'Jalview' object.
692    */
693   private static void executeGroovyScript(String groovyscript,
694           Object[] jalviewContext)
695   {
696     if (jalviewContext == null)
697     {
698       System.err
699               .println("Sorry. Groovy support is currently only available when running with the Jalview GUI enabled.");
700     }
701     /**
702      * for scripts contained in files
703      */
704     File tfile = null;
705     /**
706      * script's URI
707      */
708     URL sfile = null;
709     if (groovyscript.trim().equals("STDIN"))
710     {
711       // read from stdin into a tempfile and execute it
712       try
713       {
714         tfile = File.createTempFile("jalview", "groovy");
715         PrintWriter outfile = new PrintWriter(new OutputStreamWriter(
716                 new FileOutputStream(tfile)));
717         BufferedReader br = new BufferedReader(
718                 new java.io.InputStreamReader(System.in));
719         String line = null;
720         while ((line = br.readLine()) != null)
721         {
722           outfile.write(line + "\n");
723         }
724         br.close();
725         outfile.flush();
726         outfile.close();
727
728       } catch (Exception ex)
729       {
730         System.err.println("Failed to read from STDIN into tempfile "
731                 + ((tfile == null) ? "(tempfile wasn't created)" : tfile
732                         .toString()));
733         ex.printStackTrace();
734         return;
735       }
736       try
737       {
738         sfile = tfile.toURI().toURL();
739       } catch (Exception x)
740       {
741         System.err
742                 .println("Unexpected Malformed URL Exception for temporary file created from STDIN: "
743                         + tfile.toURI());
744         x.printStackTrace();
745         return;
746       }
747     }
748     else
749     {
750       try
751       {
752         sfile = new URI(groovyscript).toURL();
753       } catch (Exception x)
754       {
755         tfile = new File(groovyscript);
756         if (!tfile.exists())
757         {
758           System.err.println("File '" + groovyscript + "' does not exist.");
759           return;
760         }
761         if (!tfile.canRead())
762         {
763           System.err.println("File '" + groovyscript + "' cannot be read.");
764           return;
765         }
766         if (tfile.length() < 1)
767         {
768           System.err.println("File '" + groovyscript + "' is empty.");
769           return;
770         }
771         try
772         {
773           sfile = tfile.getAbsoluteFile().toURI().toURL();
774         } catch (Exception ex)
775         {
776           System.err.println("Failed to create a file URL for "
777                   + tfile.getAbsoluteFile());
778           return;
779         }
780       }
781     }
782     boolean success = false;
783     try
784     {
785       /*
786        * The following code performs the GroovyScriptEngine invocation using
787        * reflection, and is equivalent to this fragment from the embedding
788        * groovy documentation on the groovy site: <code> import
789        * groovy.lang.Binding; import groovy.util.GroovyScriptEngine;
790        * 
791        * String[] roots = new String[] { "/my/groovy/script/path" };
792        * GroovyScriptEngine gse = new GroovyScriptEngine(roots); Binding binding
793        * = new Binding(); binding.setVariable("input", "world");
794        * gse.run("hello.groovy", binding); </code>
795        */
796       Class[] bspec;
797       Object[] binding;
798       int blen = ((jalviewContext[0] == null) ? 0 : 1)
799               + ((jalviewContext[1] == null) ? 0 : 1);
800       String cnames[] = new String[]
801       { "Jalview", "currentAlFrame" };
802       bspec = new Class[blen * 2];
803       binding = new Object[blen * 2];
804       blen = 0;
805       ClassLoader cl = null;
806       Map vbinding = new Hashtable();
807       for (int jc = 0; jc < jalviewContext.length; jc++)
808       {
809         if (jalviewContext[jc] != null)
810         {
811           if (cl == null)
812           {
813             cl = jalviewContext[jc].getClass().getClassLoader();
814           }
815           bspec[blen * 2] = String.class;
816           bspec[blen * 2 + 1] = Object.class;
817           binding[blen * 2] = cnames[jc];
818           binding[blen * 2 + 1] = jalviewContext[jc];
819           vbinding.put(cnames[jc], jalviewContext[jc]);
820           blen++;
821         }
822       }
823       Class gbindingc = cl.loadClass("groovy.lang.Binding");
824       Constructor gbcons;
825       Object gbinding;
826       try
827       {
828         gbcons = gbindingc.getConstructor(Map.class);
829         gbinding = gbcons.newInstance(vbinding);
830       } catch (NoSuchMethodException x)
831       {
832         // old style binding config - using series of string/object values to
833         // setVariable.
834         gbcons = gbindingc.getConstructor(null);
835         gbinding = gbcons.newInstance(null);
836         java.lang.reflect.Method setvar = gbindingc.getMethod(
837                 "setVariable", bspec);
838         setvar.invoke(gbinding, binding);
839       }
840       ;
841       Class gsec = cl.loadClass("groovy.util.GroovyScriptEngine");
842       Constructor gseccons = gsec.getConstructor(new Class[]
843       { URL[].class }); // String[].class });
844       Object gse = gseccons.newInstance(new Object[]
845       { new URL[]
846       { sfile } }); // .toString() } });
847       java.lang.reflect.Method run = gsec.getMethod("run", new Class[]
848       { String.class, gbindingc });
849       run.invoke(gse, new Object[]
850       { sfile.toString(), gbinding });
851       success = true;
852     } catch (Exception e)
853     {
854       System.err.println("Exception Whilst trying to execute file " + sfile
855               + " as a groovy script.");
856       e.printStackTrace(System.err);
857
858     }
859     if (success && groovyscript.equals("STDIN"))
860     {
861       // delete temp file that we made - but only if it was successfully
862       // executed
863       tfile.delete();
864     }
865   }
866
867   /**
868    * Check commandline for any das server definitions or any fetchfrom switches
869    * 
870    * @return vector of DAS source nicknames to retrieve from
871    */
872   private static Vector checkDasArguments(ArgsParser aparser)
873   {
874     Vector source = null;
875     String data;
876     String locsources = Cache.getProperty(Cache.DAS_LOCAL_SOURCE);
877     while ((data = aparser.getValue("dasserver", true)) != null)
878     {
879       String nickname = null;
880       String url = null;
881       boolean seq = false, feat = true;
882       int pos = data.indexOf('=');
883       // determine capabilities
884       if (pos > 0)
885       {
886         nickname = data.substring(0, pos);
887       }
888       url = data.substring(pos + 1);
889       if (url != null
890               && (url.startsWith("http:") || url
891                       .startsWith("sequence:http:")))
892       {
893         if (nickname == null)
894         {
895           nickname = url;
896         }
897         if (locsources == null)
898         {
899           locsources = "";
900         }
901         else
902         {
903           locsources += "\t";
904         }
905         locsources = locsources + nickname + "|" + url;
906         System.err
907                 .println("NOTE! dasserver parameter not yet really supported (got args of "
908                         + nickname + "|" + url);
909         if (source == null)
910         {
911           source = new Vector();
912         }
913         source.addElement(nickname);
914       }
915     } // loop until no more server entries are found.
916     if (locsources != null && locsources.indexOf('|') > -1)
917     {
918       Cache.log.debug("Setting local source list in properties file to:\n"
919               + locsources);
920       Cache.setProperty(Cache.DAS_LOCAL_SOURCE, locsources);
921     }
922     while ((data = aparser.getValue("fetchfrom", true)) != null)
923     {
924       System.out.println("adding source '" + data + "'");
925       if (source == null)
926       {
927         source = new Vector();
928       }
929       source.addElement(data);
930     }
931     return source;
932   }
933
934   /**
935    * start a feature fetcher for every alignment frame
936    * 
937    * @param dasSources
938    */
939   private static FeatureFetcher startFeatureFetching(final Vector dasSources)
940   {
941     FeatureFetcher ff = new FeatureFetcher();
942     AlignFrame afs[] = Desktop.getAlignframes();
943     if (afs == null || afs.length == 0)
944     {
945       return null;
946     }
947     for (int i = 0; i < afs.length; i++)
948     {
949       ff.addFetcher(afs[i], dasSources);
950     }
951     return ff;
952   }
953 }
954
955 /**
956  * Notes: this argParser does not distinguish between parameter switches,
957  * parameter values and argument text. If an argument happens to be identical to
958  * a parameter, it will be taken as such (even though it didn't have a '-'
959  * prefixing it).
960  * 
961  * @author Andrew Waterhouse and JBP documented.
962  * 
963  */
964
965 class rnabuttonlistener implements ActionListener
966 {
967   public void actionPerformed(ActionEvent arg0)
968   {
969     System.out.println("Good idea ! ");
970
971   }
972 }
973
974 class pbuttonlistener implements ActionListener
975 {
976   public void actionPerformed(ActionEvent arg0)
977   {
978
979   }
980 }
981
982 class ArgsParser
983 {
984   Vector vargs = null;
985
986   public ArgsParser(String[] args)
987   {
988     vargs = new Vector();
989     for (int i = 0; i < args.length; i++)
990     {
991       String arg = args[i].trim();
992       if (arg.charAt(0) == '-')
993       {
994         arg = arg.substring(1);
995       }
996       vargs.addElement(arg);
997     }
998   }
999
1000   /**
1001    * check for and remove first occurence of arg+parameter in arglist.
1002    * 
1003    * @param arg
1004    * @return return the argument following the given arg if arg was in list.
1005    */
1006   public String getValue(String arg)
1007   {
1008     return getValue(arg, false);
1009   }
1010
1011   public String getValue(String arg, boolean utf8decode)
1012   {
1013     int index = vargs.indexOf(arg);
1014     String dc = null, ret = null;
1015     if (index != -1)
1016     {
1017       ret = vargs.elementAt(index + 1).toString();
1018       vargs.removeElementAt(index);
1019       vargs.removeElementAt(index);
1020       if (utf8decode && ret != null)
1021       {
1022         try
1023         {
1024           dc = URLDecoder.decode(ret, "UTF-8");
1025           ret = dc;
1026         } catch (Exception e)
1027         {
1028           // TODO: log failure to decode
1029         }
1030       }
1031     }
1032     return ret;
1033   }
1034
1035   /**
1036    * check for and remove first occurence of arg in arglist.
1037    * 
1038    * @param arg
1039    * @return true if arg was present in argslist.
1040    */
1041   public boolean contains(String arg)
1042   {
1043     if (vargs.contains(arg))
1044     {
1045       vargs.removeElement(arg);
1046       return true;
1047     }
1048     else
1049     {
1050       return false;
1051     }
1052   }
1053
1054   public String nextValue()
1055   {
1056     return vargs.remove(0).toString();
1057   }
1058
1059   public int getSize()
1060   {
1061     return vargs.size();
1062   }
1063
1064 }
1065
1066 /**
1067  * keep track of feature fetching tasks.
1068  * 
1069  * @author JimP
1070  * 
1071  */
1072 class FeatureFetcher
1073 {
1074   /*
1075    * TODO: generalise to track all jalview events to orchestrate batch
1076    * processing events.
1077    */
1078
1079   private int queued = 0;
1080
1081   private int running = 0;
1082
1083   public FeatureFetcher()
1084   {
1085
1086   }
1087
1088   public void addFetcher(final AlignFrame af, final Vector dasSources)
1089   {
1090     final long id = System.currentTimeMillis();
1091     queued++;
1092     final FeatureFetcher us = this;
1093     new Thread(new Runnable()
1094     {
1095
1096       public void run()
1097       {
1098         synchronized (us)
1099         {
1100           queued--;
1101           running++;
1102         }
1103
1104         af.setProgressBar(MessageManager.getString("status.das_features_being_retrived"), id);
1105         af.featureSettings_actionPerformed(null);
1106         af.featureSettings.fetchDasFeatures(dasSources, true);
1107         af.setProgressBar(null, id);
1108         synchronized (us)
1109         {
1110           running--;
1111         }
1112       }
1113     }).start();
1114   }
1115
1116   public synchronized boolean allFinished()
1117   {
1118     return queued == 0 && running == 0;
1119   }
1120
1121 };