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