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.biojava.ontology;
023
024import java.util.Arrays;
025import java.util.Set;
026import java.util.TreeSet;
027
028import org.biojava.bio.Annotation;
029import org.biojava.utils.Unchangeable;
030
031/**
032 * A triple in an ontology.  This is two terms and a relationship between
033 * them, similar to RDF and other similar logic systems.
034 *
035 * <p>
036 * For documentation purposes, a Triple may provide a name. However, a Triple
037 * may also be named as "(subject, object, predicate)" if no specific name is
038 * provided.
039 * </p>
040 *
041 * @author Thomas Down
042 * @author Matthew Pocock
043 * @since 1.4
044 * @see org.biojavax.ontology.ComparableTriple
045 */
046
047public interface Triple
048extends Term {
049        /**
050         * Return the subject term of this triple
051         * @return the subject term
052         */
053
054        public Term getSubject();
055
056        /**
057         * Return the object term of this triple.
058         * @return the object term
059         */
060
061        public Term getObject();
062
063        /**
064         * Return a Term which defines the type of relationship between the subject and object terms.
065         * @return the predicate
066         */
067
068        public Term getPredicate();
069
070        /**
071         * The hashcode for a Triple.
072         *
073         * <p>This <em>must</em> be implemented as:
074         * <pre>
075         * return getSubject().hashCode() +
076   31 * getObject().hashCode() +
077   31 * 31 * getPredicate().hashCode();
078         * </pre>
079         * If you do not implement hashcode in this way then you have no guarantee
080         * that your Triple objects will be found in an ontology and that they will
081         * not be duplicated.
082         * </p>
083         */
084        public int hashCode();
085
086        /**
087         * Check to see if an object is an equivalent Triple.
088         *
089         * <p>
090         * Two triples are equivalent if they have the same subject, object and
091         * predicate fields.
092         * <pre>
093         * if (! (o instanceof Triple)) {
094         *     return false;
095         * }
096         * Triple to = (Triple) o;
097         * return to.getSubject() == getSubject() &&
098         *        to.getObject() == getObject() &&
099         *        to.getPredicate() == getPredicate();
100         * </pre>
101         * If you do not implement equals in this way then you have no guarantee
102         * that your Triple objects will be found in an ontology and that they will
103         * not be duplicated.
104         * </p>
105         */
106        public boolean equals(Object obj);
107
108        /**
109         * Basic in-memory implementation of a Triple in an ontology
110         *
111         * This can be used to implement Ontology.createTriple
112         * @see org.biojavax.ontology.SimpleComparableTriple
113         */
114
115        public static final class Impl
116        extends Unchangeable
117        implements Triple, java.io.Serializable {
118                /**
119                 * 
120                 */
121                private static final long serialVersionUID = 3807331980372839221L;
122                private final Term subject;
123                private final Term object;
124                private final Term predicate;
125                private /*final*/ String name;
126                private /*final*/ String description;
127                private Set<Object> synonyms;
128
129                public Impl(Term subject, Term object, Term predicate) {
130                        this(subject, object, predicate, null, null, null);
131                }
132
133                public Impl(Term subject, Term object, Term predicate, Object[] synonyms) {
134                        this(subject, object, predicate, null, null, synonyms);
135                }
136
137                public Impl(Term subject,
138                                Term object,
139                                Term predicate,
140                                String name,
141                                String description) {
142                        this(subject,object,predicate,name,description,null);
143                }
144
145                public Impl(Term subject,
146                                Term object,
147                                Term predicate,
148                                String name,
149                                String description,
150                                Object[] synonyms)
151                {
152                        if (subject == null) {
153                                throw new NullPointerException("Subject must not be null");
154                        }
155                        if (object == null) {
156                                throw new NullPointerException("Object must not be null");
157                        }
158                        if (predicate == null) {
159                                throw new NullPointerException("predicate must not be null");
160                        }
161
162                        if(
163                                        subject.getOntology() != object.getOntology() ||
164                                        subject.getOntology() != predicate.getOntology()
165                        ) {
166                                throw new IllegalArgumentException(
167                                                "All terms must be from the same ontology: " +
168                                                subject.getOntology().getName() + ", " +
169                                                object.getOntology().getName() + ", " +
170                                                predicate.getOntology().getName());
171                        }
172
173                        if(description == null) {
174                                description = "";
175                        }
176
177                        this.subject = subject;
178                        this.object = object;
179                        this.predicate = predicate;
180                        this.name = name;
181                        this.description = description;
182
183                        this.synonyms = new TreeSet<Object>();
184                        if (synonyms!=null) this.synonyms.addAll(Arrays.asList(synonyms));
185                }
186
187                public void addSynonym(Object synonym) {
188                        this.synonyms.add(synonym);
189                }
190
191                public void removeSynonym(Object synonym) {
192                        this.synonyms.remove(synonym);
193                }
194
195                public Object[] getSynonyms() {
196                        return this.synonyms.toArray();
197                }
198
199                public String getName() {
200                        if(name == null) {
201                                name = predicate + "(" + subject + ", " + object + ")";
202                        }
203                        return name;
204                }
205
206                public String getDescription() {
207                        return description;
208                }
209                public void setDescription(String desc){
210                        this.description = desc;
211                }
212
213                public Ontology getOntology() {
214                        return subject.getOntology();
215                }
216
217                public Term getSubject() {
218                        return subject;
219                }
220
221                public Term getObject() {
222                        return object;
223                }
224
225                public Term getPredicate() {
226                        return predicate;
227                }
228
229                public Annotation getAnnotation() {
230                        return Annotation.EMPTY_ANNOTATION;
231                }
232
233                /**
234                 * Two triples are equal if all their fields are identical.
235                 */
236
237                public boolean equals(Object o) {
238                        if (! (o instanceof Triple)) {
239                                return false;
240                        }
241                        Triple to = (Triple) o;
242                        return to.getSubject().equals(getSubject()) &&
243                        to.getObject().equals(getObject()) &&
244                        to.getPredicate().equals(getPredicate());
245                }
246
247                public int hashCode() {
248                        return getSubject().hashCode() +
249                        31 * getObject().hashCode() +
250                        31 * 31 * getPredicate().hashCode();
251                }
252
253                public String toString() {
254                        if (getName().length() > 0)
255                        return getName();
256                        return subject + " " + predicate + " " + object;
257                }
258        }
259}