JAL-1919 PDBfile and JmolParser refactor
[jalview.git] / src / jalview / io / StructureFile.java
1 package jalview.io;
2
3 import jalview.analysis.AlignSeq;
4 import jalview.datamodel.Alignment;
5 import jalview.datamodel.AlignmentAnnotation;
6 import jalview.datamodel.AlignmentI;
7 import jalview.datamodel.DBRefEntry;
8 import jalview.datamodel.DBRefSource;
9 import jalview.datamodel.PDBEntry;
10 import jalview.datamodel.SequenceI;
11
12 import java.awt.Color;
13 import java.io.IOException;
14 import java.lang.reflect.Constructor;
15 import java.util.Hashtable;
16 import java.util.List;
17 import java.util.Vector;
18
19 import MCview.PDBChain;
20
21 public abstract class StructureFile extends AlignFile
22 {
23
24   private String id;
25
26   /**
27    * set to true to add derived sequence annotations (temp factor read from
28    * file, or computed secondary structure) to the alignment
29    */
30   protected boolean visibleChainAnnotation = false;
31
32   /*
33    * Set true to predict secondary structure (using JMol for protein, Annotate3D
34    * for RNA)
35    */
36   protected boolean predictSecondaryStructure = true;
37
38   /*
39    * Set true (with predictSecondaryStructure=true) to predict secondary
40    * structure using an external service (currently Annotate3D for RNA only)
41    */
42   protected boolean externalSecondaryStructure = false;
43
44   private Vector<PDBChain> chains;
45
46   public StructureFile(String inFile, String type) throws IOException
47   {
48     super(inFile, type);
49   }
50
51   public StructureFile(FileParse fp) throws IOException
52   {
53     super(fp);
54   }
55
56   public StructureFile(boolean parseImmediately, String inFile, String type)
57           throws IOException
58   {
59     super(parseImmediately, inFile, type);
60   }
61
62   public StructureFile(boolean a, FileParse fp) throws IOException
63   {
64     super(a, fp);
65   }
66
67   public StructureFile()
68   {
69   }
70
71   @SuppressWarnings("rawtypes")
72   protected SequenceI postProcessChain(PDBChain chain)
73   {
74     SequenceI pdbSequence = chain.sequence;
75     pdbSequence.setName(getId() + "|" + pdbSequence.getName());
76     PDBEntry entry = new PDBEntry();
77     entry.setId(getId());
78     entry.setType(PDBEntry.Type.PDB);
79     entry.setProperty(new Hashtable());
80     if (chain.id != null)
81     {
82       entry.setChainCode(String.valueOf(chain.id));
83     }
84     if (inFile != null)
85     {
86       entry.setFile(inFile.getAbsolutePath());
87     }
88     else
89     {
90       entry.setFile(getDataName());
91     }
92
93     DBRefEntry sourceDBRef = new DBRefEntry();
94     sourceDBRef.setAccessionId(getId());
95     sourceDBRef.setSource(DBRefSource.PDB);
96     sourceDBRef.setStartRes(pdbSequence.getStart());
97     sourceDBRef.setEndRes(pdbSequence.getEnd());
98
99     // PDBChain objects maintain reference to dataset
100
101     // SequenceI chainseq = pdbSequence.deriveSequence();
102     // chainseq.setSourceDBRef(sourceDBRef);
103     // chainseq.addPDBId(entry);
104     // chainseq.addDBRef(sourceDBRef);
105     SequenceI chainseq = chain.sequence;
106     chainseq.addPDBId(entry);
107     chainseq.setSourceDBRef(sourceDBRef);
108     chainseq.addDBRef(sourceDBRef);
109     seqs.addElement(chainseq);
110
111     AlignmentAnnotation[] chainannot = chainseq.getAnnotation();
112
113     if (chainannot != null && visibleChainAnnotation)
114     {
115       for (int ai = 0; ai < chainannot.length; ai++)
116       {
117         chainannot[ai].visible = visibleChainAnnotation;
118         annotations.addElement(chainannot[ai]);
119       }
120     }
121     return chainseq;
122   }
123
124   @SuppressWarnings({ "unchecked", "rawtypes" })
125   protected void processPdbFileWithAnnotate3d(List<SequenceI> rna)
126           throws Exception
127   {
128     // System.out.println("this is a PDB format and RNA sequence");
129     // note: we use reflection here so that the applet can compile and run
130     // without the HTTPClient bits and pieces needed for accessing Annotate3D
131     // web service
132     try
133     {
134       Class cl = Class.forName("jalview.ws.jws1.Annotate3D");
135       if (cl != null)
136       {
137         // TODO: use the PDB ID of the structure if one is available, to save
138         // bandwidth and avoid uploading the whole structure to the service
139         Object annotate3d = cl.getConstructor(new Class[] {}).newInstance(
140                 new Object[] {});
141         AlignmentI al = ((AlignmentI) cl.getMethod("getRNAMLFor",
142                 new Class[] { FileParse.class }).invoke(annotate3d,
143                 new Object[] { new FileParse(getDataName(), type) }));
144         for (SequenceI sq : al.getSequences())
145         {
146           if (sq.getDatasetSequence() != null)
147           {
148             if (sq.getDatasetSequence().getAllPDBEntries() != null)
149             {
150               sq.getDatasetSequence().getAllPDBEntries().clear();
151             }
152           }
153           else
154           {
155             if (sq.getAllPDBEntries() != null)
156             {
157               sq.getAllPDBEntries().clear();
158             }
159           }
160         }
161         replaceAndUpdateChains(rna, al, AlignSeq.DNA, false);
162       }
163     } catch (ClassNotFoundException x)
164     {
165       // ignore classnotfounds - occurs in applet
166     }
167   }
168
169   @SuppressWarnings("unchecked")
170   protected void replaceAndUpdateChains(List<SequenceI> prot,
171           AlignmentI al,
172           String pep, boolean b)
173   {
174     List<List<? extends Object>> replaced = AlignSeq
175             .replaceMatchingSeqsWith(seqs, annotations, prot, al, pep,
176                     false);
177     for (PDBChain ch : getChains())
178     {
179       int p = 0;
180       for (SequenceI sq : (List<SequenceI>) replaced.get(0))
181       {
182         p++;
183         if (sq == ch.sequence || sq.getDatasetSequence() == ch.sequence)
184         {
185           p = -p;
186           break;
187         }
188       }
189       if (p < 0)
190       {
191         p = -p - 1;
192         // set shadow entry for chains
193         ch.shadow = (SequenceI) replaced.get(1).get(p);
194         ch.shadowMap = ((AlignSeq) replaced.get(2).get(p))
195                 .getMappingFromS1(false);
196       }
197     }
198   }
199
200   /**
201    * Predict secondary structure for RNA and/or protein sequences and add as
202    * annotations
203    * 
204    * @param rnaSequences
205    * @param proteinSequences
206    */
207   protected void addSecondaryStructure(List<SequenceI> rnaSequences,
208           List<SequenceI> proteinSequences)
209   {
210     /*
211      * Currently using Annotate3D for RNA, but only if the 'use external
212      * prediction' flag is set
213      */
214     if (externalSecondaryStructure && rnaSequences.size() > 0)
215     {
216       try
217       {
218         processPdbFileWithAnnotate3d(rnaSequences);
219       } catch (Exception x)
220       {
221         System.err.println("Exceptions when dealing with RNA in pdb file");
222         x.printStackTrace();
223
224       }
225     }
226
227     /*
228      * Currently using JMol PDB parser for peptide
229      */
230     if (proteinSequences.size() > 0)
231     {
232       try
233       {
234         processWithJmolParser(proteinSequences);
235       } catch (Exception x)
236       {
237         System.err
238                 .println("Exceptions from Jmol when processing data in pdb file");
239         x.printStackTrace();
240       }
241     }
242   }
243
244   @SuppressWarnings({ "unchecked", "rawtypes" })
245   private void processWithJmolParser(List<SequenceI> prot)
246           throws Exception
247   {
248     try
249     {
250
251       Class cl = Class.forName("jalview.ext.jmol.JmolParser");
252       if (cl != null)
253       {
254         final Constructor constructor = cl
255                 .getConstructor(new Class[] { FileParse.class });
256         final Object[] args = new Object[] { new FileParse(getDataName(),
257                 type) };
258         Object jmf = constructor.newInstance(args);
259         AlignmentI al = new Alignment((SequenceI[]) cl.getMethod(
260                 "getSeqsAsArray", new Class[] {}).invoke(jmf));
261         cl.getMethod("addAnnotations", new Class[] { AlignmentI.class })
262                 .invoke(jmf, al);
263         for (SequenceI sq : al.getSequences())
264         {
265           if (sq.getDatasetSequence() != null)
266           {
267             sq.getDatasetSequence().getAllPDBEntries().clear();
268           }
269           else
270           {
271             sq.getAllPDBEntries().clear();
272           }
273         }
274         replaceAndUpdateChains(prot, al, AlignSeq.PEP, false);
275       }
276     } catch (ClassNotFoundException q)
277     {
278     }
279   }
280
281   public PDBChain findChain(String id) throws Exception
282   {
283     for (PDBChain chain : getChains())
284     {
285       if (chain.id.equalsIgnoreCase(id))
286       {
287         return chain;
288       }
289     }
290     throw new Exception("PDB chain not Found!");
291   }
292
293   public void makeResidueList()
294   {
295     for (PDBChain chain : getChains())
296     {
297       chain.makeResidueList(visibleChainAnnotation);
298     }
299   }
300
301   public void makeCaBondList()
302   {
303     for (PDBChain chain : getChains())
304     {
305       chain.makeCaBondList();
306     }
307   }
308
309   public void setChargeColours()
310   {
311     for (PDBChain chain : getChains())
312     {
313       chain.setChargeColours();
314     }
315   }
316
317   public void setColours(jalview.schemes.ColourSchemeI cs)
318   {
319     for (PDBChain chain : getChains())
320     {
321       chain.setChainColours(cs);
322     }
323   }
324
325   public void setChainColours()
326   {
327     int i = 0;
328     for (PDBChain chain : getChains())
329     {
330       chain.setChainColours(Color.getHSBColor(1.0f / i++, .4f, 1.0f));
331     }
332   }
333
334   public static boolean isRNA(SequenceI seq)
335   {
336     for (char c : seq.getSequence())
337     {
338       if ((c != 'A') && (c != 'C') && (c != 'G') && (c != 'U'))
339       {
340         return false;
341       }
342     }
343     return true;
344   }
345
346   /**
347    * make a friendly ID string.
348    * 
349    * @param dataName
350    * @return truncated dataName to after last '/'
351    */
352   protected String safeName(String dataName)
353   {
354     int p = 0;
355     while ((p = dataName.indexOf("/")) > -1 && p < dataName.length())
356     {
357       dataName = dataName.substring(p + 1);
358     }
359     return dataName;
360   }
361
362   public String getId()
363   {
364     return id;
365   }
366
367   public void setId(String id)
368   {
369     this.id = id;
370   }
371
372   public Vector<PDBChain> getChains()
373   {
374     return chains;
375   }
376
377   public void setChains(Vector<PDBChain> chains)
378   {
379     this.chains = chains;
380   }
381 }