/* * Copyright (C) Lennart Martens * * Contact: lennart.martens AT UGent.be (' AT ' to be replaced with '@') */ /** * Created by IntelliJ IDEA. * User: Lennart * Date: 1-jul-2004 * Time: 15:06:24 */ package com.compomics.util.protein; import org.apache.log4j.Logger; import java.io.Serializable; import java.util.Collection; import java.util.HashMap; import java.util.Hashtable; /* * CVS information: * * $Revision: 1.3 $ * $Date: 2007/07/06 09:41:53 $ */ /** * This class implements a specific Modification. * * @author Lennart Martens */ public class ModificationImplementation implements com.compomics.util.interfaces.Modification, Cloneable, Serializable { // Class specific log4j logger for ModificationImplementation instances. Logger logger = Logger.getLogger(ModificationImplementation.class); /** * The ModificationTemplate which holds all the shared information for a modification. * It is to be considered a singleton and it is immutable. */ protected ModificationTemplate iTemplate = null; /** * The location for the modification in the parent sequence. */ protected int iLocation = -1; /** * This constructor allows initialization of all the properties for the modification. * * @param aTemplate ModificationTemplate with the shared information for this modification * @param aLocation int with the location of this modification in the parent sequence. */ public ModificationImplementation(ModificationTemplate aTemplate, int aLocation) { this.iTemplate = aTemplate; this.iLocation = aLocation; } /** * This constructor allows initialization of all the properties for the modification. * * @param aTitle String with the title for the modification (eg., Oxidation Met). * @param aCode String with the code for the modification (eg., Mox). The code can be used when * annotating a sequence String (eg., NH2-MGTEFSM<Mox>R-COOH). * @param aMassDeltas HashMap with the following 'key-value' mappings: (key > value) <br> * (residue > double[]{MONOISOTOPIC_DELTA, AVERAGE_DELTA} <br> * Note that the residues for the N-terminus and C-terminus are represented * by the NTERMINUS and CTERMINUS constants, respectively. * @param aLocation int with the location for this modification. */ public ModificationImplementation(String aTitle, String aCode, HashMap aMassDeltas, int aLocation) { this(aTitle, aCode, aMassDeltas, false, aLocation); } /** * This constructor allows initialization of all the properties for the modification. * * @param aTitle String with the title for the modification (eg., Oxidation Met). * @param aCode String with the code for the modification (eg., Mox). The code can be used when * annotating a sequence String (eg., NH2-MGTEFSM<Mox>R-COOH). * @param aMassDeltas HashMap with the following 'key-value' mappings: (key > value) <br> * (residue > double[]{MONOISOTOPIC_DELTA, AVERAGE_DELTA} <br> * Note that the residues for the N-terminus and C-terminus are represented * by the NTERMINUS and CTERMINUS constants, respectively. * @param aArtifact boolean to indicate whether this modification is an artifact. * @param aLocation int with the location for this modification. */ public ModificationImplementation(String aTitle, String aCode, HashMap aMassDeltas, boolean aArtifact, int aLocation) { this(new ModificationTemplate(aTitle, aCode, aMassDeltas, aArtifact), aLocation); } /** * This method returns a double with the average mass difference * conferred on the sequence by this modification for the specified residue. * This mass delta can be negative! When a residue was specified that is not affected by this * modification, '0.0' is returned. * * @param aResidue String with the residue for which the mass delta needs to be calculated. * @return double with the average mass difference. */ public double getAverageMassDelta(String aResidue) { return this.getMassDelta(aResidue, AVERAGE); } /** * This method returns the short code for the modification, eg. 'Mox'. * * @return String with the short code for the modification. * Can be used to annotate a sequence. */ public String getCode() { return this.iTemplate.getCode(); } /** * This method returns the title of the modification, * eg. 'Oxidation Met'. * * @return String with the title for the modification. */ public String getTitle() { return this.iTemplate.getTitle(); } /** * This method returns the location of the modification in the sequence. * Note that the N-terminus is 0, and the C-terminus is (sequence_length)+1. * * @return int with the location for the modification. */ public int getLocation() { return this.iLocation; } /** * This method reports on all the residues that can be modified by this Modification. * * @return Collection with the residues that can be modified by this modification. */ public Collection getResidues() { return this.iTemplate.getResidues(); } /** * This method returns a double with the monoisotopic mass difference * conferred on the sequence by this modification for the specified residue. * This mass delta can be negative! When a residue was specified that is not affected by this * modification, '0.0' is returned. * * @param aResidue String with the residue for which the mass delta needs to be calculated. * @return double with the monoisotopic mass difference. */ public double getMonoisotopicMassDelta(String aResidue) { return this.getMassDelta(aResidue, MONOISOTOPIC); } /** * This method allows the setting of the location for this modification. * The specified integer should be calculated from the start of the parent sequence, * where the N-terminus is 0, and the C-terminus is (sequence_length)+1. * * @param aLocation int with the location for this modification within the parent sequence. */ public void setLocation(int aLocation) { this.iLocation = aLocation; } /** * This method indicates whether this modification is considered an artifact. * * @return boolean that indicates whether this modification is an artifact. */ public boolean isArtifact() { return this.iTemplate.isArtifact(); } /** * Indicates whether some other object is "equal to" this one. * For this class comparison is based on: * <ul> * <li> class identity </li> * <li> title equality </li> * <li> location equality </li> * </ul> * * @param obj the reference object with which to compare. * @return <code>true</code> if this object is the same as the obj * argument; <code>false</code> otherwise. * @see #hashCode() * @see Hashtable */ public boolean equals(Object obj) { boolean result = true; // Class equality (instanceof is too lenient as it will vouch for subclasses as well!) if(obj == null || !obj.getClass().equals(this.getClass())) { result = false; } else if(((ModificationImplementation)obj).iLocation == this.iLocation) { // Equality is further defined by title. result = this.iTemplate.equals(((ModificationImplementation)obj).iTemplate); } else { // This means that the location was different, and therefore these // instances cannot be equal. result = false; } return result; } /** * Returns a hash code value for the object. This method is * supported for the benefit of hashtables such as those provided by * <code>java.util.Hashtable</code>. * <p> * The general contract of <code>hashCode</code> is: * <ul> * <li>Whenever it is invoked on the same object more than once during * an execution of a Java application, the <tt>hashCode</tt> method * must consistently return the same integer, provided no information * used in <tt>equals</tt> comparisons on the object is modified. * This integer need not remain consistent from one execution of an * application to another execution of the same application. * <li>If two objects are equal according to the <tt>equals(Object)</tt> * method, then calling the <code>hashCode</code> method on each of * the two objects must produce the same integer result. * <li>It is <em>not</em> required that if two objects are unequal * according to the {@link Object#equals(Object)} * method, then calling the <tt>hashCode</tt> method on each of the * two objects must produce distinct integer results. However, the * programmer should be aware that producing distinct integer results * for unequal objects may improve the performance of hashtables. * </ul> * <p> * As much as is reasonably practical, the hashCode method defined by * class <tt>Object</tt> does return distinct integers for distinct * objects. (This is typically implemented by converting the internal * address of the object into an integer, but this implementation * technique is not required by the Java programming language.) * * @return a hash code value for this object. * @see Object#equals(Object) * @see Hashtable */ public int hashCode() { return iTemplate.hashCode(); } /** * This method returns a String representation of the Modification. * * @return String with a String Representation of the Modification. */ public String toString() { return this.iTemplate.toString() + "\n\tLocation: : " + this.iLocation; } /** * Override of the clone method. It doesn't do anything except making the method public * and catching the 'CloneNotSupportedException'. The method now returns a 'null' when cloning was not * possible. * * @return Object with a clone of this class, or 'null' when the CloneNotSupportedException was thrown. */ public Object clone () { Object clone = null; try { clone = super.clone(); } catch(CloneNotSupportedException cnse) { logger.error(cnse.getMessage(), cnse); } return clone; } /** * Compares this object with the specified object for order. Returns a * negative integer, zero, or a positive integer as this object is less * than, equal to, or greater than the specified object.<p> * * In this implementation, ordering is first done on location, and only if this is * identical, the title is compared. Therefore, since equals uses title and location as well, * two equals instances will compare to '0'. * * @param o the Object to be compared. * @return a negative integer, zero, or a positive integer as this object * is less than, equal to, or greater than the specified object. * * @throws ClassCastException if the specified object's type prevents it * from being compared to this Object. */ public int compareTo(Object o) { // Cast first. ModificationImplementation mi = (ModificationImplementation)o; // Compare the locations. int result = this.iLocation-mi.iLocation; if(result == 0) { result = this.iTemplate.compareTo(mi.iTemplate); } return result; } /** * This method returns the mass delta for the specified residue, measured either * monoisotopically or averaged. * * @param aResidue String with the residue for which the modification applies (value for the N-terminus is * the NTERMINUS constant and for the C-terminus the CTERMINUS constant). * @param aMonoOrAvg int which should be either MONOISOTOPIC or AVERAGE * @return double with the mass delta (can be negative, of course!) or '0.0' if this modification * does not apply to the specified residue. */ protected double getMassDelta(String aResidue, int aMonoOrAvg) { return this.iTemplate.getMassDelta(aResidue, aMonoOrAvg); } }