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