Cancel added
[jalview.git] / src / jalview / io / DasSequenceFeatureFetcher.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2006 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 jalview.datamodel.*;\r
22 \r
23 import jalview.gui.*;\r
24 \r
25 import java.util.*;\r
26 \r
27 import java.net.URL;\r
28 \r
29 import org.biojava.dasobert.das.FeatureThread;\r
30 import org.biojava.dasobert.eventmodel.FeatureEvent;\r
31 import org.biojava.dasobert.eventmodel.FeatureListener;\r
32 import org.biojava.dasobert.dasregistry.DasSource;\r
33 \r
34 import org.biojava.dasobert.das2.io.DasSourceReaderImpl;\r
35 import org.biojava.dasobert.dasregistry.Das1Source;\r
36 import org.biojava.dasobert.dasregistry.DasSource;\r
37 import org.biojava.dasobert.das2.Das2Source;\r
38 import org.biojava.dasobert.das2.DasSourceConverter;\r
39 \r
40 import jalview.bin.Cache;\r
41 import org.biojava.dasobert.dasregistry.DasCoordinateSystem;\r
42 \r
43 import javax.swing.*;\r
44 \r
45 /**\r
46  * DOCUMENT ME!\r
47  *\r
48  * @author $author$\r
49  * @version $Revision$\r
50  */\r
51 public class DasSequenceFeatureFetcher\r
52 {\r
53   SequenceI[] sequences;\r
54   AlignFrame af;\r
55   FeatureSettings fsettings;\r
56   StringBuffer sbuffer = new StringBuffer();\r
57   Vector selectedSources;\r
58   boolean cancelled = false;\r
59 \r
60   long startTime;\r
61 \r
62   /**\r
63    * Creates a new SequenceFeatureFetcher object.\r
64    * Uses default\r
65    *\r
66    * @param align DOCUMENT ME!\r
67    * @param ap DOCUMENT ME!\r
68    */\r
69   public DasSequenceFeatureFetcher(SequenceI[] sequences,\r
70                                    FeatureSettings fsettings,\r
71                                    Vector selectedSources)\r
72   {\r
73     this.selectedSources = selectedSources;\r
74     this.sequences = sequences;\r
75     this.af = fsettings.af;\r
76 \r
77     int uniprotCount = 0;\r
78     for (int i = 0; i < selectedSources.size(); i++)\r
79     {\r
80       DasSource source = (DasSource) selectedSources.elementAt(i);\r
81       DasCoordinateSystem[] coords = source.getCoordinateSystem();\r
82       for (int c = 0; c < coords.length; c++)\r
83       {\r
84         if (coords[c].getName().indexOf("UniProt") > -1)\r
85         {\r
86           uniprotCount++;\r
87           break;\r
88         }\r
89       }\r
90     }\r
91 \r
92     int refCount = 0;\r
93     for (int i = 0; i < sequences.length; i++)\r
94     {\r
95       DBRefEntry[] dbref = sequences[i].getDBRef();\r
96       if (dbref != null)\r
97       {\r
98         for (int j = 0; j < dbref.length; j++)\r
99         {\r
100           if (dbref[j].getSource()\r
101               .equals(jalview.datamodel.DBRefSource.UNIPROT))\r
102           {\r
103             refCount++;\r
104             break;\r
105           }\r
106         }\r
107       }\r
108     }\r
109 \r
110     if (refCount < sequences.length && uniprotCount > 0)\r
111     {\r
112 \r
113       int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop,\r
114           "Do you want Jalview to find\n"\r
115           + "Uniprot Accession ids for given sequence names?",\r
116           "Find Uniprot Accession Ids",\r
117           JOptionPane.YES_NO_OPTION,\r
118           JOptionPane.QUESTION_MESSAGE);\r
119 \r
120       if (reply == JOptionPane.YES_OPTION)\r
121       {\r
122         Thread thread = new Thread(new FetchDBRefs());\r
123         thread.start();\r
124       }\r
125       else\r
126         startFetching();\r
127     }\r
128     else\r
129       startFetching();\r
130 \r
131     }\r
132 \r
133   class FetchDBRefs\r
134       implements Runnable\r
135   {\r
136     public void run()\r
137     {\r
138       new DBRefFetcher(\r
139           af.getViewport().getAlignment(), af).fetchDBRefs(true);\r
140       startFetching();\r
141     }\r
142   }\r
143 \r
144 \r
145    /**\r
146     * Spawns a number of dasobert Fetcher threads to add features to sequences in the dataset\r
147     */\r
148    void startFetching()\r
149    {\r
150      cancelled = false;\r
151      startTime = System.currentTimeMillis();\r
152      af.setProgressBar("Fetching DAS Sequence Features", startTime);\r
153 \r
154      DasSource[] sources = new jalview.gui.DasSourceBrowser().getDASSource();\r
155 \r
156      if (selectedSources == null || selectedSources.size() == 0)\r
157      {\r
158        String active = jalview.bin.Cache.getDefault("DAS_ACTIVE_SOURCE",\r
159            "uniprot");\r
160        StringTokenizer st = new StringTokenizer(active, "\t");\r
161        Vector selectedSources = new Vector();\r
162        String token;\r
163        while (st.hasMoreTokens())\r
164        {\r
165          token = st.nextToken();\r
166          for (int i = 0; i < sources.length; i++)\r
167          {\r
168            if (sources[i].getNickname().equals(token))\r
169            {\r
170              selectedSources.addElement(sources[i]);\r
171              break;\r
172            }\r
173          }\r
174        }\r
175      }\r
176 \r
177      if (selectedSources == null || selectedSources.size() == 0)\r
178      {\r
179        System.out.println("No DAS Sources active");\r
180        af.setProgressBar("No DAS Sources Active", startTime);\r
181        return;\r
182      }\r
183 \r
184        sourcesRemaining = selectedSources.size();\r
185        //Now sending requests one at a time to each server\r
186        for (int sourceIndex = 0;\r
187             sourceIndex < selectedSources.size()\r
188             && !cancelled;\r
189             sourceIndex++)\r
190        {\r
191          DasSource dasSource = (DasSource) selectedSources.elementAt(\r
192              sourceIndex);\r
193 \r
194          nextSequence(dasSource, sequences[0]);\r
195        }\r
196    }\r
197 \r
198    public void cancel()\r
199    {\r
200      af.setProgressBar("DAS Feature Fetching Cancelled", startTime);\r
201      cancelled = true;\r
202    }\r
203 \r
204    int sourcesRemaining=0;\r
205    void responseComplete(DasSource dasSource, SequenceI seq)\r
206    {\r
207      if (seq != null)\r
208      {\r
209        for (int seqIndex = 0;\r
210             seqIndex < sequences.length-1\r
211             && !cancelled; seqIndex++)\r
212        {\r
213          if (sequences[seqIndex] == seq)\r
214          {\r
215            nextSequence(dasSource, sequences[++seqIndex]);\r
216            return;\r
217          }\r
218        }\r
219      }\r
220 \r
221      sourcesRemaining --;\r
222 \r
223      if(sourcesRemaining==0)\r
224      {\r
225        af.setProgressBar("DAS Feature Fetching Complete", startTime);\r
226 \r
227        if(af.featureSettings!=null)\r
228          af.featureSettings.setTableData();\r
229 \r
230        fsettings.complete();\r
231      }\r
232 \r
233    }\r
234 \r
235    void featuresAdded(SequenceI seq)\r
236    {\r
237      af.getFeatureRenderer().featuresAdded();\r
238 \r
239      int start = af.getViewport().getStartSeq();\r
240      int end = af.getViewport().getEndSeq();\r
241      int index;\r
242      for(index=start; index<end; index++)\r
243       if(seq == af.getViewport().getAlignment().getSequenceAt(index).getDatasetSequence())\r
244        {\r
245          af.alignPanel.repaint();\r
246          break;\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       });\r
259 \r
260         if (uprefs != null)\r
261         {\r
262           // we know the id for this entry, so don't note its ID in the unknownSequences list\r
263          // for (int j = 0; j < uprefs.length; j++)\r
264           {\r
265             // Will have to pass any mapping information to the fetcher\r
266             //- the start/end for the DBRefEntry may not be the same as the sequence's start/end\r
267             DasCoordinateSystem cs[] = dasSource.getCoordinateSystem();\r
268             if(cs.length>0)\r
269             {\r
270              // for (int l = 0; l < cs.length; l++)\r
271               {\r
272                //\r
273                if (jalview.util.DBRefUtils\r
274                     .isDasCoordinateSystem(cs[0].getName(), uprefs[0]))\r
275                 {\r
276                   Cache.log.debug("Launched fetcher for coordinate system " +\r
277                                   cs[0].getName());\r
278 \r
279                   createFeatureFetcher(seq,\r
280                                        dasSource,\r
281                                        uprefs[0].getAccessionId());\r
282                 }\r
283               }\r
284             }\r
285           }\r
286         }\r
287         else\r
288         {\r
289           String id = null;\r
290           // try and use the name as the sequence id\r
291           if (seq.getName().indexOf("|") > -1)\r
292           {\r
293             id = seq.getName().substring(\r
294                 seq.getName().lastIndexOf("|") + 1);\r
295           }\r
296           else\r
297           {\r
298             id = seq.getName();\r
299           }\r
300           if (id != null)\r
301           {\r
302             // Should try to call a general feature fetcher that\r
303             // queries many sources with name to discover applicable ID references\r
304             createFeatureFetcher(seq,\r
305                                  dasSource,\r
306                                  id);\r
307           }\r
308         }\r
309 \r
310    }\r
311 \r
312   /**\r
313    * fetch and add das features to a sequence using the given source URL and Id to create a feature request\r
314    * @param seq\r
315    * @param SourceUrl\r
316    * @param id\r
317    */\r
318   protected void createFeatureFetcher(final SequenceI seq,\r
319                                       final DasSource dasSource,\r
320                                       String id)\r
321   {\r
322     //////////////\r
323     /// fetch DAS features\r
324     final Das1Source source = new Das1Source();\r
325     source.setUrl(dasSource.getUrl());\r
326     source.setNickname(dasSource.getNickname());\r
327 \r
328     Cache.log.debug("new Das Feature Fetcher for " + id + " querying " +\r
329                     dasSource.getUrl());\r
330 \r
331     if (id != null && id.length() > 0)\r
332     {\r
333       FeatureThread fetcher = new FeatureThread(id\r
334                                                 //  +  ":" + start + "," + end,\r
335                                                 , source);\r
336 \r
337       fetcher.addFeatureListener(new FeatureListener()\r
338       {\r
339         public void comeBackLater(FeatureEvent e)\r
340         {\r
341           responseComplete(dasSource, seq);\r
342           Cache.log.debug("das source " + e.getDasSource().getNickname() +\r
343                           " asked us to come back in " + e.getComeBackLater() +\r
344                           " secs.");\r
345         }\r
346 \r
347         public void newFeatures(FeatureEvent e)\r
348         {\r
349 \r
350           Das1Source ds = e.getDasSource();\r
351 \r
352           Map[] features = e.getFeatures();\r
353           // add features to sequence\r
354           Cache.log.debug("das source " + ds.getUrl() + " returned " +\r
355                           features.length + " features");\r
356 \r
357           if (features.length > 0)\r
358           {\r
359             for (int i = 0; i < features.length; i++)\r
360             {\r
361               SequenceFeature f = newSequenceFeature(features[i],\r
362                   source.getNickname());\r
363 \r
364               seq.addSequenceFeature(f);\r
365             }\r
366 \r
367             featuresAdded(seq);\r
368           }\r
369           else\r
370           {\r
371           //  System.out.println("No features found for " + seq.getName()\r
372           //                     + " from: " + e.getDasSource().getNickname());\r
373           }\r
374           responseComplete(dasSource, seq);\r
375 \r
376         }\r
377       }\r
378 \r
379       );\r
380 \r
381       fetcher.start();\r
382     }\r
383   }\r
384 \r
385   /**\r
386    * creates a jalview sequence feature from a das feature document\r
387    * @param dasfeature\r
388    * @return sequence feature object created using dasfeature information\r
389    */\r
390   SequenceFeature newSequenceFeature(Map dasfeature, String nickname)\r
391   {\r
392     try\r
393     {\r
394       /**\r
395        * Different qNames for a DAS Feature - are string keys to the HashMaps in features\r
396        * "METHOD") ||\r
397                   qName.equals("TYPE") ||\r
398                   qName.equals("START") ||\r
399                   qName.equals("END") ||\r
400                   qName.equals("NOTE") ||\r
401                   qName.equals("LINK") ||\r
402                   qName.equals("SCORE")\r
403        */\r
404       String desc = new String();\r
405       if (dasfeature.containsKey("NOTE"))\r
406         desc += (String) dasfeature.get("NOTE");\r
407 \r
408       int start = 0, end = 0;\r
409       float score = 0f;\r
410 \r
411       try\r
412       {\r
413         start = Integer.parseInt(dasfeature.get("START").toString());\r
414       }\r
415       catch (Exception ex)\r
416       {}\r
417       try\r
418       {\r
419         end = Integer.parseInt(dasfeature.get("END").toString());\r
420       }\r
421       catch (Exception ex)\r
422       {}\r
423       try\r
424       {\r
425         score = Integer.parseInt(dasfeature.get("SCORE").toString());\r
426       }\r
427       catch (Exception ex)\r
428       {}\r
429 \r
430       SequenceFeature f = new SequenceFeature(\r
431           (String) dasfeature.get("TYPE"),\r
432           desc,\r
433           start,\r
434           end,\r
435           score,\r
436           nickname);\r
437 \r
438       if (dasfeature.containsKey("LINK"))\r
439       {\r
440         f.addLink(f.getType() + " " + f.begin + "_" + f.end\r
441                   + "|" + dasfeature.get("LINK"));\r
442       }\r
443 \r
444       return f;\r
445     }\r
446     catch (Exception e)\r
447     {\r
448       System.out.println("ERRR " + e);\r
449       e.printStackTrace();\r
450       System.out.println("############");\r
451       Cache.log.debug("Failed to parse " + dasfeature.toString(), e);\r
452       return null;\r
453     }\r
454   }\r
455 \r
456   public static DasSource[] getDASSources()\r
457   {\r
458     DasSourceReaderImpl reader = new DasSourceReaderImpl();\r
459 \r
460     String registryURL = jalview.bin.Cache.getDefault("DAS_REGISTRY_URL",\r
461         "http://www.dasregistry.org/registry/das1/sources/"\r
462         );\r
463 \r
464     try\r
465     {\r
466       URL url = new URL(registryURL);\r
467 \r
468       DasSource[] sources = reader.readDasSource(url);\r
469 \r
470       List das1sources = new ArrayList();\r
471       for (int i = 0; i < sources.length; i++)\r
472       {\r
473         DasSource ds = sources[i];\r
474         if (ds instanceof Das2Source)\r
475         {\r
476           Das2Source d2s = (Das2Source) ds;\r
477           if (d2s.hasDas1Capabilities())\r
478           {\r
479             Das1Source d1s = DasSourceConverter.toDas1Source(d2s);\r
480             das1sources.add(d1s);\r
481           }\r
482 \r
483         }\r
484         else if (ds instanceof Das1Source)\r
485         {\r
486           das1sources.add( (Das1Source) ds);\r
487         }\r
488       }\r
489 \r
490       return (Das1Source[]) das1sources.toArray(new Das1Source[das1sources.size()]);\r
491     }\r
492     catch (Exception ex)\r
493     {\r
494       ex.printStackTrace();\r
495       return null;\r
496     }\r
497   }\r
498 \r
499 }\r
500 \r