    001    // This file is part of the Attempto Java Packages.
    002    // Copyright 2008, Attempto Group, University of Zurich (see http://attempto.ifi.uzh.ch).
    003    //
    004    // The Attempto Java Packages is free software: you can redistribute it and/or modify it under the
    005    // terms of the GNU Lesser General Public License as published by the Free Software Foundation,
    006    // either version 3 of the License, or (at your option) any later version.
    007    //
    008    // The Attempto Java Packages is distributed in the hope that it will be useful, but WITHOUT ANY
    009    // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
    010    // PURPOSE. See the GNU Lesser General Public License for more details.
    011    //
    012    // You should have received a copy of the GNU Lesser General Public License along with the Attempto
    013    // Java Packages. If not, see http://www.gnu.org/licenses/.
    014
    015    package ch.uzh.ifi.attempto.acewiki.core.ontology;
    016
    017    import java.net.URI;
    018    import java.net.URISyntaxException;
    019    import java.util.ArrayList;
    020    import java.util.List;
    021    import java.util.Vector;
    022
    023    import ch.uzh.ifi.attempto.ape.LexiconEntry;
    024
    025    /**
    026     * This class represents an ontology element which can be an individual ("constant"), a concept
    027     * ("unary relation", "class", "type"), or a role ("binary relation", "property"). See the
    028     * respective sub-classes.
    029     *<p>
    030     * In AceWiki, each ontology element corresponds to a word which has one or more word forms.
    031     * Word forms are identified by a number (the word form id).
    032     *<p>
    033     * Every ontology element has an article which consists of a list of sentences.
    034     *
    035     * @author Tobias Kuhn
    036     */
    037    public abstract class OntologyElement implements Comparable<OntologyElement> {
    038
    039            private Ontology ontology;
    040
    041            private final Vector<Sentence> text = new Vector<Sentence>();
    042            private long id = -1;
    043
    044            /**
    045             * Initializes the ontology element.
    046             */
    047            protected OntologyElement() {
    048            }
    049
    050            /**
    051             * Loads an ontology element from its serialized form.
    052             *
    053             * @param serializedElement The serialized ontology element.
    054             * @param id The id of the ontology element.
    055             * @param ontology The ontology at which the ontology element should be registered.
    056             * @return The ontology element.
    057             */
    058            static OntologyElement loadOntologyElement(String serializedElement, long id, Ontology ontology) {
    059                    String[] lines = serializedElement.split("\n");
    060                    if (!lines[0].startsWith("type:") || !lines[1].startsWith("words:")) {
    061                            System.err.println("Cannot read ontology element " + id);
    062                            return null;
    063                    }
    064                    String type = lines[0].substring("type:".length());
    065                    String[] words = lines[1].substring("words:".length()).split(";");
    066                    OntologyElement oe;
    067                    if (type.equals("propername")) {
    068                            oe = new Individual();
    069                    } else if (type.equals("noun")) {
    070                            oe = new NounConcept();
    071                    } else if (type.equals("nounof")) {
    072                            oe = new OfRole();
    073                    } else if (type.equals("trverb")) {
    074                            oe = new VerbRole();
    075                    } else if (type.equals("tradj")) {
    076                            oe = new TrAdjRole();
    077                    } else {
    078                            System.err.println("Cannot read ontology element " + id);
    079                            return null;
    080                    }
    081                    oe.setId(id);
    082                    oe.setWords(words);
    083                    for (int i=2 ; i < lines.length ; i++) {
    084                            Sentence sentence = Sentence.loadSentence(lines[i], oe);
    085                            oe.text.add(sentence);
    086                    }
    087                    oe.ontology = ontology;
    088                    ontology.register(oe);
    089                    return oe;
    090            }
    091
    092            /**
    093             * Returns the word forms. The position in the array corresponds to the word form id.
    094             *
    095             * @return An array containing the word forms.
    096             */
    097            public abstract String[] getWords();
    098
    099            /**
    100             * Returns the word form for the given word form id.
    101             *
    102             * @param n The word form id.
    103             * @return The word form.
    104             */
    105            public String getWord(int n) {
    106                    return getWords()[n];
    107            }
    108
    109            /**
    110             * Returns the word form with the id 0 (the default word form).
    111             *
    112             * @return The word form.
    113             */
    114            public String getWord() {
    115                    return getWord(0);
    116            }
    117
    118            /**
    119             * Returns the pretty-printed word form for the given word form id. The pretty-printing
    120             * transforms underscores into blanks.
    121             *
    122             * @param n The word form id.
    123             * @return The word form.
    124             */
    125            public String getPrettyWord(int n) {
    126                    String w = getWord(n);
    127                    if (w == null) return null;
    128                    return w.replace("_", " ");
    129            }
    130
    131            /**
    132             * Sets the word forms. The order reflects the word form ids. The indexes of the
    133             * ontology are automatically updated.
    134             *
    135             * @param words The word forms.
    136             */
    137            public final void setWords(String... words) {
    138                    if (ontology == null) {
    139                            changeWords(words);
    140                    } else {
    141                            synchronized (ontology) {
    142                                    ontology.removeFromWordIndex(this);
    143                                    changeWords(words);
    144                                    ontology.addToWordIndex(this);
    145                                    ontology.refresh(this);
    146                            }
    147                    }
    148            }
    149
    150            /**
    151             * Changes the word forms without updating the ontology indexes. The order reflects
    152             * the word form ids.
    153             *
    154             * @param words The word forms.
    155             */
    156            protected abstract void changeWords(String... words);
    157
    158            /**
    159             * Returns the headword that is used in the GUI to refer to this ontology element.
    160             * For example, it is used for the title of the article. Unless overridden, it is
    161             * the same as the pretty-printed word form with the id 0.
    162             *
    163             * @return The headword.
    164             */
    165            public String getHeadword() {
    166                    return getPrettyWord(0);
    167            }
    168
    169            /**
    170             * Returns the word type as it is shown to the user. Newer versions of AceWiki can
    171             * savely change this value.
    172             *
    173             * @return The word type.
    174             */
    175            public abstract String getType();
    176
    177            /**
    178             * Returns the word type as it is used internally. Changing this value in newer versions
    179             * of AceWiki breaks backwards compatibility for loading ontologies.
    180             *
    181             * @return The internal word type.
    182             */
    183            public abstract String getInternalType();
    184
    185            /**
    186             * Returns the ontology this ontology element is registered at.
    187             *
    188             * @return The ontology.
    189             */
    190            public Ontology getOntology() {
    191                    return ontology;
    192            }
    193
    194            /**
    195             * Registers this ontology element at the given ontology. An ontology element can be
    196             * registered only once.
    197             *
    198             * @param ontology
    199             */
    200            public void registerAt(Ontology ontology) {
    201                    if (this.ontology != null) {
    202                            throw new RuntimeException("Cannot change the ontology for element " + toString());
    203                    }
    204                    if (ontology == null) {
    205                            return;
    206                    }
    207                    this.ontology = ontology;
    208                    synchronized (ontology) {
    209                            ontology.register(this);
    210                            ontology.save(this);
    211                    }
    212            }
    213
    214            /**
    215             * Returns the article text as a list of sentences.
    216             *
    217             * @return The sentences.
    218             */
    219            public List<Sentence> getSentences() {
    220                    return new ArrayList<Sentence>(text);
    221            }
    222
    223            /**
    224             * Edits a sentence of the article. The old sentence is replaces by the new sentences.
    225             *
    226             * @param oldSentence The sentence that should be edited.
    227             * @param newSentences The new sentences.
    228             * @return An integer value denoting the success/failure of the operation.
    229             * @see Ontology#commitSentence(Sentence)
    230             */
    231            public int edit(Sentence oldSentence, List<Sentence> newSentences) {
    232                    log("edit sentence of " + getWord() + ": " + oldSentence.getText() +
    233                                    " > " + getSentencesString(newSentences));
    234
    235                    synchronized (ontology) {
    236                            if (text.contains(oldSentence)) {
    237                                    int i = text.indexOf(oldSentence);
    238                                    text.remove(i);
    239                                    text.addAll(i, newSentences);
    240                            } else {
    241                                    log("error: sentence is not around anymore");
    242                                    text.addAll(0, newSentences);
    243                            }
    244                            int success = 0;
    245                            if (ontology != null) {
    246                                    ontology.retractSentence(oldSentence);
    247                                    for (Sentence s : newSentences) {
    248                                            int successThis = ontology.commitSentence(s);
    249                                            if (successThis > success) success = successThis;
    250                                    }
    251                                    ontology.save(this);
    252                            }
    253                            return success;
    254                    }
    255            }
    256
    257            /**
    258             * Adds one or more new sentences to the article. It has to be specified in front of which
    259             * sentence the new sentences should be added.
    260             *
    261             * @param followingSentence The sentence in front of which the new sentences should be added,
    262             *   or null if the sentences should be added to the end of the article.
    263             * @param newSentences The new sentences to be added.
    264             * @return An integer value denoting the success/failure of the operation.
    265             * @see Ontology#commitSentence(Sentence)
    266             */
    267            public int add(Sentence followingSentence, List<Sentence> newSentences) {
    268                    log("add sentences of " + getWord() + ": " + getSentencesString(newSentences));
    269
    270                    synchronized (ontology) {
    271                            if (text.contains(followingSentence)) {
    272                                    text.addAll(text.indexOf(followingSentence), newSentences);
    273                            } else {
    274                                    if (followingSentence != null) {
    275                                            log("error: sentence is not around anymore");
    276                                    }
    277                                    text.addAll(newSentences);
    278                            }
    279                            int success = 0;
    280                            if (ontology != null) {
    281                                    for (Sentence s : newSentences) {
    282                                            int successThis = ontology.commitSentence(s);
    283                                            if (successThis > success) success = successThis;
    284                                    }
    285                                    ontology.save(this);
    286                            }
    287                            return success;
    288                    }
    289            }
    290
    291            private String getSentencesString(List<Sentence> sentences) {
    292                    String result = "";
    293                    for (Sentence s : sentences) {
    294                            result += s.getText() + " ";
    295                    }
    296                    return result;
    297            }
    298
    299            /**
    300             * Removes the given sentence from the article.
    301             *
    302             * @param sentence The sentence to be removed.
    303             */
    304            public void remove(Sentence sentence) {
    305                    synchronized (ontology) {
    306                            if (text.contains(sentence)) {
    307                                    log("remove sentence: " + sentence.getText());
    308                                    text.remove(sentence);
    309                            }
    310                            if (ontology != null) {
    311                                    ontology.retractSentence(sentence);
    312                                    ontology.save(this);
    313                            }
    314                    }
    315            }
    316
    317            /**
    318             * Returns the lexicon entries (one for each word form).
    319             *
    320             * @return The lexicon entries.
    321             */
    322            List<LexiconEntry> getLexiconEntries() {
    323                    return null;
    324            }
    325
    326            /**
    327             * Returns the URI of the ontology element. This URI is a concatenation of the
    328             * ontology URI and the URI suffix of the ontology element.
    329             *
    330             * @return The URI.
    331             * @see #getURISuffix()
    332             */
    333            public final URI getURI() {
    334                    String ontologyURI = "";
    335                    if (ontology != null) {
    336                            ontologyURI = ontology.getURI();
    337                    }
    338
    339                    URI uri = null;
    340                    try {
    341                            uri = new URI(ontologyURI + getURISuffix());
    342                    } catch (URISyntaxException ex) {
    343                            ex.printStackTrace();
    344                    }
    345                    return uri;
    346            }
    347
    348            /**
    349             * Returns the URI suffix of this ontology element. For example "#country".
    350             *
    351             * @return The URI suffix.
    352             * @see #getURI()
    353             */
    354            public String getURISuffix() {
    355                    return "#" + getWord();
    356            }
    357
    358            final void setId(long id) {
    359                    this.id = id;
    360            }
    361
    362            final long getId() {
    363                    return id;
    364            }
    365
    366            /**
    367             * Writes the text to the log file.
    368             *
    369             * @param text The text to be written to the log file.
    370             */
    371            protected void log(String text) {
    372                    if (ontology != null) {
    373                            ontology.log(text);
    374                    }
    375            }
    376
    377            /**
    378             * Serializes this ontology element as a string.
    379             *
    380             * @return The serialized ontology element.
    381             */
    382            String serialize() {
    383                    String s = "type:";
    384                    s += getInternalType() + "\nwords:";
    385                    for (String word : getWords()) {
    386                            if (word == null) {
    387                                    s += ";";
    388                            } else {
    389                                    s += word + ";";
    390                            }
    391                    }
    392                    s += "\n";
    393                    for (Sentence sentence : text) {
    394                            s += sentence.serialize();
    395                    }
    396                    return s;
    397            }
    398
    399            public int compareTo(OntologyElement e) {
    400                    return getHeadword().toLowerCase().compareTo(e.getHeadword().toLowerCase());
    401            }
    402
    403            public String toString() {
    404                    String l = "";
    405                    for (String s : getWords()) {
    406                            if (s == null) {
    407                                    l += ",";
    408                            } else {
    409                                    l += s + ",";
    410                            }
    411                    }
    412                    if (l.length() > 0) l = l.substring(0, l.length()-1);
    413                    return getType() + "{" + l + "}";
    414            }
    415
    416    }