inprogress
[jalview.git] / forester / java / src / org / forester / ws / seqdb / SequenceDbWsTools.java
1 // $Id:
2 // forester -- software libraries and applications
3 // for genomics and evolutionary biology research.
4 //
5 // Copyright (C) 2010 Christian M Zmasek
6 // Copyright (C) 2010 Sanford-Burnham Medical Research Institute
7 // All rights reserved
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 //
23 // Contact: phylosoft @ gmail . com
24 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
25
26 package org.forester.ws.seqdb;
27
28 import java.io.BufferedReader;
29 import java.io.IOException;
30 import java.io.InputStreamReader;
31 import java.io.UnsupportedEncodingException;
32 import java.net.URL;
33 import java.net.URLConnection;
34 import java.net.URLEncoder;
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.SortedSet;
38 import java.util.TreeSet;
39
40 import org.forester.phylogeny.Phylogeny;
41 import org.forester.phylogeny.PhylogenyNode;
42 import org.forester.phylogeny.data.Accession;
43 import org.forester.phylogeny.data.Identifier;
44 import org.forester.phylogeny.data.Sequence;
45 import org.forester.phylogeny.data.Taxonomy;
46 import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
47 import org.forester.util.ForesterUtil;
48 import org.forester.util.SequenceIdParser;
49
50 public final class SequenceDbWsTools {
51
52     private static final boolean ALLOW_TAXONOMY_CODE_HACKS = true;                                         //TODO turn off for final realease!
53     public final static String   BASE_UNIPROT_URL          = "http://www.uniprot.org/";
54     public final static String   BASE_EMBL_DB_URL          = "http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/";
55     public final static String   EMBL_DBS_EMBL             = "embl";
56     public final static String   EMBL_DBS_REFSEQ_P         = "refseqp";
57     public final static String   EMBL_DBS_REFSEQ_N         = "refseqn";
58     private final static String  URL_ENC                   = "UTF-8";
59     private final static boolean DEBUG                     = false;
60
61     public static List<UniProtTaxonomy> getTaxonomiesFromCommonName( final String cn, final int max_taxonomies_return )
62             throws IOException {
63         final List<String> result = getTaxonomyStringFromCommonName( cn, max_taxonomies_return );
64         if ( result.size() > 0 ) {
65             return parseUniProtTaxonomy( result );
66         }
67         return null;
68     }
69
70     public static List<UniProtTaxonomy> getTaxonomiesFromCommonNameStrict( final String cn,
71                                                                            final int max_taxonomies_return )
72             throws IOException {
73         final List<UniProtTaxonomy> taxonomies = getTaxonomiesFromCommonName( cn, max_taxonomies_return );
74         if ( ( taxonomies != null ) && ( taxonomies.size() > 0 ) ) {
75             final List<UniProtTaxonomy> filtered_taxonomies = new ArrayList<UniProtTaxonomy>();
76             for( final UniProtTaxonomy taxonomy : taxonomies ) {
77                 if ( taxonomy.getCommonName().equalsIgnoreCase( cn ) ) {
78                     filtered_taxonomies.add( taxonomy );
79                 }
80             }
81             return filtered_taxonomies;
82         }
83         return null;
84     }
85
86     public static List<UniProtTaxonomy> getTaxonomiesFromId( final String id, final int max_taxonomies_return )
87             throws IOException {
88         final List<String> result = getTaxonomyStringFromId( id, max_taxonomies_return );
89         if ( result.size() > 0 ) {
90             return parseUniProtTaxonomy( result );
91         }
92         return null;
93     }
94
95     public static List<UniProtTaxonomy> getTaxonomiesFromScientificName( final String sn,
96                                                                          final int max_taxonomies_return )
97             throws IOException {
98         // Hack!  Craniata? .. 
99         if ( sn.equals( "Drosophila" ) ) {
100             return uniProtTaxonomyToList( UniProtTaxonomy.DROSOPHILA_GENUS );
101         }
102         else if ( sn.equals( "Xenopus" ) ) {
103             return uniProtTaxonomyToList( UniProtTaxonomy.XENOPUS_GENUS );
104         }
105         // else if ( sn.equals( "Nucleariidae and Fonticula group" ) ) {
106         //     return hack( UniProtTaxonomy.NUCLEARIIDAE_AND_FONTICULA );
107         // }
108         final List<String> result = getTaxonomyStringFromScientificName( sn, max_taxonomies_return );
109         if ( result.size() > 0 ) {
110             return parseUniProtTaxonomy( result );
111         }
112         return null;
113     }
114
115     /**
116      * Does not return "sub-types".
117      * For example, for "Mus musculus" only returns "Mus musculus"
118      * and not "Mus musculus", "Mus musculus bactrianus", ...
119      * 
120      */
121     public static List<UniProtTaxonomy> getTaxonomiesFromScientificNameStrict( final String sn,
122                                                                                final int max_taxonomies_return )
123             throws IOException {
124         final List<UniProtTaxonomy> taxonomies = getTaxonomiesFromScientificName( sn, max_taxonomies_return );
125         if ( ( taxonomies != null ) && ( taxonomies.size() > 0 ) ) {
126             final List<UniProtTaxonomy> filtered_taxonomies = new ArrayList<UniProtTaxonomy>();
127             for( final UniProtTaxonomy taxonomy : taxonomies ) {
128                 if ( taxonomy.getScientificName().equalsIgnoreCase( sn ) ) {
129                     filtered_taxonomies.add( taxonomy );
130                 }
131             }
132             return filtered_taxonomies;
133         }
134         return null;
135     }
136
137     public static List<UniProtTaxonomy> getTaxonomiesFromTaxonomyCode( final String code,
138                                                                        final int max_taxonomies_return )
139             throws IOException {
140         final String my_code = new String( code );
141         if ( ALLOW_TAXONOMY_CODE_HACKS ) {
142             final List<UniProtTaxonomy> l = resolveFakeTaxonomyCodes( max_taxonomies_return, my_code );
143             if ( l != null ) {
144                 return l;
145             }
146         }
147         final List<String> result = getTaxonomyStringFromTaxonomyCode( my_code, max_taxonomies_return );
148         if ( result.size() > 0 ) {
149             return parseUniProtTaxonomy( result );
150         }
151         return null;
152     }
153
154     public static SequenceDatabaseEntry obtainEmblEntry( final Identifier id, final int max_lines_to_return )
155             throws IOException {
156         final List<String> lines = queryEmblDb( id, max_lines_to_return );
157         return EbiDbEntry.createInstanceFromPlainText( lines );
158     }
159
160     public static SequenceDatabaseEntry obtainRefSeqEntryFromEmbl( final Identifier id, final int max_lines_to_return )
161             throws IOException {
162         final List<String> lines = queryEmblDb( id, max_lines_to_return );
163         return EbiDbEntry.createInstanceFromPlainTextForRefSeq( lines );
164     }
165
166     public static SortedSet<String> obtainSeqInformation( final Phylogeny phy,
167                                                           final boolean ext_nodes_only,
168                                                           final boolean allow_to_set_taxonomic_data,
169                                                           final int lines_to_return ) throws IOException {
170         final SortedSet<String> not_found = new TreeSet<String>();
171         for( final PhylogenyNodeIterator iter = phy.iteratorPostorder(); iter.hasNext(); ) {
172             final PhylogenyNode node = iter.next();
173             if ( ext_nodes_only && node.isInternal() ) {
174                 continue;
175             }
176             String query = null;
177             Identifier id = null;
178             Db db = Db.NONE;
179             if ( node.getNodeData().isHasSequence() && ( node.getNodeData().getSequence().getAccession() != null )
180                     && !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().getSource() )
181                     && !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().getValue() )
182                     && node.getNodeData().getSequence().getAccession().getValue().toLowerCase().startsWith( "uniprot" ) ) {
183                 query = node.getNodeData().getSequence().getAccession().getValue();
184                 db = Db.UNIPROT;
185             }
186             else if ( node.getNodeData().isHasSequence()
187                     && ( node.getNodeData().getSequence().getAccession() != null )
188                     && !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().getSource() )
189                     && !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().getValue() )
190                     && ( node.getNodeData().getSequence().getAccession().getValue().toLowerCase().startsWith( "embl" ) || node
191                             .getNodeData().getSequence().getAccession().getValue().toLowerCase().startsWith( "ebi" ) ) ) {
192                 query = node.getNodeData().getSequence().getAccession().getValue();
193                 db = Db.EMBL;
194             }
195             else if ( !ForesterUtil.isEmpty( node.getName() ) ) {
196                 if ( ( query = ForesterUtil.extractUniProtKbProteinSeqIdentifier( node ) ) != null ) {
197                     db = Db.UNIPROT;
198                 }
199                 else if ( ( id = SequenceIdParser.parse( node.getName() ) ) != null ) {
200                     if ( id.getProvider().equalsIgnoreCase( Identifier.NCBI ) ) {
201                         db = Db.NCBI;
202                     }
203                     else if ( id.getProvider().equalsIgnoreCase( Identifier.REFSEQ ) ) {
204                         db = Db.REFSEQ;
205                     }
206                 }
207             }
208             if ( db == Db.NONE ) {
209                 not_found.add( node.getName() );
210             }
211             SequenceDatabaseEntry db_entry = null;
212             if ( !ForesterUtil.isEmpty( query ) ) {
213                 if ( db == Db.UNIPROT ) {
214                     if ( DEBUG ) {
215                         System.out.println( "uniprot: " + query );
216                     }
217                     db_entry = obtainUniProtEntry( query, lines_to_return );
218                 }
219                 if ( ( db == Db.EMBL ) || ( ( db == Db.UNIPROT ) && ( db_entry == null ) ) ) {
220                     if ( DEBUG ) {
221                         System.out.println( "embl: " + query );
222                     }
223                     db_entry = obtainEmblEntry( new Identifier( query ), lines_to_return );
224                     if ( ( db == Db.UNIPROT ) && ( db_entry != null ) ) {
225                         db = Db.EMBL;
226                     }
227                 }
228             }
229             else if ( ( db == Db.REFSEQ ) && ( id != null ) ) {
230                 db_entry = obtainRefSeqEntryFromEmbl( id, lines_to_return );
231             }
232             else if ( ( db == Db.NCBI ) && ( id != null ) ) {
233                 db_entry = obtainEmblEntry( id, lines_to_return ); //TODO ?
234             }
235             if ( ( db_entry != null ) && !db_entry.isEmpty() ) {
236                 final Sequence seq = node.getNodeData().isHasSequence() ? node.getNodeData().getSequence()
237                         : new Sequence();
238                 if ( !ForesterUtil.isEmpty( db_entry.getAccession() ) ) {
239                     String type = null;
240                     if ( db == Db.EMBL ) {
241                         type = "embl";
242                     }
243                     else if ( db == Db.UNIPROT ) {
244                         type = "uniprot";
245                     }
246                     else if ( db == Db.NCBI ) {
247                         type = "ncbi";
248                     }
249                     else if ( db == Db.REFSEQ ) {
250                         type = "refseq";
251                     }
252                     seq.setAccession( new Accession( db_entry.getAccession(), type ) );
253                 }
254                 if ( !ForesterUtil.isEmpty( db_entry.getSequenceName() ) ) {
255                     seq.setName( db_entry.getSequenceName() );
256                 }
257                 if ( !ForesterUtil.isEmpty( db_entry.getSequenceSymbol() ) ) {
258                     seq.setSymbol( db_entry.getSequenceSymbol() );
259                 }
260                 final Taxonomy tax = node.getNodeData().isHasTaxonomy() ? node.getNodeData().getTaxonomy()
261                         : new Taxonomy();
262                 if ( !ForesterUtil.isEmpty( db_entry.getTaxonomyScientificName() ) ) {
263                     tax.setScientificName( db_entry.getTaxonomyScientificName() );
264                 }
265                 if ( allow_to_set_taxonomic_data && !ForesterUtil.isEmpty( db_entry.getTaxonomyIdentifier() ) ) {
266                     tax.setIdentifier( new Identifier( db_entry.getTaxonomyIdentifier(), "uniprot" ) );
267                 }
268                 node.getNodeData().setTaxonomy( tax );
269                 node.getNodeData().setSequence( seq );
270             }
271             else if ( db != Db.NONE ) {
272                 not_found.add( node.getName() );
273             }
274             try {
275                 Thread.sleep( 10 );// Sleep for 10 ms
276             }
277             catch ( final InterruptedException ie ) {
278             }
279         }
280         return not_found;
281     }
282
283     public static SequenceDatabaseEntry obtainUniProtEntry( final String query, final int max_lines_to_return )
284             throws IOException {
285         final List<String> lines = queryUniprot( "uniprot/" + query + ".txt", max_lines_to_return );
286         return UniProtEntry.createInstanceFromPlainText( lines );
287     }
288
289     public static List<String> queryDb( final String query, int max_lines_to_return, final String base_url )
290             throws IOException {
291         if ( ForesterUtil.isEmpty( query ) ) {
292             throw new IllegalArgumentException( "illegal attempt to use empty query " );
293         }
294         if ( max_lines_to_return < 1 ) {
295             max_lines_to_return = 1;
296         }
297         final URL url = new URL( base_url + query );
298         if ( DEBUG ) {
299             System.out.println( "url: " + url.toString() );
300         }
301         final URLConnection urlc = url.openConnection();
302         final BufferedReader in = new BufferedReader( new InputStreamReader( urlc.getInputStream() ) );
303         String line;
304         final List<String> result = new ArrayList<String>();
305         while ( ( line = in.readLine() ) != null ) {
306             if ( DEBUG ) {
307                 System.out.println( line );
308             }
309             result.add( line );
310             if ( result.size() > max_lines_to_return ) {
311                 break;
312             }
313         }
314         in.close();
315         try {
316             // To prevent accessing online dbs in too quick succession. 
317             Thread.sleep( 20 );
318         }
319         catch ( final InterruptedException e ) {
320             e.printStackTrace();
321         }
322         return result;
323     }
324
325     public static List<String> queryEmblDb( final Identifier id, final int max_lines_to_return ) throws IOException {
326         final StringBuilder url_sb = new StringBuilder();
327         url_sb.append( BASE_EMBL_DB_URL );
328         if ( ForesterUtil.isEmpty( id.getProvider() ) || id.getProvider().equalsIgnoreCase( Identifier.NCBI ) ) {
329             url_sb.append( SequenceDbWsTools.EMBL_DBS_EMBL );
330             url_sb.append( '/' );
331         }
332         else if ( id.getProvider().equalsIgnoreCase( Identifier.REFSEQ ) ) {
333             if ( id.getValue().toUpperCase().indexOf( 'P' ) == 1 ) {
334                 url_sb.append( SequenceDbWsTools.EMBL_DBS_REFSEQ_P );
335                 url_sb.append( '/' );
336             }
337             else {
338                 url_sb.append( SequenceDbWsTools.EMBL_DBS_REFSEQ_N );
339                 url_sb.append( '/' );
340             }
341         }
342         return queryDb( id.getValue(), max_lines_to_return, url_sb.toString() );
343     }
344
345     public static List<String> queryUniprot( final String query, final int max_lines_to_return ) throws IOException {
346         return queryDb( query, max_lines_to_return, BASE_UNIPROT_URL );
347     }
348
349     private static String encode( final String str ) throws UnsupportedEncodingException {
350         return URLEncoder.encode( str.trim(), URL_ENC );
351     }
352
353     private static List<String> getTaxonomyStringFromCommonName( final String cn, final int max_lines_to_return )
354             throws IOException {
355         return queryUniprot( "taxonomy/?query=common%3a%22" + encode( cn ) + "%22&format=tab", max_lines_to_return );
356     }
357
358     private static List<String> getTaxonomyStringFromId( final String id, final int max_lines_to_return )
359             throws IOException {
360         return queryUniprot( "taxonomy/?query=id%3a%22" + encode( id ) + "%22&format=tab", max_lines_to_return );
361     }
362
363     private static List<String> getTaxonomyStringFromScientificName( final String sn, final int max_lines_to_return )
364             throws IOException {
365         return queryUniprot( "taxonomy/?query=scientific%3a%22" + encode( sn ) + "%22&format=tab", max_lines_to_return );
366     }
367
368     private static List<String> getTaxonomyStringFromTaxonomyCode( final String code, final int max_lines_to_return )
369             throws IOException {
370         return queryUniprot( "taxonomy/?query=mnemonic%3a%22" + encode( code ) + "%22&format=tab", max_lines_to_return );
371     }
372
373     private static List<UniProtTaxonomy> parseUniProtTaxonomy( final List<String> result ) throws IOException {
374         final List<UniProtTaxonomy> taxonomies = new ArrayList<UniProtTaxonomy>();
375         for( final String line : result ) {
376             if ( ForesterUtil.isEmpty( line ) ) {
377                 // Ignore empty lines.
378             }
379             else if ( line.startsWith( "Taxon" ) ) {
380                 final String[] items = line.split( "\t" );
381                 if ( !( items[ 1 ].equalsIgnoreCase( "Mnemonic" ) && items[ 2 ].equalsIgnoreCase( "Scientific name" )
382                         && items[ 3 ].equalsIgnoreCase( "Common name" ) && items[ 4 ].equalsIgnoreCase( "Synonym" )
383                         && items[ 5 ].equalsIgnoreCase( "Other Names" ) && items[ 6 ].equalsIgnoreCase( "Reviewed" )
384                         && items[ 7 ].equalsIgnoreCase( "Rank" ) && items[ 8 ].equalsIgnoreCase( "Lineage" ) ) ) {
385                     throw new IOException( "Unreconized UniProt Taxonomy format: " + line );
386                 }
387             }
388             else {
389                 if ( line.split( "\t" ).length > 4 ) {
390                     taxonomies.add( new UniProtTaxonomy( line ) );
391                 }
392             }
393         }
394         return taxonomies;
395     }
396
397     private static List<UniProtTaxonomy> resolveFakeTaxonomyCodes( final int max_taxonomies_return, final String code )
398             throws IOException {
399         if ( code.equals( "CAP" ) ) {
400             return getTaxonomiesFromId( "283909", max_taxonomies_return );
401         }
402         else if ( code.equals( "FUGRU" ) ) {
403             return getTaxonomiesFromId( "31033", max_taxonomies_return );
404         }
405         else if ( code.equals( "GIALA" ) ) {
406             return getTaxonomiesFromId( "5741", max_taxonomies_return );
407         }
408         else if ( code.equals( "TRIVE" ) ) {
409             return getTaxonomiesFromId( "413071", max_taxonomies_return );
410         }
411         else if ( code.equals( "CAPOWC" ) ) {
412             return getTaxonomiesFromId( "192875", max_taxonomies_return );
413         }
414         else if ( code.equals( "SPHARC" ) ) {
415             return getTaxonomiesFromId( "667725", max_taxonomies_return );
416         }
417         else if ( code.equals( "THETRA" ) ) {
418             return getTaxonomiesFromId( "529818", max_taxonomies_return );
419         }
420         else if ( code.equals( "CHLVUL" ) ) {
421             return getTaxonomiesFromId( "574566", max_taxonomies_return );
422         }
423         else if ( code.equals( "CITCLE" ) ) {
424             return getTaxonomiesFromId( "85681", max_taxonomies_return );
425         }
426         else if ( code.equals( "MYCPOP" ) ) {
427             return getTaxonomiesFromId( "85929", max_taxonomies_return );
428         }
429         else if ( code.equals( "AGABB" ) ) {
430             return getTaxonomiesFromId( "597362", max_taxonomies_return );
431         }
432         else if ( code.equals( "BAUCOM" ) ) {
433             return getTaxonomiesFromId( "430998", max_taxonomies_return );
434         }
435         else if ( code.equals( "DICSQU" ) ) {
436             return getTaxonomiesFromId( "114155", max_taxonomies_return );
437         }
438         else if ( code.equals( "FOMPIN" ) ) {
439             return getTaxonomiesFromId( "40483", max_taxonomies_return );
440         }
441         else if ( code.equals( "HYDMA" ) ) {
442             return getTaxonomiesFromId( "6085", max_taxonomies_return );
443         }
444         else if ( code.equals( "MYCFI" ) ) {
445             return getTaxonomiesFromId( "83344", max_taxonomies_return );
446         }
447         else if ( code.equals( "OIDMAI" ) ) {
448             return getTaxonomiesFromId( "78148", max_taxonomies_return );
449         }
450         else if ( code.equals( "OSTRC" ) ) {
451             return getTaxonomiesFromId( "385169", max_taxonomies_return );
452         }
453         else if ( code.equals( "POSPL" ) ) {
454             return getTaxonomiesFromId( "104341", max_taxonomies_return );
455         }
456         else if ( code.equals( "SAICOM" ) ) {
457             return getTaxonomiesFromId( "5606", max_taxonomies_return );
458         }
459         else if ( code.equals( "SERLA" ) ) {
460             return getTaxonomiesFromId( "85982", max_taxonomies_return );
461         }
462         else if ( code.equals( "SPORO" ) ) {
463             return getTaxonomiesFromId( "40563", max_taxonomies_return );
464         }
465         else if ( code.equals( "ACRALC" ) ) {
466             return getTaxonomiesFromId( "398408", max_taxonomies_return );
467         }
468         else if ( code.equals( "THITER" ) ) {
469             return getTaxonomiesFromId( "35720", max_taxonomies_return );
470         }
471         else if ( code.equals( "MYCTHE" ) ) {
472             return getTaxonomiesFromId( "78579", max_taxonomies_return );
473         }
474         else if ( code.equals( "CONPUT" ) ) {
475             return getTaxonomiesFromId( "80637", max_taxonomies_return );
476         }
477         else if ( code.equals( "WOLCOC" ) ) {
478             return getTaxonomiesFromId( "81056", max_taxonomies_return );
479         }
480         else if ( code.equals( "CLAGRA" ) ) {
481             return getTaxonomiesFromId( "27339", max_taxonomies_return );
482         }
483         else if ( code.equals( "XANPAR" ) ) {
484             return getTaxonomiesFromId( "107463", max_taxonomies_return );
485         }
486         else if ( code.equals( "HYDPIN" ) ) {
487             return getTaxonomiesFromId( "388859", max_taxonomies_return );
488         }
489         else if ( code.equals( "SERLAC" ) ) {
490             return getTaxonomiesFromId( "85982", max_taxonomies_return );
491         }
492         else {
493             return null;
494         }
495     }
496
497     private static List<UniProtTaxonomy> uniProtTaxonomyToList( final UniProtTaxonomy tax ) {
498         final List<UniProtTaxonomy> l = new ArrayList<UniProtTaxonomy>();
499         l.add( tax );
500         return l;
501     }
502
503     public enum Db {
504         UNIPROT, EMBL, NCBI, NONE, REFSEQ;
505     }
506 }