JAL-1140 - handled VARNA specific RNA exceptions within the IO class - which should...
[jalview.git] / src / jalview / io / StockholmFile.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)\r
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle\r
4  * \r
5  * This file is part of Jalview.\r
6  * \r
7  * Jalview is free software: you can redistribute it and/or\r
8  * modify it under the terms of the GNU General Public License \r
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
10  *  \r
11  * Jalview is distributed in the hope that it will be useful, but \r
12  * WITHOUT ANY WARRANTY; without even the implied warranty \r
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
14  * PURPOSE.  See the GNU General Public License for more details.\r
15  * \r
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
17  */\r
18 /*\r
19  * This extension was written by Benjamin Schuster-Boeckler at sanger.ac.uk\r
20  */\r
21 package jalview.io;\r
22 \r
23 import jalview.datamodel.AlignmentAnnotation;\r
24 import jalview.datamodel.Annotation;\r
25 import jalview.datamodel.Sequence;\r
26 import jalview.datamodel.SequenceI;\r
27 \r
28 import java.io.BufferedReader;\r
29 import java.io.FileReader;\r
30 import java.io.IOException;\r
31 import java.util.ArrayList;\r
32 import java.util.Enumeration;\r
33 import java.util.Hashtable;\r
34 import java.util.Vector;\r
35 \r
36 import com.stevesoft.pat.Regex;\r
37 \r
38 import fr.orsay.lri.varna.exceptions.ExceptionUnmatchedClosingParentheses;\r
39 import fr.orsay.lri.varna.factories.RNAFactory;\r
40 import fr.orsay.lri.varna.models.rna.RNA;\r
41 \r
42 // import org.apache.log4j.*;\r
43 \r
44 /**\r
45  * This class is supposed to parse a Stockholm format file into Jalview There\r
46  * are TODOs in this class: we do not know what the database source and version\r
47  * is for the file when parsing the #GS= AC tag which associates accessions with\r
48  * sequences. Database references are also not parsed correctly: a separate\r
49  * reference string parser must be added to parse the database reference form\r
50  * into Jalview's local representation.\r
51  * \r
52  * @author bsb at sanger.ac.uk\r
53  * @version 0.3 + jalview mods\r
54  * \r
55  */\r
56 public class StockholmFile extends AlignFile\r
57 {\r
58   // static Logger logger = Logger.getLogger("jalview.io.StockholmFile");\r
59   protected ArrayList<RNA> result;\r
60 \r
61   public String id;\r
62 \r
63   public StockholmFile()\r
64   {\r
65   }\r
66 \r
67   public StockholmFile(String inFile, String type) throws IOException\r
68   {\r
69     super(inFile, type);\r
70   }\r
71 \r
72   public StockholmFile(FileParse source) throws IOException\r
73   {\r
74     super(source);\r
75   }\r
76 \r
77   public void initData()\r
78   {\r
79     super.initData();\r
80   }\r
81 \r
82   /**\r
83    * Parse a file in Stockholm format into Jalview's data model. The file has to\r
84    * be passed at construction time\r
85    * \r
86    * @throws IOException\r
87    *           If there is an error with the input file\r
88    */\r
89   public void parse() throws IOException\r
90   {\r
91     FileReader fr = null;\r
92     fr = new FileReader(inFile);\r
93 \r
94     BufferedReader r = new BufferedReader(fr);\r
95     result = null;\r
96     try\r
97     {\r
98       result = RNAFactory.loadSecStrStockholm(r);\r
99     } catch (ExceptionUnmatchedClosingParentheses umcp)\r
100     {\r
101       errormessage = "Unmatched parentheses in annotation. Aborting ("\r
102               + umcp.getMessage() + ")";\r
103       throw new IOException(umcp);\r
104     }\r
105     // DEBUG System.out.println("this is the secondary scructure:"\r
106     // +result.size());\r
107     SequenceI[] seqs = new SequenceI[result.size()];\r
108     for (int i = 0; i < result.size(); i++)\r
109     {\r
110       // DEBUG System.err.println("Processing i'th sequence in Stockholm file")\r
111       RNA current = result.get(i);\r
112 \r
113       String seq = current.getSeq();\r
114       String rna = current.getStructDBN(true);\r
115       // DEBUG System.out.println(seq);\r
116       // DEBUG System.err.println(rna);\r
117       int begin = 0;\r
118       int end = seq.length() - 1;\r
119       id = safeName(getDataName());\r
120       seqs[i] = new Sequence(id, seq, begin, end);\r
121       String[] annot = new String[rna.length()];\r
122       Annotation[] ann = new Annotation[rna.length()];\r
123       for (int j = 0; j < rna.length(); j++)\r
124       {\r
125         annot[j] = rna.substring(j, j + 1);\r
126 \r
127       }\r
128 \r
129       for (int k = 0; k < rna.length(); k++)\r
130       {\r
131         ann[k] = new Annotation(annot[k], "",\r
132                 jalview.schemes.ResidueProperties.getRNASecStrucState(\r
133                         annot[k]).charAt(0), 0f);\r
134 \r
135       }\r
136       AlignmentAnnotation align = new AlignmentAnnotation("Sec. str.",\r
137               current.getID(), ann);\r
138 \r
139       seqs[i].addAlignmentAnnotation(align);\r
140       seqs[i].setRNA(result.get(i));\r
141       this.annotations.addElement(align);\r
142     }\r
143     this.setSeqs(seqs);\r
144 \r
145   }\r
146 \r
147   protected static AlignmentAnnotation parseAnnotationRow(\r
148           Vector annotation, String label, String annots)\r
149   {\r
150     String convert1, convert2 = null;\r
151 \r
152     // Convert all bracket types to parentheses\r
153     Regex openparen = new Regex("(<|\\[)", "(");\r
154     Regex closeparen = new Regex("(>|\\])", ")");\r
155 \r
156     // Detect if file is RNA by looking for bracket types\r
157     Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))");\r
158 \r
159     convert1 = openparen.replaceAll(annots);\r
160     convert2 = closeparen.replaceAll(convert1);\r
161     annots = convert2;\r
162 \r
163     String type = (label.indexOf("_cons") == label.length() - 5) ? label\r
164             .substring(0, label.length() - 5) : label;\r
165     boolean ss = false;\r
166     type = id2type(type);\r
167     if (type.equals("secondary structure"))\r
168     {\r
169       ss = true;\r
170     }\r
171     // decide on secondary structure or not.\r
172     Annotation[] els = new Annotation[annots.length()];\r
173     for (int i = 0; i < annots.length(); i++)\r
174     {\r
175       String pos = annots.substring(i, i + 1);\r
176       Annotation ann;\r
177       ann = new Annotation(pos, "", ' ', 0f); // 0f is 'valid' null - will not\r
178       // be written out\r
179       if (ss)\r
180       {\r
181         if (detectbrackets.search(pos))\r
182         {\r
183           ann.secondaryStructure = jalview.schemes.ResidueProperties\r
184                   .getRNASecStrucState(pos).charAt(0);\r
185         }\r
186         else\r
187         {\r
188           ann.secondaryStructure = jalview.schemes.ResidueProperties\r
189                   .getDssp3state(pos).charAt(0);\r
190         }\r
191 \r
192         if (ann.secondaryStructure == pos.charAt(0) || pos.charAt(0) == 'C')\r
193         {\r
194           ann.displayCharacter = ""; // null; // " ";\r
195         }\r
196         else\r
197         {\r
198           ann.displayCharacter = " " + ann.displayCharacter;\r
199         }\r
200       }\r
201 \r
202       els[i] = ann;\r
203     }\r
204     AlignmentAnnotation annot = null;\r
205     Enumeration e = annotation.elements();\r
206     while (e.hasMoreElements())\r
207     {\r
208       annot = (AlignmentAnnotation) e.nextElement();\r
209       if (annot.label.equals(type))\r
210         break;\r
211       annot = null;\r
212     }\r
213     if (annot == null)\r
214     {\r
215       annot = new AlignmentAnnotation(type, type, els);\r
216       annotation.addElement(annot);\r
217     }\r
218     else\r
219     {\r
220       Annotation[] anns = new Annotation[annot.annotations.length\r
221               + els.length];\r
222       System.arraycopy(annot.annotations, 0, anns, 0,\r
223               annot.annotations.length);\r
224       System.arraycopy(els, 0, anns, annot.annotations.length, els.length);\r
225       annot.annotations = anns;\r
226       // System.out.println("else: ");\r
227     }\r
228     return annot;\r
229   }\r
230 \r
231   public static String print(SequenceI[] s)\r
232   {\r
233     return "not yet implemented";\r
234   }\r
235 \r
236   public String print()\r
237   {\r
238     return print(getSeqsAsArray());\r
239   }\r
240 \r
241   private static Hashtable typeIds = null;\r
242   static\r
243   {\r
244     if (typeIds == null)\r
245     {\r
246       typeIds = new Hashtable();\r
247       typeIds.put("SS", "secondary structure");\r
248       typeIds.put("SA", "surface accessibility");\r
249       typeIds.put("TM", "transmembrane");\r
250       typeIds.put("PP", "posterior probability");\r
251       typeIds.put("LI", "ligand binding");\r
252       typeIds.put("AS", "active site");\r
253       typeIds.put("IN", "intron");\r
254       typeIds.put("IR", "interacting residue");\r
255       typeIds.put("AC", "accession");\r
256       typeIds.put("OS", "organism");\r
257       typeIds.put("CL", "class");\r
258       typeIds.put("DE", "description");\r
259       typeIds.put("DR", "reference");\r
260       typeIds.put("LO", "look");\r
261       typeIds.put("RF", "reference positions");\r
262 \r
263     }\r
264   }\r
265 \r
266   protected static String id2type(String id)\r
267   {\r
268     if (typeIds.containsKey(id))\r
269     {\r
270       return (String) typeIds.get(id);\r
271     }\r
272     System.err.println("Warning : Unknown Stockholm annotation type code "\r
273             + id);\r
274     return id;\r
275   }\r
276   /**\r
277    * make a friendly ID string.\r
278    * \r
279    * @param dataName\r
280    * @return truncated dataName to after last '/'\r
281    */\r
282   private String safeName(String dataName)\r
283   {\r
284     int b = 0;\r
285     while ((b = dataName.indexOf("/")) > -1 && b < dataName.length())\r
286     {\r
287       dataName = dataName.substring(b + 1).trim();\r
288 \r
289     }\r
290     int e = (dataName.length() - dataName.indexOf(".")) + 1;\r
291     dataName = dataName.substring(1, e).trim();\r
292     return dataName;\r
293   }\r
294 }