JAL-653 JAL-1780 reorder imports
[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.SequenceFeature;
29 import jalview.datamodel.SequenceI;
30 import jalview.datamodel.UniprotEntry;
31 import jalview.datamodel.UniprotFile;
32 import jalview.ws.ebi.EBIFetchClient;
33 import jalview.ws.seqfetcher.DbSourceProxy;
34 import jalview.ws.seqfetcher.DbSourceProxyImpl;
35
36 import java.io.File;
37 import java.io.FileReader;
38 import java.io.Reader;
39 import java.util.Vector;
40
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 implements DbSourceProxy
50 {
51
52   private static final String BAR_DELIMITER = "|";
53
54   private static final String NEWLINE = "\n";
55
56   private static org.exolab.castor.mapping.Mapping map;
57
58   /**
59    * Constructor
60    */
61   public Uniprot()
62   {
63     super();
64     addDbSourceProperty(DBRefSource.SEQDB, DBRefSource.SEQDB);
65     addDbSourceProperty(DBRefSource.PROTSEQDB);
66     // addDbSourceProperty(DBRefSource.MULTIACC, new Integer(50));
67   }
68
69   /*
70    * (non-Javadoc)
71    * 
72    * @see jalview.ws.DbSourceProxy#getAccessionSeparator()
73    */
74   public String getAccessionSeparator()
75   {
76     return null; // ";";
77   }
78
79   /*
80    * (non-Javadoc)
81    * 
82    * @see jalview.ws.DbSourceProxy#getAccessionValidator()
83    */
84   public Regex getAccessionValidator()
85   {
86     return new Regex("([A-Z]+[0-9]+[A-Z0-9]+|[A-Z0-9]+_[A-Z0-9]+)");
87   }
88
89   /*
90    * (non-Javadoc)
91    * 
92    * @see jalview.ws.DbSourceProxy#getDbSource()
93    */
94   public String getDbSource()
95   {
96     return DBRefSource.UNIPROT;
97   }
98
99   /*
100    * (non-Javadoc)
101    * 
102    * @see jalview.ws.DbSourceProxy#getDbVersion()
103    */
104   public String getDbVersion()
105   {
106     return "0"; // we really don't know what version we're on.
107   }
108
109   /**
110    * Reads a file containing the reply to the EBI Fetch Uniprot data query,
111    * unmarshals it to a UniprotFile object, and returns the list of UniprotEntry
112    * data models (mapped from &lt;entry&gt; elements)
113    * 
114    * @param fileReader
115    * @return
116    */
117   public Vector<UniprotEntry> getUniprotEntries(Reader fileReader)
118   {
119     UniprotFile uni = new UniprotFile();
120     try
121     {
122       if (map == null)
123       {
124         // 1. Load the mapping information from the file
125         map = new org.exolab.castor.mapping.Mapping(uni.getClass()
126                 .getClassLoader());
127         java.net.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   public AlignmentI getSequenceRecords(String queries) throws Exception
153   {
154     startQuery();
155     try
156     {
157       queries = queries.toUpperCase().replaceAll(
158               "(UNIPROT\\|?|UNIPROT_|UNIREF\\d+_|UNIREF\\d+\\|?)", "");
159       Alignment al = null;
160       EBIFetchClient ebi = new EBIFetchClient();
161       // uniprotxml parameter required since december 2007
162       // uniprotkb dbname changed introduced december 2008
163       File file = ebi.fetchDataAsFile("uniprotkb:" + queries, "uniprotxml",
164               null);
165       Vector<UniprotEntry> entries = getUniprotEntries(new FileReader(file));
166
167       if (entries != null)
168       {
169         /*
170          * If Castor binding included sequence@length, we could guesstimate the
171          * size of buffer to hold the alignment
172          */
173         StringBuffer result = new StringBuffer(128);
174         // First, make the new sequences
175         for (UniprotEntry entry : entries)
176         {
177           StringBuilder name = constructSequenceFastaHeader(entry);
178
179           result.append(name).append(NEWLINE)
180                   .append(entry.getUniprotSequence().getContent())
181                   .append(NEWLINE);
182         }
183
184         // Then read in the features and apply them to the dataset
185         al = parseResult(result.toString());
186         if (al != null)
187         {
188           // Decorate the alignment with database entries.
189           addUniprotXrefs(al, entries);
190         }
191         else
192         {
193           results = result;
194         }
195       }
196       stopQuery();
197       return al;
198     } catch (Exception e)
199     {
200       stopQuery();
201       throw (e);
202     }
203   }
204
205   /**
206    * Construct a Fasta-format sequence header by concatenating the source,
207    * accession id(s) and name(s), delimited by '|', plus any protein names, now
208    * with space rather than bar delimiter
209    * 
210    * @param entry
211    * @return
212    */
213   public static StringBuilder constructSequenceFastaHeader(
214           UniprotEntry entry)
215   {
216     StringBuilder name = new StringBuilder(32);
217     name.append(">UniProt/Swiss-Prot");
218     for (String accessionId : entry.getAccession())
219     {
220       name.append(BAR_DELIMITER);
221       name.append(accessionId);
222     }
223     for (String n : entry.getName())
224     {
225       name.append(BAR_DELIMITER);
226       name.append(n);
227     }
228
229     if (entry.getProtein() != null
230             && 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(Alignment 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   public boolean isValidReference(String accession)
308   {
309     // TODO: make the following a standard validator
310     return (accession == null || accession.length() < 2) ? false
311             : getAccessionValidator().search(accession);
312   }
313
314   /**
315    * return LDHA_CHICK uniprot entry
316    */
317   public String getTestQuery()
318   {
319     return "P00340";
320   }
321
322   public String getDbName()
323   {
324     return "Uniprot"; // getDbSource();
325   }
326
327   @Override
328   public int getTier()
329   {
330     return 0;
331   }
332 }