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