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