JAL-1064 - refactor to iterate over many sources associated with a database authority
[jalview.git] / src / jalview / ws / DBRefFetcher.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.analysis.AlignSeq;\r
21 import jalview.bin.Cache;\r
22 import jalview.datamodel.AlignmentI;\r
23 import jalview.datamodel.DBRefEntry;\r
24 import jalview.datamodel.DBRefSource;\r
25 import jalview.datamodel.Mapping;\r
26 import jalview.datamodel.SequenceFeature;\r
27 import jalview.datamodel.SequenceI;\r
28 import jalview.gui.AlignFrame;\r
29 import jalview.gui.CutAndPasteTransfer;\r
30 import jalview.gui.Desktop;\r
31 import jalview.gui.IProgressIndicator;\r
32 import jalview.gui.OOMWarning;\r
33 import jalview.ws.dbsources.das.api.jalviewSourceI;\r
34 \r
35 import java.lang.reflect.Array;\r
36 import java.util.Enumeration;\r
37 import java.util.Hashtable;\r
38 import java.util.List;\r
39 import java.util.StringTokenizer;\r
40 import java.util.Vector;\r
41 \r
42 import uk.ac.ebi.picr.model.UPEntry;\r
43 \r
44 /**\r
45  * Implements a runnable for validating a sequence against external databases\r
46  * and then propagating references and features onto the sequence(s)\r
47  * \r
48  * @author $author$\r
49  * @version $Revision$\r
50  */\r
51 public class DBRefFetcher implements Runnable\r
52 {\r
53   SequenceI[] dataset;\r
54 \r
55   IProgressIndicator af;\r
56 \r
57   CutAndPasteTransfer output = new CutAndPasteTransfer();\r
58 \r
59   StringBuffer sbuffer = new StringBuffer();\r
60 \r
61   boolean running = false;\r
62 \r
63   /**\r
64    * picr client instance\r
65    */\r
66   uk.ac.ebi.www.picr.AccessionMappingService.AccessionMapperInterface picrClient = null;\r
67 \r
68   // /This will be a collection of Vectors of sequenceI refs.\r
69   // The key will be the seq name or accession id of the seq\r
70   Hashtable seqRefs;\r
71 \r
72   String[] dbSources;\r
73 \r
74   SequenceFetcher sfetcher;\r
75 \r
76   private SequenceI[] alseqs;\r
77 \r
78   public DBRefFetcher()\r
79   {\r
80   }\r
81 \r
82   /**\r
83    * Creates a new SequenceFeatureFetcher object and fetches from the currently\r
84    * selected set of databases.\r
85    * \r
86    * @param seqs\r
87    *          fetch references for these sequences\r
88    * @param af\r
89    *          the parent alignframe for progress bar monitoring.\r
90    */\r
91   public DBRefFetcher(SequenceI[] seqs, AlignFrame af)\r
92   {\r
93     this(seqs, af, null);\r
94   }\r
95 \r
96   /**\r
97    * Creates a new SequenceFeatureFetcher object and fetches from the currently\r
98    * selected set of databases.\r
99    * \r
100    * @param seqs\r
101    *          fetch references for these sequences\r
102    * @param af\r
103    *          the parent alignframe for progress bar monitoring.\r
104    * @param sources\r
105    *          array of database source strings to query references from\r
106    */\r
107   public DBRefFetcher(SequenceI[] seqs, AlignFrame af, String[] sources)\r
108   {\r
109     this.af = af;\r
110     alseqs = new SequenceI[seqs.length];\r
111     SequenceI[] ds = new SequenceI[seqs.length];\r
112     for (int i = 0; i < seqs.length; i++)\r
113     {\r
114       alseqs[i] = seqs[i];\r
115       if (seqs[i].getDatasetSequence() != null)\r
116         ds[i] = seqs[i].getDatasetSequence();\r
117       else\r
118         ds[i] = seqs[i];\r
119     }\r
120     this.dataset = ds;\r
121     // TODO Jalview 2.5 lots of this code should be in the gui package!\r
122     sfetcher = jalview.gui.SequenceFetcher.getSequenceFetcherSingleton(af);\r
123     if (sources == null)\r
124     {\r
125       // af.featureSettings_actionPerformed(null);\r
126       String[] defdb = null, otherdb = sfetcher\r
127               .getDbInstances(jalview.ws.dbsources.das.datamodel.DasSequenceSource.class);\r
128       Vector selsources = new Vector(), dasselsrc = (af.featureSettings != null) ? af.featureSettings\r
129               .getSelectedSources() : new jalview.gui.DasSourceBrowser()\r
130               .getSelectedSources();\r
131       Enumeration en = dasselsrc.elements();\r
132       while (en.hasMoreElements())\r
133       {\r
134         jalviewSourceI src = (jalviewSourceI) en.nextElement();\r
135         selsources.addElement(src.getTitle());\r
136       }\r
137       int osel = 0;\r
138       for (int o = 0; otherdb != null && o < otherdb.length; o++)\r
139       {\r
140         if (!selsources.contains(otherdb[o]))\r
141         {\r
142           otherdb[o] = null;\r
143         }\r
144         else\r
145         {\r
146           osel++;\r
147         }\r
148       }\r
149       // select appropriate databases based on alignFrame context.\r
150       if (af.getViewport().getAlignment().isNucleotide())\r
151       {\r
152         defdb = DBRefSource.DNACODINGDBS;\r
153       }\r
154       else\r
155       {\r
156         defdb = DBRefSource.PROTEINDBS;\r
157       }\r
158       // append the selected sequence sources to the default dbs\r
159       dbSources = new String[defdb.length + osel];\r
160       System.arraycopy(defdb, 0, dbSources, 0, defdb.length);\r
161       for (int o = 0, op = defdb.length; otherdb != null\r
162               && o < otherdb.length; o++)\r
163       {\r
164         if (otherdb[o] != null)\r
165         {\r
166           dbSources[op++] = otherdb[o];\r
167         }\r
168       }\r
169     }\r
170     else\r
171     {\r
172       // we assume the caller knows what they're doing and ensured that all the\r
173       // db source names are valid\r
174       dbSources = sources;\r
175     }\r
176   }\r
177 \r
178   /**\r
179    * retrieve all the das sequence sources and add them to the list of db\r
180    * sources to retrieve from\r
181    */\r
182   public void appendAllDasSources()\r
183   {\r
184     if (dbSources == null)\r
185     {\r
186       dbSources = new String[]\r
187       {};\r
188     }\r
189     // append additional sources\r
190     String[] otherdb = sfetcher\r
191             .getDbInstances(jalview.ws.dbsources.das.datamodel.DasSequenceSource.class);\r
192     if (otherdb != null && otherdb.length > 0)\r
193     {\r
194       String[] newsrc = new String[dbSources.length + otherdb.length];\r
195       System.arraycopy(dbSources, 0, newsrc, 0, dbSources.length);\r
196       System.arraycopy(otherdb, 0, newsrc, dbSources.length, otherdb.length);\r
197       dbSources = newsrc;\r
198     }\r
199   }\r
200 \r
201   /**\r
202    * start the fetcher thread\r
203    * \r
204    * @param waitTillFinished\r
205    *          true to block until the fetcher has finished\r
206    */\r
207   public void fetchDBRefs(boolean waitTillFinished)\r
208   {\r
209     Thread thread = new Thread(this);\r
210     thread.start();\r
211     running = true;\r
212 \r
213     if (waitTillFinished)\r
214     {\r
215       while (running)\r
216       {\r
217         try\r
218         {\r
219           Thread.sleep(500);\r
220         } catch (Exception ex)\r
221         {\r
222         }\r
223       }\r
224     }\r
225   }\r
226 \r
227   /**\r
228    * The sequence will be added to a vector of sequences belonging to key which\r
229    * could be either seq name or dbref id\r
230    * \r
231    * @param seq\r
232    *          SequenceI\r
233    * @param key\r
234    *          String\r
235    */\r
236   void addSeqId(SequenceI seq, String key)\r
237   {\r
238     key = key.toUpperCase();\r
239 \r
240     Vector seqs;\r
241     if (seqRefs.containsKey(key))\r
242     {\r
243       seqs = (Vector) seqRefs.get(key);\r
244 \r
245       if (seqs != null && !seqs.contains(seq))\r
246       {\r
247         seqs.addElement(seq);\r
248       }\r
249       else if (seqs == null)\r
250       {\r
251         seqs = new Vector();\r
252         seqs.addElement(seq);\r
253       }\r
254 \r
255     }\r
256     else\r
257     {\r
258       seqs = new Vector();\r
259       seqs.addElement(seq);\r
260     }\r
261 \r
262     seqRefs.put(key, seqs);\r
263   }\r
264 \r
265   /**\r
266    * DOCUMENT ME!\r
267    */\r
268   public void run()\r
269   {\r
270     if (dbSources == null)\r
271     {\r
272       throw new Error("Implementation error. Must initialise dbSources");\r
273     }\r
274     running = true;\r
275     long startTime = System.currentTimeMillis();\r
276     af.setProgressBar("Fetching db refs", startTime);\r
277     try\r
278     {\r
279       if (Cache.getDefault("DBREFFETCH_USEPICR", false))\r
280       {\r
281         picrClient = new uk.ac.ebi.www.picr.AccessionMappingService.AccessionMapperServiceLocator()\r
282                 .getAccessionMapperPort();\r
283       }\r
284     } catch (Exception e)\r
285     {\r
286       System.err.println("Couldn't locate PICR service instance.\n");\r
287       e.printStackTrace();\r
288     }\r
289     int db = 0;\r
290     Vector sdataset = new Vector();\r
291     for (int s = 0; s < dataset.length; s++)\r
292     {\r
293       sdataset.addElement(dataset[s]);\r
294     }\r
295     while (sdataset.size() > 0 && db < dbSources.length)\r
296     {\r
297       int maxqlen = 1; // default number of queries made to at one time\r
298       System.err.println("Verifying against " + dbSources[db]);\r
299       boolean dn = false;\r
300       List<jalview.ws.seqfetcher.DbSourceProxy> srcs = sfetcher\r
301               .getSourceProxy(dbSources[db]);\r
302       if (srcs == null)\r
303       {\r
304         System.err.println("No proxy for " + dbSources[db]);\r
305         db++;\r
306         continue;\r
307       }\r
308 \r
309       // iterate through db for each remaining un-verified sequence\r
310       SequenceI[] currSeqs = new SequenceI[sdataset.size()];\r
311       sdataset.copyInto(currSeqs);// seqs that are to be validated against\r
312       // dbSources[db]\r
313       Vector queries = new Vector(); // generated queries curSeq\r
314       seqRefs = new Hashtable();\r
315 \r
316       int seqIndex = 0;\r
317 \r
318       for (jalview.ws.seqfetcher.DbSourceProxy dbsource : srcs)\r
319       {\r
320         // for moment, we dumbly iterate over all retrieval sources for a particular database\r
321         // TODO: introduce multithread multisource queries and logic to remove a query from other sources if any source for a database returns a record\r
322         if (dbsource.getDbSourceProperties().containsKey(\r
323                 DBRefSource.MULTIACC))\r
324         {\r
325           maxqlen = ((Integer) dbsource.getDbSourceProperties().get(\r
326                   DBRefSource.MULTIACC)).intValue();\r
327         }\r
328         else\r
329         {\r
330           maxqlen = 1;\r
331         }\r
332         while (queries.size() > 0 || seqIndex < currSeqs.length)\r
333         {\r
334           if (queries.size() > 0)\r
335           {\r
336             // Still queries to make for current seqIndex\r
337             StringBuffer queryString = new StringBuffer("");\r
338             int numq = 0, nqSize = (maxqlen > queries.size()) ? queries\r
339                     .size() : maxqlen;\r
340 \r
341             while (queries.size() > 0 && numq < nqSize)\r
342             {\r
343               String query = (String) queries.elementAt(0);\r
344               if (dbsource.isValidReference(query))\r
345               {\r
346                 queryString.append((numq == 0) ? "" : dbsource\r
347                         .getAccessionSeparator());\r
348                 queryString.append(query);\r
349                 numq++;\r
350               }\r
351               // remove the extracted query string\r
352               queries.removeElementAt(0);\r
353             }\r
354             // make the queries and process the response\r
355             AlignmentI retrieved = null;\r
356             try\r
357             {\r
358               if (jalview.bin.Cache.log.isDebugEnabled())\r
359               {\r
360                 jalview.bin.Cache.log.debug("Querying "\r
361                         + dbsource.getDbName() + " with : '"\r
362                         + queryString.toString() + "'");\r
363               }\r
364               retrieved = dbsource.getSequenceRecords(queryString\r
365                       .toString());\r
366             } catch (Exception ex)\r
367             {\r
368               ex.printStackTrace();\r
369             } catch (OutOfMemoryError err)\r
370             {\r
371               new OOMWarning("retrieving database references ("\r
372                       + queryString.toString() + ")", err);\r
373             }\r
374             if (retrieved != null)\r
375             {\r
376               transferReferences(sdataset, dbSources[db], retrieved);\r
377             }\r
378           }\r
379           else\r
380           {\r
381             // make some more strings for use as queries\r
382             for (int i = 0; (seqIndex < dataset.length) && (i < 50); seqIndex++, i++)\r
383             {\r
384               SequenceI sequence = dataset[seqIndex];\r
385               DBRefEntry[] uprefs = jalview.util.DBRefUtils.selectRefs(\r
386                       sequence.getDBRef(), new String[]\r
387                       { dbSources[db] }); // jalview.datamodel.DBRefSource.UNIPROT\r
388               // });\r
389               // check for existing dbrefs to use\r
390               if (uprefs != null && uprefs.length > 0)\r
391               {\r
392                 for (int j = 0; j < uprefs.length; j++)\r
393                 {\r
394                   addSeqId(sequence, uprefs[j].getAccessionId());\r
395                   queries.addElement(uprefs[j].getAccessionId()\r
396                           .toUpperCase());\r
397                 }\r
398               }\r
399               else\r
400               {\r
401                 // generate queries from sequence ID string\r
402                 StringTokenizer st = new StringTokenizer(\r
403                         sequence.getName(), "|");\r
404                 while (st.hasMoreTokens())\r
405                 {\r
406                   String token = st.nextToken();\r
407                   UPEntry[] presp = null;\r
408                   if (picrClient != null)\r
409                   {\r
410                     // resolve the string against PICR to recover valid IDs\r
411                     try\r
412                     {\r
413                       presp = picrClient.getUPIForAccession(token, null,\r
414                               picrClient.getMappedDatabaseNames(), null,\r
415                               true);\r
416                     } catch (Exception e)\r
417                     {\r
418                       System.err.println("Exception with Picr for '"\r
419                               + token + "'\n");\r
420                       e.printStackTrace();\r
421                     }\r
422                   }\r
423                   if (presp != null && presp.length > 0)\r
424                   {\r
425                     for (int id = 0; id < presp.length; id++)\r
426                     {\r
427                       // construct sequences from response if sequences are\r
428                       // present, and do a transferReferences\r
429                       // otherwise transfer non sequence x-references directly.\r
430                     }\r
431                     System.out\r
432                             .println("Validated ID against PICR... (for what its worth):"\r
433                                     + token);\r
434                     addSeqId(sequence, token);\r
435                     queries.addElement(token.toUpperCase());\r
436                   }\r
437                   else\r
438                   {\r
439                     // if ()\r
440                     // System.out.println("Not querying source with token="+token+"\n");\r
441                     addSeqId(sequence, token);\r
442                     queries.addElement(token.toUpperCase());\r
443                   }\r
444                 }\r
445               }\r
446             }\r
447           }\r
448         }\r
449       }\r
450       // advance to next database\r
451       db++;\r
452     } // all databases have been queries.\r
453     if (sbuffer.length() > 0)\r
454     {\r
455       output.setText("Your sequences have been verified against known sequence databases. Some of the ids have been\n"\r
456               + "altered, most likely the start/end residue will have been updated.\n"\r
457               + "Save your alignment to maintain the updated id.\n\n"\r
458               + sbuffer.toString());\r
459       Desktop.addInternalFrame(output, "Sequence names updated ", 600, 300);\r
460       // The above is the dataset, we must now find out the index\r
461       // of the viewed sequence\r
462 \r
463     }\r
464 \r
465     af.setProgressBar("DBRef search completed", startTime);\r
466     // promptBeforeBlast();\r
467 \r
468     running = false;\r
469 \r
470   }\r
471 \r
472   /**\r
473    * Verify local sequences in seqRefs against the retrieved sequence database\r
474    * records.\r
475    * \r
476    */\r
477   void transferReferences(Vector sdataset, String dbSource,\r
478           AlignmentI retrievedAl) // File\r
479   // file)\r
480   {\r
481     if (retrievedAl == null || retrievedAl.getHeight() == 0)\r
482     {\r
483       return;\r
484     }\r
485     SequenceI[] retrieved = recoverDbSequences(retrievedAl\r
486             .getSequencesArray());\r
487     SequenceI sequence = null;\r
488     boolean transferred = false;\r
489     StringBuffer messages = new StringBuffer();\r
490 \r
491     // Vector entries = new Uniprot().getUniprotEntries(file);\r
492 \r
493     int i, iSize = retrieved.length; // entries == null ? 0 : entries.size();\r
494     // UniprotEntry entry;\r
495     for (i = 0; i < iSize; i++)\r
496     {\r
497       SequenceI entry = retrieved[i]; // (UniprotEntry) entries.elementAt(i);\r
498 \r
499       // Work out which sequences this sequence matches,\r
500       // taking into account all accessionIds and names in the file\r
501       Vector sequenceMatches = new Vector();\r
502       // look for corresponding accession ids\r
503       DBRefEntry[] entryRefs = jalview.util.DBRefUtils.selectRefs(\r
504               entry.getDBRef(), new String[]\r
505               { dbSource });\r
506       if (entryRefs == null)\r
507       {\r
508         System.err\r
509                 .println("Dud dbSource string ? no entryrefs selected for "\r
510                         + dbSource + " on " + entry.getName());\r
511         continue;\r
512       }\r
513       for (int j = 0; j < entryRefs.length; j++)\r
514       {\r
515         String accessionId = entryRefs[j].getAccessionId(); // .getAccession().elementAt(j).toString();\r
516         // match up on accessionId\r
517         if (seqRefs.containsKey(accessionId.toUpperCase()))\r
518         {\r
519           Vector seqs = (Vector) seqRefs.get(accessionId);\r
520           for (int jj = 0; jj < seqs.size(); jj++)\r
521           {\r
522             sequence = (SequenceI) seqs.elementAt(jj);\r
523             if (!sequenceMatches.contains(sequence))\r
524             {\r
525               sequenceMatches.addElement(sequence);\r
526             }\r
527           }\r
528         }\r
529       }\r
530       if (sequenceMatches.size() == 0)\r
531       {\r
532         // failed to match directly on accessionId==query so just compare all\r
533         // sequences to entry\r
534         Enumeration e = seqRefs.keys();\r
535         while (e.hasMoreElements())\r
536         {\r
537           Vector sqs = (Vector) seqRefs.get(e.nextElement());\r
538           if (sqs != null && sqs.size() > 0)\r
539           {\r
540             Enumeration sqe = sqs.elements();\r
541             while (sqe.hasMoreElements())\r
542             {\r
543               sequenceMatches.addElement(sqe.nextElement());\r
544             }\r
545           }\r
546         }\r
547       }\r
548       // look for corresponding names\r
549       // this is uniprot specific ?\r
550       // could be useful to extend this so we try to find any 'significant'\r
551       // information in common between two sequence objects.\r
552       /*\r
553        * DBRefEntry[] entryRefs =\r
554        * jalview.util.DBRefUtils.selectRefs(entry.getDBRef(), new String[] {\r
555        * dbSource }); for (int j = 0; j < entry.getName().size(); j++) { String\r
556        * name = entry.getName().elementAt(j).toString(); if\r
557        * (seqRefs.containsKey(name)) { Vector seqs = (Vector) seqRefs.get(name);\r
558        * for (int jj = 0; jj < seqs.size(); jj++) { sequence = (SequenceI)\r
559        * seqs.elementAt(jj); if (!sequenceMatches.contains(sequence)) {\r
560        * sequenceMatches.addElement(sequence); } } } }\r
561        */\r
562       // sequenceMatches now contains the set of all sequences associated with\r
563       // the returned db record\r
564       String entrySeq = entry.getSequenceAsString().toUpperCase();\r
565       for (int m = 0; m < sequenceMatches.size(); m++)\r
566       {\r
567         sequence = (SequenceI) sequenceMatches.elementAt(m);\r
568         // only update start and end positions and shift features if there are\r
569         // no existing references\r
570         // TODO: test for legacy where uniprot or EMBL refs exist but no\r
571         // mappings are made (but content matches retrieved set)\r
572         boolean updateRefFrame = sequence.getDBRef() == null\r
573                 || sequence.getDBRef().length == 0;\r
574         // verify sequence against the entry sequence\r
575 \r
576         String nonGapped = AlignSeq.extractGaps("-. ",\r
577                 sequence.getSequenceAsString()).toUpperCase();\r
578 \r
579         int absStart = entrySeq.indexOf(nonGapped);\r
580         int mapStart = entry.getStart();\r
581         jalview.datamodel.Mapping mp;\r
582 \r
583         if (absStart == -1)\r
584         {\r
585           // Is local sequence contained in dataset sequence?\r
586           absStart = nonGapped.indexOf(entrySeq);\r
587           if (absStart == -1)\r
588           { // verification failed.\r
589             messages.append(sequence.getName()\r
590                     + " SEQUENCE NOT %100 MATCH \n");\r
591             continue;\r
592           }\r
593           transferred = true;\r
594           sbuffer.append(sequence.getName() + " HAS " + absStart\r
595                   + " PREFIXED RESIDUES COMPARED TO " + dbSource + "\n");\r
596           //\r
597           // + " - ANY SEQUENCE FEATURES"\r
598           // + " HAVE BEEN ADJUSTED ACCORDINGLY \n");\r
599           // absStart = 0;\r
600           // create valid mapping between matching region of local sequence and\r
601           // the mapped sequence\r
602           mp = new Mapping(null, new int[]\r
603           { sequence.getStart() + absStart,\r
604               sequence.getStart() + absStart + entrySeq.length() - 1 },\r
605                   new int[]\r
606                   { entry.getStart(),\r
607                       entry.getStart() + entrySeq.length() - 1 }, 1, 1);\r
608           updateRefFrame = false; // mapping is based on current start/end so\r
609           // don't modify start and end\r
610         }\r
611         else\r
612         {\r
613           transferred = true;\r
614           // update start and end of local sequence to place it in entry's\r
615           // reference frame.\r
616           // apply identity map map from whole of local sequence to matching\r
617           // region of database\r
618           // sequence\r
619           mp = null; // Mapping.getIdentityMap();\r
620           // new Mapping(null,\r
621           // new int[] { absStart+sequence.getStart(),\r
622           // absStart+sequence.getStart()+entrySeq.length()-1},\r
623           // new int[] { entry.getStart(), entry.getEnd() }, 1, 1);\r
624           // relocate local features for updated start\r
625           if (updateRefFrame)\r
626           {\r
627             if (sequence.getSequenceFeatures() != null)\r
628             {\r
629               SequenceFeature[] sf = sequence.getSequenceFeatures();\r
630               int start = sequence.getStart();\r
631               int end = sequence.getEnd();\r
632               int startShift = 1 - absStart - start; // how much the features\r
633                                                      // are\r
634               // to be shifted by\r
635               for (int sfi = 0; sfi < sf.length; sfi++)\r
636               {\r
637                 if (sf[sfi].getBegin() >= start && sf[sfi].getEnd() <= end)\r
638                 {\r
639                   // shift feature along by absstart\r
640                   sf[sfi].setBegin(sf[sfi].getBegin() + startShift);\r
641                   sf[sfi].setEnd(sf[sfi].getEnd() + startShift);\r
642                 }\r
643               }\r
644             }\r
645           }\r
646         }\r
647 \r
648         System.out.println("Adding dbrefs to " + sequence.getName()\r
649                 + " from " + dbSource + " sequence : " + entry.getName());\r
650         sequence.transferAnnotation(entry, mp);\r
651         // unknownSequences.remove(sequence);\r
652         int absEnd = absStart + nonGapped.length();\r
653         absStart += 1;\r
654         if (updateRefFrame)\r
655         {\r
656           // finally, update local sequence reference frame if we're allowed\r
657           sequence.setStart(absStart);\r
658           sequence.setEnd(absEnd);\r
659           // search for alignment sequences to update coordinate frame for\r
660           for (int alsq = 0; alsq < alseqs.length; alsq++)\r
661           {\r
662             if (alseqs[alsq].getDatasetSequence() == sequence)\r
663             {\r
664               String ngAlsq = AlignSeq.extractGaps("-. ",\r
665                       alseqs[alsq].getSequenceAsString()).toUpperCase();\r
666               int oldstrt = alseqs[alsq].getStart();\r
667               alseqs[alsq].setStart(sequence.getSequenceAsString()\r
668                       .toUpperCase().indexOf(ngAlsq)\r
669                       + sequence.getStart());\r
670               if (oldstrt != alseqs[alsq].getStart())\r
671               {\r
672                 alseqs[alsq].setEnd(ngAlsq.length()\r
673                         + alseqs[alsq].getStart() - 1);\r
674               }\r
675             }\r
676           }\r
677           // TODO: search for all other references to this dataset sequence, and\r
678           // update start/end\r
679           // TODO: update all AlCodonMappings which involve this alignment\r
680           // sequence (e.g. Q30167 cdna translation from exon2 product (vamsas\r
681           // demo)\r
682         }\r
683         // and remove it from the rest\r
684         // TODO: decide if we should remove annotated sequence from set\r
685         sdataset.remove(sequence);\r
686         // TODO: should we make a note of sequences that have received new DB\r
687         // ids, so we can query all enabled DAS servers for them ?\r
688       }\r
689     }\r
690     if (!transferred)\r
691     {\r
692       // report the ID/sequence mismatches\r
693       sbuffer.append(messages);\r
694     }\r
695   }\r
696 \r
697   /**\r
698    * loop thru and collect additional sequences in Map.\r
699    * \r
700    * @param sequencesArray\r
701    * @return\r
702    */\r
703   private SequenceI[] recoverDbSequences(SequenceI[] sequencesArray)\r
704   {\r
705     Vector nseq = new Vector();\r
706     for (int i = 0; sequencesArray != null && i < sequencesArray.length; i++)\r
707     {\r
708       nseq.addElement(sequencesArray[i]);\r
709       DBRefEntry dbr[] = sequencesArray[i].getDBRef();\r
710       jalview.datamodel.Mapping map = null;\r
711       for (int r = 0; (dbr != null) && r < dbr.length; r++)\r
712       {\r
713         if ((map = dbr[r].getMap()) != null)\r
714         {\r
715           if (map.getTo() != null && !nseq.contains(map.getTo()))\r
716           {\r
717             nseq.addElement(map.getTo());\r
718           }\r
719         }\r
720       }\r
721     }\r
722     if (nseq.size() > 0)\r
723     {\r
724       sequencesArray = new SequenceI[nseq.size()];\r
725       nseq.toArray(sequencesArray);\r
726     }\r
727     return sequencesArray;\r
728   }\r
729 }\r