001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 * Created on Jun 5, 2010 021 * Author: Jianjiong Gao 022 * 023 */ 024 025package org.biojava.nbio.protmod.structure; 026 027import org.biojava.nbio.protmod.ModificationCategory; 028import org.biojava.nbio.protmod.ProteinModification; 029import org.biojava.nbio.protmod.ProteinModificationImpl; 030import org.biojava.nbio.protmod.io.ModifiedCompoundXMLConverter; 031 032import java.io.Serializable; 033import java.util.*; 034 035 036/** 037 * 038 * @author Jianjiong Gao 039 * @since 3.0 040 */ 041public class ModifiedCompoundImpl 042implements ModifiedCompound, Serializable, Comparable<ModifiedCompound> { 043 044 /** 045 * 046 */ 047 private static final long serialVersionUID = 1656563037849815427L; 048 049 ProteinModification originalModification; 050 051 ProteinModification modification; 052 053 Set<StructureGroup> groups; 054 055 Map<Set<StructureGroup>, Set<StructureAtomLinkage>> atomLinkages; 056 057 public static final String newline = System.getProperty("line.separator"); 058 059 public ModifiedCompoundImpl(){ 060 061 } 062 063 /** 064 * Create a ModifiedCompoundImpl that has only one involved component. 065 * Use this constructor for a modified residue. 066 * @param modification {@link ProteinModification}. 067 * @param modifiedResidue modified group. 068 * @throws IllegalArgumentException if either argument is null. 069 */ 070 public ModifiedCompoundImpl ( 071 ProteinModification modification, 072 StructureGroup modifiedResidue) { 073 if (modification==null || modifiedResidue==null) { 074 throw new IllegalArgumentException("Null argument(s)"); 075 } 076 077 groups = new HashSet<>(1); 078 groups.add(modifiedResidue); 079 080 // is it possible that components be added by addLinkage later? 081 atomLinkages = null; 082 083 setModification(modification); 084 } 085 086 /** 087 * 088 * @param modification ProteinModification. 089 * @param linkages a collection of atom linkages. 090 * @see ProteinModification 091 * @see StructureAtomLinkage 092 */ 093 public ModifiedCompoundImpl( ProteinModification modification, 094 Collection<StructureAtomLinkage> linkages) { 095 if (modification==null) { 096 throw new IllegalArgumentException("modification cannot be null"); 097 } 098 099 if (linkages==null||linkages.isEmpty()) { 100 throw new IllegalArgumentException("at least one linkage."); 101 } 102 103 this.groups = new HashSet<>(); 104 105 addAtomLinkages(linkages); 106 107 setModification(modification); 108 109 } 110 111 @Override 112 public void setModification(ProteinModification protmod){ 113 originalModification = protmod; 114 115 resetModification(); 116 } 117 118 @Override 119 public ProteinModification getModification() { 120 return modification; 121 } 122 123 private void resetModification() { 124 if (originalModification == null) 125 modification = originalModification; 126 else if (originalModification.getCategory()!=ModificationCategory.UNDEFINED) 127 modification = originalModification; 128 else { 129 int nRes = 0; 130 Set<String> ligands = new HashSet<>(); 131 for (StructureGroup group : groups) { 132 if (group.isAminoAcid()) { 133 nRes ++; 134 } else { 135 ligands.add(group.getPDBName().trim()); 136 } 137 } 138 139 ModificationCategory cat; 140 switch (nRes) { 141 case 0: 142 modification = originalModification; return; 143 case 1: 144 cat = ModificationCategory.ATTACHMENT; break; 145 case 2: 146 cat = ModificationCategory.CROSS_LINK_2; break; 147 case 3: 148 cat = ModificationCategory.CROSS_LINK_3; break; 149 case 4: 150 cat = ModificationCategory.CROSS_LINK_4; break; 151 case 5: 152 cat = ModificationCategory.CROSS_LINK_5; break; 153 case 6: 154 cat = ModificationCategory.CROSS_LINK_6; break; 155 case 7: 156 cat = ModificationCategory.CROSS_LINK_7; break; 157 default: 158 cat = ModificationCategory.CROSS_LINK_8_OR_LARGE; break; 159 } 160 161 modification = new ProteinModificationImpl.Builder(originalModification) 162 .setCategory(cat).addKeywords(ligands).build(); 163 } 164 } 165 166 @Override 167 public Set<StructureGroup> getGroups() { 168 if ( groups == null) 169 return null; 170 171 return Collections.unmodifiableSet(groups); 172 } 173 174 @Override 175 public Set<StructureGroup> getGroups(boolean isAminoAcid) { 176 Set<StructureGroup> result = new HashSet<>(); 177 for (StructureGroup group : groups) { 178 if (group.isAminoAcid() == isAminoAcid) { 179 result.add(group); 180 } 181 } 182 return result; 183 } 184 185 @Override 186 public void setGroups(Set<StructureGroup> groups){ 187 this.groups = groups; 188 resetModification(); 189 } 190 191 @Override 192 public Set<StructureAtomLinkage> getAtomLinkages() { 193 if (atomLinkages==null) { 194 return Collections.emptySet(); 195 } else { 196 Set<StructureAtomLinkage> result = new HashSet<>(); 197 for (Set<StructureAtomLinkage> linkages : atomLinkages.values()) { 198 result.addAll(linkages); 199 } 200 201 return result; 202 } 203 } 204 205 206 @Override 207 public void setAtomLinkages(Set<StructureAtomLinkage> linkages) { 208 for (StructureAtomLinkage sali : linkages){ 209 addAtomLinkage(sali); 210 } 211 resetModification(); 212 } 213 214 @Override 215 public boolean addAtomLinkage(StructureAtomLinkage linkage) { 216 if (linkage==null) { 217 throw new IllegalArgumentException("Null linkage"); 218 } 219 220 Set<StructureGroup> gs = new HashSet<>(2); 221 gs.add(linkage.getAtom1().getGroup()); 222 gs.add(linkage.getAtom2().getGroup()); 223 224 if (atomLinkages==null) { 225 atomLinkages = new HashMap<>(); 226 } 227 228 Set<StructureAtomLinkage> linkages = atomLinkages.get(gs); 229 if (linkages == null) { 230 linkages = new HashSet<>(); 231 atomLinkages.put(gs, linkages); 232 groups.addAll(gs); // it's possible of new groups 233 }; 234 235 return linkages.add(linkage); 236 } 237 238 @Override 239 public void addAtomLinkages(Collection<StructureAtomLinkage> linkages) { 240 if (linkages==null) { 241 throw new IllegalArgumentException("Null linkages"); 242 } 243 244 for (StructureAtomLinkage link : linkages) { 245 addAtomLinkage(link); 246 } 247 248 resetModification(); 249 } 250 251 @Override 252 public boolean crossChains() { 253 if (groups==null || groups.isEmpty()) 254 return false; 255 256 Iterator<StructureGroup> it = groups.iterator(); 257 String chain = it.next().getChainId(); 258 while (it.hasNext()) { 259 if (!it.next().getChainId().equals(chain)) 260 return true; 261 } 262 263 return false; 264 } 265 266 267 @Override 268 public String toString(){ 269 StringBuilder sb = new StringBuilder(); 270 if ( originalModification == null) 271 return "ModifiedCompoundImpl -- not initialized"; 272 273 //sb.append("Modification_"); 274 sb.append(originalModification.getId()); 275 ModificationCategory cat ; 276 if (originalModification.getCategory()==ModificationCategory.UNDEFINED) { 277 cat = getModification().getCategory(); 278 } else 279 cat = originalModification.getCategory(); 280 sb.append("_"); 281 sb.append(cat.toString()); 282 return sb.toString(); 283 } 284 285 286 @Override 287 public String getDescription() { 288 289 StringBuilder sb = new StringBuilder(); 290 //sb.append("Category: "); 291 292 if ( getModification() == null) { 293 sb.append(" !!! not initialized !!!"); 294 return sb.toString(); 295 } 296 297 sb.append(originalModification.toString()); 298// sb.append(getModification().getCategory()); 299// if (!modification.getKeywords().isEmpty()) { 300// sb.append("; "); 301// sb.append(modification.getKeywords()); 302// } 303// sb.append("; Modification ID: "); 304// sb.append(modification.getId()); 305// 306// if (modification.getResidId()!=null) { 307// sb.append("; RESID: "); 308// sb.append(modification.getResidId()); 309// sb.append(" ["); 310// sb.append(modification.getResidName()); 311// sb.append(']'); 312// } 313// 314// sb.append(" | "); 315// 316// if (atomLinkages==null) { 317// for (StructureGroup group : groups) { 318// sb.append(group); 319// sb.append(" | "); 320// } 321// } else { 322// for (Set<StructureAtomLinkage> linkages : atomLinkages.values()) { 323// for (StructureAtomLinkage linkage : linkages) { 324// sb.append(linkage); 325// sb.append(" | "); 326// } 327// } 328// } 329 330 return sb.toString(); 331 } 332 333 @Override 334 public void setDescription(String desc){ 335 // do nothing.... 336 337 } 338 339 @Override 340 public int compareTo(ModifiedCompound compound){ 341 try { 342 // quite complex objects so the easiest is to just wrap it as XML 343 // and compare the two strings... 344 String xml = ModifiedCompoundXMLConverter.toXML(this); 345 String xml2 = ModifiedCompoundXMLConverter.toXML(compound); 346 return xml.compareTo(xml2); 347 } catch (Exception e){ 348 349 } 350 return this.toString().compareTo(compound.toString()); 351 } 352 353 /** 354 * @return true if same modification and same components; false, otherwise. 355 */ 356 @Override 357 public boolean equals(Object obj) { 358 if (!(obj instanceof ModifiedCompound)) { 359 return false; 360 } 361 362 ModifiedCompound mci = (ModifiedCompound)obj; 363 if (mci.getModification() != originalModification) { 364 return false; 365 } 366 367 if (!groups.equals(mci.getGroups())) { 368 return false; 369 } 370 371 return true; 372 373 // Do not need to consider linkage, since they can be determined by 374 // modification and groups. 375 } 376 377 @Override 378 public int hashCode() { 379 int result = 17; 380 result = result * 32 + originalModification.hashCode(); 381 382 int sum = 0; 383 for (StructureGroup group : groups) { 384 sum += group.hashCode(); 385 } 386 387 result = result * 32 + sum; 388 389 return result; 390 } 391}