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    }