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