more semantic groupings of dbs
[jalview.git] / src / jalview / io / DasSequenceFeatureFetcher.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 package jalview.io;\r
20 \r
21 import java.net.*;\r
22 import java.util.*;\r
23 \r
24 import javax.swing.*;\r
25 \r
26 import org.biojava.dasobert.das.*;\r
27 import org.biojava.dasobert.das2.*;\r
28 import org.biojava.dasobert.das2.io.*;\r
29 import org.biojava.dasobert.dasregistry.*;\r
30 import org.biojava.dasobert.eventmodel.*;\r
31 import jalview.bin.Cache;\r
32 import jalview.datamodel.*;\r
33 import jalview.gui.*;\r
34 \r
35 /**\r
36  * DOCUMENT ME!\r
37  *\r
38  * @author $author$\r
39  * @version $Revision$\r
40  */\r
41 public class DasSequenceFeatureFetcher\r
42 {\r
43   SequenceI[] sequences;\r
44   AlignFrame af;\r
45   FeatureSettings fsettings;\r
46   StringBuffer sbuffer = new StringBuffer();\r
47   Vector selectedSources;\r
48   boolean cancelled = false;\r
49 \r
50   long startTime;\r
51 \r
52   /**\r
53    * Creates a new SequenceFeatureFetcher object.\r
54    * Uses default\r
55    *\r
56    * @param align DOCUMENT ME!\r
57    * @param ap DOCUMENT ME!\r
58    */\r
59   public DasSequenceFeatureFetcher(SequenceI[] sequences,\r
60                                    FeatureSettings fsettings,\r
61                                    Vector selectedSources)\r
62   {\r
63     this.selectedSources = selectedSources;\r
64     this.sequences = sequences;\r
65     this.af = fsettings.af;\r
66     this.fsettings = fsettings;\r
67 \r
68     int uniprotCount = 0;\r
69     for (int i = 0; i < selectedSources.size(); i++)\r
70     {\r
71       DasSource source = (DasSource) selectedSources.elementAt(i);\r
72       DasCoordinateSystem[] coords = source.getCoordinateSystem();\r
73       for (int c = 0; c < coords.length; c++)\r
74       {\r
75         if (coords[c].getName().indexOf("UniProt") > -1)\r
76         {\r
77           uniprotCount++;\r
78           break;\r
79         }\r
80       }\r
81     }\r
82 \r
83     int refCount = 0;\r
84     for (int i = 0; i < sequences.length; i++)\r
85     {\r
86       DBRefEntry[] dbref = sequences[i].getDBRef();\r
87       if (dbref != null)\r
88       {\r
89         for (int j = 0; j < dbref.length; j++)\r
90         {\r
91           if (dbref[j].getSource()\r
92               .equals(jalview.datamodel.DBRefSource.UNIPROT))\r
93           {\r
94             refCount++;\r
95             break;\r
96           }\r
97         }\r
98       }\r
99     }\r
100 \r
101     if (refCount < sequences.length && uniprotCount > 0)\r
102     {\r
103 \r
104       int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop,\r
105           "Do you want Jalview to find\n"\r
106           + "Uniprot Accession ids for given sequence names?",\r
107           "Find Uniprot Accession Ids",\r
108           JOptionPane.YES_NO_OPTION,\r
109           JOptionPane.QUESTION_MESSAGE);\r
110 \r
111       if (reply == JOptionPane.YES_OPTION)\r
112       {\r
113         Thread thread = new Thread(new FetchDBRefs());\r
114         thread.start();\r
115       }\r
116       else\r
117       {\r
118         startFetching();\r
119     }\r
120     }\r
121     else\r
122     {\r
123       startFetching();\r
124     }\r
125 \r
126     }\r
127 \r
128   class FetchDBRefs\r
129       implements Runnable\r
130   {\r
131     public void run()\r
132     {\r
133       new DBRefFetcher(sequences, af).fetchDBRefs(true);\r
134       startFetching();\r
135     }\r
136   }\r
137 \r
138 \r
139    /**\r
140     * Spawns a number of dasobert Fetcher threads to add features to sequences in the dataset\r
141     */\r
142    void startFetching()\r
143    {\r
144      cancelled = false;\r
145      startTime = System.currentTimeMillis();\r
146      af.setProgressBar("Fetching DAS Sequence Features", startTime);\r
147 \r
148      DasSource[] sources = new jalview.gui.DasSourceBrowser().getDASSource();\r
149 \r
150      if (selectedSources == null || selectedSources.size() == 0)\r
151      {\r
152        String active = jalview.bin.Cache.getDefault("DAS_ACTIVE_SOURCE",\r
153            "uniprot");\r
154        StringTokenizer st = new StringTokenizer(active, "\t");\r
155        Vector selectedSources = new Vector();\r
156        String token;\r
157        while (st.hasMoreTokens())\r
158        {\r
159          token = st.nextToken();\r
160          for (int i = 0; i < sources.length; i++)\r
161          {\r
162            if (sources[i].getNickname().equals(token))\r
163            {\r
164              selectedSources.addElement(sources[i]);\r
165              break;\r
166            }\r
167          }\r
168        }\r
169      }\r
170 \r
171      if (selectedSources == null || selectedSources.size() == 0)\r
172      {\r
173        System.out.println("No DAS Sources active");\r
174        af.setProgressBar("No DAS Sources Active", startTime);\r
175        cancelled = true;\r
176        fsettings.noDasSourceActive();\r
177        return;\r
178      }\r
179 \r
180        sourcesRemaining = selectedSources.size();\r
181        //Now sending requests one at a time to each server\r
182        for (int sourceIndex = 0;\r
183             sourceIndex < selectedSources.size()\r
184             && !cancelled;\r
185             sourceIndex++)\r
186        {\r
187          DasSource dasSource = (DasSource) selectedSources.elementAt(\r
188              sourceIndex);\r
189 \r
190          nextSequence(dasSource, sequences[0]);\r
191        }\r
192    }\r
193 \r
194    public void cancel()\r
195    {\r
196      af.setProgressBar("DAS Feature Fetching Cancelled", startTime);\r
197      cancelled = true;\r
198    }\r
199 \r
200    int sourcesRemaining=0;\r
201    void responseComplete(DasSource dasSource, SequenceI seq)\r
202    {\r
203      if (seq != null)\r
204      {\r
205        for (int seqIndex = 0;\r
206             seqIndex < sequences.length-1\r
207             && !cancelled; seqIndex++)\r
208        {\r
209          if (sequences[seqIndex] == seq)\r
210          {\r
211            nextSequence(dasSource, sequences[++seqIndex]);\r
212            return;\r
213          }\r
214        }\r
215      }\r
216 \r
217      sourcesRemaining --;\r
218 \r
219      if(sourcesRemaining==0)\r
220      {\r
221        af.setProgressBar("DAS Feature Fetching Complete", startTime);\r
222 \r
223        if(af.featureSettings!=null)\r
224       {\r
225          af.featureSettings.setTableData();\r
226       }\r
227 \r
228        fsettings.complete();\r
229      }\r
230 \r
231    }\r
232 \r
233    void featuresAdded(SequenceI seq)\r
234    {\r
235      af.getFeatureRenderer().featuresAdded();\r
236 \r
237      int start = af.getViewport().getStartSeq();\r
238      int end = af.getViewport().getEndSeq();\r
239      int index;\r
240      for(index=start; index<end; index++)\r
241        {\r
242       if (seq ==\r
243           af.getViewport().getAlignment().getSequenceAt(index).getDatasetSequence())\r
244       {\r
245         af.alignPanel.paintAlignment(true);\r
246          break;\r
247        }\r
248    }\r
249   }\r
250 \r
251 \r
252   void nextSequence(DasSource dasSource, SequenceI seq)\r
253   {\r
254     if (cancelled)\r
255       return;\r
256     DBRefEntry[] uprefs = jalview.util.DBRefUtils.selectRefs(seq.getDBRef(),\r
257           new String[]\r
258           {\r
259         //  jalview.datamodel.DBRefSource.PDB,\r
260           jalview.datamodel.DBRefSource.UNIPROT,\r
261         //  jalview.datamodel.DBRefSource.EMBL - not tested on any EMBL coord sys sources\r
262       });\r
263 // TODO: minimal list of DAS queries to make by querying with untyped ID if distinct from any typed IDs\r
264 \r
265       boolean dasCoordSysFound = false;\r
266 \r
267       if (uprefs != null)\r
268         {\r
269           // do any of these ids match the source's coordinate system ?\r
270           for (int j = 0; !dasCoordSysFound && j < uprefs.length; j++)\r
271           {\r
272             DasCoordinateSystem cs[] = dasSource.getCoordinateSystem();\r
273 \r
274             for(int csIndex=0; csIndex<cs.length && !dasCoordSysFound; csIndex++)\r
275             {\r
276               if (cs.length > 0 && jalview.util.DBRefUtils\r
277                   .isDasCoordinateSystem(cs[csIndex].getName(), uprefs[j]))\r
278               {\r
279                 Cache.log.debug("Launched fetcher for coordinate system " +\r
280                                 cs[0].getName());\r
281                 //  Will have to pass any mapping information to the fetcher\r
282                 //- the start/end for the DBRefEntry may not be the same as the sequence's start/end\r
283 \r
284                 System.out.println(seq.getName() + " " + (seq.getDatasetSequence() == null)\r
285                                    + " " + dasSource.getUrl());\r
286 \r
287                 dasCoordSysFound = true; // break's out of the loop\r
288                 createFeatureFetcher(seq,\r
289                                      dasSource,\r
290                                      uprefs[j]);\r
291               }\r
292               else\r
293                 System.out.println("IGNORE " + cs[csIndex].getName());\r
294             }\r
295           }\r
296         }\r
297 \r
298         if(!dasCoordSysFound)\r
299         {\r
300           String id = null;\r
301           // try and use the name as the sequence id\r
302           if (seq.getName().indexOf("|") > -1)\r
303           {\r
304             id = seq.getName().substring(\r
305                 seq.getName().lastIndexOf("|") + 1);\r
306           }\r
307           else\r
308           {\r
309             id = seq.getName();\r
310           }\r
311           if (id != null)\r
312           {\r
313             // Should try to call a general feature fetcher that\r
314             // queries many sources with name to discover applicable ID references\r
315             createFeatureFetcher(seq,\r
316                                  dasSource,\r
317                                  id);\r
318           }\r
319         }\r
320 \r
321    }\r
322 \r
323 \r
324 /**\r
325  * fetch and add das features to a sequence using the given source URL and compatible DbRef id.\r
326  * new features are mapped using the DbRef mapping to the local coordinate system.\r
327  * @param seq\r
328  * @param SourceUrl\r
329  * @param dbref\r
330  */\r
331   protected void createFeatureFetcher(final SequenceI seq, final DasSource dasSource,\r
332         final DBRefEntry dbref) {\r
333 \r
334     //////////////\r
335     /// fetch DAS features\r
336     final Das1Source source = new Das1Source();\r
337     source.setUrl(dasSource.getUrl());\r
338     source.setNickname(dasSource.getNickname());\r
339     if (dbref==null || dbref.getAccessionId()==null || dbref.getAccessionId().length()<1)\r
340     {\r
341       return;\r
342     }\r
343     Cache.log.debug("new Das Feature Fetcher for " + dbref.getSource()+":"+dbref.getAccessionId() + " querying " +\r
344                     dasSource.getUrl());\r
345     FeatureThread fetcher = new FeatureThread(dbref.getAccessionId()\r
346                                                 //  +  ":" + start + "," + end,\r
347                                                 , source);\r
348 \r
349       fetcher.addFeatureListener(new FeatureListener()\r
350       {\r
351         public void comeBackLater(FeatureEvent e)\r
352         {\r
353           responseComplete(dasSource, seq);\r
354           Cache.log.debug("das source " + e.getDasSource().getNickname() +\r
355                           " asked us to come back in " + e.getComeBackLater() +\r
356                           " secs.");\r
357         }\r
358 \r
359         public void newFeatures(FeatureEvent e)\r
360         {\r
361 \r
362           Das1Source ds = e.getDasSource();\r
363 \r
364           Map[] features = e.getFeatures();\r
365           // add features to sequence\r
366           Cache.log.debug("das source " + ds.getUrl() + " returned " +\r
367                           features.length + " features");\r
368 \r
369           if (features.length > 0)\r
370           {\r
371             for (int i = 0; i < features.length; i++)\r
372             {\r
373               SequenceFeature f = newSequenceFeature(features[i],\r
374                   source.getNickname());\r
375               if (dbref.getMap()!=null && f.getBegin()>0 && f.getEnd()>0) {\r
376                 Cache.log.debug("mapping from "+f.getBegin()+" - "+f.getEnd());\r
377                 SequenceFeature vf[]=null;\r
378                 \r
379                 try {\r
380                   vf = dbref.getMap().locateFeature(f);\r
381                 }\r
382                 catch (Exception ex)\r
383                 {\r
384                   Cache.log.info("Error in 'experimental' mapping of features. Please try to reproduce and then report info to help@jalview.org.");\r
385                   Cache.log.info("Mapping feature from "+f.getBegin()+" to "+f.getEnd()+" in dbref "+dbref.getAccessionId()+" in "+dbref.getSource());\r
386                   Cache.log.info("using das Source "+ds.getUrl());\r
387                   Cache.log.info(ex);\r
388                 }\r
389                 \r
390                 if (vf!=null) {\r
391                   for (int v=0;v<vf.length;v++)\r
392                   {\r
393                     Cache.log.debug("mapping to "+v+": "+vf[v].getBegin()+" - "+vf[v].getEnd());\r
394                     seq.addSequenceFeature(vf[v]);\r
395                   }\r
396                 }\r
397               } else {\r
398                 seq.addSequenceFeature(f);\r
399               }\r
400             }\r
401 \r
402             featuresAdded(seq);\r
403           }\r
404           else\r
405           {\r
406           //  System.out.println("No features found for " + seq.getName()\r
407           //                     + " from: " + e.getDasSource().getNickname());\r
408           }\r
409           responseComplete(dasSource, seq);\r
410 \r
411         }\r
412       }\r
413 \r
414       );\r
415 \r
416       fetcher.start();\r
417     }\r
418   protected void createFeatureFetcher(final SequenceI seq,\r
419                                       final DasSource dasSource,\r
420                                       String id)\r
421   {\r
422     //////////////\r
423     /// fetch DAS features\r
424     final Das1Source source = new Das1Source();\r
425     source.setUrl(dasSource.getUrl());\r
426     source.setNickname(dasSource.getNickname());\r
427 \r
428     Cache.log.debug("new Das Feature Fetcher for " + id + " querying " +\r
429                     dasSource.getUrl());\r
430 \r
431     if (id != null && id.length() > 0)\r
432     {\r
433       FeatureThread fetcher = new FeatureThread(id\r
434                                                 //  +  ":" + start + "," + end,\r
435                                                 , source);\r
436 \r
437       fetcher.addFeatureListener(new FeatureListener()\r
438       {\r
439         public void comeBackLater(FeatureEvent e)\r
440         {\r
441           responseComplete(dasSource, seq);\r
442           Cache.log.debug("das source " + e.getDasSource().getNickname() +\r
443                           " asked us to come back in " + e.getComeBackLater() +\r
444                           " secs.");\r
445         }\r
446 \r
447         public void newFeatures(FeatureEvent e)\r
448         {\r
449 \r
450           Das1Source ds = e.getDasSource();\r
451 \r
452           Map[] features = e.getFeatures();\r
453           // add features to sequence\r
454           Cache.log.debug("das source " + ds.getUrl() + " returned " +\r
455                           features.length + " features");\r
456 \r
457           if (features.length > 0)\r
458           {\r
459             for (int i = 0; i < features.length; i++)\r
460             {\r
461               SequenceFeature f = newSequenceFeature(features[i],\r
462                   source.getNickname());\r
463 \r
464               seq.addSequenceFeature(f);\r
465             }\r
466 \r
467             featuresAdded(seq);\r
468           }\r
469           else\r
470           {\r
471           //  System.out.println("No features found for " + seq.getName()\r
472           //                     + " from: " + e.getDasSource().getNickname());\r
473           }\r
474           responseComplete(dasSource, seq);\r
475 \r
476         }\r
477       }\r
478 \r
479       );\r
480 \r
481       fetcher.start();\r
482     }\r
483   }\r
484 \r
485   /**\r
486    * creates a jalview sequence feature from a das feature document\r
487    * @param dasfeature\r
488    * @return sequence feature object created using dasfeature information\r
489    */\r
490   SequenceFeature newSequenceFeature(Map dasfeature, String nickname)\r
491   {\r
492     if (dasfeature==null)\r
493     {\r
494       return null;\r
495     }\r
496     try\r
497     {\r
498       /**\r
499        * Different qNames for a DAS Feature - are string keys to the HashMaps in features\r
500        * "METHOD") ||\r
501                   qName.equals("TYPE") ||\r
502                   qName.equals("START") ||\r
503                   qName.equals("END") ||\r
504                   qName.equals("NOTE") ||\r
505                   qName.equals("LINK") ||\r
506                   qName.equals("SCORE")\r
507        */\r
508       String desc = new String();\r
509       if (dasfeature.containsKey("NOTE"))\r
510       {\r
511         desc += (String) dasfeature.get("NOTE");\r
512       }\r
513 \r
514       int start = 0, end = 0;\r
515       float score = 0f;\r
516 \r
517       try\r
518       {\r
519         start = Integer.parseInt(dasfeature.get("START").toString());\r
520       }\r
521       catch (Exception ex)\r
522       {}\r
523       try\r
524       {\r
525         end = Integer.parseInt(dasfeature.get("END").toString());\r
526       }\r
527       catch (Exception ex)\r
528       {}\r
529       try\r
530       {\r
531         score = Integer.parseInt(dasfeature.get("SCORE").toString());\r
532       }\r
533       catch (Exception ex)\r
534       {}\r
535 \r
536       SequenceFeature f = new SequenceFeature(\r
537           (String) dasfeature.get("TYPE"),\r
538           desc,\r
539           start,\r
540           end,\r
541           score,\r
542           nickname);\r
543 \r
544       if (dasfeature.containsKey("LINK"))\r
545       {\r
546         f.addLink(f.getType() + " " + f.begin + "_" + f.end\r
547                   + "|" + dasfeature.get("LINK"));\r
548       }\r
549 \r
550       return f;\r
551     }\r
552     catch (Exception e)\r
553     {\r
554       System.out.println("ERRR " + e);\r
555       e.printStackTrace();\r
556       System.out.println("############");\r
557       Cache.log.debug("Failed to parse " + dasfeature.toString(), e);\r
558       return null;\r
559     }\r
560   }\r
561 \r
562   public static DasSource[] getDASSources()\r
563   {\r
564     DasSourceReaderImpl reader = new DasSourceReaderImpl();\r
565 \r
566     String registryURL = jalview.bin.Cache.getDefault("DAS_REGISTRY_URL",\r
567         DasSourceBrowser.DEFAULT_REGISTRY\r
568         );\r
569 \r
570     try\r
571     {\r
572       URL url = new URL(registryURL);\r
573 \r
574       DasSource[] sources = reader.readDasSource(url);\r
575 \r
576       List das1sources = new ArrayList();\r
577       for (int i = 0; i < sources.length; i++)\r
578       {\r
579         DasSource ds = sources[i];\r
580         if (ds instanceof Das2Source)\r
581         {\r
582           Das2Source d2s = (Das2Source) ds;\r
583           if (d2s.hasDas1Capabilities())\r
584           {\r
585             Das1Source d1s = DasSourceConverter.toDas1Source(d2s);\r
586             das1sources.add(d1s);\r
587           }\r
588 \r
589         }\r
590         else if (ds instanceof Das1Source)\r
591         {\r
592           das1sources.add( (Das1Source) ds);\r
593         }\r
594       }\r
595 \r
596       return (Das1Source[]) das1sources.toArray(new Das1Source[das1sources.size()]);\r
597     }\r
598     catch (Exception ex)\r
599     {\r
600       ex.printStackTrace();\r
601       return null;\r
602     }\r
603   }\r
604 \r
605 }\r
606 \r