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