2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
21 package jalview.datamodel;
23 import jalview.util.CaseInsensitiveString;
25 import java.util.Collections;
26 import java.util.Enumeration;
27 import java.util.Hashtable;
33 * constant for storing chain code in properties table
35 private static final String CHAIN_ID = "chain_code";
37 private Hashtable<String, Object> properties;
39 private static final int PDB_ID_LENGTH = 4;
49 // TODO is FILE needed; if not is this enum needed, or can we
50 // use FileFormatI for PDB, MMCIF?
51 PDB("pdb", "pdb"), MMCIF("mmcif", "cif"), FILE("?", "?");
54 * file extension for cached structure file; must be one that
55 * is recognised by Chimera 'open' command
56 * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/filetypes.html
61 * format specifier used in dbfetch request
62 * @see http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/dbfetch.databases#pdb
66 private Type(String fmt, String ex)
72 public String getFormat()
77 public String getExtension()
83 * case insensitive matching for Type enum
88 public static Type getType(String value)
90 for (Type t : Type.values())
92 if (t.toString().equalsIgnoreCase(value))
101 * case insensitive equivalence for strings resolving to PDBEntry type
106 public boolean matches(String t)
108 return (this.toString().equalsIgnoreCase(t));
113 * Answers true if obj is a PDBEntry with the same id and chain code (both
114 * ignoring case), file, type and properties
117 public boolean equals(Object obj)
119 if (obj == null || !(obj instanceof PDBEntry))
127 PDBEntry o = (PDBEntry) obj;
130 * note that chain code is stored as a property wrapped by a
131 * CaseInsensitiveString, so we are in effect doing a
132 * case-insensitive comparison of chain codes
134 return (id == o.id || (id != null && id.equalsIgnoreCase(o.id)))
135 && (file == o.file || (file != null && file.equals(o.file)))
136 && (type == o.type || (type != null && type.equals(o.type)))
137 && (properties == o.properties || (properties != null
138 && properties.equals(o.properties)));
142 * Default constructor
148 public PDBEntry(String pdbId, String chain, PDBEntry.Type type,
151 init(pdbId, chain, type, filePath);
160 void init(String pdbId, String chain, PDBEntry.Type entryType,
164 this.type = entryType == null ? null : entryType.toString();
165 this.file = (filePath == null ? null : filePath.replace('\\', '/'));
174 public PDBEntry(PDBEntry entry)
179 if (entry.properties != null)
181 properties = (Hashtable<String, Object>) entry.properties.clone();
186 * Make a PDBEntry from a DBRefEntry. The accession code is used for the PDB
187 * id, but if it is 5 characters in length, the last character is removed and
188 * set as the chain code instead.
192 public PDBEntry(DBRefEntry dbr)
194 if (!DBRefSource.PDB.equals(dbr.getSource()))
196 throw new IllegalArgumentException(
197 "Invalid source: " + dbr.getSource());
200 String pdbId = dbr.getAccessionId();
201 String chainCode = null;
202 if (pdbId.length() == PDB_ID_LENGTH + 1)
204 char chain = pdbId.charAt(PDB_ID_LENGTH);
205 if (('a' <= chain && chain <= 'z') || ('A' <= chain && chain <= 'Z'))
207 pdbId = pdbId.substring(0, PDB_ID_LENGTH);
208 chainCode = String.valueOf(chain);
211 init(pdbId, chainCode, null, null);
214 public void setFile(String f)
216 this.file = f.replace('\\', '/');
219 public String getFile()
224 public void setType(String t)
229 public void setType(PDBEntry.Type type)
231 this.type = type == null ? null : type.toString();
234 public String getType()
239 public void setId(String id)
244 public String getId()
249 public void setProperty(String key, Object value)
251 if (this.properties == null)
253 this.properties = new Hashtable<>();
255 properties.put(key, value);
258 public Object getProperty(String key)
260 return properties == null ? null : properties.get(key);
264 * Returns an enumeration of the keys of this object's properties (or an empty
265 * enumeration if it has no properties)
269 public Enumeration<String> getProperties()
271 if (properties == null)
273 return Collections.emptyEnumeration();
275 return properties.keys();
280 * @return null or a string for associated chain IDs
282 public String getChainCode()
284 return (properties == null || properties.get(CHAIN_ID) == null) ? null
285 : properties.get(CHAIN_ID).toString();
289 * Sets a non-case-sensitive property for the given chain code. Two PDBEntry
290 * objects which differ only in the case of their chain code are considered
291 * equal. This avoids duplication of objects in lists of PDB ids.
295 public void setChainCode(String chainCode)
297 if (chainCode == null)
299 deleteProperty(CHAIN_ID);
303 setProperty(CHAIN_ID, new CaseInsensitiveString(chainCode));
308 * Deletes the property with the given key, and returns the deleted value (or
311 Object deleteProperty(String key)
313 Object result = null;
314 if (properties != null)
316 result = properties.remove(key);
322 public String toString()
328 * Getter provided for Castor binding only. Application code should call
329 * getProperty() or getProperties() instead.
332 * @see #getProperty(String)
333 * @see #getProperties()
334 * @see jalview.ws.dbsources.Uniprot#getUniprotEntries
338 public Hashtable<String, Object> getProps()
344 * Setter provided for Castor binding only. Application code should call
345 * setProperty() instead.
351 public void setProps(Hashtable<String, Object> props)
357 * Answers true if this object is either equivalent to, or can be 'improved'
358 * by, the given entry.
360 * If newEntry has the same id (ignoring case), and doesn't have a conflicting
361 * file spec or chain code, then update this entry from its file and/or chain
365 * @return true if modifications were made
367 public boolean updateFrom(PDBEntry newEntry)
369 if (this.equals(newEntry))
374 String newId = newEntry.getId();
375 if (newId == null || getId() == null)
377 return false; // shouldn't happen
381 * id has to match (ignoring case)
383 if (!getId().equalsIgnoreCase(newId))
389 * Don't update if associated with different structure files
391 String newFile = newEntry.getFile();
392 if (newFile != null && getFile() != null && !newFile.equals(getFile()))
398 * Don't update if associated with different chains (ignoring case)
400 String newChain = newEntry.getChainCode();
401 if (newChain != null && newChain.length() > 0 && getChainCode() != null
402 && getChainCode().length() > 0
403 && !getChainCode().equalsIgnoreCase(newChain))
409 * set file path if not already set
411 String newType = newEntry.getType();
412 if (getFile() == null && newFile != null)
419 * set file type if new entry has it and we don't
420 * (for the case where file was not updated)
422 if (getType() == null && newType != null)
428 * set chain if not already set (we excluded differing
429 * chains earlier) (ignoring case change only)
431 if (newChain != null && newChain.length() > 0
432 && !newChain.equalsIgnoreCase(getChainCode()))
434 setChainCode(newChain);
438 * copy any new or modified properties
440 Enumeration<String> newProps = newEntry.getProperties();
441 while (newProps.hasMoreElements())
444 * copy properties unless value matches; this defends against changing
445 * the case of chain_code which is wrapped in a CaseInsensitiveString
447 String key = newProps.nextElement();
448 Object value = newEntry.getProperty(key);
449 if (!value.equals(getProperty(key)))
451 setProperty(key, value);