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