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