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 */
021
022package org.biojavax.bio.seq;
023
024import org.biojava.utils.AbstractChangeable;
025import org.biojava.utils.ChangeEvent;
026import org.biojava.utils.ChangeSupport;
027import org.biojava.utils.ChangeVetoException;
028import org.biojavax.RichObjectFactory;
029import org.biojavax.ontology.ComparableTerm;
030
031/**
032 * Represents a relationship between two features that is described by a term.
033 * @author Richard Holland
034 * @author Mark Schreiber
035 * @since 1.5
036 *
037 */
038public class SimpleRichFeatureRelationship extends AbstractChangeable implements RichFeatureRelationship {
039
040    private RichFeature object;
041    private RichFeature subject;
042    private ComparableTerm term;
043    private int rank;
044    
045    /**
046     * Gets the default CONTAINS term used for defining the relationship between features.
047     * @return the default CONTAINS term.
048     */
049    public static ComparableTerm getContainsTerm() {
050        return RichObjectFactory.getDefaultOntology().getOrCreateTerm("contains");
051    }
052    
053    /**
054     * Creates a new instance of SimpleRichFeatureRelationship.
055     * @param subject The subject RichFeature.
056     * @param term The relationship term.
057     * @param rank the rank of the relationship.
058     */    
059    public SimpleRichFeatureRelationship(RichFeature object, RichFeature subject, ComparableTerm term, int rank) {
060        if (object==null) throw new IllegalArgumentException("Object cannot be null");
061        if (subject==null) throw new IllegalArgumentException("Subject cannot be null");
062        if (term==null) throw new IllegalArgumentException("Term cannot be null");
063        this.object = object;
064        this.subject = subject;
065        this.term = term;
066        this.rank = rank;
067    }
068    
069    // Hibernate requirement - not for public use.
070    protected SimpleRichFeatureRelationship() {}
071    
072    /**
073     * {@inheritDoc}
074     */
075    public void setRank(int rank) throws ChangeVetoException {
076        if(!this.hasListeners(RichFeatureRelationship.RANK)) {
077            this.rank = rank;
078        } else {
079            ChangeEvent ce = new ChangeEvent(
080                    this,
081                    RichFeatureRelationship.RANK,
082                    new Integer(rank),
083                    new Integer(this.rank)
084                    );
085            ChangeSupport cs = this.getChangeSupport(RichFeatureRelationship.RANK);
086            synchronized(cs) {
087                cs.firePreChangeEvent(ce);
088                this.rank = rank;
089                cs.firePostChangeEvent(ce);
090            }
091        }
092    }
093    
094    /**
095     * {@inheritDoc}
096     */
097    public int getRank() { return this.rank; }
098        
099    /**
100     * {@inheritDoc}
101     */
102    public RichFeature getObject() { return this.object; }
103    
104    // Hibernate requirement - not for public use.
105    void setObject(RichFeature object) { this.object = object; }
106        
107    /**
108     * {@inheritDoc}
109     */
110    public RichFeature getSubject() { return this.subject; }
111    
112    // Hibernate requirement - not for public use.
113    void setSubject(RichFeature subject) { this.subject = subject; }
114    
115    /**
116     * {@inheritDoc}
117     */
118    public ComparableTerm getTerm() { return this.term; }
119    
120    // Hibernate requirement - not for public use.
121    void setTerm(ComparableTerm term) { this.term = term; }
122    
123    /**
124     * {@inheritDoc}
125     * Relations are compared first by rank, then object, subject, then finally term.
126     */
127    public int compareTo(Object o) {
128        if (o==this) return 0;
129        // Hibernate comparison - we haven't been populated yet
130        if (this.object==null) return -1;
131        // Normal comparison
132        RichFeatureRelationship them = (RichFeatureRelationship)o;
133        if (this.rank!=them.getRank()) return this.rank-them.getRank();
134        if (!this.object.equals(them.getObject())) return this.object.compareTo(them.getObject());
135        if (!this.subject.equals(them.getSubject())) return this.subject.compareTo(them.getSubject());
136        else return this.getTerm().compareTo(them.getTerm());
137    }
138    
139    /**
140     * {@inheritDoc}
141     * Relations are equal if their objects, subjects and terms are equal.
142     */
143    public boolean equals(Object obj) {
144        if (this == obj) return true;
145        if (obj==null || !(obj instanceof RichFeatureRelationship)) return false;
146        // Hibernate comparison - we haven't been populated yet
147        if (this.object==null) return false;
148        // Normal comparison
149        RichFeatureRelationship them = (RichFeatureRelationship)obj;
150        return (this.object.equals(them.getObject()) &&
151                this.subject.equals(them.getSubject()) &&
152                this.term.equals(them.getTerm()));
153    }
154    
155    /**
156     * {@inheritDoc}
157     */
158    public int hashCode() {
159        int code = 17;
160        // Hibernate comparison - we haven't been populated yet
161        if (this.subject==null) return code;
162        // Normal comparison
163        code = code*37 + this.object.hashCode();
164        code = code*37 + this.subject.hashCode();
165        code = code*37 + this.term.hashCode();
166        return code;
167    }
168    
169    /**
170     * {@inheritDoc}
171     * Form: "(#rank) term(object,subject)"
172     */
173    public String toString() {
174        return "(#"+this.rank+") "+this.getTerm()+"("+this.getObject()+","+this.getSubject()+")";
175    }
176    
177    // Hibernate requirement - not for public use.
178    private Integer id;
179    
180    /**
181     * Gets the Hibernate ID. Should be used with caution.
182     * @return the Hibernate ID, if using Hibernate.
183     */
184    public Integer getId() { return this.id; }
185    
186    /**
187     * Sets the Hibernate ID. Should be used with caution.
188     * @param id the Hibernate ID, if using Hibernate.
189     */
190    public void setId(Integer id) { this.id = id;}
191}
192