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