001/* 002 * Copyright (c) 2004-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: barseghian $' 006 * '$Date: 2010-12-22 01:17:53 +0000 (Wed, 22 Dec 2010) $' 007 * '$Revision: 26584 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.kepler.sms; 031 032/** 033 * 034 */ 035 036import java.net.URI; 037import java.util.Collections; 038import java.util.Iterator; 039import java.util.NoSuchElementException; 040import java.util.Set; 041import java.util.Vector; 042import java.util.regex.Matcher; 043import java.util.regex.Pattern; 044 045import org.apache.commons.logging.Log; 046import org.apache.commons.logging.LogFactory; 047import org.semanticweb.owl.apibinding.OWLManager; 048import org.semanticweb.owl.io.RDFXMLOntologyFormat; 049import org.semanticweb.owl.model.AddAxiom; 050import org.semanticweb.owl.model.OWLAnnotation; 051import org.semanticweb.owl.model.OWLAxiom; 052import org.semanticweb.owl.model.OWLClass; 053import org.semanticweb.owl.model.OWLDataFactory; 054import org.semanticweb.owl.model.OWLDescription; 055import org.semanticweb.owl.model.OWLLabelAnnotation; 056import org.semanticweb.owl.model.OWLOntology; 057import org.semanticweb.owl.model.OWLOntologyChangeException; 058import org.semanticweb.owl.model.OWLOntologyManager; 059import org.semanticweb.owl.model.OWLOntologyStorageException; 060import org.semanticweb.owl.model.OWLRuntimeException; 061import org.semanticweb.owl.vocab.OWLRDFVocabulary; 062 063public class NamedOntClass implements Comparable { 064 065 protected OWLClass _ontClass; 066 protected OWLOntology _ontology; 067 protected String _name; 068 protected NamedOntModel _model = null; 069 protected boolean _orphaned; 070 private boolean _removable = true; 071 072 public String getManualUrl() { 073 return _manualUrl; 074 } 075 076 public void setManualUrl(String _manualUrl) { 077 this._manualUrl = _manualUrl; 078 } 079 080 protected String _manualUrl; 081 082 public boolean isOrphaned() { 083 return _orphaned; 084 } 085 086 public void setOrphaned(boolean orphaned) { 087 this._orphaned = orphaned; 088 } 089 090 public NamedOntClass(String url, String label) { 091 this.setOrphaned(true); 092 this.setManualUrl(url); 093 _name = label; 094 } 095 096 public NamedOntClass(String text) { 097 OntologyCatalog catalog = OntologyCatalog.instance(); 098 _ontology = catalog.getDefaultOntology(); 099 _name = text; 100 _ontClass = catalog.getConceptWithLabel(text); 101 _orphaned = false; 102 if (_ontClass == null) { 103 // This isn't already in the default ontology, so we have to deal with that. 104 OWLOntologyManager manager = OntologyCatalog.getManager(); 105 OWLDataFactory factory = manager.getOWLDataFactory(); 106 OWLClass cls = factory.getOWLClass(URI.create(_ontology.getURI() + makeNameIntoOWLClass(text))); 107 OWLLabelAnnotation label = factory.getOWLLabelAnnotation(text); 108 OWLAxiom axiom = factory.getOWLEntityAnnotationAxiom(cls, label); 109 try { 110 manager.applyChange(new AddAxiom(_ontology, axiom)); 111 } 112 catch(OWLOntologyChangeException ex) { 113 log.error("Error adding new class and label: " + text, ex); 114 } 115 try { 116 // NOTE: Must specify a separate physical URI or it doesn't 117 // NOTE: know where it is. The logical URI is no help. 118 Iterator<NamedOntModel> iterator = catalog.getNamedOntModels(); 119 while (iterator.hasNext()) { 120 NamedOntModel model = iterator.next(); 121 if (isDefaultModel(model)) { 122 manager.saveOntology(_ontology, new RDFXMLOntologyFormat(), model.getFile().toURI()); 123 log.info("Saved ontology"); 124 break; 125 } 126 } 127 } 128 catch(OWLOntologyStorageException ex) { 129 log.error("Error saving ontology", ex); 130 } 131 132 _ontClass = cls; 133 } 134 } 135 136 private void setModel() { 137 OntologyCatalog catalog = OntologyCatalog.instance(); 138 Iterator<NamedOntModel> iterator = catalog.getNamedOntModels(); 139 while(iterator.hasNext()) { 140 NamedOntModel model = iterator.next(); 141 if (model.getOntology().equals(_ontology)) { 142 _model = model; 143 } 144 } 145 146 } 147 148 public NamedOntClass getThisClass() { 149 return this; 150 } 151 152 private boolean isDefaultModel(NamedOntModel model) { 153 return Constants.defaultOntologyName.equals(model.getName()); 154 } 155 156 private String makeNameIntoOWLClass(String text) { 157 return makeNameIntoOWLClassByAddingUnderscores(text); 158 } 159 160 private String makeNameIntoOWLClassByAddingUnderscores(String text) { 161 StringBuilder buffer = new StringBuilder("#"); 162 for (String chunk : text.split("\\s+")) { 163 buffer.append(chunk).append("_"); 164 } 165 String string = buffer.toString(); 166 return string.substring(0, string.length() - 1); 167 } 168 169 // This has been deprecated in favor of the whitespace replacement 170 // approach (see: makeNameIntoOWLClassByAddingUnderscores(String). 171/* 172 private String makeNameIntoOWLClassByRemovingWhitespace(String text) { 173 StringBuilder buffer = new StringBuilder("#"); 174 for (String chunk : text.split("\\s+")) { 175 buffer.append(chunk); 176 } 177 return buffer.toString(); 178 } 179*/ 180 181 public NamedOntClass(OWLClass ontClass, OWLOntology ontology) { 182 _ontClass = ontClass; 183 _ontology = ontology; 184 try { 185 String str = NamedOntModel.parseLabel(ontClass.getAnnotations(ontology, OWLRDFVocabulary.RDFS_LABEL.getURI()).toArray(new OWLAnnotation[1])[0]); 186 if (str != null) 187 _name = str; 188 else 189 _name = ontClass.toString(); 190 } 191 catch(NullPointerException ex) { 192 _name = ontClass.toString(); 193 } 194 } 195 196 public NamedOntClass(NamedOntClass noc) { 197 this._ontClass = noc.ontClass(); 198 this._ontology = noc.getOntology(); 199 this._name = noc.getName(); 200 } 201 202 public boolean isRemovable() { 203 return _removable; 204 } 205 206 public void setRemovable(boolean removable) { 207 _removable = removable; 208 } 209 210 public static class IteratorIterable<T> implements Iterable<T> { 211 public IteratorIterable(Iterator<T> iterator) { 212 this.iterator = iterator; 213 } 214 215 public Iterator<T> iterator() { 216 return this.iterator; 217 } 218 219 private Iterator<T> iterator; 220 } 221 222 public static NamedOntClass createNamedOntClassFromURI(String tagURIString) { 223 String ontologyURIString; 224 String[] parts = tagURIString.split("#"); 225 if (parts.length < 2) { 226 return null; 227 } 228 else { 229 ontologyURIString = parts[0]; 230 } 231 return createNamedOntClassFromURIs(tagURIString, ontologyURIString); 232 } 233 234 public static NamedOntClass createNamedOntClassFromURIs(String tagURIString, String ontologyURIString) { 235 //String originalTagURIString = tagURIString; 236 237 String[] parts = tagURIString.split("#"); 238 239 String label; 240 if (parts.length > 2) { 241 label = parts[2]; 242 tagURIString = parts[0] + "#" + parts[1]; 243 } 244 else { 245 label = parts[1]; 246 } 247 OWLOntologyManager manager = OWLManager.createOWLOntologyManager(); 248 OWLClass cls = manager.getOWLDataFactory().getOWLClass(URI.create(tagURIString)); 249 250 NamedOntModel theModel = null; 251 for (NamedOntModel model : new IteratorIterable<NamedOntModel>(OntologyCatalog.instance().getNamedOntModels())) { 252 if (ontologyURIString.equals(model.getOntology().getURI().toString())) { 253 theModel = model; 254 } 255 } 256 if (theModel == null) { 257 // Model not found 258 /// changed 12.21.10 259 ///return new NamedOntClass(originalTagURIString, label); 260 /// sometimes the originalTagURIString looks like (dont want extra label): 261 /// urn:lsid:localhost:onto:797050988:1#testtag#testtag 262 return new NamedOntClass(tagURIString, label); 263 } 264 265 OWLOntology ontology = theModel.getOntology(); 266 return new NamedOntClass(cls, ontology); 267 } 268 269 public String toString() { 270 return getName(); 271 } 272 273 public OWLClass ontClass() { 274 return _ontClass; 275 } 276 277 public OWLOntology getOntology() { 278 return _ontology; 279 } 280 281 public String getName() { 282 return _name; 283 } 284 285 private static Pattern parseAnnotation = Pattern.compile("\"(.*)\"\\^\\^string"); 286 287 public String getComment() { 288 try { 289 OWLAnnotation annotation = _ontClass.getAnnotations(_ontology, OWLRDFVocabulary.RDFS_COMMENT.getURI()).iterator().next(); 290 String rawAnnotation = annotation.getAnnotationValue().toString(); 291 Matcher matcher = parseAnnotation.matcher(rawAnnotation); 292 if (matcher.matches()) { 293 return matcher.group(1); 294 } 295 return rawAnnotation; 296 } 297 catch(NoSuchElementException ex) { 298 return ""; 299 } 300 } 301 302 public NamedOntModel getModel() { 303 if (_model == null) { 304 setModel(); 305 } 306 return _model; 307 } 308 309 public String getOntologyName() { 310 String nspace = getNameSpace(); 311 OntologyCatalog _catalog = OntologyCatalog.instance(); 312 return _catalog.getOntologyName(nspace); 313 } 314 315 public String getLocalName() { 316 String uriString = getConceptUri(); 317 return uriString.split("#")[1]; 318// return _ontClass.toString(); 319 } 320 321 public boolean hasNameSpace() { 322 String uriString = getConceptUri(); 323// String uriString = _ontClass.getURI().toString(); 324 String localName = getLocalName(); 325 assert(uriString.endsWith(localName)); 326 return uriString.length() - localName.length() > 1; 327 } 328 329 private String getConceptUri() { 330 if (isOrphaned()) { 331 return getManualUrl(); 332 } 333 else { 334 return _ontClass.getURI().toString(); 335 } 336 } 337 338 public String getNameSpace() { 339 if (hasNameSpace()) { 340 return _getNameSpace(); 341 } 342 else { 343 return _ontology.getURI().toString() + "#"; 344 } 345 } 346 347 public String _getNameSpace() { 348 String uriString = getConceptUri(); 349 String localName = getLocalName(); 350 assert(uriString.endsWith(localName)); 351 return uriString.substring(0, uriString.length() - localName.length()); 352 } 353 354 public String getConceptId() { 355 return getNameSpace() + getLocalName(); 356 } 357 358 public String getConceptIdWithLabel() { 359 return getConceptId() + "#" + getName(); 360 } 361 362 /** 363 * @param sorted 364 * Return sorted list if true. 365 */ 366 public Iterator<NamedOntClass> getNamedSubClasses(boolean sorted) { 367 Vector<NamedOntClass> result = new Vector<NamedOntClass>(); 368 for (OWLDescription desc : _ontClass.getSubClasses(_ontology)) { 369 OWLClass subcls = desc.asOWLClass(); 370 boolean hasLabel = !subcls.getAnnotations(_ontology, OWLRDFVocabulary.RDFS_LABEL.getURI()).isEmpty(); 371 if (hasLabel || subcls.toString() != null) { 372 // NOTE: Does subcls.toString == null happen? 373 result.add(new NamedOntClass(subcls, _ontology)); 374 } 375 } 376 if (sorted) { 377 Collections.sort(result); 378 } 379 return result.iterator(); 380 } 381 382 /** 383 * @param sorted 384 * Return sorted list if true. 385 */ 386 public Iterator<NamedOntClass> getNamedSuperClasses(boolean sorted) { 387 Vector<NamedOntClass> result = new Vector<NamedOntClass>(); 388 for (OWLDescription desc : _ontClass.getSuperClasses(_ontology)) { 389 OWLClass supcls; 390 try { 391 supcls = desc.asOWLClass(); 392 } 393 catch(OWLRuntimeException ex) { 394 log.warn("Failed to parse: " + desc + " (" + desc.getClass().getName() + ")"); 395 continue; 396 } 397 boolean hasLabel = !supcls.getAnnotations(_ontology, OWLRDFVocabulary.RDFS_LABEL.getURI()).isEmpty(); 398 if (hasLabel || supcls.toString() != null) { 399 // NOTE: Does supcls.toString == null happen? 400 result.add(new NamedOntClass(supcls, _ontology)); 401 } 402 } 403 if (sorted) { 404 Collections.sort(result); 405 } 406 return result.iterator(); 407 } 408 409 public Iterator<NamedOntProperty> getNamedProperties(boolean sorted) { 410 return Collections.<NamedOntProperty>emptyList().iterator(); 411// Vector<NamedOntProperty> result = new Vector<NamedOntProperty>(); 412// 413// Set<OWLAnnotation> annotations = _ontClass.getAnnotations(_ontology); 414//// for (OWLAnnotation annotation : annotations) { 415//// annotation.getAnno 416//// } 417// for (Iterator<OWLProperty> iter = _ontClass.listDeclaredProperties(true); iter 418// .hasNext();) { 419// OWLProperty prop = (OWLProperty) iter.next(); 420// result.add(new NamedOntProperty(prop)); 421// } 422// if (sorted) 423// Collections.sort(result); 424// return result.iterator(); 425 } 426 427// /** 428// * @return The (first) comment associated with the class 429// */ 430// // NOTE: Not used 431// public String getComment() { 432// return _ontClass.getComment(null); 433// } 434 435// /** 436// * @return Answer true if the given class is a "direct" sub-class of this 437// * class. 438// */ 439// // NOTE: Not used - but would be easy to convert 440// public boolean isDirectSubClass(NamedOntClass cls) { 441// for (Iterator<NamedOntClass> iter = getNamedSubClasses(false); iter.hasNext();) { 442// NamedOntClass tmpCls = (NamedOntClass) iter.next(); 443// if (tmpCls.equals(cls)) 444// return true; 445// } 446// return false; 447// } 448 449 /** 450 * @return Answer true if the given class is a sub-class of this class. 451 */ 452 public boolean isSubClass(NamedOntClass cls) { 453 // return _ontClass.hasSubClass(cls.ontClass(), false); 454 Set<OWLDescription> descriptions = this.ontClass().getSubClasses(this.getOntology()); 455 for (OWLDescription description : descriptions) { 456 NamedOntClass newClass = new NamedOntClass(description.asOWLClass(), this.getOntology()); 457 if (cls.equals(newClass)) { 458 return true; 459 } 460 } 461 return false; 462 } 463 464// /** 465// * @return Answer true if the given class is a "direct" super-class of this 466// * class. 467// */ 468// // NOTE: Not used - but would be easy to convert 469// public boolean isDirectSuperClass(NamedOntClass cls) { 470// // return _ontClass.hasSuperClass(cls.ontClass(), true); 471// for (Iterator<NamedOntClass> iter = getNamedSuperClasses(false); iter.hasNext();) { 472// NamedOntClass tmpCls = (NamedOntClass) iter.next(); 473// if (tmpCls.equals(cls)) 474// return true; 475// } 476// return false; 477// } 478 479// /** 480// * @return Answer true if the given class is a super-class of this class. 481// */ 482// // NOTE: Not used - but would be easy to convert 483// public boolean isSuperClass(NamedOntClass cls) { 484// // return _ontClass.hasSuperClass(cls.ontClass(), false); 485// for (Iterator<NamedOntClass> iter = getNamedSuperClasses(false); iter.hasNext();) { 486// NamedOntClass tmpCls = (NamedOntClass) iter.next(); 487// if (tmpCls.equals(cls)) 488// return true; 489// if (tmpCls.isSuperClass(cls)) 490// return true; 491// } 492// return false; 493// } 494 495 /** 496 * @return Answer true if the given class is disjoint with this class. 497 */ 498 // NOTE: Not used 499 public boolean isDisjointWith(NamedOntClass cls) { 500 Set<OWLDescription> descriptions = ontClass().getDisjointClasses(this.getOntology()); 501 for (OWLDescription description : descriptions) { 502 NamedOntClass newClass = new NamedOntClass(description.asOWLClass(), this.getOntology()); 503 if (cls.equals(newClass)) { 504 return true; 505 } 506 } 507 return false; 508 } 509 510 /** 511 * @return Answer true if the given class is equivalent to this class. 512 */ 513 // NOTE: Not used 514 public boolean isEquivalent(NamedOntClass cls) { 515 Set<OWLDescription> descriptions = ontClass().getEquivalentClasses(this.getOntology()); 516 for (OWLDescription description : descriptions) { 517 NamedOntClass newClass = new NamedOntClass(description.asOWLClass(), this.getOntology()); 518 if (cls.equals(newClass)) { 519 return true; 520 } 521 } 522 return false; 523 } 524 525 public boolean equals(Object obj) { 526 if (!(obj instanceof NamedOntClass)) 527 return false; 528 NamedOntClass tmp = (NamedOntClass) obj; 529 String myUri, yourUri; 530 myUri = this.isOrphaned() ? this.getManualUrl() : this.getAbsoluteURI().toString(); 531 yourUri = tmp.isOrphaned() ? tmp.getManualUrl() : tmp.getAbsoluteURI().toString(); 532 return myUri.equals(yourUri); 533 } 534 535 @Override 536 public int hashCode() { 537 if (isOrphaned()) { 538 return getManualUrl().hashCode(); 539 } 540 return getAbsoluteURI().hashCode(); 541 } 542 543 private URI getAbsoluteURI() { 544 // Make OWL class absolute 545 URI absoluteOntClassURI; 546 if (_ontClass.getURI().toString().startsWith("#")) { 547 absoluteOntClassURI = URI.create(_ontology.getURI().toString() + _ontClass.getURI().toString()); 548 } 549 else { 550 absoluteOntClassURI = _ontClass.getURI(); 551 } 552 553 return absoluteOntClassURI; 554 } 555 556 public int compareTo(Object obj) { 557 String str1 = toString(); 558 String str2 = obj.toString(); 559 return str1.compareTo(str2); 560 } 561 562 private static final Log log = LogFactory.getLog(NamedOntClass.class); 563 564}