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.nbio.ontology;
023
024import org.biojava.nbio.ontology.utils.Annotation;
025
026import java.util.Arrays;
027import java.util.Set;
028import java.util.TreeSet;
029
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        @Override
085        public int hashCode();
086
087        /**
088         * Check to see if an object is an equivalent Triple.
089         *
090         * <p>
091         * Two triples are equivalent if they have the same subject, object and
092         * predicate fields.
093         * <pre>
094         * if (! (o instanceof Triple)) {
095         *     return false;
096         * }
097         * Triple to = (Triple) o;
098         * return to.getSubject() == getSubject() &&
099         *        to.getObject() == getObject() &&
100         *        to.getPredicate() == getPredicate();
101         * </pre>
102         * If you do not implement equals in this way then you have no guarantee
103         * that your Triple objects will be found in an ontology and that they will
104         * not be duplicated.
105         * </p>
106         */
107        @Override
108        public boolean equals(Object obj);
109
110        /**
111         * Basic in-memory implementation of a Triple in an ontology
112         *
113         * This can be used to implement Ontology.createTriple
114         * @see org.biojavax.ontology.SimpleComparableTriple
115         */
116
117        public static final class Impl
118
119        implements Triple, java.io.Serializable {
120                /**
121                 *
122                 */
123                private static final long serialVersionUID = 3807331980372839221L;
124                private final Term subject;
125                private final Term object;
126                private final Term predicate;
127                private /*final*/ String name;
128                private /*final*/ String description;
129                private Set<Object> synonyms;
130
131                public Impl(Term subject, Term object, Term predicate) {
132                        this(subject, object, predicate, null, null, null);
133                }
134
135                public Impl(Term subject, Term object, Term predicate, Object[] synonyms) {
136                        this(subject, object, predicate, null, null, synonyms);
137                }
138
139                public Impl(Term subject,
140                                Term object,
141                                Term predicate,
142                                String name,
143                                String description) {
144                        this(subject,object,predicate,name,description,null);
145                }
146
147                public Impl(Term subject,
148                                Term object,
149                                Term predicate,
150                                String name,
151                                String description,
152                                Object[] synonyms)
153                {
154                        if (subject == null) {
155                                throw new NullPointerException("Subject must not be null");
156                        }
157                        if (object == null) {
158                                throw new NullPointerException("Object must not be null");
159                        }
160                        if (predicate == null) {
161                                throw new NullPointerException("predicate must not be null");
162                        }
163
164                        if(
165                                        subject.getOntology() != object.getOntology() ||
166                                        subject.getOntology() != predicate.getOntology()
167                        ) {
168                                throw new IllegalArgumentException(
169                                                "All terms must be from the same ontology: " +
170                                                subject.getOntology().getName() + ", " +
171                                                object.getOntology().getName() + ", " +
172                                                predicate.getOntology().getName());
173                        }
174
175                        if(description == null) {
176                                description = "";
177                        }
178
179                        this.subject = subject;
180                        this.object = object;
181                        this.predicate = predicate;
182                        this.name = name;
183                        this.description = description;
184
185                        this.synonyms = new TreeSet<Object>();
186                        if (synonyms!=null) this.synonyms.addAll(Arrays.asList(synonyms));
187                }
188
189                @Override
190                public void addSynonym(Object synonym) {
191                        this.synonyms.add(synonym);
192                }
193
194                @Override
195                public void removeSynonym(Object synonym) {
196                        this.synonyms.remove(synonym);
197                }
198
199                @Override
200                public Object[] getSynonyms() {
201                        return this.synonyms.toArray();
202                }
203
204                @Override
205                public String getName() {
206                        if(name == null) {
207                                name = predicate + "(" + subject + ", " + object + ")";
208                        }
209                        return name;
210                }
211
212                @Override
213                public String getDescription() {
214                        return description;
215                }
216                @Override
217                public void setDescription(String desc){
218                        this.description = desc;
219                }
220
221                @Override
222                public Ontology getOntology() {
223                        return subject.getOntology();
224                }
225
226                @Override
227                public Term getSubject() {
228                        return subject;
229                }
230
231                @Override
232                public Term getObject() {
233                        return object;
234                }
235
236                @Override
237                public Term getPredicate() {
238                        return predicate;
239                }
240
241                @Override
242                public Annotation getAnnotation() {
243                        return Annotation.EMPTY_ANNOTATION;
244                }
245
246                /**
247                 * Two triples are equal if all their fields are identical.
248                 */
249
250                @Override
251                public boolean equals(Object o) {
252                        if (! (o instanceof Triple)) {
253                                return false;
254                        }
255                        Triple to = (Triple) o;
256                        return to.getSubject().equals(getSubject()) &&
257                        to.getObject().equals(getObject()) &&
258                        to.getPredicate().equals(getPredicate());
259                }
260
261                @Override
262                public int hashCode() {
263                        return getSubject().hashCode() +
264                        31 * getObject().hashCode() +
265                        31 * 31 * getPredicate().hashCode();
266                }
267
268                @Override
269                public String toString() {
270                        if (getName().length() > 0)
271                                return getName();
272                        return subject + " " + predicate + " " + object;
273                }
274        }
275}