Clover icon

Coverage Report

  1. Project Clover database Wed Dec 3 2025 17:03:17 GMT
  2. Package jalview.datamodel

File PDBEntry.java

 

Coverage histogram

../../img/srcFileCovDistChart8.png
21% of files have more coverage

Code metrics

78
170
68
2
820
505
130
0.76
2.5
34
1.91

Classes

Class Line # Actions
PDBEntry 32 161 124
0.7666666576.7%
PDBEntry.Type 64 9 6
0.7575%
 

Contributing tests

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