Clover icon

Coverage Report

  1. Project Clover database Tue Nov 18 2025 10:51:49 GMT
  2. Package jalview.datamodel

File PDBEntry.java

 

Coverage histogram

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

Code metrics

76
154
67
2
788
486
125
0.81
2.3
33.5
1.87

Classes

Class Line # Actions
PDBEntry 32 145 119
0.8185053581.9%
PDBEntry.Type 64 9 6
0.7575%
 

Contributing tests

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