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