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