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