Removed dependency for Jersey webservice lib and updated code to use HttpClientUtils...
[jalview.git] / src / jalview / ws / SequenceFetcher.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 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;
22
23 import jalview.datamodel.Alignment;
24 import jalview.datamodel.AlignmentI;
25 import jalview.datamodel.DBRefSource;
26 import jalview.datamodel.SequenceI;
27 import jalview.ws.dbsources.das.api.jalviewSourceI;
28 import jalview.ws.seqfetcher.ASequenceFetcher;
29 import jalview.ws.seqfetcher.DbSourceProxy;
30
31 import java.util.ArrayList;
32 import java.util.Enumeration;
33 import java.util.List;
34 import java.util.Vector;
35
36 /**
37  * This is the the concrete implementation of the sequence retrieval interface
38  * and abstract class in jalview.ws.seqfetcher. This implements the run-time
39  * discovery of sequence database clients, and provides a hardwired main for
40  * testing all registered handlers.
41  *
42  */
43 public class SequenceFetcher extends ASequenceFetcher
44 {
45   /**
46    * Thread safe construction of database proxies TODO: extend to a configurable
47    * database plugin mechanism where classes are instantiated by reflection and
48    * queried for their DbRefSource and version association.
49    *
50    */
51   public SequenceFetcher()
52   {
53     this(true);
54   }
55
56   public SequenceFetcher(boolean addDas)
57   {
58     addDBRefSourceImpl(jalview.ws.dbsources.EmblSource.class);
59     addDBRefSourceImpl(jalview.ws.dbsources.EmblCdsSouce.class);
60     addDBRefSourceImpl(jalview.ws.dbsources.Uniprot.class);
61     addDBRefSourceImpl(jalview.ws.dbsources.UnprotName.class);
62     addDBRefSourceImpl(jalview.ws.dbsources.Pdb.class);
63     addDBRefSourceImpl(jalview.ws.dbsources.PfamFull.class);
64     addDBRefSourceImpl(jalview.ws.dbsources.PfamSeed.class); // ensures Seed
65     // alignment is
66     // 'default' for
67     // PFAM
68     addDBRefSourceImpl(jalview.ws.dbsources.RfamFull.class);
69     addDBRefSourceImpl(jalview.ws.dbsources.RfamSeed.class);
70     addDBRefSourceImpl(jalview.ws.dbsources.Intermine.class);
71     if (addDas)
72     {
73       registerDasSequenceSources();
74     }
75   }
76
77   /**
78    * return an ordered list of database sources where non-das database classes
79    * appear before das database classes
80    */
81   public String[] getOrderedSupportedSources()
82   {
83     String[] srcs = this.getSupportedDb();
84     ArrayList<String> dassrc = new ArrayList<String>(), nondas = new ArrayList<String>();
85     for (String src : srcs)
86     {
87       boolean das = false, skip = false;
88       String nm;
89       for (DbSourceProxy dbs : getSourceProxy(src))
90       {
91         // Skip the alignment databases for the moment - they're not useful for
92         // verifying a single sequence against its reference source
93         if (dbs.isA(DBRefSource.ALIGNMENTDB))
94         {
95           skip = true;
96         }
97         else
98         {
99           nm = dbs.getDbName();
100           if (getSourceProxy(src) instanceof jalview.ws.dbsources.das.datamodel.DasSequenceSource)
101           {
102             if (nm.startsWith("das:"))
103             {
104               nm = nm.substring(4);
105               das = true;
106             }
107             break;
108           }
109         }
110       }
111       if (skip)
112       {
113         continue;
114       }
115       if (das)
116       {
117         dassrc.add(src);
118       }
119       else
120       {
121         nondas.add(src);
122       }
123     }
124     String[] tosort = nondas.toArray(new String[0]), sorted = nondas
125             .toArray(new String[0]);
126     for (int j = 0, jSize = sorted.length; j < jSize; j++)
127     {
128       tosort[j] = tosort[j].toLowerCase();
129     }
130     jalview.util.QuickSort.sort(tosort, sorted);
131     // construct array with all sources listed
132
133     srcs = new String[sorted.length + dassrc.size()];
134     int i = 0;
135     for (int j = sorted.length - 1; j >= 0; j--, i++)
136     {
137       srcs[i] = sorted[j];
138       sorted[j] = null;
139     }
140
141     sorted = dassrc.toArray(new String[0]);
142     tosort = dassrc.toArray(new String[0]);
143     for (int j = 0, jSize = sorted.length; j < jSize; j++)
144     {
145       tosort[j] = tosort[j].toLowerCase();
146     }
147     jalview.util.QuickSort.sort(tosort, sorted);
148     for (int j = sorted.length - 1; j >= 0; j--, i++)
149     {
150       srcs[i] = sorted[j];
151     }
152     return srcs;
153   }
154
155   /**
156    * return plaintext databse list suitable for using in a GUI element
157    */
158   public String[] _getOrderedSupportedSources()
159   {
160     String[] srcs = this.getSupportedDb();
161     ArrayList dassrc = new ArrayList(), nondas = new ArrayList();
162     for (String src : srcs)
163     {
164       for (DbSourceProxy dbs : getSourceProxy(src))
165       {
166         String nm = dbs.getDbName();
167         if (getSourceProxy(src) instanceof jalview.ws.dbsources.das.datamodel.DasSequenceSource)
168         {
169           if (nm.startsWith("das:"))
170           {
171             nm = nm.substring(4);
172           }
173           dassrc.add(new String[]
174                   { src, nm.toUpperCase() });
175         }
176         else
177         {
178           nondas.add(new String[]
179                   { src, nm.toUpperCase() });
180         }
181       }
182     }
183     Object[] sorted = nondas.toArray();
184     String[] tosort = new String[sorted.length];
185     nondas.clear();
186     for (int j = 0; j < sorted.length; j++)
187     {
188       tosort[j] = ((String[]) sorted[j])[1];
189     }
190     jalview.util.QuickSort.sort(tosort, sorted);
191     int i = 0;
192     // construct array with all sources listed
193     srcs = new String[sorted.length + dassrc.size()];
194     for (int j = sorted.length - 1; j >= 0; j--, i++)
195     {
196       srcs[i] = ((String[]) sorted[j])[0];
197       sorted[j] = null;
198     }
199
200     sorted = dassrc.toArray();
201     tosort = new String[sorted.length];
202     dassrc.clear();
203     for (int j = 0; j < sorted.length; j++)
204     {
205       tosort[j] = ((String[]) sorted[j])[1];
206     }
207     jalview.util.QuickSort.sort(tosort, sorted);
208     for (int j = sorted.length - 1; j >= 0; j--, i++)
209     {
210       srcs[i] = ((String[]) sorted[j])[0];
211       sorted[j] = null;
212     }
213     return srcs;
214   }
215
216   /**
217    * simple run method to test dbsources.
218    *
219    * @param argv
220    */
221   public static void main(String[] argv)
222   {
223     AlignmentI ds = null;
224     Vector noProds = new Vector();
225     String usage = "SequenceFetcher.main [-nodas] [<DBNAME> [<ACCNO>]]\n"
226             + "With no arguments, all DbSources will be queried with their test Accession number.\n"
227             + "With one argument, the argument will be resolved to one or more db sources and each will be queried with their test accession only.\n"
228             + "If given two arguments, SequenceFetcher will try to find the DbFetcher corresponding to <DBNAME> and retrieve <ACCNO> from it.\n"
229             + "The -nodas option will exclude DAS sources from the database fetchers Jalview will try to use.";
230     boolean withDas = true;
231     if (argv != null && argv.length > 0
232             && argv[0].toLowerCase().startsWith("-nodas"))
233     {
234       withDas = false;
235       String targs[] = new String[argv.length - 1];
236       System.arraycopy(argv, 1, targs, 0, targs.length);
237       argv = targs;
238     }
239     if (argv != null && argv.length > 0)
240     {
241       List<DbSourceProxy> sps = new SequenceFetcher(withDas)
242       .getSourceProxy(argv[0]);
243
244       if (sps != null)
245       {
246         for (DbSourceProxy sp : sps)
247         {
248           AlignmentI al = null;
249           try
250           {
251             al = sp.getSequenceRecords(argv.length > 1 ? argv[1] : sp
252                     .getTestQuery());
253           } catch (Exception e)
254           {
255             e.printStackTrace();
256             System.err.println("Error when retrieving "
257                     + (argv.length > 1 ? argv[1] : sp.getTestQuery())
258                     + " from " + argv[0] + "\nUsage: " + usage);
259           }
260           SequenceI[] prod = al.getSequencesArray();
261           if (al != null)
262           {
263             for (int p = 0; p < prod.length; p++)
264             {
265               System.out.println("Prod " + p + ": "
266                       + prod[p].getDisplayId(true) + " : "
267                       + prod[p].getDescription());
268             }
269           }
270         }
271         return;
272       }
273       else
274       {
275         System.err.println("Can't resolve " + argv[0]
276                 + " as a database name. Allowed values are :\n"
277                 + new SequenceFetcher().getSupportedDb());
278       }
279       System.out.println(usage);
280       return;
281     }
282     ASequenceFetcher sfetcher = new SequenceFetcher(withDas);
283     String[] dbSources = sfetcher.getSupportedDb();
284     for (String db : dbSources)
285     {
286       // skip me
287       if (db.equals(DBRefSource.PDB))
288       {
289         continue;
290       }
291       for (DbSourceProxy sp : sfetcher.getSourceProxy(db))
292       {
293         System.out.println("Source: " + sp.getDbName() + " (" + db
294                 + "): retrieving test:" + sp.getTestQuery());
295         AlignmentI al = null;
296         try
297         {
298           al = sp.getSequenceRecords(sp.getTestQuery());
299           if (al != null && al.getHeight() > 0
300                   && sp.getDbSourceProperties() != null)
301           {
302             boolean dna = sp.getDbSourceProperties().containsKey(
303                     DBRefSource.DNACODINGSEQDB)
304                     || sp.getDbSourceProperties().containsKey(
305                             DBRefSource.DNASEQDB)
306                             || sp.getDbSourceProperties().containsKey(
307                                     DBRefSource.CODINGSEQDB);
308             // try and find products
309             String types[] = jalview.analysis.CrossRef
310                     .findSequenceXrefTypes(dna, al.getSequencesArray());
311             if (types != null)
312             {
313               System.out.println("Xref Types for: "
314                       + (dna ? "dna" : "prot"));
315               for (String type : types)
316               {
317                 System.out.println("Type: " + type);
318                 SequenceI[] prod = jalview.analysis.CrossRef
319                         .findXrefSequences(al.getSequencesArray(), dna,
320                                 type).getSequencesArray();
321                 System.out.println("Found "
322                         + ((prod == null) ? "no" : "" + prod.length)
323                         + " products");
324                 if (prod != null)
325                 {
326                   for (int p = 0; p < prod.length; p++)
327                   {
328                     System.out.println("Prod " + p + ": "
329                             + prod[p].getDisplayId(true));
330                   }
331                 }
332               }
333             }
334             else
335             {
336               noProds.addElement((dna ? new Object[]
337                       { al, al } : new Object[]
338                               { al }));
339             }
340
341           }
342         } catch (Exception ex)
343         {
344           System.out.println("ERROR:Failed to retrieve test query.");
345           ex.printStackTrace(System.out);
346         }
347
348         if (al == null)
349         {
350           System.out.println("ERROR:No alignment retrieved.");
351           StringBuffer raw = sp.getRawRecords();
352           if (raw != null)
353           {
354             System.out.println(raw.toString());
355           }
356           else
357           {
358             System.out.println("ERROR:No Raw results.");
359           }
360         }
361         else
362         {
363           System.out.println("Retrieved " + al.getHeight() + " sequences.");
364           for (int s = 0; s < al.getHeight(); s++)
365           {
366             SequenceI sq = al.getSequenceAt(s);
367             while (sq.getDatasetSequence() != null)
368             {
369               sq = sq.getDatasetSequence();
370
371             }
372             if (ds == null)
373             {
374               ds = new Alignment(new SequenceI[]
375                       { sq });
376
377             }
378             else
379             {
380               ds.addSequence(sq);
381             }
382           }
383         }
384         System.out.flush();
385         System.err.flush();
386
387       }
388       if (noProds.size() > 0)
389       {
390         Enumeration ts = noProds.elements();
391         while (ts.hasMoreElements())
392
393         {
394           Object[] typeSq = (Object[]) ts.nextElement();
395           boolean dna = (typeSq.length > 1);
396           AlignmentI al = (AlignmentI) typeSq[0];
397           System.out.println("Trying getProducts for "
398                   + al.getSequenceAt(0).getDisplayId(true));
399           System.out.println("Search DS Xref for: "
400                   + (dna ? "dna" : "prot"));
401           // have a bash at finding the products amongst all the retrieved
402           // sequences.
403           SequenceI[] seqs = al.getSequencesArray();
404           Alignment prodal = jalview.analysis.CrossRef.findXrefSequences(
405                   seqs, dna, null, ds);
406           System.out.println("Found "
407                   + ((prodal == null) ? "no" : "" + prodal.getHeight())
408                   + " products");
409           if (prodal != null)
410           {
411             SequenceI[] prod = prodal.getSequencesArray(); // note
412             // should
413             // test
414             // rather
415             // than
416             // throw
417             // away
418             // codon
419             // mapping
420             // (if
421             // present)
422             for (int p = 0; p < prod.length; p++)
423             {
424               System.out.println("Prod " + p + ": "
425                       + prod[p].getDisplayId(true));
426             }
427           }
428         }
429
430       }
431
432     }
433   }
434
435   /**
436    * query the currently defined DAS source registry for sequence sources and
437    * add a DasSequenceSource instance for each source to the SequenceFetcher
438    * source list.
439    */
440   public void registerDasSequenceSources()
441   {
442     // TODO: define a context as a registry provider (either desktop,
443     // jalview.bin.cache, or something else).
444     for (jalviewSourceI source : jalview.bin.Cache.getDasSourceRegistry()
445             .getSources())
446     {
447       if (source.isSequenceSource())
448       {
449         List<DbSourceProxy> dassources = source.getSequenceSourceProxies();
450         for (DbSourceProxy seqsrc : dassources)
451         {
452           addDbRefSourceImpl(seqsrc);
453         }
454       }
455     }
456   }
457
458 }