JAL-2847 Rearranging and cleaning up of database query code
[jalview.git] / src / jalview / ext / archaeopteryx / AptxInit.java
1 package jalview.ext.archaeopteryx;
2
3 import jalview.analysis.TreeBuilder;
4 import jalview.datamodel.SequenceI;
5 import jalview.ext.treeviewer.ExternalTreeBuilderI;
6 import jalview.ext.treeviewer.ExternalTreeViewerBindingI;
7 import jalview.gui.Desktop;
8 import jalview.gui.JvOptionPane;
9 import jalview.util.MessageManager;
10 import jalview.viewmodel.AlignmentViewport;
11
12 import java.awt.Dimension;
13 import java.io.File;
14 import java.io.FileNotFoundException;
15 import java.io.IOException;
16 import java.net.MalformedURLException;
17 import java.net.URL;
18 import java.util.HashMap;
19 import java.util.Map;
20
21 import org.forester.archaeopteryx.AptxUtil;
22 import org.forester.archaeopteryx.Archaeopteryx;
23 import org.forester.archaeopteryx.Configuration;
24 import org.forester.archaeopteryx.MainFrame;
25 import org.forester.archaeopteryx.webservices.PhylogeniesWebserviceClient;
26 import org.forester.archaeopteryx.webservices.WebserviceUtil;
27 import org.forester.io.parsers.PhylogenyParser;
28 import org.forester.io.parsers.nexus.NexusPhylogeniesParser;
29 import org.forester.io.parsers.nhx.NHXParser;
30 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
31 import org.forester.io.parsers.phyloxml.PhyloXmlParser;
32 import org.forester.io.parsers.tol.TolParser;
33 import org.forester.io.parsers.util.ParserUtils;
34 import org.forester.phylogeny.Phylogeny;
35 import org.forester.phylogeny.PhylogenyMethods;
36 import org.forester.phylogeny.PhylogenyNode;
37 import org.forester.phylogeny.data.Identifier;
38 import org.forester.util.ForesterUtil;
39
40 /**
41  * Static class for creating Archaeopteryx tree viewer instances from calculated
42  * trees and letting them be bound to Jalview.
43  * 
44  * @author kjvanderheide
45  *
46  */
47 public final class AptxInit
48 {
49
50   private final static Configuration APTX_CONFIG = new Configuration(
51           "_aptx_jalview_configuration_file", false, false, false);
52
53   private final static boolean VALIDATE_PHYLOXML_XSD = APTX_CONFIG
54           .isValidatePhyloXmlAgainstSchema();
55
56   private final static boolean REPLACE_NHX_UNDERSCORES = APTX_CONFIG
57           .isReplaceUnderscoresInNhParsing();
58
59   private final static boolean INTERNAL_NUMBERS_AS_CONFIDENCE = APTX_CONFIG
60           .isInternalNumberAreConfidenceForNhParsing();
61
62   private final static boolean MIDPOINT_REROOT = APTX_CONFIG
63           .isMidpointReroot();
64
65   private final static NHXParser.TAXONOMY_EXTRACTION TAXONOMY_EXTRACTION = APTX_CONFIG
66           .getTaxonomyExtraction();
67
68   private static Map<MainFrame, JalviewBinding> activeAptx = new HashMap<>();
69
70
71
72   public static MainFrame createInstanceFromCalculation(
73           final TreeBuilder calculatedTree)
74   {
75     ExternalTreeBuilderI<Phylogeny, PhylogenyNode> aptxTreeBuilder = new AptxTreeBuilder(
76             calculatedTree);
77
78     Phylogeny aptxTree = aptxTreeBuilder.buildTree();
79
80     MainFrame aptxApp = createAptxFrame(aptxTree,
81             calculatedTree.getAvport(), null);
82             
83     return aptxApp;
84   }
85
86   /**
87    * Refactored from Archaeopteryx.main
88    * 
89    * @param filePath
90    * @param viewport
91    * @return
92    * @throws IOException
93    * @throws FileNotFoundException
94    */
95   public static MainFrame[] createInstancesFromFile(String filePath,
96           AlignmentViewport viewport)
97           throws FileNotFoundException, IOException
98   {
99     File treeFile = new File(filePath);
100     final String err = ForesterUtil.isReadableFile(treeFile);
101     if (!ForesterUtil.isEmpty(err))
102     {
103       JvOptionPane.showMessageDialog(Desktop.desktop, err,
104               MessageManager.getString("label.problem_reading_tree_file"),
105               JvOptionPane.WARNING_MESSAGE);
106     }
107
108     if (Desktop.instance != null)
109     {
110       Desktop.instance.startLoading(filePath);
111     }
112     boolean nhx_or_nexus = false;
113     final PhylogenyParser parser = ParserUtils.createParserDependingOnFileType(
114             treeFile, VALIDATE_PHYLOXML_XSD);
115     if (parser instanceof NHXParser)
116     {
117       nhx_or_nexus = true;
118       final NHXParser nhx = (NHXParser) parser;
119       nhx.setReplaceUnderscores(REPLACE_NHX_UNDERSCORES);
120       nhx.setIgnoreQuotes(false);
121       nhx.setTaxonomyExtraction(TAXONOMY_EXTRACTION);
122     }
123     else if (parser instanceof NexusPhylogeniesParser)
124     {
125       nhx_or_nexus = true;
126       final NexusPhylogeniesParser nex = (NexusPhylogeniesParser) parser;
127       nex.setReplaceUnderscores(REPLACE_NHX_UNDERSCORES);
128       nex.setIgnoreQuotes(false);
129     }
130     else if (parser instanceof PhyloXmlParser)
131     {
132       if (VALIDATE_PHYLOXML_XSD == false)
133       {
134         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
135                 MessageManager.getString("error.phyloxml_validation"),
136                 MessageManager.getString("label.file_open_error"),
137                                        JvOptionPane.WARNING_MESSAGE );
138       }
139     }
140     Phylogeny[] trees = PhylogenyMethods.readPhylogenies(parser, treeFile);
141     MainFrame[] aptxFrames = new MainFrame[trees.length];
142
143
144     for (int i = 0; i < trees.length; i++)
145       {
146       Phylogeny tree = trees[i];
147
148       if (nhx_or_nexus && INTERNAL_NUMBERS_AS_CONFIDENCE)
149       {
150         PhylogenyMethods.transferInternalNodeNamesToConfidence(tree, "");
151       }
152       String treeTitle = treeFile.getName() + "[" + i + "]";
153       tree.setName(treeTitle);
154       aptxFrames[i] = createAptxFrame(tree, viewport, treeTitle);
155
156     }
157     if (Desktop.instance != null)
158     {
159       Desktop.instance.stopLoading();
160     }
161     return aptxFrames;
162     }
163
164
165   public static MainFrame[] createInstancesFromUrl(URL treeUrl,
166           AlignmentViewport viewport)
167           throws FileNotFoundException, IOException, RuntimeException
168   {
169     
170     String treeTitle = treeUrl.getFile();
171     if (Desktop.instance != null)
172     {
173       Desktop.instance.startLoading(treeTitle);
174     }
175     Phylogeny[] trees = AptxUtil.readPhylogeniesFromUrl(treeUrl,
176             VALIDATE_PHYLOXML_XSD,
177              REPLACE_NHX_UNDERSCORES, INTERNAL_NUMBERS_AS_CONFIDENCE,
178             TAXONOMY_EXTRACTION, MIDPOINT_REROOT);
179
180     MainFrame[] aptxFrames = new MainFrame[trees.length];
181     for (int i = 0; i < trees.length; i++)
182     {
183       Phylogeny tree = trees[i];
184       aptxFrames[i] = createAptxFrame(tree, viewport, treeTitle);
185     }
186
187     if (Desktop.instance != null)
188     {
189       Desktop.instance.stopLoading();
190     }
191
192     return aptxFrames;
193
194   }
195
196   /**
197    * Refactored from Forester's UrlTreeReader, this can be more efficient
198    * 
199    * @param databaseIndex
200    * @param viewport
201    * @return
202    */
203   public static MainFrame[] createInstancesFromDb(
204           PhylogeniesWebserviceClient treeDbClient, String identifier,
205           AlignmentViewport viewport)
206   {
207
208     URL url = null;
209     Phylogeny[] trees = null;
210
211     if ((identifier != null) && (identifier.trim().length() > 0))
212     {
213       if (Desktop.instance != null)
214       {
215         Desktop.instance.startLoading(identifier);
216       }
217
218       identifier = identifier.trim();
219       if (treeDbClient.isQueryInteger())
220       {
221         identifier = identifier.replaceAll("^\\D+", "");
222
223         int id;
224         try
225         {
226           id = Integer.parseInt(identifier);
227         } catch (final NumberFormatException e)
228         {
229           JvOptionPane.showInternalMessageDialog(Desktop.desktop,
230                   MessageManager.formatMessage(
231                           "error.database_id_has_letters", new String[]
232                           { identifier }),
233                   MessageManager.getString("label.invalid_url"),
234                   JvOptionPane.ERROR_MESSAGE);
235           return new MainFrame[0];
236         }
237         identifier = id + "";
238       }
239       boolean exception = false;
240       try
241       {
242         String url_str = treeDbClient.getUrl();
243         url_str = url_str.replaceFirst(
244                 PhylogeniesWebserviceClient.QUERY_PLACEHOLDER, identifier);
245         url = new URL(url_str);
246         PhylogenyParser parser = null;
247         switch (treeDbClient.getReturnFormat())
248         {
249         case TOL_XML_RESPONSE:
250           parser = new TolParser();
251           break;
252         case NEXUS:
253           parser = new NexusPhylogeniesParser();
254           ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true);
255           break;
256         case TREEBASE_TREE:
257           parser = new NexusPhylogeniesParser();
258           ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true);
259           ((NexusPhylogeniesParser) parser)
260                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
261           break;
262         case TREEBASE_STUDY:
263           parser = new NexusPhylogeniesParser();
264           ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true);
265           ((NexusPhylogeniesParser) parser)
266                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
267           break;
268         case NH:
269           parser = new NHXParser();
270           ((NHXParser) parser)
271                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
272           ((NHXParser) parser).setReplaceUnderscores(true);
273           ((NHXParser) parser).setGuessRootedness(true);
274           break;
275         case NH_EXTRACT_TAXONOMY:
276           parser = new NHXParser();
277           ((NHXParser) parser).setTaxonomyExtraction(
278                   NHXParser.TAXONOMY_EXTRACTION.AGGRESSIVE);
279           ((NHXParser) parser).setReplaceUnderscores(false);
280           ((NHXParser) parser).setGuessRootedness(true);
281           break;
282         case PFAM:
283           parser = new NHXParser();
284           ((NHXParser) parser).setTaxonomyExtraction(
285                   NHXParser.TAXONOMY_EXTRACTION.PFAM_STYLE_STRICT);
286           ((NHXParser) parser).setReplaceUnderscores(false);
287           ((NHXParser) parser).setGuessRootedness(true);
288           break;
289         case NHX:
290           parser = new NHXParser();
291           ((NHXParser) parser)
292                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
293           ((NHXParser) parser).setReplaceUnderscores(false);
294           ((NHXParser) parser).setGuessRootedness(true);
295           break;
296         case PHYLOXML:
297           parser = PhyloXmlParser.createPhyloXmlParserXsdValidating();
298           break;
299         default:
300           throw new IllegalArgumentException(
301                   "unknown format: " + treeDbClient.getReturnFormat());
302         }
303         //
304         // if (_main_frame.getMainPanel().getCurrentTreePanel() != null)
305         // {
306         // _main_frame.getMainPanel().getCurrentTreePanel().setWaitCursor();
307         // }
308         // else
309         // {
310         // _main_frame.getMainPanel().setWaitCursor();
311         // }
312         trees = ForesterUtil.readPhylogeniesFromUrl(url, parser);
313       } catch (final MalformedURLException e)
314       {
315         exception = true;
316         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
317                 MessageManager.formatMessage(
318                         "exception.unable_to_launch_url", new String[]
319                         { url.toString() }),
320                 MessageManager.getString("label.invalid_url"),
321                 JvOptionPane.ERROR_MESSAGE);
322         System.err.println(e.getLocalizedMessage());
323       } catch (final IOException e)
324       {
325         exception = true;
326         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
327                 "Could not read from " + url + "\n"
328                         + e.getLocalizedMessage(),
329                 "Failed to read tree from " + treeDbClient.getName() + " for "
330                         + identifier,
331                 JvOptionPane.ERROR_MESSAGE);
332         System.err.println(e.getLocalizedMessage());
333       } catch (final NumberFormatException e)
334       {
335         exception = true;
336         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
337                 "Could not read from " + url + "\n"
338                         + e.getLocalizedMessage(),
339                 "Failed to read tree from " + treeDbClient.getName() + " for "
340                         + identifier,
341                 JvOptionPane.ERROR_MESSAGE);
342         System.err.println(e.getLocalizedMessage());
343       } catch (final Exception e)
344       {
345         exception = true;
346         e.printStackTrace();
347         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
348                 e.getLocalizedMessage(), "Unexpected Exception",
349                 JvOptionPane.ERROR_MESSAGE);
350         System.err.println(e.getLocalizedMessage());
351       }
352       if ((trees != null) && (trees.length > 0))
353       {
354         for (final Phylogeny phylogeny : trees)
355         {
356           if (!phylogeny.isEmpty())
357           {
358             if (treeDbClient.getName().equals(WebserviceUtil.TREE_FAM_NAME))
359             {
360               phylogeny.setRerootable(false);
361               phylogeny.setRooted(true);
362             }
363             if (treeDbClient.getProcessingInstructions() != null)
364             {
365               try
366               {
367                 WebserviceUtil.processInstructions(treeDbClient, phylogeny);
368               } catch (final PhyloXmlDataFormatException e)
369               {
370                 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
371                         "Error:\n" + e.getLocalizedMessage(), "Error",
372                         JvOptionPane.ERROR_MESSAGE);
373               }
374             }
375             if (treeDbClient.getNodeField() != null)
376             {
377               try
378               {
379                 PhylogenyMethods.transferNodeNameToField(phylogeny,
380                         treeDbClient.getNodeField(), false);
381               } catch (final PhyloXmlDataFormatException e)
382               {
383                 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
384                         "Error:\n" + e.getLocalizedMessage(), "Error",
385                         JvOptionPane.ERROR_MESSAGE);
386               }
387             }
388             phylogeny.setIdentifier(
389                     new Identifier(identifier, treeDbClient.getName()));
390             // _main_frame.getJMenuBar().remove(_main_frame.getHelpMenu());
391             // _main_frame.getMenuBarOfMainFrame()
392             // .add(_main_frame.getHelpMenu());
393             // _main_frame.getMainPanel().addPhylogenyInNewTab(phylogeny,
394             // _main_frame.getConfiguration(),
395             // new File(url.getFile()).getName(), url.toString());
396
397             MainFrame aptxApp = createAptxFrame(phylogeny, viewport,
398                     url.getFile());
399             String my_name_for_file = "";
400             if (!ForesterUtil.isEmpty(phylogeny.getName()))
401             {
402               my_name_for_file = new String(phylogeny.getName())
403                       .replaceAll(" ", "_");
404             }
405             else if (phylogeny.getIdentifier() != null)
406             {
407               final StringBuffer sb = new StringBuffer();
408               if (!ForesterUtil
409                       .isEmpty(phylogeny.getIdentifier().getProvider()))
410               {
411                 sb.append(phylogeny.getIdentifier().getProvider());
412                 sb.append("_");
413               }
414               sb.append(phylogeny.getIdentifier().getValue());
415               my_name_for_file = new String(
416                       sb.toString().replaceAll(" ", "_"));
417             }
418             aptxApp.getMainPanel().getCurrentTreePanel()
419                     .setTreeFile(new File(my_name_for_file));
420             AptxUtil.lookAtSomeTreePropertiesForAptxControlSettings(
421                     phylogeny, aptxApp.getMainPanel().getControlPanel(),
422                     APTX_CONFIG);
423             // _main_frame.getMainPanel().getControlPanel().showWhole();
424
425             aptxApp.activateSaveAllIfNeeded();
426           }
427         }
428       }
429       else if (!exception) // ..what?
430       {
431         JvOptionPane.showMessageDialog(null,
432                 ForesterUtil.wordWrap(
433                         "Failed to read in tree(s) from [" + url + "]", 80),
434                 "Error", JvOptionPane.ERROR_MESSAGE);
435       }
436       if ((trees != null) && (trees.length > 0))
437       {
438         try
439         {
440           JvOptionPane.showMessageDialog(null,
441                   ForesterUtil.wordWrap("Successfully read in "
442                           + trees.length + " tree(s) from [" + url + "]",
443                           80),
444                   "Success", JvOptionPane.INFORMATION_MESSAGE);
445         } catch (final Exception e)
446         {
447           // Not important if this fails, do nothing.
448         }
449         // _main_frame.getContentPane().repaint();
450       }
451     }
452
453     System.gc();
454
455
456     if (Desktop.instance != null)
457     {
458       Desktop.instance.stopLoading();
459     }
460     return null;
461
462
463   }
464
465
466
467
468
469   public static MainFrame createAptxFrame(
470           final Phylogeny aptxTree,
471           final AlignmentViewport jalviewAlignport, String treeTitle)
472   {
473     MainFrame aptxApp = Archaeopteryx.createApplication(aptxTree,
474             APTX_CONFIG, treeTitle);
475
476     LoadedTreeSequenceAssociation bindAptxNodes = new LoadedTreeSequenceAssociation(
477             jalviewAlignport.getAlignment().getSequencesArray(), aptxTree);
478     bindAptxNodes.associateLeavesToSequences();
479
480     bindNodesToJalviewSequences(aptxApp, jalviewAlignport,
481             bindAptxNodes.getAlignmentWithNodes(),
482             bindAptxNodes.getNodesWithAlignment());
483     bindTreeViewFrameToJalview(aptxApp);
484
485     return aptxApp;
486   }
487
488
489   public static ExternalTreeViewerBindingI<?> bindNodesToJalviewSequences(
490           final MainFrame aptxApp,
491           final AlignmentViewport jalviewAlignViewport,
492           final Map<SequenceI, PhylogenyNode> alignMappedToNodes,
493           final Map<PhylogenyNode, SequenceI> nodesMappedToAlign)
494   {
495     JalviewBinding treeBinding = new JalviewBinding(aptxApp,
496             jalviewAlignViewport,
497             alignMappedToNodes, nodesMappedToAlign);
498     activeAptx.put(aptxApp, treeBinding);
499     return treeBinding;
500   }
501
502
503   public static MainFrame bindTreeViewFrameToJalview(
504           final MainFrame aptxApp)
505   {
506     int width = 400;
507     int height = 550;
508     aptxApp.setMinimumSize(new Dimension(width, height));
509     // aptxApp.setFont(Desktop.instance.getFont());
510     // aptxApp.getMainPanel().setFont(Desktop.instance.getFont());
511     String frameTitle = MessageManager.getString("label.aptx_title");
512     File treeFile = aptxApp.getMainPanel().getCurrentTreePanel()
513             .getTreeFile();
514     if (treeFile != null)
515     {
516       frameTitle += MessageManager.formatMessage("label.aptx_title_append",
517               new String[]
518               { treeFile.getAbsolutePath() });
519     }
520     Desktop.addInternalFrame(aptxApp, frameTitle, true, width, height, true,
521             true);
522     return aptxApp;
523
524   }
525
526   public static Map<MainFrame, JalviewBinding> getAllAptxFrames()
527   {
528     return activeAptx;
529   }
530
531
532 }