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