17c56d1bb2818bcc953d9b53cd59da219071bdb6
[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.FileNotFoundException;
30 import java.io.IOException;
31 import java.io.InputStreamReader;
32 import java.io.UnsupportedEncodingException;
33 import java.net.URL;
34 import java.net.URLConnection;
35 import java.net.URLEncoder;
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.SortedSet;
39 import java.util.TreeSet;
40
41 import org.forester.go.GoTerm;
42 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
43 import org.forester.phylogeny.Phylogeny;
44 import org.forester.phylogeny.PhylogenyNode;
45 import org.forester.phylogeny.data.Accession;
46 import org.forester.phylogeny.data.Annotation;
47 import org.forester.phylogeny.data.Identifier;
48 import org.forester.phylogeny.data.Sequence;
49 import org.forester.phylogeny.data.Taxonomy;
50 import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
51 import org.forester.util.ForesterUtil;
52 import org.forester.util.SequenceAccessionTools;
53
54 public final class SequenceDbWsTools {
55
56     public final static String   BASE_UNIPROT_URL  = "http://www.uniprot.org/";
57     public final static String   BASE_EMBL_DB_URL  = "http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/";
58     public final static String   EMBL_DBS_EMBL     = "embl";
59     public final static String   EMBL_DBS_REFSEQ_P = "refseqp";
60     public final static String   EMBL_DBS_REFSEQ_N = "refseqn";
61     private final static String  URL_ENC           = "UTF-8";
62     private final static boolean DEBUG             = true;
63
64     private static List<UniProtTaxonomy> getTaxonomiesFromCommonName( final String cn, final int max_taxonomies_return )
65             throws IOException {
66         final List<String> result = getTaxonomyStringFromCommonName( cn, max_taxonomies_return );
67         if ( result.size() > 0 ) {
68             return parseUniProtTaxonomy( result );
69         }
70         return null;
71     }
72
73     public static List<UniProtTaxonomy> getTaxonomiesFromCommonNameStrict( final String cn,
74                                                                            final int max_taxonomies_return )
75             throws IOException {
76         final List<UniProtTaxonomy> taxonomies = getTaxonomiesFromCommonName( cn, max_taxonomies_return );
77         if ( ( taxonomies != null ) && ( taxonomies.size() > 0 ) ) {
78             final List<UniProtTaxonomy> filtered_taxonomies = new ArrayList<UniProtTaxonomy>();
79             for( final UniProtTaxonomy taxonomy : taxonomies ) {
80                 if ( taxonomy.getCommonName().equalsIgnoreCase( cn ) ) {
81                     filtered_taxonomies.add( taxonomy );
82                 }
83             }
84             return filtered_taxonomies;
85         }
86         return null;
87     }
88
89     public static List<UniProtTaxonomy> getTaxonomiesFromId( final String id, final int max_taxonomies_return )
90             throws IOException {
91         final List<String> result = getTaxonomyStringFromId( id, max_taxonomies_return );
92         if ( result.size() > 0 ) {
93             return parseUniProtTaxonomy( result );
94         }
95         return null;
96     }
97
98     private static List<UniProtTaxonomy> getTaxonomiesFromScientificName( final String sn,
99                                                                           final int max_taxonomies_return )
100             throws IOException {
101         final List<String> result = getTaxonomyStringFromScientificName( sn, max_taxonomies_return );
102         if ( result.size() > 0 ) {
103             return parseUniProtTaxonomy( result );
104         }
105         return null;
106     }
107
108     /**
109      * Does not return "sub-types".
110      * For example, for "Mus musculus" only returns "Mus musculus"
111      * and not "Mus musculus", "Mus musculus bactrianus", ...
112      * 
113      */
114     public static List<UniProtTaxonomy> getTaxonomiesFromScientificNameStrict( final String sn,
115                                                                                final int max_taxonomies_return )
116             throws IOException {
117         final List<UniProtTaxonomy> taxonomies = getTaxonomiesFromScientificName( sn, max_taxonomies_return );
118         if ( ( taxonomies != null ) && ( taxonomies.size() > 0 ) ) {
119             final List<UniProtTaxonomy> filtered_taxonomies = new ArrayList<UniProtTaxonomy>();
120             for( final UniProtTaxonomy taxonomy : taxonomies ) {
121                 if ( taxonomy.getScientificName().equalsIgnoreCase( sn ) ) {
122                     filtered_taxonomies.add( taxonomy );
123                 }
124             }
125             return filtered_taxonomies;
126         }
127         return null;
128     }
129
130     public static List<UniProtTaxonomy> getTaxonomiesFromTaxonomyCode( final String code,
131                                                                        final int max_taxonomies_return )
132             throws IOException {
133         final String my_code = new String( code );
134         final List<String> result = getTaxonomyStringFromTaxonomyCode( my_code, max_taxonomies_return );
135         if ( result.size() > 0 ) {
136             return parseUniProtTaxonomy( result );
137         }
138         return null;
139     }
140
141     public static SequenceDatabaseEntry obtainEmblEntry( final Accession id, final int max_lines_to_return )
142             throws IOException {
143         final List<String> lines = queryEmblDb( id, max_lines_to_return );
144         return EbiDbEntry.createInstanceFromPlainText( lines );
145     }
146
147     public static SequenceDatabaseEntry obtainRefSeqEntryFromEmbl( final Accession id, final int max_lines_to_return )
148             throws IOException {
149         final List<String> lines = queryEmblDb( id, max_lines_to_return );
150         return EbiDbEntry.createInstanceFromPlainTextForRefSeq( lines );
151     }
152
153     public static SortedSet<String> obtainSeqInformation( final Phylogeny phy,
154                                                           final boolean ext_nodes_only,
155                                                           final boolean allow_to_set_taxonomic_data,
156                                                           final int lines_to_return ) throws IOException {
157         final SortedSet<String> not_found = new TreeSet<String>();
158         for( final PhylogenyNodeIterator iter = phy.iteratorPostorder(); iter.hasNext(); ) {
159             final PhylogenyNode node = iter.next();
160             if ( ext_nodes_only && node.isInternal() ) {
161                 continue;
162             }
163             Accession acc = SequenceAccessionTools.obtainFromSeqAccession( node );
164             if ( ( acc == null )
165                     || ForesterUtil.isEmpty( acc.getSource() )
166                     || ForesterUtil.isEmpty( acc.getValue() )
167                     || ( ( acc.getSource() != Accession.UNIPROT ) && ( acc.getSource() != Accession.EMBL ) && ( acc
168                             .getSource() != Accession.REFSEQ ) ) ) {
169                 acc = SequenceAccessionTools.obtainAccessorFromDataFields( node );
170             }
171             if ( ( acc == null )
172                     || ForesterUtil.isEmpty( acc.getSource() )
173                     || ForesterUtil.isEmpty( acc.getValue() )
174                     || ( ( acc.getSource() != Accession.UNIPROT ) && ( acc.getSource() != Accession.EMBL ) && ( acc
175                             .getSource() != Accession.REFSEQ ) ) ) {
176                 not_found.add( node.toString() );
177             }
178             else {
179                 SequenceDatabaseEntry db_entry = null;
180                 final String query = acc.getValue();
181                 if ( acc.getSource() == Accession.UNIPROT ) {
182                     if ( DEBUG ) {
183                         System.out.println( "uniprot: " + query );
184                     }
185                     try {
186                         db_entry = obtainUniProtEntry( query, lines_to_return );
187                     }
188                     catch ( FileNotFoundException e ) {
189                         // Eat this, and move to next.
190                     }
191                 }
192                 else if ( acc.getSource() == Accession.EMBL ) {
193                     if ( DEBUG ) {
194                         System.out.println( "embl: " + query );
195                     }
196                     try {
197                         db_entry = obtainEmblEntry( new Accession( query ), lines_to_return );
198                     }
199                     catch ( FileNotFoundException e ) {
200                         // Eat this, and move to next.
201                     }
202                 }
203                 else if ( acc.getSource() == Accession.REFSEQ ) {
204                     if ( DEBUG ) {
205                         System.out.println( "refseq: " + query );
206                     }
207                     try {
208                         db_entry = obtainRefSeqEntryFromEmbl( new Accession( query ), lines_to_return );
209                     }
210                     catch ( FileNotFoundException e ) {
211                         // Eat this, and move to next.
212                     }
213                 }
214                 if ( ( db_entry != null ) && !db_entry.isEmpty() ) {
215                     final Sequence seq = node.getNodeData().isHasSequence() ? node.getNodeData().getSequence()
216                             : new Sequence();
217                     if ( !ForesterUtil.isEmpty( db_entry.getAccession() ) ) {
218                         seq.setAccession( new Accession( db_entry.getAccession(), acc.getSource() ) );
219                     }
220                     if ( !ForesterUtil.isEmpty( db_entry.getSequenceName() ) ) {
221                         seq.setName( db_entry.getSequenceName() );
222                     }
223                     if ( !ForesterUtil.isEmpty( db_entry.getGeneName() ) ) {
224                         seq.setGeneName( db_entry.getGeneName() );
225                     }
226                     if ( !ForesterUtil.isEmpty( db_entry.getSequenceSymbol() ) ) {
227                         try {
228                             seq.setSymbol( db_entry.getSequenceSymbol() );
229                         }
230                         catch ( final PhyloXmlDataFormatException e ) {
231                             // Eat this exception.
232                         }
233                     }
234                     if ( ( db_entry.getGoTerms() != null ) && !db_entry.getGoTerms().isEmpty() ) {
235                         for( final GoTerm go : db_entry.getGoTerms() ) {
236                             final Annotation ann = new Annotation( go.getGoId().getId() );
237                             ann.setDesc( go.getName() );
238                             seq.addAnnotation( ann );
239                         }
240                     }
241                     if ( ( db_entry.getCrossReferences() != null ) && !db_entry.getCrossReferences().isEmpty() ) {
242                         for( final Accession x : db_entry.getCrossReferences() ) {
243                             seq.addCrossReference( x );
244                         }
245                     }
246                     final Taxonomy tax = node.getNodeData().isHasTaxonomy() ? node.getNodeData().getTaxonomy()
247                             : new Taxonomy();
248                     if ( !ForesterUtil.isEmpty( db_entry.getTaxonomyScientificName() ) ) {
249                         tax.setScientificName( db_entry.getTaxonomyScientificName() );
250                     }
251                     if ( allow_to_set_taxonomic_data && !ForesterUtil.isEmpty( db_entry.getTaxonomyIdentifier() ) ) {
252                         tax.setIdentifier( new Identifier( db_entry.getTaxonomyIdentifier(), "uniprot" ) );
253                     }
254                     node.getNodeData().setTaxonomy( tax );
255                     node.getNodeData().setSequence( seq );
256                 }
257                 else {
258                     node.i
259                     not_found.add( node.getName() );
260                 }
261                 try {
262                     Thread.sleep( 10 );// Sleep for 10 ms
263                 }
264                 catch ( final InterruptedException ie ) {
265                 }
266             }
267         }
268         return not_found;
269     }
270
271     public static SequenceDatabaseEntry obtainUniProtEntry( final String query, final int max_lines_to_return )
272             throws IOException {
273         final List<String> lines = queryUniprot( "uniprot/" + query + ".txt", max_lines_to_return );
274         return UniProtEntry.createInstanceFromPlainText( lines );
275     }
276
277     public static List<String> queryDb( final String query, int max_lines_to_return, final String base_url )
278             throws IOException {
279         if ( ForesterUtil.isEmpty( query ) ) {
280             throw new IllegalArgumentException( "illegal attempt to use empty query " );
281         }
282         if ( max_lines_to_return < 1 ) {
283             max_lines_to_return = 1;
284         }
285         final URL url = new URL( base_url + query );
286         if ( DEBUG ) {
287             System.out.println( "url: " + url.toString() );
288         }
289         final URLConnection urlc = url.openConnection();
290         final BufferedReader in = new BufferedReader( new InputStreamReader( urlc.getInputStream() ) );
291         String line;
292         final List<String> result = new ArrayList<String>();
293         while ( ( line = in.readLine() ) != null ) {
294             if ( DEBUG ) {
295                 System.out.println( line );
296             }
297             result.add( line );
298             if ( result.size() > max_lines_to_return ) {
299                 break;
300             }
301         }
302         in.close();
303         try {
304             // To prevent accessing online dbs in too quick succession. 
305             Thread.sleep( 20 );
306         }
307         catch ( final InterruptedException e ) {
308             e.printStackTrace();
309         }
310         return result;
311     }
312
313     public static List<String> queryEmblDb( final Accession id, final int max_lines_to_return ) throws IOException {
314         final StringBuilder url_sb = new StringBuilder();
315         url_sb.append( BASE_EMBL_DB_URL );
316         if ( ForesterUtil.isEmpty( id.getSource() ) || ( id.getSource() == Accession.NCBI ) ) {
317             url_sb.append( SequenceDbWsTools.EMBL_DBS_EMBL );
318             url_sb.append( '/' );
319         }
320         else if ( id.getSource() == Accession.REFSEQ ) {
321             if ( id.getValue().toUpperCase().indexOf( 'P' ) == 1 ) {
322                 url_sb.append( SequenceDbWsTools.EMBL_DBS_REFSEQ_P );
323                 url_sb.append( '/' );
324             }
325             else {
326                 url_sb.append( SequenceDbWsTools.EMBL_DBS_REFSEQ_N );
327                 url_sb.append( '/' );
328             }
329         }
330         return queryDb( id.getValue(), max_lines_to_return, url_sb.toString() );
331     }
332
333     public static List<String> queryUniprot( final String query, final int max_lines_to_return ) throws IOException {
334         return queryDb( query, max_lines_to_return, BASE_UNIPROT_URL );
335     }
336
337     private static String encode( final String str ) throws UnsupportedEncodingException {
338         return URLEncoder.encode( str.trim(), URL_ENC );
339     }
340
341     private static List<String> getTaxonomyStringFromCommonName( final String cn, final int max_lines_to_return )
342             throws IOException {
343         return queryUniprot( "taxonomy/?query=common%3a%22" + encode( cn ) + "%22&format=tab", max_lines_to_return );
344     }
345
346     private static List<String> getTaxonomyStringFromId( final String id, final int max_lines_to_return )
347             throws IOException {
348         return queryUniprot( "taxonomy/?query=id%3a%22" + encode( id ) + "%22&format=tab", max_lines_to_return );
349     }
350
351     private static List<String> getTaxonomyStringFromScientificName( final String sn, final int max_lines_to_return )
352             throws IOException {
353         return queryUniprot( "taxonomy/?query=scientific%3a%22" + encode( sn ) + "%22&format=tab", max_lines_to_return );
354     }
355
356     private static List<String> getTaxonomyStringFromTaxonomyCode( final String code, final int max_lines_to_return )
357             throws IOException {
358         return queryUniprot( "taxonomy/?query=mnemonic%3a%22" + encode( code ) + "%22&format=tab", max_lines_to_return );
359     }
360
361     private static List<UniProtTaxonomy> parseUniProtTaxonomy( final List<String> result ) throws IOException {
362         final List<UniProtTaxonomy> taxonomies = new ArrayList<UniProtTaxonomy>();
363         for( final String line : result ) {
364             if ( ForesterUtil.isEmpty( line ) ) {
365                 // Ignore empty lines.
366             }
367             else if ( line.startsWith( "Taxon" ) ) {
368                 final String[] items = line.split( "\t" );
369                 if ( !( items[ 1 ].equalsIgnoreCase( "Mnemonic" ) && items[ 2 ].equalsIgnoreCase( "Scientific name" )
370                         && items[ 3 ].equalsIgnoreCase( "Common name" ) && items[ 4 ].equalsIgnoreCase( "Synonym" )
371                         && items[ 5 ].equalsIgnoreCase( "Other Names" ) && items[ 6 ].equalsIgnoreCase( "Reviewed" )
372                         && items[ 7 ].equalsIgnoreCase( "Rank" ) && items[ 8 ].equalsIgnoreCase( "Lineage" ) ) ) {
373                     throw new IOException( "Unreconized UniProt Taxonomy format: " + line );
374                 }
375             }
376             else {
377                 if ( line.split( "\t" ).length > 4 ) {
378                     taxonomies.add( new UniProtTaxonomy( line ) );
379                 }
380             }
381         }
382         return taxonomies;
383     }
384 }