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