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