JAL-1085 - ensure sequence fetching client waits around until feature retrieval has...
[jalview.git] / src / jalview / ws / DasSequenceFeatureFetcher.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)\r
3  * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle\r
4  * \r
5  * This file is part of Jalview.\r
6  * \r
7  * Jalview is free software: you can redistribute it and/or\r
8  * modify it under the terms of the GNU General Public License \r
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
10  * \r
11  * Jalview is distributed in the hope that it will be useful, but \r
12  * WITHOUT ANY WARRANTY; without even the implied warranty \r
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
14  * PURPOSE.  See the GNU General Public License for more details.\r
15  * \r
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
17  */\r
18 package jalview.ws;\r
19 \r
20 import jalview.bin.Cache;\r
21 import jalview.datamodel.DBRefEntry;\r
22 import jalview.datamodel.SequenceFeature;\r
23 import jalview.datamodel.SequenceI;\r
24 import jalview.gui.AlignFrame;\r
25 import jalview.gui.Desktop;\r
26 import jalview.gui.FeatureSettings;\r
27 import jalview.util.UrlLink;\r
28 import jalview.ws.dbsources.das.api.DasSourceRegistryI;\r
29 import jalview.ws.dbsources.das.api.jalviewSourceI;\r
30 \r
31 import java.util.ArrayList;\r
32 import java.util.Arrays;\r
33 import java.util.Enumeration;\r
34 import java.util.HashMap;\r
35 import java.util.HashSet;\r
36 import java.util.Iterator;\r
37 import java.util.List;\r
38 import java.util.Map;\r
39 import java.util.Set;\r
40 import java.util.StringTokenizer;\r
41 import java.util.Vector;\r
42 \r
43 import javax.swing.JOptionPane;\r
44 \r
45 import org.biodas.jdas.client.FeaturesClient;\r
46 import org.biodas.jdas.client.adapters.features.DasGFFAdapter;\r
47 import org.biodas.jdas.client.adapters.features.DasGFFAdapter.GFFAdapter;\r
48 import org.biodas.jdas.client.threads.FeaturesClientMultipleSources;\r
49 import org.biodas.jdas.schema.features.ERRORSEGMENT;\r
50 import org.biodas.jdas.schema.features.FEATURE;\r
51 import org.biodas.jdas.schema.features.LINK;\r
52 import org.biodas.jdas.schema.features.SEGMENT;\r
53 import org.biodas.jdas.schema.features.TYPE;\r
54 import org.biodas.jdas.schema.features.UNKNOWNFEATURE;\r
55 import org.biodas.jdas.schema.features.UNKNOWNSEGMENT;\r
56 import org.biodas.jdas.schema.sources.COORDINATES;\r
57 \r
58 /**\r
59  * DOCUMENT ME!\r
60  * \r
61  * @author $author$\r
62  * @version $Revision$\r
63  */\r
64 public class DasSequenceFeatureFetcher\r
65 {\r
66   SequenceI[] sequences;\r
67 \r
68   AlignFrame af;\r
69 \r
70   FeatureSettings fsettings;\r
71 \r
72   StringBuffer sbuffer = new StringBuffer();\r
73 \r
74   List<jalviewSourceI> selectedSources;\r
75 \r
76   boolean cancelled = false;\r
77 \r
78   private void debug(String mesg)\r
79   {\r
80     debug(mesg, null);\r
81   }\r
82 \r
83   private void debug(String mesg, Exception e)\r
84   {\r
85     if (Cache.log != null)\r
86     {\r
87       Cache.log.debug(mesg, e);\r
88     }\r
89     else\r
90     {\r
91       System.err.println(mesg);\r
92       if (e != null)\r
93       {\r
94         e.printStackTrace();\r
95       }\r
96     }\r
97   }\r
98 \r
99   long startTime;\r
100 \r
101   private DasSourceRegistryI sourceRegistry;\r
102   private boolean useJDASMultiThread=true;\r
103   /**\r
104    * Creates a new SequenceFeatureFetcher object. Uses default\r
105    * \r
106    * @param align\r
107    *          DOCUMENT ME!\r
108    * @param ap\r
109    *          DOCUMENT ME!\r
110    */\r
111   public DasSequenceFeatureFetcher(SequenceI[] sequences,\r
112           FeatureSettings fsettings, Vector selectedSources)\r
113   {\r
114     this(sequences, fsettings, selectedSources, true, true, true);\r
115   }\r
116 \r
117   public DasSequenceFeatureFetcher(SequenceI[] oursequences,\r
118           FeatureSettings fsettings, List<jalviewSourceI> selectedSources2,\r
119           boolean checkDbrefs, boolean promptFetchDbrefs)\r
120   {\r
121     this(oursequences,fsettings,selectedSources2,checkDbrefs,promptFetchDbrefs,true);\r
122   }\r
123   public DasSequenceFeatureFetcher(SequenceI[] oursequences,\r
124           FeatureSettings fsettings, List<jalviewSourceI> selectedSources2,\r
125           boolean checkDbrefs, boolean promptFetchDbrefs, boolean useJDasMultiThread)\r
126   {\r
127     this.useJDASMultiThread=useJDasMultiThread;\r
128     this.selectedSources = new ArrayList<jalviewSourceI>();\r
129     // filter both sequences and sources to eliminate duplicates\r
130     for (jalviewSourceI src : selectedSources2)\r
131     {\r
132       if (!selectedSources.contains(src))\r
133       {\r
134         selectedSources.add(src);\r
135       }\r
136       ;\r
137     }\r
138     Vector sqs = new Vector();\r
139     for (int i = 0; i < oursequences.length; i++)\r
140     {\r
141       if (!sqs.contains(oursequences[i]))\r
142       {\r
143         sqs.addElement(oursequences[i]);\r
144       }\r
145     }\r
146     sequences = new SequenceI[sqs.size()];\r
147     for (int i = 0; i < sequences.length; i++)\r
148     {\r
149       sequences[i] = (SequenceI) sqs.elementAt(i);\r
150     }\r
151     if (fsettings != null)\r
152     {\r
153       this.fsettings = fsettings;\r
154       this.af = fsettings.af;\r
155       af.setShowSeqFeatures(true);\r
156     }\r
157     int uniprotCount = 0;\r
158     for (jalviewSourceI source : selectedSources)\r
159     {\r
160       for (COORDINATES coords : source.getVersion().getCOORDINATES())\r
161       {\r
162         // TODO: match UniProt coord system canonically (?) - does\r
163         // UniProt==uniprot==UNIPROT ?\r
164         if (coords.getAuthority().toLowerCase().equals("uniprot"))\r
165         {\r
166           uniprotCount++;\r
167           break;\r
168         }\r
169       }\r
170     }\r
171 \r
172     int refCount = 0;\r
173     for (int i = 0; i < sequences.length; i++)\r
174     {\r
175       DBRefEntry[] dbref = sequences[i].getDBRef();\r
176       if (dbref != null)\r
177       {\r
178         for (int j = 0; j < dbref.length; j++)\r
179         {\r
180           if (dbref[j].getSource().equals(\r
181                   jalview.datamodel.DBRefSource.UNIPROT))\r
182           {\r
183             refCount++;\r
184             break;\r
185           }\r
186         }\r
187       }\r
188     }\r
189 \r
190     if (checkDbrefs && refCount < sequences.length && uniprotCount > 0)\r
191     {\r
192 \r
193       int reply = JOptionPane.YES_OPTION;\r
194       if (promptFetchDbrefs)\r
195       {\r
196         reply = JOptionPane\r
197                 .showInternalConfirmDialog(\r
198                         Desktop.desktop,\r
199                         "Do you want Jalview to find\n"\r
200                                 + "Uniprot Accession ids for given sequence names?",\r
201                         "Find Uniprot Accession Ids",\r
202                         JOptionPane.YES_NO_OPTION,\r
203                         JOptionPane.QUESTION_MESSAGE);\r
204       }\r
205 \r
206       if (reply == JOptionPane.YES_OPTION)\r
207       {\r
208         Thread thread = new Thread(new FetchDBRefs());\r
209         thread.start();\r
210       }\r
211       else\r
212       {\r
213         _startFetching();\r
214       }\r
215     }\r
216     else\r
217     {\r
218       _startFetching();\r
219     }\r
220 \r
221   }\r
222   private void _startFetching()\r
223   {\r
224     running=true;\r
225     new Thread(new FetchSeqFeatures()).start();\r
226   }\r
227   class FetchSeqFeatures implements Runnable\r
228   {\r
229     public void run()\r
230     {\r
231       startFetching();\r
232       setGuiFetchComplete();\r
233     }\r
234   }\r
235   class FetchDBRefs implements Runnable\r
236   {\r
237     public void run()\r
238     {\r
239       running=true;\r
240       new DBRefFetcher(sequences, af).fetchDBRefs(true);\r
241       startFetching();\r
242       setGuiFetchComplete();\r
243     }\r
244   }\r
245 \r
246   /**\r
247    * Spawns Fetcher threads to add features to sequences in the dataset\r
248    */\r
249   void startFetching()\r
250   {\r
251     running=true;\r
252     cancelled = false;\r
253     startTime = System.currentTimeMillis();\r
254     if (af != null)\r
255     {\r
256       af.setProgressBar("Fetching DAS Sequence Features", startTime);\r
257     }\r
258     if (sourceRegistry == null)\r
259     {\r
260       sourceRegistry = Cache.getDasSourceRegistry();\r
261     }\r
262     if (selectedSources == null || selectedSources.size() == 0)\r
263     {\r
264       try\r
265       {\r
266         jalviewSourceI[] sources = sourceRegistry.getSources().toArray(\r
267                 new jalviewSourceI[0]);\r
268         String active = jalview.bin.Cache.getDefault("DAS_ACTIVE_SOURCE",\r
269                 "uniprot");\r
270         StringTokenizer st = new StringTokenizer(active, "\t");\r
271         selectedSources = new Vector();\r
272         String token;\r
273         while (st.hasMoreTokens())\r
274         {\r
275           token = st.nextToken();\r
276           for (int i = 0; i < sources.length; i++)\r
277           {\r
278             if (sources[i].getTitle().equals(token))\r
279             {\r
280               selectedSources.add(sources[i]);\r
281               break;\r
282             }\r
283           }\r
284         }\r
285       } catch (Exception ex)\r
286       {\r
287         debug("Exception whilst setting default feature sources from registry and local preferences.",\r
288                 ex);\r
289       }\r
290     }\r
291 \r
292     if (selectedSources == null || selectedSources.size() == 0)\r
293     {\r
294       System.out.println("No DAS Sources active");\r
295       cancelled = true;\r
296       setGuiNoDassourceActive();\r
297       return;\r
298     }\r
299 \r
300     sourcesRemaining = selectedSources.size();\r
301     FeaturesClientMultipleSources fc = new FeaturesClientMultipleSources();\r
302     fc.setConnProps(sourceRegistry.getSessionHandler());\r
303     // Now sending requests one at a time to each server\r
304     ArrayList<jalviewSourceI> srcobj = new ArrayList<jalviewSourceI>();\r
305     ArrayList<String> src = new ArrayList<String>();\r
306     List<List<String>> ids = new ArrayList<List<String>>();\r
307     List<List<DBRefEntry>> idobj = new ArrayList<List<DBRefEntry>>();\r
308     List<Map<String, SequenceI>> sqset = new ArrayList<Map<String, SequenceI>>();\r
309     for (jalviewSourceI _sr : selectedSources)\r
310     {\r
311 \r
312       Map<String, SequenceI> slist = new HashMap<String, SequenceI>();\r
313       List<DBRefEntry> idob = new ArrayList<DBRefEntry>();\r
314       List<String> qset = new ArrayList<String>();\r
315 \r
316       for (SequenceI seq : sequences)\r
317       {\r
318         Object[] idset = nextSequence(_sr, seq);\r
319         if (idset != null)\r
320         {\r
321           List<DBRefEntry> _idob = (List<DBRefEntry>) idset[0];\r
322           List<String> _qset = (List<String>) idset[1];\r
323           if (_idob.size() > 0)\r
324           {\r
325             // add sequence's ref for each id derived from it\r
326             // (space inefficient, but most unambiguous)\r
327             // could replace with hash with _qset values as keys.\r
328             Iterator<DBRefEntry> dbobj = _idob.iterator();\r
329             for (String q : _qset)\r
330             {\r
331               SequenceI osq = slist.get(q);\r
332               DBRefEntry dr = dbobj.next();\r
333               if (osq != null && osq != seq)\r
334               {\r
335                 // skip - non-canonical query\r
336               }\r
337               else\r
338               {\r
339                 idob.add(dr);\r
340                 qset.add(q);\r
341                 slist.put(q, seq);\r
342               }\r
343             }\r
344           }\r
345         }\r
346       }\r
347       if (idob.size() > 0)\r
348       {\r
349         srcobj.add(_sr);\r
350         src.add(_sr.getSourceURL());\r
351         ids.add(qset);\r
352         idobj.add(idob);\r
353         sqset.add(slist);\r
354       }\r
355     }\r
356     Map<String, Map<List<String>, Exception>> errors = new HashMap<String, Map<List<String>, Exception>>();\r
357     Map<String, Map<List<String>, DasGFFAdapter>> results = new HashMap<String, Map<List<String>, DasGFFAdapter>>();\r
358     if (!useJDASMultiThread)\r
359     {\r
360       Iterator<String> sources=src.iterator();\r
361       // iterate over each query for each source and do each one individually\r
362       for (List<String> idl:ids)\r
363       {\r
364         String source=sources.next();\r
365         FeaturesClient featuresc=new FeaturesClient(sourceRegistry.getSessionHandler().getConnectionPropertyProviderFor(source));\r
366         for (String id:idl)\r
367         {\r
368           List<String> qid=Arrays.asList(new String[] { id});\r
369           try {\r
370             DasGFFAdapter dga=featuresc.fetchData(source, qid);\r
371             Map<List<String>,DasGFFAdapter> ers=results.get(source);\r
372             if (ers==null)\r
373             {\r
374               results.put(source, ers=new HashMap<List<String>,DasGFFAdapter>());\r
375             }\r
376             ers.put(qid, dga);\r
377           } catch (Exception ex)\r
378           {\r
379             Map<List<String>,Exception> ers=errors.get(source);\r
380             if (ers==null)\r
381             {\r
382               errors.put(source, ers=new HashMap<List<String>,Exception>());\r
383             }\r
384             ers.put(qid, ex);\r
385           }\r
386         }\r
387       }\r
388     } else {\r
389       // pass them all at once\r
390     fc.fetchData(src, ids, false, results, errors);\r
391     fc.shutDown();\r
392     while (!fc.isTerminated())\r
393     {\r
394       try\r
395       {\r
396         Thread.sleep(200);\r
397       } catch (InterruptedException x)\r
398       {\r
399 \r
400       }\r
401     }\r
402     }\r
403     Iterator<List<String>> idset = ids.iterator();\r
404     Iterator<List<DBRefEntry>> idobjset = idobj.iterator();\r
405     Iterator<Map<String, SequenceI>> seqset = sqset.iterator();\r
406     for (jalviewSourceI source : srcobj)\r
407     {\r
408       processResponse(seqset.next(), source, idset.next(), idobjset.next(),\r
409               results.get(source.getSourceURL()),\r
410               errors.get(source.getSourceURL()));\r
411     }\r
412   }\r
413 \r
414   private void processResponse(Map<String, SequenceI> sequencemap,\r
415           jalviewSourceI jvsource, List<String> ids,\r
416           List<DBRefEntry> idobj, Map<List<String>, DasGFFAdapter> results,\r
417           Map<List<String>, Exception> errors)\r
418   {\r
419     Set<SequenceI> sequences = new HashSet<SequenceI>();\r
420     String source = jvsource.getSourceURL();\r
421     // process features\r
422     DasGFFAdapter result = (results == null) ? null : results.get(ids);\r
423     Exception error = (errors == null) ? null : errors.get(ids);\r
424     if (result == null)\r
425     {\r
426       debug("das source " + source + " could not be contacted. "\r
427               + (error == null ? "" : error.toString()));\r
428     }\r
429     else\r
430     {\r
431 \r
432       GFFAdapter gff = result.getGFF();\r
433       List<SEGMENT> segments = gff.getSegments();\r
434       List<ERRORSEGMENT> errorsegs = gff.getErrorSegments();\r
435       List<UNKNOWNFEATURE> unkfeats = gff.getUnknownFeatures();\r
436       List<UNKNOWNSEGMENT> unksegs = gff.getUnknownSegments();\r
437       debug("das source " + source + " returned " + gff.getTotal()\r
438               + " responses. " + (errorsegs != null ? errorsegs.size() : 0)\r
439               + " were incorrect segment queries, "\r
440               + (unkfeats != null ? unkfeats.size() : 0)\r
441               + " were unknown features "\r
442               + (unksegs != null ? unksegs.size() : 0)\r
443               + " were unknown segments and "\r
444               + (segments != null ? segments.size() : 0)\r
445               + " were segment responses.");\r
446       Iterator<DBRefEntry> dbr = idobj.iterator();\r
447       if (segments != null)\r
448       {\r
449         for (SEGMENT seg : segments)\r
450         {\r
451           String id = seg.getId();\r
452           DBRefEntry dbref = idobj.get(ids.indexOf(id));\r
453           SequenceI sequence = sequencemap.get(id);\r
454           boolean added = false;\r
455           sequences.add(sequence);\r
456 \r
457           for (FEATURE feat : seg.getFEATURE())\r
458           {\r
459             // standard DAS feature-> jalview sequence feature transformation\r
460             SequenceFeature f = newSequenceFeature(feat, jvsource.getTitle());\r
461             if (!parseSeqFeature(sequence, f, feat, jvsource))\r
462             {\r
463               if (dbref.getMap() != null && f.getBegin() > 0\r
464                       && f.getEnd() > 0)\r
465               {\r
466                 debug("mapping from " + f.getBegin() + " - " + f.getEnd());\r
467                 SequenceFeature vf[] = null;\r
468 \r
469                 try\r
470                 {\r
471                   vf = dbref.getMap().locateFeature(f);\r
472                 } catch (Exception ex)\r
473                 {\r
474                   Cache.log\r
475                           .info("Error in 'experimental' mapping of features. Please try to reproduce and then report info to jalview-discuss@jalview.org.");\r
476                   Cache.log.info("Mapping feature from " + f.getBegin()\r
477                           + " to " + f.getEnd() + " in dbref "\r
478                           + dbref.getAccessionId() + " in "\r
479                           + dbref.getSource());\r
480                   Cache.log.info("using das Source " + source);\r
481                   Cache.log.info("Exception", ex);\r
482                 }\r
483 \r
484                 if (vf != null)\r
485                 {\r
486                   for (int v = 0; v < vf.length; v++)\r
487                   {\r
488                     debug("mapping to " + v + ": " + vf[v].getBegin()\r
489                             + " - " + vf[v].getEnd());\r
490                     sequence.addSequenceFeature(vf[v]);\r
491                   }\r
492                 }\r
493               }\r
494               else\r
495               {\r
496                 sequence.addSequenceFeature(f);\r
497               }\r
498             }\r
499           }\r
500         }\r
501         featuresAdded(sequences);\r
502       }\r
503       else\r
504       {\r
505         // System.out.println("No features found for " + seq.getName()\r
506         // + " from: " + e.getDasSource().getNickname());\r
507       }\r
508     }\r
509   }\r
510 \r
511   private void setGuiNoDassourceActive()\r
512   {\r
513 \r
514     if (af != null)\r
515     {\r
516       af.setProgressBar("No DAS Sources Active", startTime);\r
517     }\r
518     if (getFeatSettings() != null)\r
519     {\r
520       fsettings.noDasSourceActive();\r
521     }\r
522   }\r
523 \r
524   /**\r
525    * Update our fsettings dialog reference if we didn't have one when we were\r
526    * first initialised.\r
527    * \r
528    * @return fsettings\r
529    */\r
530   private FeatureSettings getFeatSettings()\r
531   {\r
532     if (fsettings == null)\r
533     {\r
534       if (af != null)\r
535       {\r
536         fsettings = af.featureSettings;\r
537       }\r
538     }\r
539     return fsettings;\r
540   }\r
541 \r
542   public void cancel()\r
543   {\r
544     if (af != null)\r
545     {\r
546       af.setProgressBar("DAS Feature Fetching Cancelled", startTime);\r
547     }\r
548     cancelled = true;\r
549   }\r
550 \r
551   int sourcesRemaining = 0;\r
552   private boolean running=false;\r
553   private void setGuiFetchComplete()\r
554   {\r
555     running=false;\r
556     if (!cancelled && af != null)\r
557     {\r
558       // only update the progress bar if we've completed the fetch normally\r
559       af.setProgressBar("DAS Feature Fetching Complete", startTime);\r
560     }\r
561 \r
562     if (af != null && af.featureSettings != null)\r
563     {\r
564       af.featureSettings.setTableData();\r
565     }\r
566 \r
567     if (getFeatSettings() != null)\r
568     {\r
569       fsettings.complete();\r
570     }\r
571   }\r
572 \r
573   void featuresAdded(Set<SequenceI> seqs)\r
574   {\r
575     if (af == null)\r
576     {\r
577       // no gui to update with features.\r
578       return;\r
579     }\r
580     af.getFeatureRenderer().featuresAdded();\r
581 \r
582     int start = af.getViewport().getStartSeq();\r
583     int end = af.getViewport().getEndSeq();\r
584     int index;\r
585     for (index = start; index < end; index++)\r
586     {\r
587       for (SequenceI seq : seqs)\r
588       {\r
589         if (seq == af.getViewport().getAlignment().getSequenceAt(index)\r
590                 .getDatasetSequence())\r
591         {\r
592           af.alignPanel.paintAlignment(true);\r
593           index = end;\r
594           break;\r
595         }\r
596       }\r
597     }\r
598   }\r
599 \r
600   Object[] nextSequence(jalviewSourceI dasSource, SequenceI seq)\r
601   {\r
602     if (cancelled)\r
603       return null;\r
604     DBRefEntry[] uprefs = jalview.util.DBRefUtils.selectRefs(\r
605             seq.getDBRef(), new String[]\r
606             {\r
607             // jalview.datamodel.DBRefSource.PDB,\r
608             jalview.datamodel.DBRefSource.UNIPROT,\r
609             // jalview.datamodel.DBRefSource.EMBL - not tested on any EMBL coord\r
610             // sys sources\r
611             });\r
612     // TODO: minimal list of DAS queries to make by querying with untyped ID if\r
613     // distinct from any typed IDs\r
614 \r
615     List<DBRefEntry> ids = new ArrayList<DBRefEntry>();\r
616     List<String> qstring = new ArrayList<String>();\r
617     boolean dasCoordSysFound = false;\r
618 \r
619     if (uprefs != null)\r
620     {\r
621       // do any of these ids match the source's coordinate system ?\r
622       for (int j = 0; !dasCoordSysFound && j < uprefs.length; j++)\r
623       {\r
624 \r
625         for (COORDINATES csys : dasSource.getVersion().getCOORDINATES())\r
626         {\r
627           if (jalview.util.DBRefUtils.isDasCoordinateSystem(\r
628                   csys.getAuthority(), uprefs[j]))\r
629           {\r
630             debug("Launched fetcher for coordinate system "\r
631                     + csys.getAuthority());\r
632             // Will have to pass any mapping information to the fetcher\r
633             // - the start/end for the DBRefEntry may not be the same as the\r
634             // sequence's start/end\r
635 \r
636             System.out.println(seq.getName() + " "\r
637                     + (seq.getDatasetSequence() == null) + " "\r
638                     + csys.getUri());\r
639 \r
640             dasCoordSysFound = true; // break's out of the loop\r
641             ids.add(uprefs[j]);\r
642             qstring.add(uprefs[j].getAccessionId());\r
643           }\r
644           else\r
645             System.out.println("IGNORE " + csys.getAuthority());\r
646         }\r
647       }\r
648     }\r
649 \r
650     if (!dasCoordSysFound)\r
651     {\r
652       String id = null;\r
653       // try and use the name as the sequence id\r
654       if (seq.getName().indexOf("|") > -1)\r
655       {\r
656         id = seq.getName().substring(seq.getName().lastIndexOf("|") + 1);\r
657         if (id.trim().length() < 4)\r
658         {\r
659           // hack - we regard a significant ID as being at least 4\r
660           // non-whitespace characters\r
661           id = seq.getName().substring(0, seq.getName().lastIndexOf("|"));\r
662           if (id.indexOf("|") > -1)\r
663           {\r
664             id = id.substring(id.lastIndexOf("|") + 1);\r
665           }\r
666         }\r
667       }\r
668       else\r
669       {\r
670         id = seq.getName();\r
671       }\r
672       if (id != null)\r
673       {\r
674         DBRefEntry dbre = new DBRefEntry();\r
675         dbre.setAccessionId(id);\r
676         // Should try to call a general feature fetcher that\r
677         // queries many sources with name to discover applicable ID references\r
678         ids.add(dbre);\r
679         qstring.add(dbre.getAccessionId());\r
680       }\r
681     }\r
682 \r
683     return new Object[]\r
684     { ids, qstring };\r
685   }\r
686 \r
687   /**\r
688    * examine the given sequence feature to determine if it should actually be\r
689    * turned into sequence annotation or database cross references rather than a\r
690    * simple sequence feature.\r
691    * \r
692    * @param seq\r
693    *          the sequence to annotate\r
694    * @param f\r
695    *          the jalview sequence feature generated from the DAS feature\r
696    * @param map\r
697    *          the sequence feature attributes\r
698    * @param source\r
699    *          the source that emitted the feature\r
700    * @return true if feature was consumed as another kind of annotation.\r
701    */\r
702   protected boolean parseSeqFeature(SequenceI seq, SequenceFeature f,\r
703           FEATURE feature, jalviewSourceI source)\r
704   {\r
705     SequenceI mseq = seq;\r
706     while (seq.getDatasetSequence() != null)\r
707     {\r
708       seq = seq.getDatasetSequence();\r
709     }\r
710     if (f.getType() != null)\r
711     {\r
712       String type = f.getType();\r
713       if (type.equalsIgnoreCase("protein_name"))\r
714       {\r
715         // parse name onto the alignment sequence or the dataset sequence.\r
716         if (seq.getDescription() == null\r
717                 || seq.getDescription().trim().length() == 0)\r
718         {\r
719           // could look at the note series to pick out the first long name, for\r
720           // the moment just use the whole description string\r
721           seq.setDescription(f.getDescription());\r
722         }\r
723         if (mseq.getDescription() == null\r
724                 || mseq.getDescription().trim().length() == 0)\r
725         {\r
726           // could look at the note series to pick out the first long name, for\r
727           // the moment just use the whole description string\r
728           mseq.setDescription(f.getDescription());\r
729         }\r
730         return true;\r
731       }\r
732       // check if source has biosapiens or other sequence ontology label\r
733       if (type.equalsIgnoreCase("DBXREF") || type.equalsIgnoreCase("DBREF"))\r
734       {\r
735         // try to parse the accession out\r
736 \r
737         DBRefEntry dbr = new DBRefEntry();\r
738         dbr.setVersion(source.getTitle());\r
739         StringTokenizer st = new StringTokenizer(f.getDescription(), ":");\r
740         if (st.hasMoreTokens())\r
741         {\r
742           dbr.setSource(st.nextToken());\r
743         }\r
744         if (st.hasMoreTokens())\r
745         {\r
746           dbr.setAccessionId(st.nextToken());\r
747         }\r
748         seq.addDBRef(dbr);\r
749 \r
750         if (f.links != null && f.links.size() > 0)\r
751         {\r
752           // feature is also appended to enable links to be seen.\r
753           // TODO: consider extending dbrefs to have their own links ?\r
754           // TODO: new feature: extract dbref links from DAS servers and add the\r
755           // URL pattern to the list of DB name associated links in the user's\r
756           // preferences ?\r
757           // for the moment - just fix up the existing feature so it displays\r
758           // correctly.\r
759           // f.setType(dbr.getSource());\r
760           // f.setDescription();\r
761           f.setValue("linkonly", Boolean.TRUE);\r
762           // f.setDescription("");\r
763           Vector newlinks = new Vector();\r
764           Enumeration it = f.links.elements();\r
765           while (it.hasMoreElements())\r
766           {\r
767             String elm;\r
768             UrlLink urllink = new UrlLink(elm = (String) it.nextElement());\r
769             if (urllink.isValid())\r
770             {\r
771               urllink.setLabel(f.getDescription());\r
772               newlinks.addElement(urllink.toString());\r
773             }\r
774             else\r
775             {\r
776               // couldn't parse the link properly. Keep it anyway - just in\r
777               // case.\r
778               debug("couldn't parse link string - " + elm);\r
779               newlinks.addElement(elm);\r
780             }\r
781           }\r
782           f.links = newlinks;\r
783           seq.addSequenceFeature(f);\r
784         }\r
785         return true;\r
786       }\r
787     }\r
788     return false;\r
789   }\r
790 \r
791   /**\r
792    * creates a jalview sequence feature from a das feature document\r
793    * \r
794    * @param feat\r
795    * @return sequence feature object created using dasfeature information\r
796    */\r
797   SequenceFeature newSequenceFeature(FEATURE feat, String nickname)\r
798   {\r
799     if (feat == null)\r
800     {\r
801       return null;\r
802     }\r
803     try\r
804     {\r
805       /**\r
806        * Different qNames for a DAS Feature - are string keys to the HashMaps in\r
807        * features "METHOD") || qName.equals("TYPE") || qName.equals("START") ||\r
808        * qName.equals("END") || qName.equals("NOTE") || qName.equals("LINK") ||\r
809        * qName.equals("SCORE")\r
810        */\r
811       String desc = new String();\r
812       if (feat.getNOTE() != null)\r
813       {\r
814         for (String note : feat.getNOTE())\r
815         {\r
816           desc += (String) note;\r
817         }\r
818       }\r
819 \r
820       int start = 0, end = 0;\r
821       float score = 0f;\r
822 \r
823       try\r
824       {\r
825         start = Integer.parseInt(feat.getSTART().toString());\r
826       } catch (Exception ex)\r
827       {\r
828       }\r
829       try\r
830       {\r
831         end = Integer.parseInt(feat.getEND().toString());\r
832       } catch (Exception ex)\r
833       {\r
834       }\r
835       try\r
836       {\r
837         Object scr = feat.getSCORE();\r
838         if (scr != null)\r
839         {\r
840           score = (float) Double.parseDouble(scr.toString());\r
841 \r
842         }\r
843       } catch (Exception ex)\r
844       {\r
845       }\r
846 \r
847       SequenceFeature f = new SequenceFeature(\r
848               getTypeString(feat.getTYPE()), desc, start, end, score,\r
849               nickname);\r
850 \r
851       if (feat.getLINK() != null)\r
852       {\r
853         for (LINK link : feat.getLINK())\r
854         {\r
855           // Do not put feature extent in link text for non-positional features\r
856           if (f.begin == 0 && f.end == 0)\r
857           {\r
858             f.addLink(f.getType() + " " + link.getContent() + "|"\r
859                     + link.getHref());\r
860           }\r
861           else\r
862           {\r
863             f.addLink(f.getType() + " " + f.begin + "_" + f.end + " "\r
864                     + link.getContent() + "|" + link.getHref());\r
865           }\r
866         }\r
867       }\r
868 \r
869       return f;\r
870     } catch (Exception e)\r
871     {\r
872       System.out.println("ERRR " + e);\r
873       e.printStackTrace();\r
874       System.out.println("############");\r
875       debug("Failed to parse " + feat.toString(), e);\r
876       return null;\r
877     }\r
878   }\r
879 \r
880   private String getTypeString(TYPE type)\r
881   {\r
882     return type.getContent();\r
883   }\r
884 \r
885   public boolean isRunning()\r
886   {\r
887     return running;\r
888   }\r
889 \r
890 }\r