001 // This file is part of AceWiki. 002 // Copyright 2008-2012, AceWiki developers. 003 // 004 // AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU 005 // Lesser General Public License as published by the Free Software Foundation, either version 3 of 006 // the License, or (at your option) any later version. 007 // 008 // AceWiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 009 // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 010 // Lesser General Public License for more details. 011 // 012 // You should have received a copy of the GNU Lesser General Public License along with AceWiki. If 013 // not, see http://www.gnu.org/licenses/. 014 015 package ch.uzh.ifi.attempto.acewiki.core; 016 017 import java.util.ArrayList; 018 import java.util.List; 019 import java.util.Map; 020 import java.util.TreeMap; 021 022 import ch.uzh.ifi.attempto.base.Logger; 023 024 /** 025 * This class represents an AceWiki ontology which consists of ontology element definitions and 026 * of ontological statements. Each ontology element has its own article that consists of 027 * ontological statements. 028 * 029 * @author Tobias Kuhn 030 */ 031 public class Ontology { 032 033 private AceWikiEngine engine; 034 private CachingReasoner reasoner; 035 private StatementFactory statementFactory; 036 private AceWikiStorage storage; 037 private Logger logger; 038 039 private Map<Long, OntologyElement> idIndex = new TreeMap<Long, OntologyElement>(); 040 041 private final String name; 042 private final String baseURI; 043 private long idCount = 0; 044 private long stateID = 0; 045 046 private Map<String, String> parameters; 047 048 /** 049 * Creates a new empty ontology with the given name and parameters. 050 * 051 * @param name The name of the ontology. 052 * @param parameters The parameters. 053 */ 054 Ontology(String name, Map<String, String> parameters, AceWikiStorage storage) { 055 this.name = name.toString(); // null value throws an exception 056 this.parameters = parameters; 057 this.storage = storage; 058 059 logger = new Logger(parameters.get("context:logdir") + "/" + name, "onto", 0); 060 061 engine = AbstractAceWikiEngine.createLanguageEngine(this); 062 reasoner = new CachingReasoner(engine.getReasoner()); 063 reasoner.init(this); 064 statementFactory = new StatementFactory(this); 065 066 String b = getParameter("baseuri"); 067 if (b == null || b.equals("")) { 068 baseURI = "http://attempto.ifi.uzh.ch/acewiki/default/"; 069 } else { 070 if (b.endsWith("/")) { 071 baseURI = b; 072 } else { 073 baseURI = b + "/"; 074 } 075 } 076 } 077 078 /** 079 * Returns the AceWiki engine. 080 * 081 * @return The AceWiki engine. 082 */ 083 public AceWikiEngine getEngine() { 084 return engine; 085 } 086 087 /** 088 * Returns the reasoner object in the form of a caching reasoner. 089 * 090 * @return The reasoner. 091 */ 092 public CachingReasoner getReasoner() { 093 return reasoner; 094 } 095 096 /** 097 * Returns the statement factory. 098 * 099 * @return The statement factory. 100 */ 101 public StatementFactory getStatementFactory() { 102 return statementFactory; 103 } 104 105 /** 106 * Returns the storage object. 107 * 108 * @return The storage object. 109 */ 110 public AceWikiStorage getStorage() { 111 return storage; 112 } 113 114 /** 115 * Registers the given ontology element. 116 * 117 * @param element The ontology element to register. 118 */ 119 public synchronized void register(OntologyElement element) { 120 if (contains(element)) { 121 log("error: element already registered"); 122 throw new RuntimeException("Registration failed: Element is already registered."); 123 } 124 element.initOntology(this); 125 126 log("register: " + element); 127 stateID++; 128 129 if (element.getId() == -1) { 130 element.initId(nextId()); 131 } 132 idIndex.put(element.getId(), element); 133 if (element.getId() > idCount) idCount = element.getId(); 134 135 engine.getWordIndex().elementAdded(element); 136 137 getReasoner().loadElement(element); 138 getReasoner().flushElements(); 139 140 getStorage().save(element); 141 } 142 143 /** 144 * Removes the given ontology element from the ontology. 145 * 146 * @param element The ontology element to be removed. 147 */ 148 public synchronized void remove(OntologyElement element) { 149 if (!contains(element)) { 150 log("error: unknown element"); 151 return; 152 } 153 154 log("remove: " + element.getWord()); 155 stateID++; 156 157 engine.getWordIndex().elementRemoved(element); 158 159 idIndex.remove(element.getId()); 160 for (Sentence s : element.getArticle().getSentences()) { 161 retractSentence(s); 162 } 163 storage.save(element); 164 165 getReasoner().unloadElement(element); 166 getReasoner().flushElements(); 167 } 168 169 /** 170 * Changes the word forms of the given ontology element. 171 * 172 * @param element The ontology element to be changed. 173 * @param serializedWords The serialized word forms. 174 */ 175 public synchronized void change(OntologyElement element, String serializedWords) { 176 if (contains(element)) { 177 engine.getWordIndex().elementBeforeChange(element); 178 getReasoner().unloadElement(element); 179 element.setWords(serializedWords); 180 engine.getWordIndex().elementAfterChange(element); 181 getReasoner().loadElement(element); 182 refresh(element); 183 } else { 184 element.setWords(serializedWords); 185 } 186 } 187 188 /** 189 * Returns all the sentences that use the given ontology element. 190 * 191 * @param element The ontology element. 192 * @return A list of all sentence that contain the ontology element. 193 */ 194 public synchronized List<Sentence> getReferences(OntologyElement element) { 195 List<Sentence> list = new ArrayList<Sentence>(); 196 for (OntologyElement el : idIndex.values()) { 197 for (Sentence s : el.getArticle().getSentences()) { 198 if (s.contains(element)) { 199 list.add(s); 200 } 201 } 202 } 203 return list; 204 } 205 206 /** 207 * Returns the ontology element with the given name, or null if there is no such element. 208 * 209 * @param name The name of the ontology element. 210 * @return The ontology element. 211 */ 212 public synchronized OntologyElement getElement(String name) { 213 return engine.getWordIndex().getElement(name); 214 } 215 216 /** 217 * Returns the ontology element with the given id, or null if there is no such element. 218 * 219 * @param id The id of the ontology element. 220 * @return The ontology element. 221 */ 222 public synchronized OntologyElement get(long id) { 223 return idIndex.get(id); 224 } 225 226 /** 227 * Returns all ontology elements. The list is a copy of the internal list. 228 * 229 * @return A list of all ontology elements. 230 */ 231 public synchronized List<OntologyElement> getOntologyElements() { 232 return new ArrayList<OntologyElement>(idIndex.values()); 233 } 234 235 /** 236 * Returns true if the given ontology element is contained by the ontology (identity check). 237 * 238 * @param ontologyElement The ontology element. 239 * @return true if the ontology element is contained by the ontology. 240 */ 241 public synchronized boolean contains(OntologyElement ontologyElement) { 242 return idIndex.containsValue(ontologyElement); 243 } 244 245 /** 246 * Returns the name of the ontology. 247 * 248 * @return The name of the ontology. 249 */ 250 public String getName() { 251 return name; 252 } 253 254 /** 255 * Returns the URI of the ontology (baseURI + name). 256 * 257 * @return The URI of the ontology. 258 */ 259 public String getURI() { 260 return baseURI + name; 261 } 262 263 /** 264 * Refreshes the given ontology element. All sentences that use the ontology element are 265 * updated. 266 * 267 * @param element The ontology element to be refreshed. 268 */ 269 synchronized void refresh(OntologyElement element) { 270 for (Sentence s : getReferences(element)) { 271 if (s.isIntegrated()) { 272 retractSentence(s); 273 s.update(); 274 commitSentence(s); 275 } else { 276 s.update(); 277 } 278 } 279 storage.save(element); 280 } 281 282 /** 283 * Commits the sentence. This means that it is added to the reasoner. 284 * 285 * @param sentence The sentence to be commited. 286 * @throws InconsistencyException if the sentence is inconsistent with the existing sentences. 287 */ 288 protected synchronized void commitSentence(Sentence sentence) throws InconsistencyException { 289 if (sentence == null || sentence.isIntegrated()) return; 290 291 if (!sentence.isReasonable()) { 292 sentence.setIntegrated(true); 293 return; 294 } 295 296 log("commit sentence"); 297 298 try { 299 getReasoner().loadSentence(sentence); 300 } catch (InconsistencyException ex) { 301 log("not consistent!"); 302 getReasoner().unloadSentence(sentence); 303 throw ex; 304 } catch (Throwable t) { 305 log("error encountered!"); 306 t.printStackTrace(); 307 System.gc(); 308 getReasoner().unloadSentence(sentence); 309 return; 310 } 311 312 if (!getReasoner().isConsistent()) { 313 log("not consistent!"); 314 getReasoner().unloadSentence(sentence); 315 throw new InconsistencyException(); 316 } 317 318 log("consistent!"); 319 sentence.setIntegrated(true); 320 stateID++; 321 } 322 323 /** 324 * This method tries to reassert a sentence that is not yet integrated. 325 * 326 * @param sentence The sentence to be reasserted. 327 * @throws InconsistencyException if the sentence is inconsistent with the existing sentences. 328 */ 329 public synchronized void reassert(Sentence sentence) throws InconsistencyException { 330 commitSentence(sentence); 331 getStorage().save(sentence.getArticle().getOntologyElement()); 332 } 333 334 /** 335 * Retracts the sentence. This means that the sentence is removed from the reasoner. 336 * 337 * @param sentence The sentence to be retracted. 338 */ 339 protected synchronized void retractSentence(Sentence sentence) { 340 if ( 341 sentence == null || 342 !sentence.isIntegrated() || 343 !sentence.isReasonable() 344 ) return; 345 346 log("retract sentence"); 347 stateID++; 348 getReasoner().unloadSentence(sentence); 349 sentence.setIntegrated(false); 350 } 351 352 /** 353 * This method retracts an integrated sentence so that it is still part of the wiki 354 * article but does not participate in reasoning anymore. 355 * 356 * @param sentence The sentence to be retracted. 357 */ 358 public synchronized void retract(Sentence sentence) { 359 retractSentence(sentence); 360 getStorage().save(sentence.getArticle().getOntologyElement()); 361 } 362 363 /** 364 * Writes a log entry. 365 * 366 * @param text Log text. 367 */ 368 public void log(String text) { 369 logger.log("onto", text); 370 } 371 372 private long nextId() { 373 return ++idCount; 374 } 375 376 /** 377 * Returns the state id of the ontology. This id increases each time the ontology changes (more 378 * precisely: each time the part of the ontology that participates in reasoning changes). This 379 * id is used to find out whether cached information is still valid or has to be recalculated. 380 * 381 * @return The state id of the ontology. 382 */ 383 public long getStateID() { 384 return stateID; 385 } 386 387 /** 388 * Returns a parameter value. 389 * 390 * @param name The parameter name. 391 * @return The parameter value. 392 */ 393 public String getParameter(String name) { 394 return parameters.get(name); 395 } 396 397 }