1e8eadba5dba1640396477d8fb9e2906b48a4475
[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.AlignmentI;
24 import jalview.datamodel.DBRefEntry;
25 import jalview.datamodel.DBRefSource;
26 import jalview.datamodel.PDBEntry;
27 import jalview.datamodel.SequenceFeature;
28 import jalview.datamodel.SequenceI;
29 import jalview.datamodel.UniprotEntry;
30 import jalview.datamodel.UniprotFile;
31 import jalview.ws.ebi.EBIFetchClient;
32 import jalview.ws.seqfetcher.DbSourceProxy;
33 import jalview.ws.seqfetcher.DbSourceProxyImpl;
34
35 import java.io.File;
36 import java.io.FileReader;
37 import java.io.Reader;
38 import java.util.Vector;
39
40 import org.exolab.castor.xml.Unmarshaller;
41
42 import com.stevesoft.pat.Regex;
43
44 /**
45  * @author JimP
46  * 
47  */
48 public class Uniprot extends DbSourceProxyImpl implements DbSourceProxy
49 {
50
51   private static final String BAR_DELIMITER = "|";
52
53   private static final String NEWLINE = "\n";
54
55   private static org.exolab.castor.mapping.Mapping map;
56
57   /**
58    * Constructor
59    */
60   public Uniprot()
61   {
62     super();
63     addDbSourceProperty(DBRefSource.SEQDB, DBRefSource.SEQDB);
64     addDbSourceProperty(DBRefSource.PROTSEQDB);
65     // addDbSourceProperty(DBRefSource.MULTIACC, new Integer(50));
66   }
67
68   /*
69    * (non-Javadoc)
70    * 
71    * @see jalview.ws.DbSourceProxy#getAccessionSeparator()
72    */
73   public String getAccessionSeparator()
74   {
75     return null; // ";";
76   }
77
78   /*
79    * (non-Javadoc)
80    * 
81    * @see jalview.ws.DbSourceProxy#getAccessionValidator()
82    */
83   public Regex getAccessionValidator()
84   {
85     return new Regex("([A-Z]+[0-9]+[A-Z0-9]+|[A-Z0-9]+_[A-Z0-9]+)");
86   }
87
88   /*
89    * (non-Javadoc)
90    * 
91    * @see jalview.ws.DbSourceProxy#getDbSource()
92    */
93   public String getDbSource()
94   {
95     return DBRefSource.UNIPROT;
96   }
97
98   /*
99    * (non-Javadoc)
100    * 
101    * @see jalview.ws.DbSourceProxy#getDbVersion()
102    */
103   public String getDbVersion()
104   {
105     return "0"; // we really don't know what version we're on.
106   }
107
108   /**
109    * Reads a file containing the reply to the EBI Fetch Uniprot data query,
110    * unmarshals it to a UniprotFile object, and returns the list of UniprotEntry
111    * data models (mapped from &lt;entry&gt; elements)
112    * 
113    * @param fileReader
114    * @return
115    */
116   public Vector<UniprotEntry> getUniprotEntries(Reader fileReader)
117   {
118     UniprotFile uni = new UniprotFile();
119     try
120     {
121       if (map == null)
122       {
123         // 1. Load the mapping information from the file
124         map = new org.exolab.castor.mapping.Mapping(uni.getClass()
125                 .getClassLoader());
126         java.net.URL url = getClass().getResource("/uniprot_mapping.xml");
127         map.loadMapping(url);
128       }
129
130       // 2. Unmarshal the data
131       Unmarshaller unmar = new Unmarshaller(uni);
132       unmar.setIgnoreExtraElements(true);
133       unmar.setMapping(map);
134       if (fileReader != null)
135       {
136         uni = (UniprotFile) unmar.unmarshal(fileReader);
137       }
138     } catch (Exception e)
139     {
140       System.out.println("Error getUniprotEntries() " + e);
141     }
142
143     return uni.getUniprotEntries();
144   }
145
146   /*
147    * (non-Javadoc)
148    * 
149    * @see jalview.ws.DbSourceProxy#getSequenceRecords(java.lang.String[])
150    */
151   public AlignmentI getSequenceRecords(String queries) throws Exception
152   {
153     startQuery();
154     try
155     {
156       queries = queries.toUpperCase().replaceAll(
157               "(UNIPROT\\|?|UNIPROT_|UNIREF\\d+_|UNIREF\\d+\\|?)", "");
158       AlignmentI al = null;
159       EBIFetchClient ebi = new EBIFetchClient();
160       // uniprotxml parameter required since december 2007
161       // uniprotkb dbname changed introduced december 2008
162       File file = ebi.fetchDataAsFile("uniprotkb:" + queries, "uniprotxml",
163               null);
164       Vector<UniprotEntry> entries = getUniprotEntries(new FileReader(file));
165
166       if (entries != null)
167       {
168         /*
169          * If Castor binding included sequence@length, we could guesstimate the
170          * size of buffer to hold the alignment
171          */
172         StringBuffer result = new StringBuffer(128);
173         // First, make the new sequences
174         for (UniprotEntry entry : entries)
175         {
176           StringBuilder name = constructSequenceFastaHeader(entry);
177
178           result.append(name).append(NEWLINE)
179                   .append(entry.getUniprotSequence().getContent())
180                   .append(NEWLINE);
181         }
182
183         // Then read in the features and apply them to the dataset
184         al = parseResult(result.toString());
185         if (al != null)
186         {
187           // Decorate the alignment with database entries.
188           addUniprotXrefs(al, entries);
189         }
190         else
191         {
192           results = result;
193         }
194       }
195       stopQuery();
196       return al;
197     } catch (Exception e)
198     {
199       stopQuery();
200       throw (e);
201     }
202   }
203
204   /**
205    * Construct a Fasta-format sequence header by concatenating the source,
206    * accession id(s) and name(s), delimited by '|', plus any protein names, now
207    * with space rather than bar delimiter
208    * 
209    * @param entry
210    * @return
211    */
212   public static StringBuilder constructSequenceFastaHeader(
213           UniprotEntry entry)
214   {
215     StringBuilder name = new StringBuilder(32);
216     name.append(">UniProt/Swiss-Prot");
217     for (String accessionId : entry.getAccession())
218     {
219       name.append(BAR_DELIMITER);
220       name.append(accessionId);
221     }
222     for (String n : entry.getName())
223     {
224       name.append(BAR_DELIMITER);
225       name.append(n);
226     }
227
228     if (entry.getProtein() != null && entry.getProtein().getName() != null)
229     {
230       for (String nm : entry.getProtein().getName())
231       {
232         name.append(" ").append(nm);
233       }
234     }
235     return name;
236   }
237
238   /**
239    * add an ordered set of UniprotEntry objects to an ordered set of seuqences.
240    * 
241    * @param al
242    *          - a sequence of n sequences
243    * @param entries
244    *          a list of n uniprot entries to be analysed.
245    */
246   public void addUniprotXrefs(AlignmentI al, Vector<UniprotEntry> entries)
247   {
248     final String dbVersion = getDbVersion();
249
250     for (int i = 0; i < entries.size(); i++)
251     {
252       UniprotEntry entry = entries.elementAt(i);
253       Vector<PDBEntry> onlyPdbEntries = new Vector<PDBEntry>();
254       Vector<DBRefEntry> dbxrefs = new Vector<DBRefEntry>();
255
256       for (PDBEntry pdb : entry.getDbReference())
257       {
258         DBRefEntry dbr = new DBRefEntry();
259         dbr.setSource(pdb.getType());
260         dbr.setAccessionId(pdb.getId());
261         dbr.setVersion(DBRefSource.UNIPROT + ":" + dbVersion);
262         dbxrefs.addElement(dbr);
263         if ("PDB".equals(pdb.getType()))
264         {
265           onlyPdbEntries.addElement(pdb);
266         }
267       }
268
269       SequenceI sq = al.getSequenceAt(i);
270       while (sq.getDatasetSequence() != null)
271       {
272         sq = sq.getDatasetSequence();
273       }
274
275       for (String accessionId : entry.getAccession())
276       {
277         /*
278          * add as uniprot whether retrieved from uniprot or uniprot_name
279          */
280         sq.addDBRef(new DBRefEntry(DBRefSource.UNIPROT, dbVersion,
281                 accessionId));
282       }
283
284       for (DBRefEntry dbRef : dbxrefs)
285       {
286         sq.addDBRef(dbRef);
287       }
288       sq.setPDBId(onlyPdbEntries);
289       if (entry.getFeature() != null)
290       {
291         for (SequenceFeature sf : entry.getFeature())
292         {
293           sf.setFeatureGroup("Uniprot");
294           sq.addSequenceFeature(sf);
295         }
296       }
297     }
298   }
299
300   /*
301    * (non-Javadoc)
302    * 
303    * @see jalview.ws.DbSourceProxy#isValidReference(java.lang.String)
304    */
305   public boolean isValidReference(String accession)
306   {
307     // TODO: make the following a standard validator
308     return (accession == null || accession.length() < 2) ? false
309             : getAccessionValidator().search(accession);
310   }
311
312   /**
313    * return LDHA_CHICK uniprot entry
314    */
315   public String getTestQuery()
316   {
317     return "P00340";
318   }
319
320   public String getDbName()
321   {
322     return "Uniprot"; // getDbSource();
323   }
324
325   @Override
326   public int getTier()
327   {
328     return 0;
329   }
330 }