JAL-1780 JAL-653 Format/AppletFormat import and export pipeline regularised, uses...
[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
229             && entry.getProtein().getName() != null)
230     {
231       for (String nm : entry.getProtein().getName())
232       {
233         name.append(" ").append(nm);
234       }
235     }
236     return name;
237   }
238
239   /**
240    * add an ordered set of UniprotEntry objects to an ordered set of seuqences.
241    * 
242    * @param al
243    *          - a sequence of n sequences
244    * @param entries
245    *          a list of n uniprot entries to be analysed.
246    */
247   public void addUniprotXrefs(AlignmentI al, Vector<UniprotEntry> entries)
248   {
249     final String dbVersion = getDbVersion();
250
251     for (int i = 0; i < entries.size(); i++)
252     {
253       UniprotEntry entry = entries.elementAt(i);
254       Vector<PDBEntry> onlyPdbEntries = new Vector<PDBEntry>();
255       Vector<DBRefEntry> dbxrefs = new Vector<DBRefEntry>();
256
257       for (PDBEntry pdb : entry.getDbReference())
258       {
259         DBRefEntry dbr = new DBRefEntry();
260         dbr.setSource(pdb.getType());
261         dbr.setAccessionId(pdb.getId());
262         dbr.setVersion(DBRefSource.UNIPROT + ":" + dbVersion);
263         dbxrefs.addElement(dbr);
264         if ("PDB".equals(pdb.getType()))
265         {
266           onlyPdbEntries.addElement(pdb);
267         }
268       }
269
270       SequenceI sq = al.getSequenceAt(i);
271       while (sq.getDatasetSequence() != null)
272       {
273         sq = sq.getDatasetSequence();
274       }
275
276       for (String accessionId : entry.getAccession())
277       {
278         /*
279          * add as uniprot whether retrieved from uniprot or uniprot_name
280          */
281         sq.addDBRef(new DBRefEntry(DBRefSource.UNIPROT, dbVersion,
282                 accessionId));
283       }
284
285       for (DBRefEntry dbRef : dbxrefs)
286       {
287         sq.addDBRef(dbRef);
288       }
289       sq.setPDBId(onlyPdbEntries);
290       if (entry.getFeature() != null)
291       {
292         for (SequenceFeature sf : entry.getFeature())
293         {
294           sf.setFeatureGroup("Uniprot");
295           sq.addSequenceFeature(sf);
296         }
297       }
298     }
299   }
300
301   /*
302    * (non-Javadoc)
303    * 
304    * @see jalview.ws.DbSourceProxy#isValidReference(java.lang.String)
305    */
306   public boolean isValidReference(String accession)
307   {
308     // TODO: make the following a standard validator
309     return (accession == null || accession.length() < 2) ? false
310             : getAccessionValidator().search(accession);
311   }
312
313   /**
314    * return LDHA_CHICK uniprot entry
315    */
316   public String getTestQuery()
317   {
318     return "P00340";
319   }
320
321   public String getDbName()
322   {
323     return "Uniprot"; // getDbSource();
324   }
325
326   @Override
327   public int getTier()
328   {
329     return 0;
330   }
331 }