Clover icon

Coverage Report

  1. Project Clover database Fri Dec 6 2024 13:47:14 GMT
  2. Package jalview.datamodel

File PDBEntry.java

 

Coverage histogram

../../img/srcFileCovDistChart9.png
12% of files have more coverage

Code metrics

70
128
48
2
667
391
102
0.8
2.67
24
2.12

Classes

Class Line # Actions
PDBEntry 30 119 96
0.834782683.5%
PDBEntry.Type 62 9 6
0.7575%
 

Contributing tests

This file is covered by 80 tests. .

Source view

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.datamodel;
22   
23    import java.util.Collections;
24    import java.util.Enumeration;
25    import java.util.Hashtable;
26   
27    import jalview.io.StructureFile;
28    import jalview.util.CaseInsensitiveString;
29   
 
30    public class PDBEntry
31    {
32   
33    /**
34    * constant for storing chain code in properties table
35    */
36    private static final String CHAIN_ID = "chain_code";
37   
38    private Hashtable<String, Object> properties;
39   
40    private static final int PDB_ID_LENGTH = 4;
41   
42    /**
43    * property set when id is a 'manufactured' identifier from the structure
44    * data's filename
45    */
46    private static final String FAKED_ID = "faked_pdbid";
47   
48    /**
49    * property set when the id is authoritative, and should be used in preference
50    * to any identifiers in the structure data
51    */
52    private static final String AUTHORITATIVE_ID = "authoritative_pdbid";
53   
54    private String file;
55   
56    private String type;
57   
58    private String id;
59   
60    private StructureFile sf = null;
61   
 
62    public enum Type
63    {
64    // TODO is FILE needed; if not is this enum needed, or can we
65    // use FileFormatI for PDB, MMCIF?
66    PDB("pdb", "pdb"), MMCIF("mmcif", "cif"), BCIF("bcif", "bcif"),
67    FILE("?", "?");
68   
69    /*
70    * file extension for cached structure file; must be one that
71    * is recognised by Chimera 'open' command
72    * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/filetypes.html
73    */
74    String ext;
75   
76    /*
77    * format specifier used in dbfetch request
78    * @see http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/dbfetch.databases#pdb
79    */
80    String format;
81   
 
82  220 toggle private Type(String fmt, String ex)
83    {
84  220 format = fmt;
85  220 ext = ex;
86    }
87   
 
88  0 toggle public String getFormat()
89    {
90  0 return format;
91    }
92   
 
93  0 toggle public String getExtension()
94    {
95  0 return ext;
96    }
97   
98    /**
99    * case insensitive matching for Type enum
100    *
101    * @param value
102    * @return
103    */
 
104  96 toggle public static Type getType(String value)
105    {
106  96 for (Type t : Type.values())
107    {
108  108 if (t.toString().equalsIgnoreCase(value))
109    {
110  95 return t;
111    }
112    }
113  1 return null;
114    }
115   
116    /**
117    * case insensitive equivalence for strings resolving to PDBEntry type
118    *
119    * @param t
120    * @return
121    */
 
122  4 toggle public boolean matches(String t)
123    {
124  4 return (this.toString().equalsIgnoreCase(t));
125    }
126    }
127   
128    /**
129    * Answers true if obj is a PDBEntry with the same id and chain code (both
130    * ignoring case), file, type and properties
131    */
 
132  17540 toggle @Override
133    public boolean equals(Object obj)
134    {
135  17540 if (obj == null || !(obj instanceof PDBEntry))
136    {
137  2 return false;
138    }
139  17538 if (obj == this)
140    {
141  11 return true;
142    }
143  17527 PDBEntry o = (PDBEntry) obj;
144   
145    /*
146    * note that chain code is stored as a property wrapped by a
147    * CaseInsensitiveString, so we are in effect doing a
148    * case-insensitive comparison of chain codes
149    */
150  17527 boolean idMatches = id == o.id
151    || (id != null && id.equalsIgnoreCase(o.id));
152  17527 boolean fileMatches = file == o.file
153    || (file != null && file.equals(o.file));
154  17527 boolean typeMatches = type == o.type
155    || (type != null && type.equals(o.type));
156  17527 if (idMatches && fileMatches && typeMatches)
157    {
158  377 return properties == o.properties
159    || (properties != null && properties.equals(o.properties));
160    }
161  17150 return false;
162    }
163   
164    /**
165    * Default constructor
166    */
 
167  737 toggle public PDBEntry()
168    {
169    }
170   
 
171  90 toggle public PDBEntry(String pdbId, String chain, PDBEntry.Type type,
172    String filePath)
173    {
174  90 init(pdbId, chain, type, filePath);
175    }
176   
177    /**
178    * @param pdbId
179    * @param chain
180    * @param entryType
181    * @param filePath
182    */
 
183  302 toggle void init(String pdbId, String chain, PDBEntry.Type entryType,
184    String filePath)
185    {
186  302 this.id = pdbId;
187  302 this.type = entryType == null ? null : entryType.toString();
188  302 this.file = filePath;
189  302 setChainCode(chain);
190    }
191   
192    /**
193    * Copy constructor.
194    *
195    * @param entry
196    */
 
197  146 toggle public PDBEntry(PDBEntry entry)
198    {
199  146 file = entry.file;
200  146 type = entry.type;
201  146 id = entry.id;
202  146 if (entry.properties != null)
203    {
204  6 properties = (Hashtable<String, Object>) entry.properties.clone();
205    }
206    }
207   
208    /**
209    * Make a PDBEntry from a DBRefEntry. The accession code is used for the PDB
210    * id, but if it is 5 characters in length, the last character is removed and
211    * set as the chain code instead.
212    *
213    * @param dbr
214    */
 
215  213 toggle public PDBEntry(DBRefEntry dbr)
216    {
217  213 if (!DBRefSource.PDB.equals(dbr.getSource()))
218    {
219  1 throw new IllegalArgumentException(
220    "Invalid source: " + dbr.getSource());
221    }
222   
223  212 String pdbId = dbr.getAccessionId();
224  212 String chainCode = null;
225  212 if (pdbId.length() == PDB_ID_LENGTH + 1)
226    {
227  17 char chain = pdbId.charAt(PDB_ID_LENGTH);
228  17 if (('a' <= chain && chain <= 'z') || ('A' <= chain && chain <= 'Z'))
229    {
230  15 pdbId = pdbId.substring(0, PDB_ID_LENGTH);
231  15 chainCode = String.valueOf(chain);
232    }
233    }
234  212 init(pdbId, chainCode, null, null);
235    }
236   
 
237  474 toggle public void setFile(String f)
238    {
239  474 this.file = f;
240    }
241   
 
242  19501 toggle public String getFile()
243    {
244  19501 return file;
245    }
246   
 
247  312 toggle public void setType(String t)
248    {
249  312 this.type = t;
250    }
251   
 
252  120 toggle public void setType(PDBEntry.Type type)
253    {
254  120 this.type = type == null ? null : type.toString();
255    }
256   
 
257  361 toggle public String getType()
258    {
259  361 return type;
260    }
261   
 
262  737 toggle public void setId(String id)
263    {
264  737 this.id = id;
265    }
266   
 
267  96793 toggle public String getId()
268    {
269  96793 return id;
270    }
271   
 
272  636 toggle public void setProperty(String key, Object value)
273    {
274  636 if (this.properties == null)
275    {
276  495 this.properties = new Hashtable<String, Object>();
277    }
278  636 properties.put(key, value);
279    }
280   
 
281  45263 toggle public Object getProperty(String key)
282    {
283  45263 return properties == null ? null : properties.get(key);
284    }
285   
286    /**
287    * Returns an enumeration of the keys of this object's properties (or an empty
288    * enumeration if it has no properties)
289    *
290    * @return
291    */
 
292  203 toggle public Enumeration<String> getProperties()
293    {
294  203 if (properties == null)
295    {
296  114 return Collections.emptyEnumeration();
297    }
298  89 return properties.keys();
299    }
300   
301    /**
302    *
303    * @return null or a string for associated chain IDs
304    */
 
305  386 toggle public String getChainCode()
306    {
307  386 return (properties == null || properties.get(CHAIN_ID) == null) ? null
308    : properties.get(CHAIN_ID).toString();
309    }
310   
311    /**
312    * Sets a non-case-sensitive property for the given chain code. Two PDBEntry
313    * objects which differ only in the case of their chain code are considered
314    * equal. This avoids duplication of objects in lists of PDB ids.
315    *
316    * @param chainCode
317    */
 
318  651 toggle public void setChainCode(String chainCode)
319    {
320  651 if (chainCode == null)
321    {
322  227 deleteProperty(CHAIN_ID);
323    }
324    else
325    {
326  424 setProperty(CHAIN_ID, new CaseInsensitiveString(chainCode));
327    }
328    }
329   
330    /**
331    * Deletes the property with the given key, and returns the deleted value (or
332    * null)
333    */
 
334  227 toggle Object deleteProperty(String key)
335    {
336  227 Object result = null;
337  227 if (properties != null)
338    {
339  1 result = properties.remove(key);
340    }
341  227 return result;
342    }
343   
 
344  26 toggle @Override
345    public String toString()
346    {
347  26 return id;
348    }
349   
350    /**
351    * Getter provided for Castor binding only. Application code should call
352    * getProperty() or getProperties() instead.
353    *
354    * @deprecated
355    * @see #getProperty(String)
356    * @see #getProperties()
357    * @see jalview.ws.dbsources.Uniprot#getUniprotEntries
358    * @return
359    */
 
360  0 toggle @Deprecated
361    public Hashtable<String, Object> getProps()
362    {
363  0 return properties;
364    }
365   
366    /**
367    * Setter provided for Castor binding only. Application code should call
368    * setProperty() instead.
369    *
370    * @deprecated
371    * @return
372    */
 
373  0 toggle @Deprecated
374    public void setProps(Hashtable<String, Object> props)
375    {
376  0 properties = props;
377    }
378   
379    /**
380    * Answers true if this object is either equivalent to, or can be 'improved'
381    * by, the given entry.
382    * <p>
383    * If newEntry has the same id (ignoring case), and doesn't have a conflicting
384    * file spec or chain code, then update this entry from its file and/or chain
385    * code.
386    *
387    * @param newEntry
388    * @return true if modifications were made
389    */
 
390  17498 toggle public boolean updateFrom(PDBEntry newEntry)
391    {
392  17498 if (this.equals(newEntry))
393    {
394  327 return true;
395    }
396   
397  17171 String newId = newEntry.getId();
398  17171 if (newId == null || getId() == null)
399    {
400  0 return false; // shouldn't happen
401    }
402   
403  17171 boolean idMatches = getId().equalsIgnoreCase(newId);
404   
405    /*
406    * Don't update if associated with different structure files
407    */
408  17171 String newFile = newEntry.getFile();
409  17171 if (newFile != null && getFile() != null)
410    {
411  179 if (!newFile.equals(getFile()))
412    {
413  103 return false;
414    }
415    else
416    {
417    // files match.
418  76 if (!idMatches)
419    {
420    // this shouldn't happen, but could do if the id from the
421    // file is not the same as the id from the authority that provided
422    // the file
423  2 if (!newEntry.fakedPDBId() && !isAuthoritative())
424    {
425  0 return false;
426    } // otherwise we can update
427    }
428    }
429    }
430    else
431    {
432    // one has data, one doesn't ..
433  16992 if (!idMatches)
434    {
435  16919 return false;
436    } // otherwise maybe can update
437    }
438   
439    /*
440    * Don't update if associated with different chains (ignoring case)
441    */
442  149 String newChain = newEntry.getChainCode();
443  149 if (newChain != null && newChain.length() > 0 && getChainCode() != null
444    && getChainCode().length() > 0
445    && !getChainCode().equalsIgnoreCase(newChain))
446    {
447  8 return false;
448    }
449   
450    /*
451    * set file path if not already set
452    */
453  141 String newType = newEntry.getType();
454  141 if (getFile() == null && newFile != null)
455    {
456  3 setFile(newFile);
457  3 setType(newType);
458    }
459   
460    /*
461    * set file type if new entry has it and we don't
462    * (for the case where file was not updated)
463    */
464  141 if (getType() == null && newType != null)
465    {
466  7 setType(newType);
467    }
468   
469    /*
470    * set chain if not already set (we excluded differing
471    * chains earlier) (ignoring case change only)
472    */
473  141 if (newChain != null && newChain.length() > 0
474    && !newChain.equalsIgnoreCase(getChainCode()))
475    {
476  18 setChainCode(newChain);
477    }
478   
479    /*
480    * copy any new or modified properties
481    */
482  141 Enumeration<String> newProps = newEntry.getProperties();
483  186 while (newProps.hasMoreElements())
484    {
485    /*
486    * copy properties unless value matches; this defends against changing
487    * the case of chain_code which is wrapped in a CaseInsensitiveString
488    */
489  45 String key = newProps.nextElement();
490  45 Object value = newEntry.getProperty(key);
491  45 if (FAKED_ID.equals(key) || AUTHORITATIVE_ID.equals(key))
492    {
493    // we never update the fake ID property
494  1 continue;
495    }
496  44 if (!value.equals(getProperty(key)))
497    {
498  11 setProperty(key, value);
499    }
500    }
501  141 return true;
502    }
503   
 
504  1 toggle public void setAuthoritative(boolean isAuthoritative)
505    {
506  1 setProperty(AUTHORITATIVE_ID, Boolean.valueOf(isAuthoritative));
507    }
508   
509    /**
510    *
511    * @return true if the identifier should be preferred over any identifiers
512    * embedded in the structure data
513    */
 
514  3 toggle public boolean isAuthoritative()
515    {
516  3 if (_hasProperty(AUTHORITATIVE_ID))
517    {
518  2 Object authId = getProperty(AUTHORITATIVE_ID);
519  2 return (authId instanceof Boolean) ? (Boolean) authId
520    : Boolean.valueOf(authId.toString());
521    }
522  1 return false;
523    }
524   
525    /**
526    * set when Jalview has manufactured the ID using a local filename
527    *
528    * @return
529    */
 
530  4 toggle public boolean fakedPDBId()
531    {
532  4 if (_hasProperty(FAKED_ID))
533    {
534  2 return true;
535    }
536  2 return false;
537    }
538   
 
539  303 toggle public void setFakedPDBId(boolean faked)
540    {
541  303 if (faked)
542    {
543  96 setProperty(FAKED_ID, Boolean.TRUE);
544    }
545    else
546    {
547  207 if (properties != null)
548    {
549  0 properties.remove(FAKED_ID);
550    }
551    }
552    }
553   
 
554  7 toggle private boolean _hasProperty(final String key)
555    {
556  7 return (properties != null && properties.containsKey(key));
557    }
558   
559    private static final String RETRIEVE_FROM = "RETRIEVE_FROM";
560   
561    private static final String PROVIDER = "PROVIDER";
562   
563    private static final String MODELPAGE = "PROVIDERPAGE";
564   
565    private static final String PROVIDERCATEGORY = "PROVIDERCATEGORY";
566   
567    /**
568    * Permanent URI for retrieving the original structure data
569    *
570    * @param urlStr
571    */
 
572  0 toggle public void setRetrievalUrl(String urlStr)
573    {
574  0 setProperty(RETRIEVE_FROM, urlStr);
575    }
576   
 
577  0 toggle public boolean hasRetrievalUrl()
578    {
579  0 return _hasProperty(RETRIEVE_FROM);
580    }
581   
582    /**
583    * get the Permanent URI for retrieving the original structure data
584    */
 
585  0 toggle public String getRetrievalUrl()
586    {
587  0 return (String) getProperty(RETRIEVE_FROM);
588    }
589   
590    /**
591    * Data provider name - from 3D Beacons
592    *
593    * @param provider
594    */
 
595  0 toggle public void setProvider(String provider)
596    {
597  0 setProperty(PROVIDER, provider);
598    }
599   
600    /**
601    * Get Data provider name - from 3D Beacons
602    *
603    */
 
604  44934 toggle public String getProvider()
605    {
606  44934 return (String) getProperty(PROVIDER);
607    }
608   
609    /**
610    * Permanent URI for retrieving the original structure data
611    *
612    * @param urlStr
613    */
 
614  0 toggle public void setProviderPage(String urlStr)
615    {
616  0 setProperty(MODELPAGE, urlStr);
617    }
618   
619    /**
620    * get the Permanent URI for retrieving the original structure data
621    */
 
622  0 toggle public String getProviderPage()
623    {
624  0 return (String) getProperty(MODELPAGE);
625    }
626   
 
627  0 toggle public boolean hasProviderPage()
628    {
629  0 return _hasProperty(MODELPAGE);
630    }
631   
 
632  0 toggle public boolean hasProvider()
633    {
634  0 return _hasProperty(PROVIDER);
635    }
636   
 
637  0 toggle public StructureFile getStructureFile()
638    {
639  0 return sf;
640    }
641   
 
642  55 toggle public void setStructureFile(StructureFile f)
643    {
644  55 sf = f;
645    }
646   
 
647  0 toggle public boolean hasStructureFile()
648    {
649  0 return sf != null && sf.inFile != null && sf.inFile.exists();
650    }
651   
 
652  0 toggle public void setProviderCategory(String providerCategory)
653    {
654  0 setProperty(PROVIDERCATEGORY, providerCategory);
655    }
656   
 
657  0 toggle public String getProviderCategory()
658    {
659  0 return (String) getProperty(PROVIDERCATEGORY);
660    }
661   
 
662  0 toggle public boolean hasProviderCategory()
663    {
664  0 return _hasProperty(PROVIDERCATEGORY);
665    }
666   
667    }