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