disabled simple blast parser for 2.4.1 release
[jalview.git] / src / jalview / io / AppletFormatAdapter.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
3  * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.io;
20
21 import java.io.File;
22
23 import jalview.datamodel.*;
24
25 /**
26  * A low level class for alignment and feature IO with alignment formatting
27  * methods used by both applet and application for generating flat alignment
28  * files. It also holds the lists of magic format names that the applet and
29  * application will allow the user to read or write files with.
30  * 
31  * @author $author$
32  * @version $Revision$
33  */
34 public class AppletFormatAdapter
35 {
36   /**
37    * List of valid format strings used in the isValidFormat method
38    */
39   public static final String[] READABLE_FORMATS = new String[]
40   { "BLC", "CLUSTAL", "FASTA", "MSF", "PileUp", "PIR", "PFAM", "STH",
41       "PDB", "JnetFile"}; //, "SimpleBLAST" };
42
43   /**
44    * List of valid format strings for use by callers of the formatSequences
45    * method
46    */
47   public static final String[] WRITEABLE_FORMATS = new String[]
48   { "BLC", "CLUSTAL", "FASTA", "MSF", "PileUp", "PIR", "PFAM", "AMSA" };
49
50   /**
51    * List of extensions corresponding to file format types in WRITABLE_FNAMES
52    * that are writable by the application.
53    */
54   public static final String[] WRITABLE_EXTENSIONS = new String[]
55   { "fa, fasta, fastq", "aln", "pfam", "msf", "pir", "blc", "amsa", "jar" };
56
57   /**
58    * List of writable formats by the application. Order must correspond with the
59    * WRITABLE_EXTENSIONS list of formats.
60    */
61   public static final String[] WRITABLE_FNAMES = new String[]
62   { "Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "AMSA", "Jalview" };
63
64   /**
65    * List of readable format file extensions by application in order
66    * corresponding to READABLE_FNAMES
67    */
68   public static final String[] READABLE_EXTENSIONS = new String[]
69   { "fa, fasta, fastq", "aln", "pfam", "msf", "pir", "blc", "amsa", "jar"}; //, ".blast" };
70
71   /**
72    * List of readable formats by application in order corresponding to
73    * READABLE_EXTENSIONS
74    */
75   public static final String[] READABLE_FNAMES = new String[]
76   { "Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "AMSA", "Jalview"};// , "SimpleBLAST" };
77
78   public static String INVALID_CHARACTERS = "Contains invalid characters";
79
80   // TODO: make these messages dynamic
81   public static String SUPPORTED_FORMATS = "Formats currently supported are\n"
82           + prettyPrint(READABLE_FORMATS);
83
84   /**
85    * 
86    * @param els
87    * @return grammatically correct(ish) list consisting of els elements.
88    */
89   public static String prettyPrint(String[] els)
90   {
91     StringBuffer list = new StringBuffer();
92     for (int i = 0, iSize = els.length - 1; i < iSize; i++)
93     {
94       list.append(els[i]);
95       list.append(",");
96     }
97     list.append(" and " + els[els.length - 1] + ".");
98     return list.toString();
99   }
100
101   public static String FILE = "File";
102
103   public static String URL = "URL";
104
105   public static String PASTE = "Paste";
106
107   public static String CLASSLOADER = "ClassLoader";
108
109   AlignFile afile = null;
110
111   String inFile;
112
113   /**
114    * check that this format is valid for reading
115    * 
116    * @param format
117    *                a format string to be compared with READABLE_FORMATS
118    * @return true if format is readable
119    */
120   public static final boolean isValidFormat(String format)
121   {
122     return isValidFormat(format, false);
123   }
124
125   /**
126    * validate format is valid for IO
127    * 
128    * @param format
129    *                a format string to be compared with either READABLE_FORMATS
130    *                or WRITEABLE_FORMATS
131    * @param forwriting
132    *                when true, format is checked for containment in
133    *                WRITEABLE_FORMATS
134    * @return true if format is valid
135    */
136   public static final boolean isValidFormat(String format,
137           boolean forwriting)
138   {
139     boolean valid = false;
140     String[] format_list = (forwriting) ? WRITEABLE_FORMATS
141             : READABLE_FORMATS;
142     for (int i = 0; i < format_list.length; i++)
143     {
144       if (format_list[i].equalsIgnoreCase(format))
145       {
146         return true;
147       }
148     }
149
150     return valid;
151   }
152
153   /**
154    * Constructs the correct filetype parser for a characterised datasource
155    * 
156    * @param inFile
157    *                data/data location
158    * @param type
159    *                type of datasource
160    * @param format
161    *                File format of data provided by datasource
162    * 
163    * @return DOCUMENT ME!
164    */
165   public Alignment readFile(String inFile, String type, String format)
166           throws java.io.IOException
167   {
168     // TODO: generalise mapping between format string and io. class instances
169     // using Constructor.invoke reflection
170     this.inFile = inFile;
171     try
172     {
173       if (format.equals("FASTA"))
174       {
175         afile = new FastaFile(inFile, type);
176       }
177       else if (format.equals("MSF"))
178       {
179         afile = new MSFfile(inFile, type);
180       }
181       else if (format.equals("PileUp"))
182       {
183         afile = new PileUpfile(inFile, type);
184       }
185       else if (format.equals("CLUSTAL"))
186       {
187         afile = new ClustalFile(inFile, type);
188       }
189       else if (format.equals("BLC"))
190       {
191         afile = new BLCFile(inFile, type);
192       }
193       else if (format.equals("PIR"))
194       {
195         afile = new PIRFile(inFile, type);
196       }
197       else if (format.equals("PFAM"))
198       {
199         afile = new PfamFile(inFile, type);
200       }
201       else if (format.equals("JnetFile"))
202       {
203         afile = new JPredFile(inFile, type);
204         ((JPredFile) afile).removeNonSequences();
205       }
206       else if (format.equals("PDB"))
207       {
208         afile = new MCview.PDBfile(inFile, type);
209       }
210       else if (format.equals("STH"))
211       {
212         afile = new StockholmFile(inFile, type);
213       }
214       else if (format.equals("SimpleBLAST"))
215       {
216         afile = new SimpleBlastFile(inFile,type);
217       }
218
219       Alignment al = new Alignment(afile.getSeqsAsArray());
220
221       afile.addAnnotations(al);
222
223       return al;
224     } catch (Exception e)
225     {
226       e.printStackTrace();
227       System.err.println("Failed to read alignment using the '" + format
228               + "' reader.\n" + e);
229
230       if (e.getMessage() != null
231               && e.getMessage().startsWith(INVALID_CHARACTERS))
232       {
233         throw new java.io.IOException(e.getMessage());
234       }
235
236       // Finally test if the user has pasted just the sequence, no id
237       if (type.equalsIgnoreCase("Paste"))
238       {
239         try
240         {
241           // Possible sequence is just residues with no label
242           afile = new FastaFile(">UNKNOWN\n" + inFile, "Paste");
243           Alignment al = new Alignment(afile.getSeqsAsArray());
244           afile.addAnnotations(al);
245           return al;
246
247         } catch (Exception ex)
248         {
249           if (ex.toString().startsWith(INVALID_CHARACTERS))
250           {
251             throw new java.io.IOException(e.getMessage());
252           }
253
254           ex.printStackTrace();
255         }
256       }
257
258       // If we get to this stage, the format was not supported
259       throw new java.io.IOException(SUPPORTED_FORMATS);
260     }
261   }
262
263   /**
264    * Constructs the correct filetype parser for an already open datasource
265    * 
266    * @param source
267    *                an existing datasource
268    * @param format
269    *                File format of data that will be provided by datasource
270    * 
271    * @return DOCUMENT ME!
272    */
273   public Alignment readFromFile(FileParse source, String format)
274           throws java.io.IOException
275   {
276     // TODO: generalise mapping between format string and io. class instances
277     // using Constructor.invoke reflection
278     // This is exactly the same as the readFile method except we substitute
279     // 'inFile, type' with 'source'
280     this.inFile = source.getInFile();
281     String type = source.type;
282     try
283     {
284       if (format.equals("FASTA"))
285       {
286         afile = new FastaFile(source);
287       }
288       else if (format.equals("MSF"))
289       {
290         afile = new MSFfile(source);
291       }
292       else if (format.equals("PileUp"))
293       {
294         afile = new PileUpfile(source);
295       }
296       else if (format.equals("CLUSTAL"))
297       {
298         afile = new ClustalFile(source);
299       }
300       else if (format.equals("BLC"))
301       {
302         afile = new BLCFile(source);
303       }
304       else if (format.equals("PIR"))
305       {
306         afile = new PIRFile(source);
307       }
308       else if (format.equals("PFAM"))
309       {
310         afile = new PfamFile(source);
311       }
312       else if (format.equals("JnetFile"))
313       {
314         afile = new JPredFile(source);
315         ((JPredFile) afile).removeNonSequences();
316       }
317       else if (format.equals("PDB"))
318       {
319         afile = new MCview.PDBfile(source);
320       }
321       else if (format.equals("STH"))
322       {
323         afile = new StockholmFile(source);
324       }
325       else if (format.equals("SimpleBLAST"))
326       {
327         afile = new SimpleBlastFile(source);
328       }
329
330       Alignment al = new Alignment(afile.getSeqsAsArray());
331
332       afile.addAnnotations(al);
333
334       return al;
335     } catch (Exception e)
336     {
337       e.printStackTrace();
338       System.err.println("Failed to read alignment using the '" + format
339               + "' reader.\n" + e);
340
341       if (e.getMessage() != null
342               && e.getMessage().startsWith(INVALID_CHARACTERS))
343       {
344         throw new java.io.IOException(e.getMessage());
345       }
346
347       // Finally test if the user has pasted just the sequence, no id
348       if (type.equalsIgnoreCase("Paste"))
349       {
350         try
351         {
352           // Possible sequence is just residues with no label
353           afile = new FastaFile(">UNKNOWN\n" + inFile, "Paste");
354           Alignment al = new Alignment(afile.getSeqsAsArray());
355           afile.addAnnotations(al);
356           return al;
357
358         } catch (Exception ex)
359         {
360           if (ex.toString().startsWith(INVALID_CHARACTERS))
361           {
362             throw new java.io.IOException(e.getMessage());
363           }
364
365           ex.printStackTrace();
366         }
367       }
368
369       // If we get to this stage, the format was not supported
370       throw new java.io.IOException(SUPPORTED_FORMATS);
371     }
372   }
373
374   /**
375    * Construct an output class for an alignment in a particular filetype
376    * TODO: allow caller to detect errors and warnings encountered when generating output
377    *
378    * @param format
379    *                string name of alignment format
380    * @param alignment
381    *                the alignment to be written out
382    * @param jvsuffix
383    *                passed to AlnFile class controls whether /START-END is added
384    *                to sequence names
385    * 
386    * @return alignment flat file contents
387    */
388   public String formatSequences(String format, AlignmentI alignment,
389           boolean jvsuffix)
390   {
391     try
392     {
393       AlignFile afile = null;
394
395       if (format.equalsIgnoreCase("FASTA"))
396       {
397         afile = new FastaFile();
398       }
399       else if (format.equalsIgnoreCase("MSF"))
400       {
401         afile = new MSFfile();
402       }
403       else if (format.equalsIgnoreCase("PileUp"))
404       {
405         afile = new PileUpfile();
406       }
407       else if (format.equalsIgnoreCase("CLUSTAL"))
408       {
409         afile = new ClustalFile();
410       }
411       else if (format.equalsIgnoreCase("BLC"))
412       {
413         afile = new BLCFile();
414       }
415       else if (format.equalsIgnoreCase("PIR"))
416       {
417         afile = new PIRFile();
418       }
419       else if (format.equalsIgnoreCase("PFAM"))
420       {
421         afile = new PfamFile();
422       }
423       else if (format.equalsIgnoreCase("STH"))
424       {
425         afile = new StockholmFile();
426       }
427       else if (format.equalsIgnoreCase("AMSA"))
428       {
429         afile = new AMSAFile(alignment);
430       }
431       else
432       {
433         throw new Exception(
434                 "Implementation error: Unknown file format string");
435       }
436
437       afile.addJVSuffix(jvsuffix);
438
439       afile.setSeqs(alignment.getSequencesArray());
440
441       String afileresp = afile.print();
442       if (afile.hasWarningMessage())
443       {
444         System.err.println("Warning raised when writing as "+format+" : "+afile.getWarningMessage());
445       }
446       return afileresp;
447     } catch (Exception e)
448     {
449       System.err.println("Failed to write alignment as a '" + format
450               + "' file\n");
451       e.printStackTrace();
452     }
453
454     return null;
455   }
456
457   public static void main(String[] args)
458   {
459     int i = 0;
460     while (i < args.length)
461     {
462       File f = new File(args[i]);
463       if (f.exists())
464       {
465         try
466         {
467           System.out.println("Reading file: " + f);
468           AppletFormatAdapter afa = new AppletFormatAdapter();
469           Runtime r = Runtime.getRuntime();
470           System.gc();
471           long memf = -r.totalMemory() + r.freeMemory();
472           long t1 = -System.currentTimeMillis();
473           Alignment al = afa.readFile(args[i], FILE, new IdentifyFile()
474                   .Identify(args[i], FILE));
475           t1 += System.currentTimeMillis();
476           System.gc();
477           memf += r.totalMemory() - r.freeMemory();
478           if (al != null)
479           {
480             System.out.println("Alignment contains " + al.getHeight()
481                     + " sequences and " + al.getWidth() + " columns.");
482             try {
483               System.out.println(new AppletFormatAdapter().formatSequences("FASTA", al, true));
484             } catch (Exception e)
485             {
486               System.err.println("Couln't format the alignment for output as a FASTA file.");
487               e.printStackTrace(System.err);
488             }
489           }
490           else
491           {
492             System.out.println("Couldn't read alignment");
493           }
494           System.out.println("Read took " + (t1 / 1000.0) + " seconds.");
495           System.out
496                   .println("Difference between free memory now and before is "
497                           + (memf / (1024.0 * 1024.0) * 1.0) + " MB");
498
499         } catch (Exception e)
500         {
501           System.err.println("Exception when dealing with " + i
502                   + "'th argument: " + args[i] + "\n" + e);
503         }
504       }
505       else
506       {
507         System.err.println("Ignoring argument '" + args[i] + "' (" + i
508                 + "'th)- not a readable file.");
509       }
510       i++;
511     }
512
513   }
514 }