comment on jalview.io.AlignFile architecture
[jalview.git] / src / jalview / io / AlignFile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.io;
19
20 import jalview.datamodel.Alignment;
21 import jalview.datamodel.AlignmentAnnotation;
22 import jalview.datamodel.Sequence;
23 import jalview.datamodel.SequenceI;
24
25 import java.io.IOException;
26 import java.util.Enumeration;
27 import java.util.Hashtable;
28 import java.util.Vector;
29
30 import javax.xml.parsers.ParserConfigurationException;
31
32 import org.xml.sax.SAXException;
33
34 import fr.orsay.lri.varna.exceptions.ExceptionFileFormatOrSyntax;
35 import fr.orsay.lri.varna.exceptions.ExceptionLoadingFailed;
36 import fr.orsay.lri.varna.exceptions.ExceptionPermissionDenied;
37 import fr.orsay.lri.varna.exceptions.ExceptionUnmatchedClosingParentheses;
38
39 /**
40  * DOCUMENT ME!
41  * 
42  * @author $author$
43  * @version $Revision$
44  */
45 public abstract class AlignFile extends FileParse
46 {
47   int noSeqs = 0;
48
49   int maxLength = 0;
50
51   /**
52    * Sequences to be added to form a new alignment.
53    */
54   protected Vector<SequenceI> seqs;
55
56   /**
57    * annotation to be added to generated alignment object
58    */
59   protected Vector annotations;
60
61   /**
62    * Properties to be added to generated alignment object
63    */
64   protected Hashtable properties;
65
66   long start;
67
68   long end;
69
70   boolean jvSuffix = true;
71
72   /**
73    * Creates a new AlignFile object.
74    */
75   public AlignFile()
76   {
77           // Shouldn't we init data structures (JBPNote: not sure - initData is for initialising the structures used for reading from a datasource, and the bare constructor hasn't got any datasource)
78           initData();
79   }
80
81   /**
82    * Constructor which parses the data from a file of some specified type.
83    * 
84    * @param inFile
85    *          Filename to read from.
86    * @param type
87    *          What type of file to read from (File, URL)
88  * @throws SAXException 
89  * @throws ParserConfigurationException 
90  * @throws ExceptionFileFormatOrSyntax 
91  * @throws ExceptionLoadingFailed 
92  * @throws ExceptionPermissionDenied 
93  * @throws InterruptedException 
94  * @throws ExceptionUnmatchedClosingParentheses 
95    */
96   public AlignFile(String inFile, String type) throws IOException, ExceptionFileFormatOrSyntax, ParserConfigurationException, SAXException, ExceptionPermissionDenied, ExceptionLoadingFailed, InterruptedException, ExceptionUnmatchedClosingParentheses
97   {
98     super(inFile, type);
99     initData();
100     parse();
101     // sets the index of each sequence in the alignment
102     for (int i = 0, c = seqs.size(); i < c; i++)
103     {
104       seqs.get(i).setIndex(i);
105     }
106   }
107
108   /**
109    * Attempt to read from the position where some other parsing process left
110    * off.
111    * 
112    * @param source
113    * @throws IOException
114  * @throws SAXException 
115  * @throws ParserConfigurationException 
116  * @throws ExceptionFileFormatOrSyntax 
117  * @throws ExceptionLoadingFailed 
118  * @throws ExceptionPermissionDenied 
119  * @throws InterruptedException 
120  * @throws ExceptionUnmatchedClosingParentheses 
121    */
122   public AlignFile(FileParse source) throws IOException, ExceptionFileFormatOrSyntax, ParserConfigurationException, SAXException, ExceptionPermissionDenied, ExceptionLoadingFailed, InterruptedException, ExceptionUnmatchedClosingParentheses
123   {
124     super(source);
125     initData();
126     parse();
127     // sets the index of each sequence in the alignment
128     for (int i = 0, c = seqs.size(); i < c; i++)
129     {
130       seqs.get(i).setIndex(i);
131     }
132   }
133
134   /**
135    * Return the seqs Vector
136    */
137   public Vector<SequenceI> getSeqs()
138   {
139     return seqs;
140   }
141
142   /**
143    * Return the Sequences in the seqs Vector as an array of Sequences
144    */
145   public SequenceI[] getSeqsAsArray()
146   {
147     SequenceI[] s = new SequenceI[seqs.size()];
148
149     for (int i = 0; i < seqs.size(); i++)
150     {
151       s[i] = (SequenceI) seqs.elementAt(i);
152     }
153
154     return s;
155   }
156
157   /**
158    * called by AppletFormatAdapter to generate an annotated alignment, rather
159    * than bare sequences.
160    * 
161    * @param al
162    */
163   public void addAnnotations(Alignment al)
164   {
165     addProperties(al);
166     for (int i = 0; i < annotations.size(); i++)
167     {
168       // detect if annotations.elementAt(i) rna secondary structure
169       // if so then do:
170       /*
171        * SequenceFeature[] pairArray =
172        * Rna.GetBasePairsFromAlignmentAnnotation(annotations.elementAt(i));
173        * Rna.HelixMap(pairArray);
174        */
175       AlignmentAnnotation an = (AlignmentAnnotation) annotations
176               .elementAt(i);
177       an.validateRangeAndDisplay();
178       al.addAnnotation(an);
179     }
180
181   }
182
183   /**
184    * Add any additional information extracted from the file to the alignment
185    * properties.
186    * 
187    * @note implicitly called by addAnnotations()
188    * @param al
189    */
190   public void addProperties(Alignment al)
191   {
192     if (properties != null && properties.size() > 0)
193     {
194       Enumeration keys = properties.keys();
195       Enumeration vals = properties.elements();
196       while (keys.hasMoreElements())
197       {
198         al.setProperty(keys.nextElement(), vals.nextElement());
199       }
200     }
201   }
202
203   /**
204    * Store a non-null key-value pair in a hashtable used to set alignment
205    * properties note: null keys will raise an error, null values will result in
206    * the key/value pair being silently ignored.
207    * 
208    * @param key
209    *          - non-null key object
210    * @param value
211    *          - non-null value
212    */
213   protected void setAlignmentProperty(Object key, Object value)
214   {
215     if (key == null)
216     {
217       throw new Error(
218               "Implementation error: Cannot have null alignment property key.");
219     }
220     if (value == null)
221     {
222       return; // null properties are ignored.
223     }
224     if (properties == null)
225     {
226       properties = new Hashtable();
227     }
228     properties.put(key, value);
229   }
230
231   protected Object getAlignmentProperty(Object key)
232   {
233     if (properties != null && key != null)
234     {
235       return properties.get(key);
236     }
237     return null;
238   }
239
240   /**
241    * Initialise objects to store sequence data in.
242    */
243   protected void initData()
244   {
245     seqs = new Vector();
246     annotations = new Vector();
247   }
248
249   /**
250    * DOCUMENT ME!
251    * 
252    * @param s
253    *          DOCUMENT ME!
254    */
255   protected void setSeqs(SequenceI[] s)
256   {
257     seqs = new Vector();
258
259     for (int i = 0; i < s.length; i++)
260     {
261       seqs.addElement(s[i]);
262     }
263   }
264
265   /**
266    * This method must be implemented to parse the contents of the file.
267  * @throws ExceptionFileFormatOrSyntax 
268  * @throws SAXException 
269  * @throws ParserConfigurationException 
270  * @throws ExceptionLoadingFailed 
271  * @throws ExceptionPermissionDenied 
272  * @throws InterruptedException 
273  * @throws ExceptionUnmatchedClosingParentheses 
274    */
275   public abstract void parse() throws IOException, ExceptionFileFormatOrSyntax, ParserConfigurationException, SAXException, ExceptionPermissionDenied, ExceptionLoadingFailed, InterruptedException, ExceptionUnmatchedClosingParentheses;
276
277   /**
278    * Print out in alignment file format the Sequences in the seqs Vector.
279    */
280   public abstract String print();
281
282   public void addJVSuffix(boolean b)
283   {
284     jvSuffix = b;
285   }
286
287   /**
288    * A general parser for ids.
289    * 
290    * @String id Id to be parsed
291    */
292   Sequence parseId(String id)
293   {
294     Sequence seq = null;
295     id = id.trim();
296     int space = id.indexOf(" ");
297     if (space > -1)
298     {
299       seq = new Sequence(id.substring(0, space), "");
300       seq.setDescription(id.substring(space + 1));
301     }
302     else
303     {
304       seq = new Sequence(id, "");
305     }
306
307     return seq;
308   }
309
310   /**
311    * Creates the output id. Adds prefix Uniprot format source|id And suffix
312    * Jalview /start-end
313    * 
314    * @String id Id to be parsed
315    */
316   String printId(SequenceI seq)
317   {
318     return seq.getDisplayId(jvSuffix);
319   }
320
321   /**
322    * vector of String[] treeName, newickString pairs
323    */
324   Vector newickStrings = null;
325
326   protected void addNewickTree(String treeName, String newickString)
327   {
328     if (newickStrings == null)
329     {
330       newickStrings = new Vector();
331     }
332     newickStrings.addElement(new String[]
333     { treeName, newickString });
334   }
335
336   protected int getTreeCount()
337   {
338     if (newickStrings == null)
339     {
340       return 0;
341     }
342     return newickStrings.size();
343   }
344
345 }