flag for dasCoordSysFound added
[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(\r
134           af.getViewport().getAlignment(), af).fetchDBRefs(true);\r
135       startFetching();\r
136     }\r
137   }\r
138 \r
139 \r
140    /**\r
141     * Spawns a number of dasobert Fetcher threads to add features to sequences in the dataset\r
142     */\r
143    void startFetching()\r
144    {\r
145      cancelled = false;\r
146      startTime = System.currentTimeMillis();\r
147      af.setProgressBar("Fetching DAS Sequence Features", startTime);\r
148 \r
149      DasSource[] sources = new jalview.gui.DasSourceBrowser().getDASSource();\r
150 \r
151      if (selectedSources == null || selectedSources.size() == 0)\r
152      {\r
153        String active = jalview.bin.Cache.getDefault("DAS_ACTIVE_SOURCE",\r
154            "uniprot");\r
155        StringTokenizer st = new StringTokenizer(active, "\t");\r
156        Vector selectedSources = new Vector();\r
157        String token;\r
158        while (st.hasMoreTokens())\r
159        {\r
160          token = st.nextToken();\r
161          for (int i = 0; i < sources.length; i++)\r
162          {\r
163            if (sources[i].getNickname().equals(token))\r
164            {\r
165              selectedSources.addElement(sources[i]);\r
166              break;\r
167            }\r
168          }\r
169        }\r
170      }\r
171 \r
172      if (selectedSources == null || selectedSources.size() == 0)\r
173      {\r
174        System.out.println("No DAS Sources active");\r
175        af.setProgressBar("No DAS Sources Active", startTime);\r
176        return;\r
177      }\r
178 \r
179        sourcesRemaining = selectedSources.size();\r
180        //Now sending requests one at a time to each server\r
181        for (int sourceIndex = 0;\r
182             sourceIndex < selectedSources.size()\r
183             && !cancelled;\r
184             sourceIndex++)\r
185        {\r
186          DasSource dasSource = (DasSource) selectedSources.elementAt(\r
187              sourceIndex);\r
188 \r
189          nextSequence(dasSource, sequences[0]);\r
190        }\r
191    }\r
192 \r
193    public void cancel()\r
194    {\r
195      af.setProgressBar("DAS Feature Fetching Cancelled", startTime);\r
196      cancelled = true;\r
197    }\r
198 \r
199    int sourcesRemaining=0;\r
200    void responseComplete(DasSource dasSource, SequenceI seq)\r
201    {\r
202      if (seq != null)\r
203      {\r
204        for (int seqIndex = 0;\r
205             seqIndex < sequences.length-1\r
206             && !cancelled; seqIndex++)\r
207        {\r
208          if (sequences[seqIndex] == seq)\r
209          {\r
210            nextSequence(dasSource, sequences[++seqIndex]);\r
211            return;\r
212          }\r
213        }\r
214      }\r
215 \r
216      sourcesRemaining --;\r
217 \r
218      if(sourcesRemaining==0)\r
219      {\r
220        af.setProgressBar("DAS Feature Fetching Complete", startTime);\r
221 \r
222        if(af.featureSettings!=null)\r
223       {\r
224          af.featureSettings.setTableData();\r
225       }\r
226 \r
227        fsettings.complete();\r
228      }\r
229 \r
230    }\r
231 \r
232    void featuresAdded(SequenceI seq)\r
233    {\r
234      af.getFeatureRenderer().featuresAdded();\r
235 \r
236      int start = af.getViewport().getStartSeq();\r
237      int end = af.getViewport().getEndSeq();\r
238      int index;\r
239      for(index=start; index<end; index++)\r
240        {\r
241       if (seq ==\r
242           af.getViewport().getAlignment().getSequenceAt(index).getDatasetSequence())\r
243       {\r
244         af.alignPanel.paintAlignment(true);\r
245          break;\r
246        }\r
247    }\r
248   }\r
249 \r
250 \r
251   void nextSequence(DasSource dasSource, SequenceI seq)\r
252   {\r
253       DBRefEntry[] uprefs = jalview.util.DBRefUtils.selectRefs(seq.getDBRef(),\r
254           new String[]\r
255           {\r
256         //  jalview.datamodel.DBRefSource.PDB,\r
257           jalview.datamodel.DBRefSource.UNIPROT,\r
258         //  jalview.datamodel.DBRefSource.EMBL - not tested on any EMBL coord sys sources\r
259       });\r
260 // TODO: minimal list of DAS queries to make by querying with untyped ID if distinct from any typed IDs\r
261 \r
262       boolean dasCoordSysFound = false;\r
263 \r
264       if (uprefs != null)\r
265         {\r
266           // do any of these ids match the source's coordinate system ?\r
267           for (int j = 0; j < uprefs.length; j++)\r
268           {\r
269             DasCoordinateSystem cs[] = dasSource.getCoordinateSystem();\r
270 \r
271             for(int csIndex=0; csIndex<cs.length; csIndex++)\r
272             {\r
273               if (cs.length > 0 && jalview.util.DBRefUtils\r
274                   .isDasCoordinateSystem(cs[csIndex].getName(), uprefs[j]))\r
275               {\r
276                 Cache.log.debug("Launched fetcher for coordinate system " +\r
277                                 cs[0].getName());\r
278                 //  Will have to pass any mapping information to the fetcher\r
279                 //- the start/end for the DBRefEntry may not be the same as the sequence's start/end\r
280 \r
281                 System.out.println(seq.getName() + " " + (seq.getDatasetSequence() == null)\r
282                                    + " " + dasSource.getUrl());\r
283 \r
284                 dasCoordSysFound = false;\r
285                 createFeatureFetcher(seq,\r
286                                      dasSource,\r
287                                      uprefs[j]);\r
288                 break; // only do this for one reference - assume same source will send same features for all IDs\r
289               }\r
290               else\r
291                 System.out.println("IGNORE " + cs[csIndex].getName());\r
292             }\r
293           }\r
294         }\r
295 \r
296         if(!dasCoordSysFound)\r
297         {\r
298           String id = null;\r
299           // try and use the name as the sequence id\r
300           if (seq.getName().indexOf("|") > -1)\r
301           {\r
302             id = seq.getName().substring(\r
303                 seq.getName().lastIndexOf("|") + 1);\r
304           }\r
305           else\r
306           {\r
307             id = seq.getName();\r
308           }\r
309           if (id != null)\r
310           {\r
311             // Should try to call a general feature fetcher that\r
312             // queries many sources with name to discover applicable ID references\r
313             createFeatureFetcher(seq,\r
314                                  dasSource,\r
315                                  id);\r
316           }\r
317         }\r
318 \r
319    }\r
320 \r
321 \r
322 /**\r
323  * fetch and add das features to a sequence using the given source URL and compatible DbRef id.\r
324  * new features are mapped using the DbRef mapping to the local coordinate system.\r
325  * @param seq\r
326  * @param SourceUrl\r
327  * @param dbref\r
328  */\r
329   protected void createFeatureFetcher(final SequenceI seq, final DasSource dasSource,\r
330         final DBRefEntry dbref) {\r
331 \r
332     //////////////\r
333     /// fetch DAS features\r
334     final Das1Source source = new Das1Source();\r
335     source.setUrl(dasSource.getUrl());\r
336     source.setNickname(dasSource.getNickname());\r
337     if (dbref==null || dbref.getAccessionId()==null || dbref.getAccessionId().length()<1)\r
338     {\r
339       return;\r
340     }\r
341     Cache.log.debug("new Das Feature Fetcher for " + dbref.getSource()+":"+dbref.getAccessionId() + " querying " +\r
342                     dasSource.getUrl());\r
343     FeatureThread fetcher = new FeatureThread(dbref.getAccessionId()\r
344                                                 //  +  ":" + start + "," + end,\r
345                                                 , source);\r
346 \r
347       fetcher.addFeatureListener(new FeatureListener()\r
348       {\r
349         public void comeBackLater(FeatureEvent e)\r
350         {\r
351           responseComplete(dasSource, seq);\r
352           Cache.log.debug("das source " + e.getDasSource().getNickname() +\r
353                           " asked us to come back in " + e.getComeBackLater() +\r
354                           " secs.");\r
355         }\r
356 \r
357         public void newFeatures(FeatureEvent e)\r
358         {\r
359 \r
360           Das1Source ds = e.getDasSource();\r
361 \r
362           Map[] features = e.getFeatures();\r
363           // add features to sequence\r
364           Cache.log.debug("das source " + ds.getUrl() + " returned " +\r
365                           features.length + " features");\r
366 \r
367           if (features.length > 0)\r
368           {\r
369             for (int i = 0; i < features.length; i++)\r
370             {\r
371               SequenceFeature f = newSequenceFeature(features[i],\r
372                   source.getNickname());\r
373               if (dbref.getMap()!=null && f.getBegin()>0 && f.getEnd()>0) {\r
374                 Cache.log.debug("mapping from "+f.getBegin()+" - "+f.getEnd());\r
375                 SequenceFeature vf[] = dbref.getMap().locateFeature(f);\r
376                 if (vf!=null) {\r
377                   for (int v=0;v<vf.length;v++)\r
378                   {\r
379                     Cache.log.debug("mapping to "+v+": "+vf[v].getBegin()+" - "+vf[v].getEnd());\r
380                     seq.addSequenceFeature(vf[v]);\r
381                   }\r
382                 }\r
383               } else {\r
384                 seq.addSequenceFeature(f);\r
385               }\r
386             }\r
387 \r
388             featuresAdded(seq);\r
389           }\r
390           else\r
391           {\r
392           //  System.out.println("No features found for " + seq.getName()\r
393           //                     + " from: " + e.getDasSource().getNickname());\r
394           }\r
395           responseComplete(dasSource, seq);\r
396 \r
397         }\r
398       }\r
399 \r
400       );\r
401 \r
402       fetcher.start();\r
403     }\r
404   protected void createFeatureFetcher(final SequenceI seq,\r
405                                       final DasSource dasSource,\r
406                                       String id)\r
407   {\r
408     //////////////\r
409     /// fetch DAS features\r
410     final Das1Source source = new Das1Source();\r
411     source.setUrl(dasSource.getUrl());\r
412     source.setNickname(dasSource.getNickname());\r
413 \r
414     Cache.log.debug("new Das Feature Fetcher for " + id + " querying " +\r
415                     dasSource.getUrl());\r
416 \r
417     if (id != null && id.length() > 0)\r
418     {\r
419       FeatureThread fetcher = new FeatureThread(id\r
420                                                 //  +  ":" + start + "," + end,\r
421                                                 , source);\r
422 \r
423       fetcher.addFeatureListener(new FeatureListener()\r
424       {\r
425         public void comeBackLater(FeatureEvent e)\r
426         {\r
427           responseComplete(dasSource, seq);\r
428           Cache.log.debug("das source " + e.getDasSource().getNickname() +\r
429                           " asked us to come back in " + e.getComeBackLater() +\r
430                           " secs.");\r
431         }\r
432 \r
433         public void newFeatures(FeatureEvent e)\r
434         {\r
435 \r
436           Das1Source ds = e.getDasSource();\r
437 \r
438           Map[] features = e.getFeatures();\r
439           // add features to sequence\r
440           Cache.log.debug("das source " + ds.getUrl() + " returned " +\r
441                           features.length + " features");\r
442 \r
443           if (features.length > 0)\r
444           {\r
445             for (int i = 0; i < features.length; i++)\r
446             {\r
447               SequenceFeature f = newSequenceFeature(features[i],\r
448                   source.getNickname());\r
449 \r
450               seq.addSequenceFeature(f);\r
451             }\r
452 \r
453             featuresAdded(seq);\r
454           }\r
455           else\r
456           {\r
457           //  System.out.println("No features found for " + seq.getName()\r
458           //                     + " from: " + e.getDasSource().getNickname());\r
459           }\r
460           responseComplete(dasSource, seq);\r
461 \r
462         }\r
463       }\r
464 \r
465       );\r
466 \r
467       fetcher.start();\r
468     }\r
469   }\r
470 \r
471   /**\r
472    * creates a jalview sequence feature from a das feature document\r
473    * @param dasfeature\r
474    * @return sequence feature object created using dasfeature information\r
475    */\r
476   SequenceFeature newSequenceFeature(Map dasfeature, String nickname)\r
477   {\r
478     try\r
479     {\r
480       /**\r
481        * Different qNames for a DAS Feature - are string keys to the HashMaps in features\r
482        * "METHOD") ||\r
483                   qName.equals("TYPE") ||\r
484                   qName.equals("START") ||\r
485                   qName.equals("END") ||\r
486                   qName.equals("NOTE") ||\r
487                   qName.equals("LINK") ||\r
488                   qName.equals("SCORE")\r
489        */\r
490       String desc = new String();\r
491       if (dasfeature.containsKey("NOTE"))\r
492       {\r
493         desc += (String) dasfeature.get("NOTE");\r
494       }\r
495 \r
496       int start = 0, end = 0;\r
497       float score = 0f;\r
498 \r
499       try\r
500       {\r
501         start = Integer.parseInt(dasfeature.get("START").toString());\r
502       }\r
503       catch (Exception ex)\r
504       {}\r
505       try\r
506       {\r
507         end = Integer.parseInt(dasfeature.get("END").toString());\r
508       }\r
509       catch (Exception ex)\r
510       {}\r
511       try\r
512       {\r
513         score = Integer.parseInt(dasfeature.get("SCORE").toString());\r
514       }\r
515       catch (Exception ex)\r
516       {}\r
517 \r
518       SequenceFeature f = new SequenceFeature(\r
519           (String) dasfeature.get("TYPE"),\r
520           desc,\r
521           start,\r
522           end,\r
523           score,\r
524           nickname);\r
525 \r
526       if (dasfeature.containsKey("LINK"))\r
527       {\r
528         f.addLink(f.getType() + " " + f.begin + "_" + f.end\r
529                   + "|" + dasfeature.get("LINK"));\r
530       }\r
531 \r
532       return f;\r
533     }\r
534     catch (Exception e)\r
535     {\r
536       System.out.println("ERRR " + e);\r
537       e.printStackTrace();\r
538       System.out.println("############");\r
539       Cache.log.debug("Failed to parse " + dasfeature.toString(), e);\r
540       return null;\r
541     }\r
542   }\r
543 \r
544   public static DasSource[] getDASSources()\r
545   {\r
546     DasSourceReaderImpl reader = new DasSourceReaderImpl();\r
547 \r
548     String registryURL = jalview.bin.Cache.getDefault("DAS_REGISTRY_URL",\r
549         DasSourceBrowser.DEFAULT_REGISTRY\r
550         );\r
551 \r
552     try\r
553     {\r
554       URL url = new URL(registryURL);\r
555 \r
556       DasSource[] sources = reader.readDasSource(url);\r
557 \r
558       List das1sources = new ArrayList();\r
559       for (int i = 0; i < sources.length; i++)\r
560       {\r
561         DasSource ds = sources[i];\r
562         if (ds instanceof Das2Source)\r
563         {\r
564           Das2Source d2s = (Das2Source) ds;\r
565           if (d2s.hasDas1Capabilities())\r
566           {\r
567             Das1Source d1s = DasSourceConverter.toDas1Source(d2s);\r
568             das1sources.add(d1s);\r
569           }\r
570 \r
571         }\r
572         else if (ds instanceof Das1Source)\r
573         {\r
574           das1sources.add( (Das1Source) ds);\r
575         }\r
576       }\r
577 \r
578       return (Das1Source[]) das1sources.toArray(new Das1Source[das1sources.size()]);\r
579     }\r
580     catch (Exception ex)\r
581     {\r
582       ex.printStackTrace();\r
583       return null;\r
584     }\r
585   }\r
586 \r
587 }\r
588 \r