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 }