JAL-1620 version bump and release notes
[jalview.git] / src / jalview / util / DBRefUtils.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
3  * Copyright (C) 2014 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.util;
22
23 import java.util.*;
24
25 import jalview.datamodel.*;
26
27 public class DBRefUtils
28 {
29   /**
30    * Utilities for handling DBRef objects and their collections.
31    */
32   /**
33    * 
34    * @param dbrefs
35    *          Vector of DBRef objects to search
36    * @param sources
37    *          String[] array of source DBRef IDs to retrieve
38    * @return Vector
39    */
40   public static DBRefEntry[] selectRefs(DBRefEntry[] dbrefs,
41           String[] sources)
42   {
43     if (dbrefs == null)
44     {
45       return null;
46     }
47     if (sources == null)
48     {
49       return dbrefs;
50     }
51     Hashtable srcs = new Hashtable();
52     Vector res = new Vector();
53
54     for (int i = 0; i < sources.length; i++)
55     {
56       srcs.put(new String(sources[i]), new Integer(i));
57     }
58     for (int i = 0, j = dbrefs.length; i < j; i++)
59     {
60       if (srcs.containsKey(dbrefs[i].getSource()))
61       {
62         res.addElement(dbrefs[i]);
63       }
64     }
65
66     if (res.size() > 0)
67     {
68       DBRefEntry[] reply = new DBRefEntry[res.size()];
69       for (int i = 0; i < res.size(); i++)
70       {
71         reply[i] = (DBRefEntry) res.elementAt(i);
72       }
73       return reply;
74     }
75     res = null;
76     // there are probable memory leaks in the hashtable!
77     return null;
78   }
79
80   /**
81    * isDasCoordinateSystem
82    * 
83    * @param string
84    *          String
85    * @param dBRefEntry
86    *          DBRefEntry
87    * @return boolean true if Source DBRefEntry is compatible with DAS
88    *         CoordinateSystem name
89    */
90   public static Hashtable DasCoordinateSystemsLookup = null;
91
92   public static boolean isDasCoordinateSystem(String string,
93           DBRefEntry dBRefEntry)
94   {
95     if (DasCoordinateSystemsLookup == null)
96     {
97       // TODO: Make a DasCoordinateSystemsLookup properties resource
98       // Initialise
99       DasCoordinateSystemsLookup = new Hashtable();
100       DasCoordinateSystemsLookup.put("pdbresnum",
101               jalview.datamodel.DBRefSource.PDB);
102       DasCoordinateSystemsLookup.put("uniprot",
103               jalview.datamodel.DBRefSource.UNIPROT);
104       DasCoordinateSystemsLookup.put("EMBL",
105               jalview.datamodel.DBRefSource.EMBL);
106       // DasCoordinateSystemsLookup.put("EMBL",
107       // jalview.datamodel.DBRefSource.EMBLCDS);
108     }
109
110     String coordsys = (String) DasCoordinateSystemsLookup.get(string
111             .toLowerCase());
112     if (coordsys != null)
113     {
114       return coordsys.equals(dBRefEntry.getSource());
115     }
116     return false;
117   }
118
119   public static Hashtable CanonicalSourceNameLookup = null;
120
121   /**
122    * look up source in an internal list of database reference sources and return
123    * the canonical jalview name for the source, or the original string if it has
124    * no canonical form.
125    * 
126    * @param source
127    * @return canonical jalview source (one of jalview.datamodel.DBRefSource.*)
128    *         or original source
129    */
130   public static String getCanonicalName(String source)
131   {
132     if (CanonicalSourceNameLookup == null)
133     {
134       CanonicalSourceNameLookup = new Hashtable();
135       CanonicalSourceNameLookup.put("uniprotkb/swiss-prot",
136               jalview.datamodel.DBRefSource.UNIPROT);
137       CanonicalSourceNameLookup.put("uniprotkb/trembl",
138               jalview.datamodel.DBRefSource.UNIPROT);
139       CanonicalSourceNameLookup.put("pdb",
140               jalview.datamodel.DBRefSource.PDB);
141     }
142     String canonical = (String) CanonicalSourceNameLookup.get(source
143             .toLowerCase());
144     if (canonical == null)
145     {
146       return source;
147     }
148     return canonical;
149   }
150
151   /**
152    * find RefEntry corresponding to a particular pattern the equals method of
153    * each entry is used, from String attributes right down to Mapping
154    * attributes.
155    * 
156    * @param ref
157    *          Set of references to search
158    * @param entry
159    *          pattern to collect - null any entry for wildcard match
160    * @return
161    */
162   public static DBRefEntry[] searchRefs(DBRefEntry[] ref, DBRefEntry entry)
163   {
164     return searchRefs(ref, entry,
165             matchDbAndIdAndEitherMapOrEquivalentMapList);
166   }
167
168   public static DBRefEntry[] searchRefs(DBRefEntry[] ref, DBRefEntry entry,
169           DbRefComp comparator)
170   {
171     if (ref == null || entry == null)
172       return null;
173     Vector rfs = new Vector();
174     for (int i = 0; i < ref.length; i++)
175     {
176       if (comparator.matches(entry, ref[i]))
177       {
178         rfs.addElement(ref[i]);
179       }
180     }
181     // TODO Auto-generated method stub
182     if (rfs.size() > 0)
183     {
184       DBRefEntry[] rf = new DBRefEntry[rfs.size()];
185       rfs.copyInto(rf);
186       return rf;
187     }
188     return null;
189   }
190
191   public interface DbRefComp
192   {
193     public boolean matches(DBRefEntry refa, DBRefEntry refb);
194   }
195
196   /**
197    * match on all non-null fields in refa
198    */
199   public static DbRefComp matchNonNullonA = new DbRefComp()
200   {
201     public boolean matches(DBRefEntry refa, DBRefEntry refb)
202     {
203       if (refa.getSource() == null
204               || refb.getSource().equals(refa.getSource()))
205       {
206         if (refa.getVersion() == null
207                 || refb.getVersion().equals(refa.getVersion()))
208         {
209           if (refa.getAccessionId() == null
210                   || refb.getAccessionId().equals(refa.getAccessionId()))
211           {
212             if (refa.getMap() == null
213                     || (refb.getMap() != null && refb.getMap().equals(
214                             refa.getMap())))
215             {
216               return true;
217             }
218           }
219         }
220       }
221       return false;
222     }
223   };
224
225   /**
226    * either field is null or field matches for all of source, version, accession
227    * id and map.
228    */
229   public static DbRefComp matchEitherNonNull = new DbRefComp()
230   {
231     public boolean matches(DBRefEntry refa, DBRefEntry refb)
232     {
233       if ((refa.getSource() == null || refb.getSource() == null)
234               || refb.getSource().equals(refa.getSource()))
235       {
236         if ((refa.getVersion() == null || refb.getVersion() == null)
237                 || refb.getVersion().equals(refa.getVersion()))
238         {
239           if ((refa.getAccessionId() == null || refb.getAccessionId() == null)
240                   || refb.getAccessionId().equals(refa.getAccessionId()))
241           {
242             if ((refa.getMap() == null || refb.getMap() == null)
243                     || (refb.getMap() != null && refb.getMap().equals(
244                             refa.getMap())))
245             {
246               return true;
247             }
248           }
249         }
250       }
251       return false;
252     }
253   };
254
255   /**
256    * accession ID and DB must be identical. Version is ignored. Map is either
257    * not defined or is a match (or is compatible?)
258    */
259   public static DbRefComp matchDbAndIdAndEitherMap = new DbRefComp()
260   {
261     public boolean matches(DBRefEntry refa, DBRefEntry refb)
262     {
263       if (refa.getSource() != null && refb.getSource() != null
264               && refb.getSource().equals(refa.getSource()))
265       {
266         // We dont care about version
267         // if ((refa.getVersion()==null || refb.getVersion()==null)
268         // || refb.getVersion().equals(refa.getVersion()))
269         // {
270         if (refa.getAccessionId() != null && refb.getAccessionId() != null
271                 || refb.getAccessionId().equals(refa.getAccessionId()))
272         {
273           if ((refa.getMap() == null || refb.getMap() == null)
274                   || (refa.getMap() != null && refb.getMap() != null && refb
275                           .getMap().equals(refa.getMap())))
276           {
277             return true;
278           }
279         }
280       }
281       return false;
282     }
283   };
284
285   /**
286    * accession ID and DB must be identical. Version is ignored. No map on either
287    * or map but no maplist on either or maplist of map on a is the complement of
288    * maplist of map on b.
289    */
290   public static DbRefComp matchDbAndIdAndComplementaryMapList = new DbRefComp()
291   {
292     public boolean matches(DBRefEntry refa, DBRefEntry refb)
293     {
294       if (refa.getSource() != null && refb.getSource() != null
295               && refb.getSource().equals(refa.getSource()))
296       {
297         // We dont care about version
298         // if ((refa.getVersion()==null || refb.getVersion()==null)
299         // || refb.getVersion().equals(refa.getVersion()))
300         // {
301         if (refa.getAccessionId() != null && refb.getAccessionId() != null
302                 || refb.getAccessionId().equals(refa.getAccessionId()))
303         {
304           if ((refa.getMap() == null && refb.getMap() == null)
305                   || (refa.getMap() != null && refb.getMap() != null))
306             if ((refb.getMap().getMap() == null && refa.getMap().getMap() == null)
307                     || (refb.getMap().getMap() != null
308                             && refa.getMap().getMap() != null && refb
309                             .getMap().getMap().getInverse()
310                             .equals(refa.getMap().getMap())))
311             {
312               return true;
313             }
314         }
315       }
316       return false;
317     }
318   };
319
320   /**
321    * accession ID and DB must be identical. Version is ignored. No map on both
322    * or or map but no maplist on either or maplist of map on a is equivalent to
323    * the maplist of map on b.
324    */
325   public static DbRefComp matchDbAndIdAndEquivalentMapList = new DbRefComp()
326   {
327     public boolean matches(DBRefEntry refa, DBRefEntry refb)
328     {
329       if (refa.getSource() != null && refb.getSource() != null
330               && refb.getSource().equals(refa.getSource()))
331       {
332         // We dont care about version
333         // if ((refa.getVersion()==null || refb.getVersion()==null)
334         // || refb.getVersion().equals(refa.getVersion()))
335         // {
336         if (refa.getAccessionId() != null && refb.getAccessionId() != null
337                 || refb.getAccessionId().equals(refa.getAccessionId()))
338         {
339           if (refa.getMap() == null && refb.getMap() == null)
340           {
341             return true;
342           }
343           if (refa.getMap() != null
344                   && refb.getMap() != null
345                   && ((refb.getMap().getMap() == null && refa.getMap()
346                           .getMap() == null) || (refb.getMap().getMap() != null
347                           && refa.getMap().getMap() != null && refb
348                           .getMap().getMap().equals(refa.getMap().getMap()))))
349           {
350             return true;
351           }
352         }
353       }
354       return false;
355     }
356   };
357
358   /**
359    * accession ID and DB must be identical. Version is ignored. No map on either
360    * or map but no maplist on either or maplist of map on a is equivalent to the
361    * maplist of map on b.
362    */
363   public static DbRefComp matchDbAndIdAndEitherMapOrEquivalentMapList = new DbRefComp()
364   {
365     public boolean matches(DBRefEntry refa, DBRefEntry refb)
366     {
367       // System.err.println("Comparing A: "+refa.getSrcAccString()+(refa.hasMap()?" has map.":"."));
368       // System.err.println("Comparing B: "+refb.getSrcAccString()+(refb.hasMap()?" has map.":"."));
369       if (refa.getSource() != null && refb.getSource() != null
370               && refb.getSource().equals(refa.getSource()))
371       {
372         // We dont care about version
373         // if ((refa.getVersion()==null || refb.getVersion()==null)
374         // || refb.getVersion().equals(refa.getVersion()))
375         // {
376         if (refa.getAccessionId() != null && refb.getAccessionId() != null
377                 && refb.getAccessionId().equals(refa.getAccessionId()))
378         {
379           if (refa.getMap() == null || refb.getMap() == null)
380           {
381             return true;
382           }
383           if ((refa.getMap() != null && refb.getMap() != null)
384                   && (refb.getMap().getMap() == null && refa.getMap()
385                           .getMap() == null)
386                   || (refb.getMap().getMap() != null
387                           && refa.getMap().getMap() != null && (refb
388                           .getMap().getMap().equals(refa.getMap().getMap()))))
389           { // getMap().getMap().containsEither(false,refa.getMap().getMap())
390             return true;
391           }
392         }
393       }
394       return false;
395     }
396   };
397
398   /**
399    * used by file parsers to generate DBRefs from annotation within file (eg
400    * stockholm)
401    * 
402    * @param dbname
403    * @param version
404    * @param acn
405    * @param seq
406    *          where to anotate with reference
407    * @return parsed version of entry that was added to seq (if any)
408    */
409   public static DBRefEntry parseToDbRef(SequenceI seq, String dbname,
410           String version, String acn)
411   {
412     DBRefEntry ref = null;
413     if (dbname != null)
414     {
415       String locsrc = jalview.util.DBRefUtils.getCanonicalName(dbname);
416       if (locsrc.equals(jalview.datamodel.DBRefSource.PDB))
417       {
418         // check for chaincode and mapping
419         // PFAM style stockhom PDB citation
420         com.stevesoft.pat.Regex r = new com.stevesoft.pat.Regex(
421                 "([0-9][0-9A-Za-z]{3})\\s*(.?)\\s*;\\s*([0-9]+)-([0-9]+)");
422         if (r.search(acn.trim()))
423         {
424           String pdbid = r.stringMatched(1);
425           String chaincode = r.stringMatched(2);
426           if (chaincode==null)
427           {
428             chaincode = " ";
429           }
430           String mapstart = r.stringMatched(3);
431           String mapend = r.stringMatched(4);
432           if (chaincode.equals(" "))
433           {
434             chaincode = "_";
435           }
436           // construct pdb ref.
437           ref = new DBRefEntry(locsrc, version, pdbid + chaincode);
438           PDBEntry pdbr = new PDBEntry();
439           pdbr.setId(pdbid);
440           pdbr.setProperty(new Hashtable());
441           pdbr.getProperty().put("CHAIN", chaincode);
442           seq.addPDBId(pdbr);
443         } else {
444           System.err.println("Malformed PDB DR line:"+acn);
445         }
446       }
447       else
448       {
449         // default:
450         ref = new DBRefEntry(locsrc, version, acn);
451       }
452     }
453     if (ref != null)
454     {
455       seq.addDBRef(ref);
456     }
457     return ref;
458   }
459
460 }