001 package nl.tudelft.tbm.eeni.owl2java.generator;
002
003 import com.hp.hpl.jena.ontology.*;
004 import com.hp.hpl.jena.rdf.model.RDFNode;
005 import com.hp.hpl.jena.rdf.model.Resource;
006 import com.hp.hpl.jena.util.ResourceUtils;
007 import com.hp.hpl.jena.util.iterator.ExtendedIterator;
008 import nl.tudelft.tbm.eeni.owl2java.model.jenautils.ResourceError;
009 import nl.tudelft.tbm.eeni.owl2java.model.jmodel.*;
010 import nl.tudelft.tbm.eeni.owl2java.model.jmodel.utils.DebugUtils;
011 import nl.tudelft.tbm.eeni.owl2java.model.jmodel.utils.LogUtils;
012 import nl.tudelft.tbm.eeni.owl2java.model.jmodel.utils.NamingUtils;
013 import nl.tudelft.tbm.eeni.owl2java.model.ns.NamespaceUtils;
014 import org.apache.commons.logging.Log;
015 import org.apache.commons.logging.LogFactory;
016
017 import java.util.ArrayList;
018 import java.util.Iterator;
019 import java.util.List;
020
021
022 public class OwlReader {
023
024 private static Log log = LogFactory.getLog(OwlReader.class);
025
026 private OntModel ontModel;
027 public JModel jmodel;
028
029 private String basePackage;
030 private List<String> forbiddenPrefixes = new ArrayList<String>();
031 private List<JClass> deferredIntersectionClasses = new ArrayList<JClass>();
032
033 public void addForbiddenPrefix(String prefix) {
034 forbiddenPrefixes.add(prefix);
035 }
036
037 protected void createJPackages() {
038 // add a default model for all classes /wo a prefix
039 JPackage defaultPkg = new JPackage(jmodel, basePackage);
040 this.jmodel.addPackage(basePackage, defaultPkg);
041
042 // find all namespaces, generate prefixes if required
043 handleNamespaces();
044
045 // Based on this create the required packages
046 List<String> ns = jmodel.listNamespaces();
047 for (String uri : ns) {
048 String prefix = jmodel.getPrefix(uri);
049
050 // Don't create packages for default namespaces
051 if (NamespaceUtils.defaultNs2UriMapping.containsKey(uri))
052 continue;
053
054 // abort if we have an invalid prefix
055 if (forbiddenPrefixes.contains(prefix)) {
056 log
057 .error("Prefix " + prefix
058 + " is identical with a system internal prefix (toolspackage?). Aborting!");
059 System.exit(1);
060 }
061
062 // empty prefix (base uri) > assign to base package
063 if (prefix == JModel.BASEPREFIX) {
064 log.info("Assigning namespace " + uri + " to base package " + basePackage);
065 jmodel.addPackage(uri, basePackage);
066 continue;
067 }
068
069 String pkgName = NamingUtils.getJavaPackageName(basePackage, prefix);
070 log.info("Generating package " + pkgName);
071 JPackage p = new JPackage(jmodel, pkgName);
072 this.jmodel.addPackage(pkgName, p);
073 jmodel.addPackage(uri, pkgName);
074 }
075
076 }
077
078 protected void createJRestriction(Restriction res, OntClass cls, OntProperty prop) {
079 // one restriction per property and class only!
080
081 JClass jClass = jmodel.getJClass(cls.getURI());
082 JProperty jProp = jmodel.getJProperty(prop.getURI());
083
084 // we are reusing existing restriction if possible
085 JRestrictionsContainer jRestriction;
086 if (jClass.hasDomainRestrictionsContainer(jProp)) {
087 log.debug(LogUtils.toLogName(jClass, jProp) + ": Reusing existing restriction");
088 jRestriction = jClass.getDomainRestrictionsContainer(jProp);
089 } else {
090 jRestriction = new JRestrictionsContainer(jClass, jProp);
091 log.debug(LogUtils.toLogName(jClass, jProp) + ": Creating new restriction");
092 }
093
094 // max. cardinality
095 if (res.isMaxCardinalityRestriction()) {
096 MaxCardinalityRestriction maxCardinalityRestriction = res.asMaxCardinalityRestriction();
097 int maxCardinality = maxCardinalityRestriction.getMaxCardinality();
098 jRestriction.getCardinalityRestriction().setMaxCardinality(maxCardinality);
099 log.debug(DebugUtils.logPropertyOnClass(cls, prop) + ": Max cardinality set to " + maxCardinality);
100 }
101
102 // min cardinality -> skipped, does not make sense
103 if (res.isMinCardinalityRestriction()) {
104 MinCardinalityRestriction minCardinalityRestriction = res.asMinCardinalityRestriction();
105 int minCardinality = minCardinalityRestriction.getMinCardinality();
106 jRestriction.getCardinalityRestriction().setMinCardinality(minCardinality);
107 log.debug(DebugUtils.logPropertyOnClass(cls, prop) + ": Min cardinality set to " + minCardinality);
108 }
109
110 // exactly -> only useful for exactly = 1
111 if (res.isCardinalityRestriction()) {
112 CardinalityRestriction cardinalityRestriction = res.asCardinalityRestriction();
113 int cardinality = cardinalityRestriction.getCardinality();
114 jRestriction.getCardinalityRestriction().setCardinality(cardinality);
115 log.debug(DebugUtils.logPropertyOnClass(cls, prop) + ": Cardinality (min=max) set to " + cardinality);
116 }
117
118 // All values
119 if (res.isAllValuesFromRestriction()) {
120 // TODO: currently, only allValues from ObjectProperties can be handled
121 if (prop.isDatatypeProperty()) {
122 log.warn(LogUtils.toLogName(prop) + ": Not creating allValues restriction on datatype property");
123 return;
124 }
125 AllValuesFromRestriction allValuesRestriction = res.asAllValuesFromRestriction();
126 Resource allValuesResource = allValuesRestriction.getAllValuesFrom();
127 JClass allValuesJClass = jmodel.getJClass(allValuesResource.getURI());
128 jRestriction.addAllValuesRestriction(allValuesJClass);
129 log.debug(DebugUtils.logPropertyOnClass(cls, prop) + ": Added allValues restriction:"
130 + LogUtils.toLogName(allValuesJClass));
131 }
132
133 if (res.isHasValueRestriction()) {
134 // TODO: currently, only allValues from ObjectProperties can be handled
135 if (prop.isDatatypeProperty()) {
136 log.warn(LogUtils.toLogName(prop) + ": Not creating hasValue restriction on datatype property");
137 return;
138 }
139 HasValueRestriction hasValueRestriction = res.asHasValueRestriction();
140 RDFNode hasValueResource = hasValueRestriction.getHasValue();
141 jRestriction.getOtherRestriction().addHasValue(hasValueResource.toString());
142 log.debug(DebugUtils.logPropertyOnClass(cls, prop) + ": Added hasValue restriction:"
143 + hasValueResource.toString());
144 log.warn(DebugUtils.logPropertyOnClass(cls, prop) + ": HasValueRestriction currently ignored");
145 }
146
147 if (res.isSomeValuesFromRestriction()) {
148 // TODO: currently, only allValues from ObjectProperties can be handled
149 if (prop.isDatatypeProperty()) {
150 log.warn(LogUtils.toLogName(prop) + ": Not creating someValues restriction on datatype property");
151 return;
152 }
153 SomeValuesFromRestriction someValuesRestriction = res.asSomeValuesFromRestriction();
154 Resource someValuesResource = someValuesRestriction.getSomeValuesFrom();
155 JClass someValuesJClass = jmodel.getJClass(someValuesResource.getURI());
156 jRestriction.getOtherRestriction().addSomeValues(someValuesJClass);
157 log.debug(DebugUtils.logPropertyOnClass(cls, prop) + ": Added someValues restriction:"
158 + LogUtils.toLogName(someValuesJClass));
159 log.warn(DebugUtils.logPropertyOnClass(cls, prop) + ": SomeValuesRestriction currently ignored");
160 }
161 }
162
163 protected void createProperty(OntProperty ontProperty) {
164 log.info(LogUtils.toLogName(ontProperty) + ": Found property");
165 log.debug(DebugUtils.logProperty(ontProperty));
166
167 // create the property if not already present
168 if (!jmodel.hasJProperty(ontProperty.getURI()))
169 jmodel.createJProperty(ontProperty);
170 JProperty jProperty = jmodel.getJProperty(ontProperty.getURI());
171 jProperty.setOntProperty(ontProperty);
172
173 // set the type of the property
174 if (ontProperty.isDatatypeProperty())
175 jProperty.setPropertyType(JProperty.DataTypeProperty);
176 else
177 jProperty.setPropertyType(JProperty.ObjectProperty);
178
179 // property has range -> add range to property
180 Iterator<? extends OntResource> rIt = ontProperty.listRange();
181 while (rIt.hasNext()) {
182 OntResource range = rIt.next();
183 log.debug(LogUtils.toLogName(ontProperty) + ": Found range " + LogUtils.toLogName(range));
184
185 // Range points to a valid class -> object property
186 if (jmodel.hasJClass(range.getURI())) {
187 jProperty.setPropertyType(JProperty.ObjectProperty);
188 jProperty.addRange(jmodel.getJClass(range.getURI()));
189
190 log.debug(LogUtils.toLogName(ontProperty) + ": Registering class " + LogUtils.toLogName(range)
191 + " as range");
192
193 } else if (ontProperty.isDatatypeProperty()) {
194 // data type property
195 jProperty.setPropertyType(JProperty.DataTypeProperty);
196 jProperty.addRange(range.getURI());
197 log.debug(LogUtils.toLogName(ontProperty) + ": Registering " + LogUtils.toLogName(range) + " as range");
198 }
199 }
200
201 // property is functional -> set to functional
202 if (ontProperty.isFunctionalProperty()) {
203 log.debug(LogUtils.toLogName(ontProperty) + ": Is a functional property. Marking it. ");
204 jProperty.setFunctional(true);
205 }
206
207 // property is inverse functional -> we do not handle this case
208 if (ontProperty.isInverseFunctionalProperty()) {
209 log.warn(LogUtils.toLogName(ontProperty) + ": Is a inverse functional property. Ignored");
210 jProperty.setInverseFunctional(true);
211 }
212
213 // property is symetric -> this is handled via owl:inverseOf,
214 // rdfs:range, rdfs:domain
215 if (ontProperty.isSymmetricProperty()) {
216 log.debug(LogUtils.toLogName(ontProperty) + ": Is a symmetric property: handled elsewhere");
217 jProperty.setSymetric(true);
218 }
219
220 if (ontProperty.isTransitiveProperty()) {
221 log.warn(LogUtils.toLogName(ontProperty) + ": Is a transitive property: IGNORED");
222 jProperty.setTransitive(true);
223 }
224
225 // property has inverses; mark accordingly
226 if (ontProperty.hasInverse()) {
227 Iterator<? extends OntProperty> inverseIt = ontProperty.listInverse();
228 while (inverseIt.hasNext()) {
229 OntProperty inverseProp = inverseIt.next();
230
231 // property already present?
232 if (!jmodel.hasJProperty(inverseProp.getURI()))
233 jmodel.createJProperty(inverseProp);
234 JProperty iProp = jmodel.getJProperty(inverseProp.getURI());
235 iProp.setOntProperty(inverseProp);
236 iProp.setPropertyType(JProperty.ObjectProperty);
237
238 // mark inverse
239 if (!iProp.hasInverseProperty(jProperty)) {
240 iProp.addInverseProperty(jProperty);
241 log.info(LogUtils.toLogName(ontProperty) + ": Marked as inverse of " + LogUtils.toLogName(iProp));
242 } else {
243 log.debug(LogUtils.toLogName(ontProperty) + ": Already defined as inverse of "
244 + LogUtils.toLogName(iProp));
245 }
246 }
247 }
248
249 // property has parent properties -> create and mark
250 Iterator<? extends OntProperty> superIt = ontProperty.listSuperProperties(true);
251 while (superIt.hasNext()) {
252 OntProperty superProp = superIt.next();
253 log
254 .debug(LogUtils.toLogName(ontProperty) + ": Registering super property "
255 + LogUtils.toLogName(superProp));
256
257 // property already present?
258 if (!jmodel.hasJProperty(superProp.getURI()))
259 jmodel.createJProperty(superProp);
260 JProperty sProp = jmodel.getJProperty(superProp.getURI());
261 if (superProp.isDatatypeProperty())
262 sProp.setPropertyType(JProperty.DataTypeProperty);
263 else
264 sProp.setPropertyType(JProperty.ObjectProperty);
265 sProp.setOntProperty(superProp);
266 sProp.addSubProperty(jProperty);
267 }
268
269 // property has equivalent properties -> create and link
270 Iterator<? extends OntProperty> equivalentIt = ontProperty.listEquivalentProperties();
271 while (equivalentIt.hasNext()) {
272 OntProperty equProp = equivalentIt.next();
273
274 // property already present?
275 if (!jmodel.hasJProperty(equProp.getURI()))
276 jmodel.createJProperty(equProp);
277 JProperty eProp = jmodel.getJProperty(equProp.getURI());
278 if (equProp.isDatatypeProperty())
279 eProp.setPropertyType(JProperty.DataTypeProperty);
280 else
281 eProp.setPropertyType(JProperty.ObjectProperty);
282
283 eProp.setOntProperty(equProp);
284
285 // mark as equivalent
286 if (eProp.hasEquivalentProperty(jProperty)) {
287 log.debug(LogUtils.toLogName(ontProperty) + ": Registering inverse property "
288 + LogUtils.toLogName(equProp));
289 eProp.addEquivalentProperty(jProperty);
290 } else {
291 log.debug(LogUtils.toLogName(ontProperty) + ": Alredy defined as inverse property of "
292 + LogUtils.toLogName(equProp));
293 }
294 }
295
296 // property has domain -> add it to the correct domain class
297 boolean domainProp = false;
298 ExtendedIterator<? extends OntResource> dIt = ontProperty.listDomain();
299 while (dIt.hasNext()) {
300 OntResource domain = dIt.next();
301 log.debug(LogUtils.toLogName(ontProperty) + ": Found domain " + LogUtils.toLogName(domain));
302
303 if (domain.isAnon()) {
304 // anonymous classes as domain > done in handleAnonClasses
305 log.debug(LogUtils.toLogName(ontProperty) + ": Domain is Anonymous class. Ignored.");
306 continue;
307 }
308
309 JClass domainCls = jmodel.getJClass(domain.getURI());
310 domainCls.addDomainProperty(jProperty);
311 domainProp = true;
312 log.debug(LogUtils.toLogName(ontProperty) + ": Registering as domain property in class "
313 + LogUtils.toLogName(domainCls));
314 }
315
316 // not a domain property > add it to the base thing (root) object
317 if (!domainProp) {
318 JClass domainCls = jmodel.getJClass(jmodel.getBaseThingUri());
319 domainCls.addDomainProperty(jProperty);
320 log.debug(LogUtils.toLogName(ontProperty) + ": Registering property without domain in "
321 + LogUtils.toLogName(domainCls));
322 }
323
324 }
325
326 protected boolean hasBaseThingURI(OntClass ontClass) {
327 // check if ontClass.localName = Thing.... This is currently not
328 // supported
329 String ontClassUri = ontClass.getURI();
330 String baseThingUri = jmodel.getBaseNamespace() + JModel.getBaseThingName();
331
332 if (ontClassUri == null)
333 return false;
334
335 if (ontClassUri.equals(baseThingUri)) {
336 return true;
337 }
338 return false;
339 }
340
341 protected void createJClassish(OntClass ontClass) {
342 log.info(LogUtils.toLogName(ontClass) + ": Found owl/rdf class");
343 log.debug(DebugUtils.logClass(ontClass));
344
345 // ignore base classes
346 if (NamespaceUtils.defaultNs2UriMapping.containsKey(ontClass.getNameSpace())) {
347 log.debug(LogUtils.toLogName(ontClass) + ": Is a base owl/rdfs class. Ignored");
348 return;
349 }
350
351 // abort if name clash with baseThing
352 if (hasBaseThingURI(ontClass)) {
353 log.error(LogUtils.toLogName(ontClass) + ": An unprefixed class named 'Thing' in "
354 + "the BaseURI namespace is not allowed");
355 System.exit(1);
356 log.error("Aborting");
357 }
358
359 // get or create the JClass
360 if (!jmodel.hasJClass(ontClass.getURI()))
361 jmodel.createJClass(ontClass, basePackage);
362 JClass cls = jmodel.getJClass(ontClass.getURI());
363 cls.setOntClass(ontClass);
364
365 // find (or create, if not present) super class and update classes
366 ExtendedIterator<OntClass> superIt = ontClass.listSuperClasses(true);
367 while (superIt.hasNext()) {
368 OntClass superCls = superIt.next();
369 hasBaseThingURI(superCls);
370
371 if (superCls.isAnon()) {
372 // Anonymous classes (restrictions ...) are handled in
373 // handleAnonymousClasses()
374 continue;
375 }
376
377 JClass superClass;
378 if (!jmodel.hasJClass(superCls.getURI()))
379 jmodel.createJClass(superCls, basePackage);
380 superClass = jmodel.getJClass(superCls.getURI());
381 superClass.setOntClass(superCls);
382
383 superClass.addSubClass(cls);
384 log.debug(LogUtils.toLogName(ontClass) + ": Registering super class "
385 + NamingUtils.getJavaFullName(superClass.getPackage(), superClass.getName()));
386 }
387
388 // if no superclasses are given, register as subclass of basething
389 if (!cls.hasSuperClasses()) {
390 log.debug(LogUtils.toLogName(ontClass) + ": No parent class given.");
391 JClass superClass = jmodel.getJClass(jmodel.getBaseThingUri());
392 superClass.addSubClass(cls);
393 log.debug(LogUtils.toLogName(ontClass) + ": Registering super class "
394 + NamingUtils.getJavaFullName(superClass.getPackage(), superClass.getName()));
395 }
396
397 // find (or create, if not present) equivalent class definitions
398 ExtendedIterator<OntClass> equIt = ontClass.listEquivalentClasses();
399 while (equIt.hasNext()) {
400 OntClass equCls = equIt.next();
401
402 if (equCls.isAnon()) {
403 log.warn("Currently, only primitive equivalent class definitions are used (OWL Lite)");
404 // Currently, only primite equivalent classes are accepted
405 continue;
406 }
407
408 // get or create the equivalent class.
409 JClass equClass;
410 if (!jmodel.hasJClass(equCls.getURI()))
411 jmodel.createJClass(equCls, basePackage);
412 equClass = jmodel.getJClass(equCls.getURI());
413 equClass.setOntClass(equCls);
414
415 equClass.addEquivalentClass(cls);
416 log.debug(LogUtils.toLogName(ontClass) + ": Registering equivalent class "
417 + NamingUtils.getJavaFullName(equClass.getPackage(), equClass.getName()));
418 }
419
420 }
421
422 public JModel generateJModel(OntModel model) {
423 this.jmodel = new JModel();
424 this.jmodel.setOntModel(model);
425 this.ontModel = model;
426
427 // find namespaces and define the corresponding packages
428 createJPackages();
429
430 // find all defined classes and populate the JModel with the
431 // corresponding JClass instances
432 handleClassishObjects();
433
434 // find all anonymous classes that are not restrictions.
435 // if possible create the corresponding JModel classes.
436 handleAnonymousClasses();
437
438 // Dito for properties
439 handleProperties();
440
441 // handle multiple ranges for Properties
442 handlePropertyRanges();
443
444 // now we handle the properties of any intersection class
445 handleDeferredIntersectionClasses();
446
447 // Finally, we handle the restrictions etc... and add them
448 // to the JModel
449 handleRestrictions();
450
451 return this.jmodel;
452 }
453
454 protected void handleDeferredIntersectionClasses() {
455 for (JClass cls : deferredIntersectionClasses) {
456 handleIntersectionClassProperties(cls);
457 }
458 }
459
460 protected void handlePropertyRanges() {
461 log.info("");
462 log.info("Checking for multiple ranges of object properties");
463 Iterator<String> propertyIt = jmodel.getUri2property().keySet().iterator();
464 while (propertyIt.hasNext()) {
465 String propUri = propertyIt.next();
466 JProperty prop = jmodel.getUri2property().get(propUri);
467
468 if (prop.getPropertyType() == JProperty.DataTypeProperty)
469 continue;
470
471 if (prop.listObjectPropertyRange().size() < 2)
472 continue;
473
474 log.info(LogUtils.toLogName(prop) + ": Found multiple range. Replacing with IntersectionClass");
475
476 // fetch all ontology classes that are in the property range
477 ArrayList<OntClass> operandOntClasses = new ArrayList<OntClass>();
478 for (JClass operandClass : prop.listObjectPropertyRange()) {
479 operandOntClasses.add(operandClass.getOntClass());
480 }
481
482 // add an anonymous intersection class to the ontology
483 IntersectionClass intersectionClass = ontModel.createIntersectionClass(null, this.ontModel.createList(operandOntClasses.iterator()));
484
485 // create/get the java representation of the intersection class
486 JClass cls = createIntersectionClass(intersectionClass);
487
488 // reset range for property to new union class
489 prop.listObjectPropertyRange().clear();
490 prop.addRange(cls);
491 log.debug(LogUtils.toLogName(prop) + ": Setting range to " + cls.getName());
492 }
493
494 }
495
496 public JModel getJModel() {
497 return jmodel;
498 }
499
500 protected void handleAnonymousClasses() {
501 // > loop over all anonymous classes and do some magic
502 log.info("");
503 log.info("Analyzing anonymous classes");
504
505 List<OntClass> list = ontModel.listClasses().toList();
506 for (int i = 0; i < list.size(); i++) {
507 OntClass ontClass = list.get(i);
508
509 // skip all non anonymous classes
510 if (!ontClass.isAnon())
511 continue;
512
513 // dito for restrictions -> this is done in handleRestrictions()
514 if (ontClass.isRestriction())
515 continue;
516
517 // handle the union class
518 if (ontClass.isUnionClass())
519 createUnionClass(ontClass.asUnionClass());
520
521 if (ontClass.isComplementClass()) {
522 jmodel.addOntResourceError(new ResourceError(ontClass, "ComplementClass ignored"));
523 log.warn("Found non restriction anonymous class: " + "ComplementClass ignored");
524 }
525
526 if (ontClass.isIntersectionClass()) {
527 log.info(LogUtils.toLogName(ontClass)
528 + ": Is intersection class. Handled as multiple subClassOf definitions.");
529 log.info(LogUtils.toLogName(ontClass) + ": ---> This should be done by a reasoner!");
530
531 // TODO createIntersectionClass currently unused; use pellet for this
532 // if (ontClass.canAs(IntersectionClass.class))
533 // createIntersectionClass(ontClass.asIntersectionClass());
534 }
535
536 if (ontClass.isEnumeratedClass()) {
537 jmodel.addOntResourceError(new ResourceError(ontClass, "Enumerated class handled as simple class"));
538 log.warn("Found non restriction anonymous class: " + "EnumeratedClass handled " + "as simple class");
539 }
540
541 }
542
543 }
544
545 protected JClass createIntersectionClass(IntersectionClass intersectionClass) {
546 // do we have anonymous operands in this class? this, we can not handle
547 // right now. -> we skip it
548
549 // get or create the intersection class
550 JClass cls = jmodel.getAnonymousJClass(JClass.AnonymousClassType.INTERSECTION, intersectionClass.listOperands().toList());
551 // an identical intersection class exists > we use it
552 if (cls != null)
553 log.info("Reusing existing anonymous intersection class " + LogUtils.toLogName(cls));
554 else {
555 // no identical intersection class exist > create new
556 String anonClassName = NamingUtils.createIntersectionClassName(intersectionClass);
557 String namespace = getAnonymousNamespace(intersectionClass.listOperands());
558 ;
559 String anonClassUri = namespace + anonClassName;
560
561 // rename the anon. class to a named class,
562 log.info("Renaming anonymous intersection class to: " + anonClassUri);
563 ResourceUtils.renameResource(intersectionClass, anonClassUri);
564 intersectionClass = ontModel.getOntClass(anonClassUri).asIntersectionClass();
565
566 // create class
567 if (!jmodel.hasJClass(intersectionClass.getURI()))
568 jmodel.createJClass(intersectionClass, basePackage);
569 cls = jmodel.getJClass(intersectionClass.getURI());
570 cls.setAnonymous(JClass.AnonymousClassType.INTERSECTION, intersectionClass.listOperands().toList());
571 cls.setOntClass(intersectionClass);
572 }
573
574 // -> we can handle the intersection class; do so now but skip anonymous
575 // operands
576
577 // register new intersection class as parent of this class
578 Iterator<OntClass> subIt = intersectionClass.listSubClasses();
579 while (subIt.hasNext()) {
580 OntClass ontCls = subIt.next();
581 String ontUri = ontCls.getURI();
582 JClass subCls = jmodel.getJClass(ontUri);
583 subCls.addSuperClass(cls);
584 log.debug(LogUtils.toLogName(intersectionClass) + ": Registering sub class "
585 + NamingUtils.getJavaFullName(subCls.getPackage(), subCls.getName()));
586 }
587
588 // register operand classes as child classes of new intersection
589 // class
590 Iterator<? extends OntClass> operandsIt = intersectionClass.listOperands();
591 while (operandsIt.hasNext()) {
592 OntClass ontCls = operandsIt.next();
593
594 if (ontCls.isAnon())
595 continue;
596
597 String ontUri = ontCls.getURI();
598 JClass operandCls = jmodel.getJClass(ontUri);
599
600 operandCls.addSuperClass(cls);
601 log.debug(LogUtils.toLogName(intersectionClass) + ": Registering sub class "
602 + LogUtils.toLogName(operandCls));
603 }
604
605 // -> move all parent classes up one level to new intersection class
606
607 // register super classes of intersection class as super class of this
608 // store reassigned super classes in a list
609 List<JClass> reassignedSuperClasses = new ArrayList<JClass>();
610 operandsIt = intersectionClass.listOperands();
611 while (operandsIt.hasNext()) {
612 OntClass operandCls = operandsIt.next();
613 Iterator<OntClass> superIt = operandCls.listSuperClasses();
614 while (superIt.hasNext()) {
615 OntClass ontCls = superIt.next();
616 String ontUri = ontCls.getURI();
617 JClass superCls = jmodel.getJClass(ontUri);
618
619 // add new intersection class as subclass of super class
620 log.debug(LogUtils.toLogName(intersectionClass) + ": Registering super class "
621 + LogUtils.toLogName(superCls));
622 superCls.addSubClass(cls);
623 reassignedSuperClasses.add(superCls);
624 }
625 }
626
627 // remove reassigned super class relationships from operand classes
628 // operand classes are now sub class of intersection class
629 operandsIt = intersectionClass.listOperands();
630 while (operandsIt.hasNext()) {
631 OntClass ontCls = operandsIt.next();
632 // skip any anonymous class
633 if (ontCls.isAnon())
634 continue;
635 String ontUri = ontCls.getURI();
636 JClass operandCls = jmodel.getJClass(ontUri);
637
638 // remove all operandClass.superclass in reassignedSuperClasses
639 for (JClass oldSuperClass : reassignedSuperClasses) {
640 if (operandCls.hasSuperClass(oldSuperClass, false)) {
641 log.debug(LogUtils.toLogName(operandCls) + ": Removing old super class relation "
642 + LogUtils.toLogName(oldSuperClass));
643 operandCls.removeSuperClassRelation(oldSuperClass);
644 }
645 }
646 }
647
648 // add the class for deferred handling of properties
649 deferredIntersectionClasses.add(cls);
650 return cls;
651 }
652
653 protected void handleIntersectionClassProperties(JClass cls) {
654 IntersectionClass intersectionClass = cls.getOntClass().asIntersectionClass();
655 Iterator<? extends OntClass> operandsIt;
656
657 // reassign property domain for common properties to intersection class
658 // find all properties
659 List<JProperty> properties = new ArrayList<JProperty>();
660 List<JProperty> propertiesToRemove = new ArrayList<JProperty>();
661 operandsIt = intersectionClass.listOperands();
662 while (operandsIt.hasNext()) {
663 OntClass ontCls = operandsIt.next();
664 if (ontCls.isAnon())
665 continue;
666 String ontUri = ontCls.getURI();
667 JClass operandCls = jmodel.getJClass(ontUri);
668 for (JProperty p : operandCls.listDomainProperties())
669 properties.add(p);
670 }
671 // mark any property not present in at least one class for removal
672 for (JProperty p : properties) {
673 operandsIt = intersectionClass.listOperands();
674 while (operandsIt.hasNext()) {
675 OntClass ontCls = operandsIt.next();
676 String ontUri = ontCls.getURI();
677 JClass operandCls = jmodel.getJClass(ontUri);
678
679 if (!operandCls.hasDomainProperty(p))
680 // property p not present in operandCls -> mark for removal
681 propertiesToRemove.add(p);
682 }
683 }
684 // remove all properties marked for removal
685 for (JProperty p : propertiesToRemove)
686 properties.remove(p);
687
688 // now we have a list of all common properties -> we can reassign them
689 for (JProperty p : properties) {
690 // add intersection class as domain
691 cls.addDomainProperty(p);
692 log.debug(LogUtils.toLogName(p) + ": Reassigning to intersection class " + LogUtils.toLogName(cls));
693 }
694 }
695
696 protected JClass createUnionClass(UnionClass unionClass) {
697 JClass cls = jmodel.getAnonymousJClass(JClass.AnonymousClassType.UNION, unionClass.listOperands().toList());
698 // an identical anonymous class exists > we use it
699 if (cls != null) {
700 log.info("Reusing existing anonymous union class " + LogUtils.toLogName(cls));
701 } else {
702 // create a new anonymous class
703 String anonClassName = NamingUtils.createUnionClassName(unionClass);
704 String namespace = getAnonymousNamespace(unionClass.listOperands());
705 String anonClassUri = namespace + anonClassName;
706
707 // rename the anon. class to a named class,
708 log.info("Renaming anonymous union class to :" + anonClassUri);
709 ResourceUtils.renameResource(unionClass, anonClassUri);
710 unionClass = ontModel.getOntClass(anonClassUri).asUnionClass();
711
712 // create class
713 if (!jmodel.hasJClass(unionClass.getURI()))
714 jmodel.createJClass(unionClass, basePackage);
715 cls = jmodel.getJClass(unionClass.getURI());
716 cls.setAnonymous(JClass.AnonymousClassType.UNION, unionClass.listOperands().toList());
717 cls.setOntClass(unionClass);
718 }
719
720 // register the new union class as parent of this class
721 Iterator<OntClass> subIt = unionClass.listSubClasses();
722 while (subIt.hasNext()) {
723 OntClass ontCls = subIt.next();
724 String ontUri = ontCls.getURI();
725 JClass subCls = jmodel.getJClass(ontUri);
726 subCls.removeSuperClassRelation(jmodel.getBaseThing());
727 subCls.addSuperClass(cls);
728 log.debug(LogUtils.toLogName(unionClass) + ": Registering sub class "
729 + NamingUtils.getJavaFullName(subCls.getPackage(), subCls.getName()));
730 }
731
732
733 // get super classes and register them
734 Iterator<? extends OntClass> operandIt = unionClass.listOperands();
735 while (operandIt.hasNext()) {
736 OntClass superClass = operandIt.next();
737
738 JClass superCls;
739 if (!jmodel.hasJClass(superClass.getURI()))
740 jmodel.createJClass(superClass, basePackage);
741 superCls = jmodel.getJClass(superClass.getURI());
742 superCls.setOntClass(superClass);
743 superCls.addSubClass(cls);
744 log.debug(LogUtils.toLogName(unionClass) + ": Registering super class "
745 + NamingUtils.getJavaFullName(superCls.getPackage(), superCls.getName()));
746 }
747 return cls;
748 }
749
750 /*
751 * Find a namespace for an anonymous class.
752 * If all relatedClasses have the same namespace, return it;
753 * otherwise return the base namespace.
754 */
755 public String getAnonymousNamespace(ExtendedIterator<? extends OntClass> operandClasses) {
756 if (!operandClasses.hasNext()) {
757 return jmodel.getBaseNamespace();
758 }
759 String namespace = operandClasses.next().getNameSpace();
760 while (operandClasses.hasNext()) {
761 if (!namespace.equals(operandClasses.next().getNameSpace())) {
762 return jmodel.getBaseNamespace();
763 }
764 }
765 return namespace;
766 }
767
768 protected void handleClassishObjects() {
769 // create our base object "Thing" and add as class
770 createBaseJClassish();
771
772 // add all named classes to the JModel
773 log.info("");
774 log.info("Found " + ontModel.listNamedClasses().toList().size() + " named classes");
775
776 // handle the ontology classes
777 Iterator<OntClass> it = ontModel.listNamedClasses();
778 while (it.hasNext()) {
779 OntClass ontClass = it.next();
780 createJClassish(ontClass);
781 }
782 }
783
784 protected void createBaseJClassish() {
785 // create our base object "Thing" and add as class
786 String thingUri;
787 String thingName = JModel.getBaseThingName();
788 thingUri = ontModel.getNsPrefixURI("owl") + thingName;
789
790 jmodel.setBaseThingUri(thingUri);
791 jmodel.createJClass(thingName, thingUri, basePackage);
792 }
793
794 protected void handleNamespaces() {
795 // find the namespaces and add them to our namespace2prefix mapping
796 Iterator<String> it = this.ontModel.getNsPrefixMap().keySet().iterator();
797 while (it.hasNext()) {
798 String prefix = it.next();
799 String uri = this.ontModel.getNsPrefixURI(prefix);
800
801 jmodel.addNamespacePrefix(uri, prefix);
802 log.info("Adding prefix " + prefix + " for namespace " + uri);
803 }
804
805 // handle name spaces without prefix
806 Iterator<String> importedUriIt = ontModel.listImportedOntologyURIs(true).iterator();
807 while (importedUriIt.hasNext()) {
808 String importedUri = importedUriIt.next() + "#";
809 if (!jmodel.hasNamespace(importedUri)) {
810 String ns = importedUri;
811 log.info("Found namespace without prefix: " + ns);
812 String prefix = jmodel.createNewPrefix();
813 jmodel.addNamespacePrefix(ns, prefix);
814 ontModel.setNsPrefix(prefix, ns);
815 log.info("Adding auto-generated prefix " + prefix + " for namespace " + ns);
816 }
817 }
818
819 }
820
821 protected void handleProperties() {
822 Iterator<? extends OntProperty> it;
823 log.info("");
824
825 log.info("Found " + ontModel.listObjectProperties().toList().size() + " object properties");
826 it = ontModel.listObjectProperties();
827 handleProperties(it);
828
829 log.info("Found " + ontModel.listTransitiveProperties().toList().size() + " object properties");
830 it = ontModel.listTransitiveProperties();
831 handleProperties(it);
832
833
834 log.info("Found " + ontModel.listFunctionalProperties().toList().size() + " functional properties");
835 it = ontModel.listFunctionalProperties();
836 handleProperties(it);
837
838 log.info("Found " + ontModel.listInverseFunctionalProperties().toList().size()
839 + " inverse functional properties");
840 it = ontModel.listInverseFunctionalProperties();
841 handleProperties(it);
842
843 log.info("Found " + ontModel.listSymmetricProperties().toList().size() + " symetrical properties");
844 it = ontModel.listSymmetricProperties();
845 handleProperties(it);
846
847 log.info("Found " + ontModel.listDatatypeProperties().toList().size() + " datatype properties");
848 it = ontModel.listDatatypeProperties();
849 handleProperties(it);
850 }
851
852 protected void handleProperties(Iterator<? extends OntProperty> propertiesIt) {
853 while (propertiesIt.hasNext()) {
854 OntProperty ontProperty = propertiesIt.next();
855
856 // ignore primitive properties
857 String uri = ontProperty.getURI();
858
859 if (NamespaceUtils.isPrimitiveNamespace(uri))
860 continue;
861 createProperty(ontProperty);
862 }
863 }
864
865 protected void handleRestrictions() {
866
867 // > loop over all restrictions and do some magic
868 log.info("");
869 log.info("Analyzing restriction classes");
870
871 Iterator<OntClass> it = ontModel.listClasses();
872 while (it.hasNext()) {
873 OntClass cls = it.next();
874
875 // skip all non anonymous classes
876 if (!cls.isAnon())
877 continue;
878
879 // we have a restriction
880 if (cls.isRestriction()) {
881 // find the restriction and the property it acts on
882 Restriction ontRestriction = cls.asRestriction();
883 OntProperty ontProperty = ontRestriction.getOnProperty();
884
885 log.info("Found Restriction on Property " + LogUtils.toLogName(ontRestriction.getOnProperty()));
886 log.debug(DebugUtils.logRestriction(ontRestriction));
887
888 // find the classes it acts on
889 Iterator<OntClass> subClassIt = ontRestriction.listSubClasses();
890 while (subClassIt.hasNext()) {
891 OntClass ontClass = subClassIt.next();
892
893 // Any anonymous class as subject of restriction is ignored. Not supported
894 // this can be union or intersection etc.
895 if (ontClass.getURI() == null) {
896 log.info(LogUtils.toLogName(ontClass) + ": Anonymous restriction class. Ignored");
897 continue;
898 }
899
900 // owl:Thing -> ignore
901 if (NamespaceUtils.defaultNs2UriMapping.containsKey(ontClass.getNameSpace())) {
902 log.debug(LogUtils.toLogName(ontClass) + ": Is a base class. Ignored");
903 continue;
904 }
905
906 createJRestriction(ontRestriction, ontClass, ontProperty);
907 }
908 }
909 }
910 }
911
912 public void setBasePackage(String basePackage) {
913 this.basePackage = basePackage;
914 }
915
916 }