apply gpl development license
[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 (af != null)\r
334     {\r
335       af.setProgressBar("DAS Feature Fetching Complete", startTime);\r
336     }\r
337 \r
338     if (af != null && af.featureSettings != null)\r
339     {\r
340       af.featureSettings.setTableData();\r
341     }\r
342 \r
343     if (getFeatSettings() != null)\r
344     {\r
345       fsettings.complete();\r
346     }\r
347   }\r
348 \r
349   void featuresAdded(SequenceI seq)\r
350   {\r
351     if (af == null)\r
352     {\r
353       // no gui to update with features.\r
354       return;\r
355     }\r
356     af.getFeatureRenderer().featuresAdded();\r
357 \r
358     int start = af.getViewport().getStartSeq();\r
359     int end = af.getViewport().getEndSeq();\r
360     int index;\r
361     for (index = start; index < end; index++)\r
362     {\r
363       if (seq == af.getViewport().getAlignment().getSequenceAt(index)\r
364               .getDatasetSequence())\r
365       {\r
366         af.alignPanel.paintAlignment(true);\r
367         break;\r
368       }\r
369     }\r
370   }\r
371 \r
372   void nextSequence(DasSource dasSource, SequenceI seq)\r
373   {\r
374     if (cancelled)\r
375       return;\r
376     DBRefEntry[] uprefs = jalview.util.DBRefUtils.selectRefs(\r
377             seq.getDBRef(), new String[]\r
378             {\r
379             // jalview.datamodel.DBRefSource.PDB,\r
380             jalview.datamodel.DBRefSource.UNIPROT,\r
381             // jalview.datamodel.DBRefSource.EMBL - not tested on any EMBL coord\r
382             // sys sources\r
383             });\r
384     // TODO: minimal list of DAS queries to make by querying with untyped ID if\r
385     // distinct from any typed IDs\r
386 \r
387     boolean dasCoordSysFound = false;\r
388 \r
389     if (uprefs != null)\r
390     {\r
391       // do any of these ids match the source's coordinate system ?\r
392       for (int j = 0; !dasCoordSysFound && j < uprefs.length; j++)\r
393       {\r
394         DasCoordinateSystem cs[] = dasSource.getCoordinateSystem();\r
395 \r
396         for (int csIndex = 0; csIndex < cs.length && !dasCoordSysFound; csIndex++)\r
397         {\r
398           if (cs.length > 0\r
399                   && jalview.util.DBRefUtils.isDasCoordinateSystem(\r
400                           cs[csIndex].getName(), uprefs[j]))\r
401           {\r
402             debug("Launched fetcher for coordinate system "\r
403                     + cs[0].getName());\r
404             // Will have to pass any mapping information to the fetcher\r
405             // - the start/end for the DBRefEntry may not be the same as the\r
406             // sequence's start/end\r
407 \r
408             System.out.println(seq.getName() + " "\r
409                     + (seq.getDatasetSequence() == null) + " "\r
410                     + dasSource.getUrl());\r
411 \r
412             dasCoordSysFound = true; // break's out of the loop\r
413             createFeatureFetcher(seq, dasSource, uprefs[j]);\r
414           }\r
415           else\r
416             System.out.println("IGNORE " + cs[csIndex].getName());\r
417         }\r
418       }\r
419     }\r
420 \r
421     if (!dasCoordSysFound)\r
422     {\r
423       String id = null;\r
424       // try and use the name as the sequence id\r
425       if (seq.getName().indexOf("|") > -1)\r
426       {\r
427         id = seq.getName().substring(seq.getName().lastIndexOf("|") + 1);\r
428         if (id.trim().length() < 4)\r
429         {\r
430           // hack - we regard a significant ID as being at least 4\r
431           // non-whitespace characters\r
432           id = seq.getName().substring(0, seq.getName().lastIndexOf("|"));\r
433           if (id.indexOf("|") > -1)\r
434           {\r
435             id = id.substring(id.lastIndexOf("|") + 1);\r
436           }\r
437         }\r
438       }\r
439       else\r
440       {\r
441         id = seq.getName();\r
442       }\r
443       if (id != null)\r
444       {\r
445         // Should try to call a general feature fetcher that\r
446         // queries many sources with name to discover applicable ID references\r
447         createFeatureFetcher(seq, dasSource, id);\r
448       }\r
449     }\r
450 \r
451   }\r
452 \r
453   /**\r
454    * fetch and add das features to a sequence using the given source URL and\r
455    * compatible DbRef id. new features are mapped using the DbRef mapping to the\r
456    * local coordinate system.\r
457    * \r
458    * @param seq\r
459    * @param SourceUrl\r
460    * @param dbref\r
461    */\r
462   protected void createFeatureFetcher(final SequenceI seq,\r
463           final DasSource dasSource, final DBRefEntry dbref)\r
464   {\r
465 \r
466     // ////////////\r
467     // / fetch DAS features\r
468     final Das1Source source = new Das1Source();\r
469     source.setUrl(dasSource.getUrl());\r
470     source.setNickname(dasSource.getNickname());\r
471     if (dbref == null || dbref.getAccessionId() == null\r
472             || dbref.getAccessionId().length() < 1)\r
473     {\r
474       responseComplete(dasSource, seq); // reduce thread count anyhow\r
475       return;\r
476     }\r
477     debug("new Das Feature Fetcher for " + dbref.getSource() + ":"\r
478             + dbref.getAccessionId() + " querying " + dasSource.getUrl());\r
479     FeatureThread fetcher = new FeatureThread(dbref.getAccessionId()\r
480     // + ":" + start + "," + end,\r
481             , source);\r
482 \r
483     fetcher.addFeatureListener(new FeatureListener()\r
484     {\r
485       public void comeBackLater(FeatureEvent e)\r
486       {\r
487         responseComplete(dasSource, seq);\r
488         debug("das source " + e.getSource().getNickname()\r
489                 + " asked us to come back in " + e.getComeBackLater()\r
490                 + " secs.");\r
491       }\r
492 \r
493       public void newFeatures(FeatureEvent e)\r
494       {\r
495 \r
496         Das1Source ds = e.getSource();\r
497 \r
498         Map[] features = e.getFeatures();\r
499         // add features to sequence\r
500         debug("das source " + ds.getUrl() + " returned " + features.length\r
501                 + " features");\r
502 \r
503         if (features.length > 0)\r
504         {\r
505           for (int i = 0; i < features.length; i++)\r
506           {\r
507             // standard DAS feature-> jalview sequence feature transformation\r
508             SequenceFeature f = newSequenceFeature(features[i], source\r
509                     .getNickname());\r
510             if (!parseSeqFeature(seq, f, features[i], source))\r
511             {\r
512               if (dbref.getMap() != null && f.getBegin() > 0\r
513                       && f.getEnd() > 0)\r
514               {\r
515                 debug("mapping from " + f.getBegin() + " - " + f.getEnd());\r
516                 SequenceFeature vf[] = null;\r
517 \r
518                 try\r
519                 {\r
520                   vf = dbref.getMap().locateFeature(f);\r
521                 } catch (Exception ex)\r
522                 {\r
523                   Cache.log\r
524                           .info("Error in 'experimental' mapping of features. Please try to reproduce and then report info to jalview-discuss@jalview.org.");\r
525                   Cache.log.info("Mapping feature from " + f.getBegin()\r
526                           + " to " + f.getEnd() + " in dbref "\r
527                           + dbref.getAccessionId() + " in "\r
528                           + dbref.getSource());\r
529                   Cache.log.info("using das Source " + ds.getUrl());\r
530                   Cache.log.info("Exception", ex);\r
531                 }\r
532 \r
533                 if (vf != null)\r
534                 {\r
535                   for (int v = 0; v < vf.length; v++)\r
536                   {\r
537                     debug("mapping to " + v + ": " + vf[v].getBegin()\r
538                             + " - " + vf[v].getEnd());\r
539                     seq.addSequenceFeature(vf[v]);\r
540                   }\r
541                 }\r
542               }\r
543               else\r
544               {\r
545                 seq.addSequenceFeature(f);\r
546               }\r
547             }\r
548           }\r
549           featuresAdded(seq);\r
550         }\r
551         else\r
552         {\r
553           // System.out.println("No features found for " + seq.getName()\r
554           // + " from: " + e.getDasSource().getNickname());\r
555         }\r
556         responseComplete(dasSource, seq);\r
557 \r
558       }\r
559     }\r
560 \r
561     );\r
562 \r
563     fetcher.start();\r
564   }\r
565 \r
566   protected void createFeatureFetcher(final SequenceI seq,\r
567           final DasSource dasSource, String id)\r
568   {\r
569     // ////////////\r
570     // / fetch DAS features\r
571     final Das1Source source = new Das1Source();\r
572     source.setUrl(dasSource.getUrl());\r
573     source.setNickname(dasSource.getNickname());\r
574 \r
575     if (id != null)\r
576     {\r
577       id = id.trim();\r
578     }\r
579     if (id != null && id.length() > 0)\r
580     {\r
581       debug("new Das Feature Fetcher for " + id + " querying "\r
582               + dasSource.getUrl());\r
583       FeatureThread fetcher = new FeatureThread(id\r
584       // + ":" + start + "," + end,\r
585               , source);\r
586 \r
587       fetcher.addFeatureListener(new FeatureListener()\r
588       {\r
589         public void comeBackLater(FeatureEvent e)\r
590         {\r
591           responseComplete(dasSource, seq);\r
592           debug("das source " + e.getSource().getNickname()\r
593                   + " asked us to come back in " + e.getComeBackLater()\r
594                   + " secs.");\r
595         }\r
596 \r
597         public void newFeatures(FeatureEvent e)\r
598         {\r
599 \r
600           Das1Source ds = e.getSource();\r
601 \r
602           Map[] features = e.getFeatures();\r
603           // add features to sequence\r
604           debug("das source " + ds.getUrl() + " returned "\r
605                   + features.length + " features");\r
606 \r
607           if (features.length > 0)\r
608           {\r
609             for (int i = 0; i < features.length; i++)\r
610             {\r
611               // standard DAS feature-> jalview sequence feature transformation\r
612               SequenceFeature f = newSequenceFeature(features[i], source\r
613                       .getNickname());\r
614               if (!parseSeqFeature(seq, f, features[i], source))\r
615               {\r
616                 // just add as a simple sequence feature\r
617                 seq.addSequenceFeature(f);\r
618               }\r
619             }\r
620 \r
621             featuresAdded(seq);\r
622           }\r
623           else\r
624           {\r
625             // System.out.println("No features found for " + seq.getName()\r
626             // + " from: " + e.getDasSource().getNickname());\r
627           }\r
628           responseComplete(dasSource, seq);\r
629 \r
630         }\r
631       }\r
632 \r
633       );\r
634 \r
635       fetcher.start();\r
636     }\r
637     else\r
638     {\r
639       // invalid fetch - indicate it is finished.\r
640       debug("Skipping empty ID for querying " + dasSource.getUrl());\r
641       responseComplete(dasSource, seq);\r
642     }\r
643   }\r
644 \r
645   /**\r
646    * examine the given sequence feature to determine if it should actually be\r
647    * turned into sequence annotation or database cross references rather than a\r
648    * simple sequence feature.\r
649    * \r
650    * @param seq\r
651    *                the sequence to annotate\r
652    * @param f\r
653    *                the jalview sequence feature generated from the DAS feature\r
654    * @param map\r
655    *                the sequence feature attributes\r
656    * @param source\r
657    *                the source that emitted the feature\r
658    * @return true if feature was consumed as another kind of annotation.\r
659    */\r
660   protected boolean parseSeqFeature(SequenceI seq, SequenceFeature f,\r
661           Map map, Das1Source source)\r
662   {\r
663     SequenceI mseq = seq;\r
664     while (seq.getDatasetSequence()!=null)\r
665     {\r
666       seq = seq.getDatasetSequence();\r
667     }\r
668     if (f.getType() != null)\r
669     {\r
670       String type = f.getType();\r
671       if (type.equalsIgnoreCase("protein_name"))\r
672       {\r
673         // parse name onto the alignment sequence or the dataset sequence.\r
674         if (seq.getDescription()==null || seq.getDescription().trim().length() == 0)\r
675         {\r
676           // could look at the note series to pick out the first long name, for the moment just use the whole description string \r
677           seq.setDescription(f.getDescription());\r
678         }\r
679         if (mseq.getDescription()==null || mseq.getDescription().trim().length() == 0)\r
680         {\r
681           // could look at the note series to pick out the first long name, for the moment just use the whole description string \r
682           mseq.setDescription(f.getDescription());\r
683         }\r
684         return true;\r
685       }\r
686       // check if source has biosapiens or other sequence ontology label\r
687       if (type.equalsIgnoreCase("DBXREF") || type.equalsIgnoreCase("DBREF"))\r
688       {\r
689         // try to parse the accession out\r
690 \r
691         DBRefEntry dbr = new DBRefEntry();\r
692         dbr.setVersion(source.getNickname());\r
693         StringTokenizer st = new StringTokenizer(f.getDescription(), ":");\r
694         if (st.hasMoreTokens())\r
695         {\r
696           dbr.setSource(st.nextToken());\r
697         }\r
698         if (st.hasMoreTokens())\r
699         {\r
700           dbr.setAccessionId(st.nextToken());\r
701         }\r
702         seq.addDBRef(dbr);\r
703         \r
704         if (f.links != null && f.links.size() > 0)\r
705         {\r
706           // feature is also appended to enable links to be seen.\r
707           // TODO: consider extending dbrefs to have their own links ?\r
708           // 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
709           // for the moment - just fix up the existing feature so it displays correctly.\r
710           // f.setType(dbr.getSource());\r
711           //f.setDescription();\r
712           f.setValue("linkonly", Boolean.TRUE);\r
713           //f.setDescription("");\r
714           Vector newlinks = new Vector();\r
715           Enumeration it = f.links.elements();\r
716           while (it.hasMoreElements())\r
717           {\r
718             String elm;\r
719             UrlLink urllink = new UrlLink(elm = (String)it.nextElement());\r
720             if (urllink.isValid()) {\r
721               urllink.setLabel(f.getDescription());\r
722               newlinks.addElement(urllink.toString());\r
723             } else {\r
724               // couldn't parse the link properly. Keep it anyway - just in case.\r
725               debug("couldn't parse link string - "+elm);\r
726               newlinks.addElement(elm);\r
727             }\r
728           }\r
729           f.links = newlinks;\r
730           seq.addSequenceFeature(f);\r
731         }\r
732         return true;\r
733       }\r
734     }\r
735     return false;\r
736   }\r
737 \r
738   /**\r
739    * creates a jalview sequence feature from a das feature document\r
740    * \r
741    * @param dasfeature\r
742    * @return sequence feature object created using dasfeature information\r
743    */\r
744   SequenceFeature newSequenceFeature(Map dasfeature, String nickname)\r
745   {\r
746     if (dasfeature == null)\r
747     {\r
748       return null;\r
749     }\r
750     try\r
751     {\r
752       /**\r
753        * Different qNames for a DAS Feature - are string keys to the HashMaps in\r
754        * features "METHOD") || qName.equals("TYPE") || qName.equals("START") ||\r
755        * qName.equals("END") || qName.equals("NOTE") || qName.equals("LINK") ||\r
756        * qName.equals("SCORE")\r
757        */\r
758       String desc = new String();\r
759       if (dasfeature.containsKey("NOTE"))\r
760       {\r
761         desc += (String) dasfeature.get("NOTE");\r
762       }\r
763 \r
764       int start = 0, end = 0;\r
765       float score = 0f;\r
766 \r
767       try\r
768       {\r
769         start = Integer.parseInt(dasfeature.get("START").toString());\r
770       } catch (Exception ex)\r
771       {\r
772       }\r
773       try\r
774       {\r
775         end = Integer.parseInt(dasfeature.get("END").toString());\r
776       } catch (Exception ex)\r
777       {\r
778       }\r
779       try\r
780       {\r
781         Object scr = dasfeature.get("SCORE");\r
782         if (scr != null)\r
783         {\r
784           score = (float) Double.parseDouble(scr.toString());\r
785 \r
786         }\r
787       } catch (Exception ex)\r
788       {\r
789       }\r
790 \r
791       SequenceFeature f = new SequenceFeature((String) dasfeature\r
792               .get("TYPE"), desc, start, end, score, nickname);\r
793 \r
794       if (dasfeature.containsKey("LINK"))\r
795       {\r
796         // Do not put feature extent in link text for non-positional features\r
797         if (f.begin == 0 && f.end == 0)\r
798         {\r
799           f.addLink(f.getType() + "|" + dasfeature.get("LINK"));\r
800         }\r
801         else\r
802         {\r
803           f.addLink(f.getType() + " " + f.begin + "_" + f.end + "|"\r
804                   + dasfeature.get("LINK"));\r
805         }\r
806       }\r
807 \r
808       return f;\r
809     } catch (Exception e)\r
810     {\r
811       System.out.println("ERRR " + e);\r
812       e.printStackTrace();\r
813       System.out.println("############");\r
814       debug("Failed to parse " + dasfeature.toString(), e);\r
815       return null;\r
816     }\r
817   }\r
818 \r
819   /**\r
820    * query the default DAS Source Registry for sources. Uses value of jalview\r
821    * property DAS_REGISTRY_URL and the DasSourceBrowser.DEFAULT_REGISTRY if that\r
822    * doesn't exist.\r
823    * \r
824    * @return list of sources\r
825    */\r
826   public static DasSource[] getDASSources()\r
827   {\r
828 \r
829     String registryURL = jalview.bin.Cache.getDefault("DAS_REGISTRY_URL",\r
830             DasSourceBrowser.DEFAULT_REGISTRY);\r
831     return getDASSources(registryURL);\r
832   }\r
833 \r
834   /**\r
835    * query the given URL for DasSources.\r
836    * \r
837    * @param registryURL\r
838    *                return sources from registryURL\r
839    */\r
840   public static DasSource[] getDASSources(String registryURL)\r
841   {\r
842     DasSourceReaderImpl reader = new DasSourceReaderImpl();\r
843 \r
844     try\r
845     {\r
846       URL url = new URL(registryURL);\r
847 \r
848       DasSource[] sources = reader.readDasSource(url);\r
849 \r
850       List das1sources = new ArrayList();\r
851       for (int i = 0; i < sources.length; i++)\r
852       {\r
853         DasSource ds = sources[i];\r
854         if (ds instanceof Das2Source)\r
855         {\r
856           Das2Source d2s = (Das2Source) ds;\r
857           if (d2s.hasDas1Capabilities())\r
858           {\r
859             Das1Source d1s = DasSourceConverter.toDas1Source(d2s);\r
860             das1sources.add(d1s);\r
861           }\r
862 \r
863         }\r
864         else if (ds instanceof Das1Source)\r
865         {\r
866           das1sources.add((Das1Source) ds);\r
867         }\r
868       }\r
869 \r
870       return (Das1Source[]) das1sources.toArray(new Das1Source[das1sources\r
871               .size()]);\r
872     } catch (Exception ex)\r
873     {\r
874       ex.printStackTrace();\r
875       return null;\r
876     }\r
877   }\r
878 \r
879 }\r