001package org.biojava.nbio.structure.chem; 002 003import org.biojava.nbio.core.util.SoftHashMap; 004import org.biojava.nbio.structure.AminoAcid; 005import org.biojava.nbio.structure.AminoAcidImpl; 006import org.biojava.nbio.structure.Group; 007import org.biojava.nbio.structure.HetatomImpl; 008import org.biojava.nbio.structure.NucleotideImpl; 009import org.slf4j.Logger; 010import org.slf4j.LoggerFactory; 011 012public class ChemCompGroupFactory { 013 private static final Logger logger = LoggerFactory.getLogger(ChemCompGroupFactory.class); 014 private static ChemCompProvider chemCompProvider = new DownloadChemCompProvider(); 015 private static final SoftHashMap<String, ChemComp> cache = new SoftHashMap<>(0); 016 017 public static ChemComp getChemComp(String recordName) { 018 recordName = recordName.toUpperCase().trim(); 019 020 // we are using the cache, to avoid hitting the file system too often. 021 ChemComp cc = cache.get(recordName); 022 if (cc != null) { 023 logger.debug("Chem comp {} read from cache", cc.getThreeLetterCode()); 024 return cc; 025 } 026 027 // not cached, get the chem comp from the provider 028 logger.debug("Chem comp {} read from provider {}", recordName, chemCompProvider.getClass().getCanonicalName()); 029 cc = chemCompProvider.getChemComp(recordName); 030 031 // Note that this also caches null or empty responses 032 cache.put(recordName, cc); 033 return cc; 034 } 035 036 /** 037 * The new ChemCompProvider will be set in the static variable, 038 * so this provider will be used from now on until it is changed 039 * again. Note that this change can have unexpected behavior of 040 * code executed afterwards. 041 * <p> 042 * Changing the provider also resets the cache, so any groups 043 * previously accessed will be reread or re-downloaded. 044 * 045 * @param provider 046 */ 047 public static void setChemCompProvider(ChemCompProvider provider) { 048 logger.debug("Setting new chem comp provider to {}", provider.getClass().getCanonicalName()); 049 chemCompProvider = provider; 050 // clear cache 051 cache.clear(); 052 } 053 054 public static ChemCompProvider getChemCompProvider(){ 055 return chemCompProvider; 056 } 057 058 /** 059 * Force the in-memory cache to be reset. 060 * 061 * Note that the ChemCompProvider may have additional memory or disk caches that need to be cleared too. 062 */ 063 public static void clearCache() { 064 cache.clear(); 065 } 066 067 public static Group getGroupFromChemCompDictionary(String recordName) { 068 // make sure we work with upper case records 069 recordName = recordName.toUpperCase().trim(); 070 Group g; 071 ChemComp cc = getChemComp(recordName); 072 073 if (cc == null) { 074 return null; 075 } 076 077 if (PolymerType.PROTEIN_ONLY.contains(cc.getPolymerType())) { 078 AminoAcid aa = new AminoAcidImpl(); 079 080 String one_letter = cc.getOneLetterCode(); 081 if (one_letter == null || one_letter.equals("X") || one_letter.equals("?") || one_letter.length() == 0) { 082 String parent = cc.getMonNstdParentCompId(); 083 if (parent != null && parent.length() == 3) { 084 String parentid = cc.getMonNstdParentCompId(); 085 ChemComp parentCC = getChemComp(parentid); 086 one_letter = parentCC.getOneLetterCode(); 087 } 088 } 089 090 if (one_letter == null || one_letter.length() == 0 || one_letter.equals("?")) { 091 // e.g. problem with PRR, which probably should have a parent of ALA, but as of 20110127 does not. 092 logger.warn("Problem with chemical component: {} Did not find one letter code! Setting it to 'X'", 093 recordName); 094 aa.setAminoType('X'); 095 } else { 096 aa.setAminoType(one_letter.charAt(0)); 097 } 098 099 g = aa; 100 } else if (PolymerType.POLYNUCLEOTIDE_ONLY.contains(cc.getPolymerType())) { 101 g = new NucleotideImpl(); 102 } else { 103 g = new HetatomImpl(); 104 } 105 106 g.setChemComp(cc); 107 return g; 108 } 109 110 public static String getOneLetterCode(ChemComp cc) { 111 String oneLetter = cc.getOneLetterCode(); 112 if (oneLetter == null || oneLetter.equals("X") || oneLetter.equals("?")) { 113 String parentId = cc.getMonNstdParentCompId(); 114 if (parentId == null) { 115 return oneLetter; 116 } 117 // cases like OIM have multiple parents (comma separated), we shouldn't try grab a chemcomp for those strings 118 if (parentId.length() > 3) { 119 return oneLetter; 120 } 121 ChemComp parentCC = ChemCompGroupFactory.getChemComp(parentId); 122 if (parentCC == null) { 123 return oneLetter; 124 } 125 oneLetter = parentCC.getOneLetterCode(); 126 } 127 return oneLetter; 128 } 129}