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