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.ontology;
023
024import java.util.Collections;
025import java.util.Set;
026import java.util.TreeSet;
027
028import org.biojava.bio.Annotation;
029import org.biojava.ontology.Ontology;
030import org.biojava.ontology.Term;
031import org.biojava.ontology.Triple;
032import org.biojava.utils.AbstractChangeable;
033import org.biojava.utils.ChangeEvent;
034import org.biojava.utils.ChangeSupport;
035import org.biojava.utils.ChangeVetoException;
036import org.biojavax.RichAnnotation;
037
038/**
039 * Basic comparable triple, BioSQL style.
040 * @author Richard Holland
041 * @since 1.5
042 */
043public class SimpleComparableTriple extends AbstractChangeable implements ComparableTriple {
044    
045    private ComparableOntology ontology;
046    private ComparableTerm object;
047    private ComparableTerm subject;
048    private ComparableTerm predicate;
049    private Set descriptors = new TreeSet();
050    
051    /**
052     * Creates a new instance of SimpleComparableTriple. All parameters are 
053     * required and immutable.
054     * @param ontology the ontology of the triple.
055     * @param subject the subject of the triple.
056     * @param object the object of the triple.
057     * @param predicate the predicate of the triple.
058     */
059    SimpleComparableTriple(ComparableOntology ontology, ComparableTerm subject, ComparableTerm object, ComparableTerm predicate) {
060        if (ontology == null) throw new IllegalArgumentException("Ontology must not be null");
061        if (subject == null) throw new IllegalArgumentException("Subject must not be null");
062        if (object == null) throw new IllegalArgumentException("Object must not be null");
063        if (predicate == null) throw new IllegalArgumentException("Predicate must not be null");
064        this.ontology = ontology;
065        this.subject = subject;
066        this.object = object;
067        this.predicate = predicate;
068    }
069    
070    // Hibernate requirement - not for public use.
071    protected SimpleComparableTriple() {}
072    
073    /**
074     * {@inheritDoc}
075     * Triples are sorted in order of ontology, subject, object, and finally
076     * predicate.
077     */
078    public int compareTo(Object o) {
079        if (o==this) return 0;
080        Triple them = (Triple)o;
081        // Hibernate comparison - we haven't been populated yet
082        if (this.ontology==null) return -1;
083        // Normal comparison
084        if (!this.ontology.equals(them.getOntology())) return this.ontology.compareTo((ComparableOntology)them.getOntology());
085        if (!this.subject.equals(them.getSubject())) return this.subject.compareTo((ComparableTerm)them.getSubject());
086        if (!this.object.equals(them.getObject())) return this.object.compareTo((ComparableTerm)them.getObject());
087        return this.predicate.compareTo((ComparableTerm)them.getPredicate());
088    }
089    
090    /**
091     * {@inheritDoc}
092     * Triples are equal only if they are from the same ontology and share the
093     * same subject, object and predicate.
094     */
095    public boolean equals(Object o) {
096        if(this == o) return true;
097        if (o==null || !(o instanceof Triple)) return false;
098        // Hibernate comparison - we haven't been populated yet
099        if (this.ontology==null) return false;
100        // Normal comparison
101        Triple them = (Triple)o;
102        return (this.ontology.equals(them.getOntology()) &&
103                this.subject.equals(them.getSubject()) &&
104                this.object.equals(them.getObject()) &&
105                this.predicate.equals(them.getPredicate()));
106    }
107    
108    /**
109     * {@inheritDoc}
110     */
111    public int hashCode() {
112        int code = 17;
113        // Hibernate comparison - we haven't been populated yet
114        if (this.ontology==null) return code;
115        // Normal comparison
116        code = 37*code + this.ontology.hashCode();
117        code = 37*code + this.subject.hashCode();
118        code = 37*code + this.object.hashCode();
119        code = 37*code + this.predicate.hashCode();
120        return code;
121    }
122    
123    /**
124     * {@inheritDoc}
125     * Returns the output of toSring()
126     */
127    public String getName() { return this.toString(); }
128    
129    /**
130     * {@inheritDoc}
131     */
132    public Term getSubject() { return this.subject; }
133    
134    // Hibernate requirement - not for public use.
135    void setSubject(ComparableTerm subject) { this.subject = subject; }
136    
137    /**
138     * {@inheritDoc}
139     */
140    public Term getObject() { return this.object; }
141    
142    // Hibernate requirement - not for public use.
143    void setObject(ComparableTerm object) { this.object = object; }
144    
145    /**
146     * {@inheritDoc}
147     */
148    public Term getPredicate() { return this.predicate; }
149    
150    // Hibernate requirement - not for public use.
151    void setPredicate(ComparableTerm predicate) { this.predicate = predicate; }
152    
153    /**
154     * {@inheritDoc}
155     */
156    public void addDescriptor(ComparableTerm desc) throws IllegalArgumentException,ChangeVetoException {
157        if (desc==null) throw new IllegalArgumentException("Cannot have null descriptor");
158        if(!this.hasListeners(ComparableTriple.DESCRIPTOR)) {
159            this.descriptors.add(desc);
160        } else {
161            ChangeEvent ce = new ChangeEvent(
162                    this,
163                    ComparableTriple.DESCRIPTOR,
164                    desc,
165                    null
166                    );
167            ChangeSupport cs = this.getChangeSupport(ComparableTriple.DESCRIPTOR);
168            synchronized(cs) {
169                cs.firePreChangeEvent(ce);
170                this.descriptors.add(desc);
171                cs.firePostChangeEvent(ce);
172            }
173        }
174    }
175    
176    /**
177     * {@inheritDoc}
178     */
179    public boolean removeDescriptor(ComparableTerm desc) throws IllegalArgumentException,ChangeVetoException {
180        if (desc==null) throw new IllegalArgumentException("Cannot have null descriptor");
181        boolean result;
182        if(!this.hasListeners(ComparableTriple.DESCRIPTOR)) {
183            result = this.descriptors.remove(desc);
184        } else {
185            ChangeEvent ce = new ChangeEvent(
186                    this,
187                    ComparableTriple.DESCRIPTOR,
188                    null,
189                    desc
190                    );
191            ChangeSupport cs = this.getChangeSupport(ComparableTriple.DESCRIPTOR);
192            synchronized(cs) {
193                cs.firePreChangeEvent(ce);
194                result = this.descriptors.remove(desc);
195                cs.firePostChangeEvent(ce);
196            }
197        }
198        return result;
199    }
200    
201    /**
202     * {@inheritDoc}
203     * <b>Warning</b> this method gives access to the original 
204     * Collection not a copy. This is required by Hibernate. If you
205     * modify the object directly the behaviour may be unpredictable.
206     */
207    public Set getDescriptors() { return this.descriptors; } // originals for Hibernate
208    
209    /**
210     * {@inheritDoc}
211     * <b>Warning</b> this method gives access to the original 
212     * Collection not a copy. This is required by Hibernate. If you
213     * modify the object directly the behaviour may be unpredictable.
214     */
215    public void setDescriptors(Set descriptors) throws ChangeVetoException {
216        this.descriptors = descriptors;  // originals for Hibernate
217    }
218    
219    /**
220     * {@inheritDoc}
221     * NOT IMPLEMENTED
222     */
223    public void removeSynonym(Object synonym) {
224        throw new UnsupportedOperationException("BioJavaX does not know about triple synonyms.");
225    }
226    
227    /**
228     * {@inheritDoc}
229     * NOT IMPLEMENTED
230     */
231    public void addSynonym(Object synonym) {
232        throw new UnsupportedOperationException("BioJavaX does not know about triple synonyms.");
233    }
234    
235    /**
236     * {@inheritDoc}
237     * ALWAYS RETURNS AN EMPTY LIST
238     */
239    public Object[] getSynonyms() { return Collections.EMPTY_LIST.toArray(); }
240    
241    /**
242     * {@inheritDoc}
243     */
244    public Ontology getOntology() { return this.ontology; }
245    
246    // Hibernate requirement - not for public use.
247    void setOntology(ComparableOntology ontology) { this.ontology = ontology; }
248    
249    /**
250     * {@inheritDoc}
251     * ALWAYS RETURNS THE EMPTY STRING
252     */
253    public String getDescription() { return ""; }
254    
255    /**
256     * {@inheritDoc}
257     * does not do anything
258     */
259    public void setDescription(String desc) { }
260    
261    /**
262     * {@inheritDoc}
263     * ALWAYS RETURNS THE EMPTY ANNOTATION
264     */
265    public Annotation getAnnotation() { return RichAnnotation.EMPTY_ANNOTATION; }
266    
267    /**
268     * {@inheritDoc}
269     * Form: "ontology:predicate(subject,object)"
270     */
271    public String toString() {
272        return this.ontology+":"+this.predicate+"("+this.subject+","+this.object+")";
273    }
274    
275    // Hibernate requirement - not for public use.
276    private Integer id;
277    
278    /**
279     * Gets the Hibernate ID. Should be used with caution.
280     * @return the Hibernate ID, if using Hibernate.
281     */
282    public Integer getId() { return this.id; }
283    
284    /**
285     * Sets the Hibernate ID. Should be used with caution.
286     * @param id the Hibernate ID, if using Hibernate.
287     */
288    public void setId(Integer id) { this.id = id;}
289}