2452aed4b607423b0db11c01292b7b39acf4cb2e
[jalview.git] / src / jalview / ws / dbsources / Uniprot.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
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
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.ws.dbsources;
22
23 import jalview.datamodel.Alignment;
24 import jalview.datamodel.AlignmentI;
25 import jalview.datamodel.DBRefEntry;
26 import jalview.datamodel.DBRefSource;
27 import jalview.datamodel.PDBEntry;
28 import jalview.datamodel.Sequence;
29 import jalview.datamodel.SequenceFeature;
30 import jalview.datamodel.SequenceI;
31 import jalview.datamodel.xdb.uniprot.UniprotEntry;
32 import jalview.datamodel.xdb.uniprot.UniprotFeature;
33 import jalview.datamodel.xdb.uniprot.UniprotFile;
34 import jalview.ws.seqfetcher.DbSourceProxyImpl;
35
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.Reader;
39 import java.net.URL;
40 import java.net.URLConnection;
41 import java.util.ArrayList;
42 import java.util.Vector;
43
44 import org.exolab.castor.mapping.Mapping;
45 import org.exolab.castor.xml.Unmarshaller;
46
47 import com.stevesoft.pat.Regex;
48
49 /**
50  * @author JimP
51  * 
52  */
53 public class Uniprot extends DbSourceProxyImpl
54 {
55   private static final String BAR_DELIMITER = "|";
56
57   /*
58    * Castor mapping loaded from uniprot_mapping.xml
59    */
60   private static Mapping map;
61
62   /**
63    * configurable parameter controlling prefixing of entry names with accessions
64    */
65   private boolean includeAllIds = false;
66
67   /**
68    * Constructor
69    */
70   public Uniprot()
71   {
72     super();
73   }
74
75   /*
76    * (non-Javadoc)
77    * 
78    * @see jalview.ws.DbSourceProxy#getAccessionSeparator()
79    */
80   @Override
81   public String getAccessionSeparator()
82   {
83     return null;
84   }
85
86   /*
87    * (non-Javadoc)
88    * 
89    * @see jalview.ws.DbSourceProxy#getAccessionValidator()
90    */
91   @Override
92   public Regex getAccessionValidator()
93   {
94     return new Regex("([A-Z]+[0-9]+[A-Z0-9]+|[A-Z0-9]+_[A-Z0-9]+)");
95   }
96
97   /*
98    * (non-Javadoc)
99    * 
100    * @see jalview.ws.DbSourceProxy#getDbSource()
101    */
102   @Override
103   public String getDbSource()
104   {
105     return DBRefSource.UNIPROT;
106   }
107
108   /*
109    * (non-Javadoc)
110    * 
111    * @see jalview.ws.DbSourceProxy#getDbVersion()
112    */
113   @Override
114   public String getDbVersion()
115   {
116     return "0"; // we really don't know what version we're on.
117   }
118
119   /**
120    * Reads a file containing the reply to the EBI Fetch Uniprot data query,
121    * unmarshals it to a UniprotFile object, and returns the list of UniprotEntry
122    * data models (mapped from &lt;entry&gt; elements)
123    * 
124    * @param fileReader
125    * @return
126    */
127   public Vector<UniprotEntry> getUniprotEntries(Reader fileReader)
128   {
129     UniprotFile uni = new UniprotFile();
130     try
131     {
132       if (map == null)
133       {
134         // 1. Load the mapping information from the file
135         map = new Mapping(uni.getClass().getClassLoader());
136         URL url = getClass().getResource("/uniprot_mapping.xml");
137         map.loadMapping(url);
138       }
139
140       // 2. Unmarshal the data
141       Unmarshaller unmar = new Unmarshaller(uni);
142       unmar.setIgnoreExtraElements(true);
143       unmar.setMapping(map);
144       if (fileReader != null)
145       {
146         uni = (UniprotFile) unmar.unmarshal(fileReader);
147       }
148     } catch (Exception e)
149     {
150       System.out.println("Error getUniprotEntries() " + e);
151     }
152
153     return uni.getUniprotEntries();
154   }
155
156   /*
157    * (non-Javadoc)
158    * 
159    * @see jalview.ws.DbSourceProxy#getSequenceRecords(java.lang.String[])
160    */
161   @Override
162   public AlignmentI getSequenceRecords(String queries) throws Exception
163   {
164     startQuery();
165     try
166     {
167       queries = queries.toUpperCase().replaceAll(
168               "(UNIPROT\\|?|UNIPROT_|UNIREF\\d+_|UNIREF\\d+\\|?)", "");
169       AlignmentI al = null;
170
171       String downloadstring = "http://www.uniprot.org/uniprot/" + queries
172               + ".xml";
173       URL url = null;
174       URLConnection urlconn = null;
175
176       url = new URL(downloadstring);
177       urlconn = url.openConnection();
178       InputStream istr = urlconn.getInputStream();
179       Vector<UniprotEntry> entries = getUniprotEntries(
180               new InputStreamReader(istr, "UTF-8"));
181
182       if (entries != null)
183       {
184         ArrayList<SequenceI> seqs = new ArrayList<>();
185         for (UniprotEntry entry : entries)
186         {
187           seqs.add(uniprotEntryToSequenceI(entry));
188         }
189         al = new Alignment(seqs.toArray(new SequenceI[0]));
190
191       }
192       stopQuery();
193       return al;
194     } catch (Exception e)
195     {
196       throw (e);
197     } finally
198     {
199       stopQuery();
200     }
201   }
202
203   /**
204    * 
205    * @param entry
206    *          UniprotEntry
207    * @return SequenceI instance created from the UniprotEntry instance
208    */
209   public SequenceI uniprotEntryToSequenceI(UniprotEntry entry)
210   {
211     String id = getUniprotEntryId(entry, includeAllIds);
212     SequenceI sequence = new Sequence(id,
213             entry.getUniprotSequence().getContent());
214     sequence.setDescription(getUniprotEntryDescription(entry));
215
216     final String dbVersion = getDbVersion();
217     ArrayList<DBRefEntry> dbRefs = new ArrayList<>();
218     for (String accessionId : entry.getAccession())
219     {
220       DBRefEntry dbRef = new DBRefEntry(DBRefSource.UNIPROT, dbVersion,
221               accessionId);
222
223       // mark dbRef as a primary reference for this sequence
224       dbRefs.add(dbRef);
225     }
226
227     Vector<PDBEntry> onlyPdbEntries = new Vector<>();
228     for (PDBEntry pdb : entry.getDbReference())
229     {
230       DBRefEntry dbr = new DBRefEntry();
231       dbr.setSource(pdb.getType());
232       dbr.setAccessionId(pdb.getId());
233       dbr.setVersion(DBRefSource.UNIPROT + ":" + dbVersion);
234       dbRefs.add(dbr);
235       if ("PDB".equals(pdb.getType()))
236       {
237         onlyPdbEntries.addElement(pdb);
238       }
239       if ("EMBL".equals(pdb.getType()))
240       {
241         // look for a CDS reference and add it, too.
242         String cdsId = (String) pdb.getProperty("protein sequence ID");
243         if (cdsId != null && cdsId.trim().length() > 0)
244         {
245           // remove version
246           String[] vrs = cdsId.split("\\.");
247           dbr = new DBRefEntry(DBRefSource.EMBLCDS, vrs.length > 1 ? vrs[1]
248                   : DBRefSource.UNIPROT + ":" + dbVersion, vrs[0]);
249           dbRefs.add(dbr);
250         }
251       }
252       if ("Ensembl".equals(pdb.getType()))
253       {
254         /*UniprotXML
255          * <dbReference type="Ensembl" id="ENST00000321556">
256         * <molecule id="Q9BXM7-1"/>
257         * <property type="protein sequence ID" value="ENSP00000364204"/>
258         * <property type="gene ID" value="ENSG00000158828"/>
259         * </dbReference> 
260          */
261         String cdsId = (String) pdb.getProperty("protein sequence ID");
262         if (cdsId != null && cdsId.trim().length() > 0)
263         {
264           dbr = new DBRefEntry(DBRefSource.ENSEMBL,
265                   DBRefSource.UNIPROT + ":" + dbVersion, cdsId.trim());
266           dbRefs.add(dbr);
267
268         }
269       }
270     }
271
272     sequence.setPDBId(onlyPdbEntries);
273     if (entry.getFeature() != null)
274     {
275       for (UniprotFeature uf : entry.getFeature())
276       {
277         SequenceFeature copy = new SequenceFeature(uf.getType(),
278                 uf.getDescription(), uf.getBegin(), uf.getEnd(), "Uniprot");
279         copy.setStatus(uf.getStatus());
280         sequence.addSequenceFeature(copy);
281       }
282     }
283     for (DBRefEntry dbr : dbRefs)
284     {
285       sequence.addDBRef(dbr);
286     }
287     return sequence;
288   }
289
290   /**
291    * 
292    * @param entry
293    *          UniportEntry
294    * @return protein name(s) delimited by a white space character
295    */
296   public static String getUniprotEntryDescription(UniprotEntry entry)
297   {
298     StringBuilder desc = new StringBuilder(32);
299     if (entry.getProtein() != null && entry.getProtein().getName() != null)
300     {
301       boolean first = true;
302       for (String nm : entry.getProtein().getName())
303       {
304         if (!first)
305         {
306           desc.append(" ");
307         }
308         first = false;
309         desc.append(nm);
310       }
311     }
312     return desc.toString();
313   }
314
315   /**
316    *
317    * @param entry
318    *          UniportEntry
319    * @return The accession id(s) and name(s) delimited by '|'.
320    */
321   public static String getUniprotEntryId(UniprotEntry entry,
322           boolean includeAllIds)
323   {
324     StringBuilder name = new StringBuilder(32);
325     if (includeAllIds)
326     {
327       // // use 'canonicalised' name for optimal id matching
328       name.append(DBRefSource.UNIPROT);
329       for (String accessionId : entry.getAccession())
330       {
331         name.append(BAR_DELIMITER);
332         name.append(accessionId);
333       }
334
335     }
336     for (String n : entry.getName())
337     {
338       if (name.length() > 0)
339       {
340         name.append(BAR_DELIMITER);
341       }
342       name.append(n);
343     }
344     return name.toString();
345   }
346
347   /*
348    * (non-Javadoc)
349    * 
350    * @see jalview.ws.DbSourceProxy#isValidReference(java.lang.String)
351    */
352   @Override
353   public boolean isValidReference(String accession)
354   {
355     // TODO: make the following a standard validator
356     return (accession == null || accession.length() < 2) ? false
357             : getAccessionValidator().search(accession);
358   }
359
360   /**
361    * return LDHA_CHICK uniprot entry
362    */
363   @Override
364   public String getTestQuery()
365   {
366     return "P00340";
367   }
368
369   @Override
370   public String getDbName()
371   {
372     return "Uniprot"; // getDbSource();
373   }
374
375   @Override
376   public int getTier()
377   {
378     return 0;
379   }
380 }