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