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