7a001a94212283507ad9391d1011df1e8a5eb6b2
[jalview.git] / src / jalview / io / DasSequenceFeatureFetcher.java
1 /*\r
2 * Jalview - A Sequence Alignment Editor and Viewer\r
3 * Copyright (C) 2005 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 \r
41 import jalview.bin.Cache;\r
42 import org.biojava.dasobert.dasregistry.DasCoordinateSystem;\r
43 \r
44 import javax.swing.*;\r
45 \r
46 /**\r
47  * DOCUMENT ME!\r
48  *\r
49  * @author $author$\r
50  * @version $Revision$\r
51  */\r
52 public class DasSequenceFeatureFetcher implements Runnable\r
53 {\r
54   SequenceI [] sequences;\r
55   AlignFrame af;\r
56   StringBuffer sbuffer = new StringBuffer();\r
57   Vector selectedSources;\r
58 \r
59   long startTime;\r
60   int threadsRunning = 0;\r
61 \r
62 \r
63   /**\r
64    * Creates a new SequenceFeatureFetcher object.\r
65    * Uses default\r
66    *\r
67    * @param align DOCUMENT ME!\r
68    * @param ap DOCUMENT ME!\r
69    */\r
70   public DasSequenceFeatureFetcher(SequenceI [] sequences,\r
71                                    final AlignFrame af,\r
72                                    Vector selectedSources)\r
73   {\r
74     this.selectedSources = selectedSources;\r
75     this.sequences = sequences;\r
76     this.af = af;\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   /* System.out.println("User selection is "   +\r
133                        ( ( (float) uniprotCount / (float) selectedSources.size()) * 100)\r
134                       + " % Uniprot,  and "+refCount+" / " +sequences.length+" have uniprot accession");\r
135 */\r
136   }\r
137 \r
138   void startFetching()\r
139   {\r
140     Thread thread = new Thread(this);\r
141     thread.start();\r
142   }\r
143 \r
144   class FetchDBRefs implements Runnable\r
145   {\r
146     public void run()\r
147     {\r
148       new DBRefFetcher(\r
149              af.getViewport().getAlignment(), af).fetchDBRefs(true);\r
150       startFetching();\r
151     }\r
152   }\r
153 \r
154 \r
155   /**\r
156    * creates a jalview sequence feature from a das feature document\r
157    * @param dasfeature\r
158    * @return sequence feature object created using dasfeature information\r
159    */\r
160   SequenceFeature newSequenceFeature(Map dasfeature, String nickname)\r
161   {\r
162           try {\r
163                 /**\r
164            * Different qNames for a DAS Feature - are string keys to the HashMaps in features\r
165            * "METHOD") ||\r
166            qName.equals("TYPE") ||\r
167            qName.equals("START") ||\r
168            qName.equals("END") ||\r
169            qName.equals("NOTE") ||\r
170            qName.equals("LINK") ||\r
171            qName.equals("SCORE")\r
172            */\r
173                   String desc = new String();\r
174                   if (dasfeature.containsKey("NOTE"))\r
175                                 desc+=(String) dasfeature.get("NOTE");\r
176 \r
177 \r
178                   int start = 0, end = 0;\r
179                   float score = 0f;\r
180 \r
181                   try{ start = Integer.parseInt( dasfeature.get("START").toString()); }\r
182                   catch( Exception ex){}\r
183                   try{ end = Integer.parseInt( dasfeature.get("END").toString()); }\r
184                   catch (Exception ex){}\r
185                   try{ score = Integer.parseInt( dasfeature.get("SCORE").toString()); }\r
186                   catch (Exception ex){}\r
187 \r
188 \r
189                   SequenceFeature f = new SequenceFeature(\r
190                                   (String) dasfeature.get("TYPE"),\r
191                                   desc,\r
192                                   start,\r
193                                   end,\r
194                                   score,\r
195                                   nickname);\r
196 \r
197                   if (dasfeature.containsKey("LINK"))\r
198                  {\r
199                       f.addLink(f.getType()+" "+f.begin+"_"+f.end\r
200                                 +"|"+ dasfeature.get("LINK"));\r
201                   }\r
202                   // (String) dasfeature.get("ID"),\r
203                   ////  (String) dasfeature.get("METHOD"),\r
204                                 //  (String) dasfeature.get("SCORE"),\r
205                                 //  null\r
206                         // );\r
207 \r
208           return f;\r
209           }\r
210           catch (Exception e) {\r
211             e.printStackTrace();\r
212                   Cache.log.debug("Failed to parse "+dasfeature.toString(), e);\r
213                   return null;\r
214           }\r
215   }\r
216   /**\r
217    * fetch and add das features to a sequence using the given source URL and Id to create a feature request\r
218    * @param seq\r
219    * @param SourceUrl\r
220    * @param id\r
221    */\r
222   protected void createFeatureFetcher(final SequenceI seq,\r
223                                       final String sourceUrl,\r
224                                       String id,\r
225                                       String nickname)\r
226   {\r
227           //////////////\r
228           /// fetch DAS features\r
229           final Das1Source source = new Das1Source();\r
230           source.setUrl(sourceUrl);\r
231           source.setNickname(nickname);\r
232 \r
233 \r
234           Cache.log.debug("new Das Feature Fetcher for " + id + " querying " +\r
235                           sourceUrl);\r
236 \r
237           if (id != null && id.length() > 0)\r
238           {\r
239             setThreadsRunning(+1);\r
240 \r
241           //  int start=seq.getStart(), end = seq.getEnd();\r
242           /*  if(af.getViewport().getSelectionGroup()!=null)\r
243             {\r
244               SequenceI tmp = af.getViewport().getAlignment().findName(seq.getName());\r
245               start = tmp.findPosition(\r
246               af.getViewport().getSelectionGroup().getStartRes()\r
247                   );\r
248 \r
249               end = tmp.findPosition(\r
250                  af.getViewport().getSelectionGroup().getEndRes()\r
251                  );\r
252             }*/\r
253 \r
254             FeatureThread fetcher = new FeatureThread(id\r
255                                                    //  +  ":" + start + "," + end,\r
256                                                       , source);\r
257 \r
258 \r
259             fetcher.addFeatureListener(new FeatureListener()\r
260             {\r
261               public void comeBackLater(FeatureEvent e)\r
262               {\r
263                 setThreadsRunning(-1);\r
264                 Cache.log.debug("das source " + e.getDasSource().getNickname() +\r
265                                 " asked us to come back in " + e.getComeBackLater() +\r
266                                 " secs.");\r
267               }\r
268 \r
269               public void newFeatures(FeatureEvent e)\r
270               {\r
271                 setThreadsRunning(-1);\r
272                 Das1Source ds = e.getDasSource();\r
273 \r
274                 Map[] features = e.getFeatures();\r
275                 // add features to sequence\r
276                 Cache.log.debug("das source " + ds.getUrl() + " returned " +\r
277                                 features.length + " features");\r
278 \r
279                 if (features.length > 0)\r
280                 {\r
281                   for (int i = 0; i < features.length; i++)\r
282                   {\r
283                       SequenceFeature f = newSequenceFeature(features[i],\r
284                         source.getNickname());\r
285 \r
286                       seq.addSequenceFeature(f);\r
287                   }\r
288                 }\r
289                 else\r
290                 {\r
291                   System.out.println("No features found for sequence " +seq.getName()\r
292                                      +" from: "+ e.getDasSource().getNickname());\r
293                 }\r
294 \r
295               }\r
296             }\r
297 \r
298             );\r
299 \r
300             //NOTE alignPanel listener will be called after the previous\r
301             //anonymous listener!!!\r
302             fetcher.addFeatureListener(af);\r
303 \r
304             fetcher.start();\r
305           }\r
306   }\r
307 \r
308   synchronized void setThreadsRunning(int i)\r
309   {\r
310     threadsRunning += i;\r
311     if(threadsRunning<1)\r
312     {\r
313       af.setProgressBar("DAS Feature Fetching Complete", startTime);\r
314 \r
315       if(af.featureSettings!=null)\r
316         af.featureSettings.setTableData();\r
317     }\r
318   }\r
319 \r
320   /**\r
321    * Spawns a number of dasobert Fetcher threads to add features to sequences in the dataset\r
322    */\r
323   public void run()\r
324   {\r
325     startTime = System.currentTimeMillis();\r
326     af.setProgressBar("Fetching DAS Sequence Features", startTime);\r
327 \r
328     DasSource [] sources = new jalview.gui.DasSourceBrowser().getDASSource();\r
329 \r
330     if(selectedSources==null || selectedSources.size()==0)\r
331     {\r
332       String active = jalview.bin.Cache.getDefault("DAS_ACTIVE_SOURCE", "uniprot");\r
333       StringTokenizer st = new StringTokenizer(active, "\t");\r
334       Vector selectedSources = new Vector();\r
335       String token;\r
336       while (st.hasMoreTokens())\r
337       {\r
338         token = st.nextToken();\r
339         for (int i = 0; i < sources.length; i++)\r
340         {\r
341           if (sources[i].getNickname().equals(token))\r
342           {\r
343             selectedSources.addElement(sources[i]);\r
344             break;\r
345           }\r
346         }\r
347       }\r
348     }\r
349 \r
350     if(selectedSources == null || selectedSources.size()==0)\r
351     {\r
352       System.out.println("No DAS Sources active");\r
353       af.setProgressBar("No DAS Sources Active", startTime);\r
354       return;\r
355     }\r
356 \r
357     try\r
358     {\r
359       int seqIndex = 0;\r
360       while (seqIndex < sequences.length)\r
361       {\r
362           DBRefEntry [] uprefs = jalview.util.DBRefUtils.selectRefs(sequences[seqIndex].getDBRef(),\r
363               new String[]  {\r
364               jalview.datamodel.DBRefSource.PDB,\r
365               jalview.datamodel.DBRefSource.UNIPROT});\r
366 \r
367           for(int sourceIndex=0; sourceIndex<selectedSources.size(); sourceIndex++)\r
368           {\r
369             DasSource dasSource = (DasSource)selectedSources.elementAt(sourceIndex);\r
370 \r
371             if (uprefs != null)\r
372             {\r
373               // we know the id for this entry, so don't note its ID in the unknownSequences list\r
374               for (int j = 0;  j < uprefs.length; j++)\r
375               {\r
376 \r
377                 // Will have to pass any mapping information to the fetcher - the start/end for the DBRefEntry may not be the same as the sequence's start/end\r
378                 DasCoordinateSystem cs[] = dasSource.getCoordinateSystem();\r
379                 for (int l=0; l<cs.length; l++)\r
380                 {\r
381                   if (jalview.util.DBRefUtils.isDasCoordinateSystem(cs[l].getName(), uprefs[j]))\r
382                   {\r
383                     Cache.log.debug("Launched fetcher for coordinate system " +\r
384                                     cs[l].getName());\r
385 \r
386 \r
387                     createFeatureFetcher(sequences[seqIndex],\r
388                                          dasSource.getUrl(),\r
389                                           uprefs[j].getAccessionId(),\r
390                                          dasSource.getNickname());\r
391                   }\r
392                 }\r
393               }\r
394             }\r
395             else\r
396             {\r
397               String id = null;\r
398               // try and use the name as the sequence id\r
399               if (sequences[seqIndex].getName().indexOf("|") > -1)\r
400               {\r
401                 id = sequences[seqIndex].getName().substring(\r
402                     sequences[seqIndex].getName().lastIndexOf("|") + 1);\r
403               }\r
404               else\r
405               {\r
406                 id = sequences[seqIndex].getName();\r
407               }\r
408               if (id != null)\r
409               {\r
410                 // Should try to call a general feature fetcher that queries many sources with name to discover applicable ID references\r
411                 createFeatureFetcher(sequences[seqIndex],\r
412                                      dasSource.getUrl(),\r
413                                      id,\r
414                                      dasSource.getNickname());\r
415               }\r
416             }\r
417           }\r
418 \r
419           seqIndex++;\r
420     }\r
421     }\r
422     catch (Exception ex)\r
423     {\r
424       ex.printStackTrace();\r
425     }\r
426   }\r
427 \r
428 \r
429   public static DasSource[] getDASSources()\r
430   {\r
431     DasSourceReaderImpl reader = new DasSourceReaderImpl();\r
432 \r
433     String registryURL =jalview.bin.Cache.getDefault("DAS_REGISTRY_URL",\r
434         "http://das.sanger.ac.uk/registry/das1/sources/"\r
435       );\r
436 \r
437     try\r
438     {\r
439       URL url = new URL(registryURL);\r
440 \r
441       DasSource[] sources = reader.readDasSource(url);\r
442 \r
443       List das1sources = new ArrayList();\r
444       for (int i = 0; i < sources.length; i++)\r
445       {\r
446         DasSource ds = sources[i];\r
447         if (ds instanceof Das2Source)\r
448         {\r
449           Das2Source d2s = (Das2Source) ds;\r
450           if (d2s.hasDas1Capabilities())\r
451           {\r
452             Das1Source d1s = DasSourceConverter.toDas1Source(d2s);\r
453             das1sources.add(d1s);\r
454           }\r
455 \r
456         }\r
457         else if (ds instanceof Das1Source)\r
458         {\r
459           das1sources.add( (Das1Source) ds);\r
460         }\r
461       }\r
462 \r
463       return (Das1Source[]) das1sources.toArray(new Das1Source[das1sources.size()]);\r
464     }\r
465     catch (Exception ex)\r
466     {\r
467       ex.printStackTrace();\r
468       return null;\r
469     }\r
470 \r
471   }\r
472 }\r
473 \r
474 \r