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