org.openflexo.foundation.ontology.owl.OWLOntology.java Source code

Java tutorial

Introduction

Here is the source code for org.openflexo.foundation.ontology.owl.OWLOntology.java

Source

/*
 * (c) Copyright 2010-2011 AgileBirds
 *
 * This file is part of OpenFlexo.
 *
 * OpenFlexo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * OpenFlexo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package org.openflexo.foundation.ontology.owl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.filter.ElementFilter;
import org.jdom2.input.SAXBuilder;
import org.openflexo.foundation.FlexoEditor;
import org.openflexo.foundation.ontology.DuplicateURIException;
import org.openflexo.foundation.ontology.FlexoOntology;
import org.openflexo.foundation.ontology.OntologicDataType;
import org.openflexo.foundation.ontology.OntologyClass;
import org.openflexo.foundation.ontology.OntologyDataProperty;
import org.openflexo.foundation.ontology.OntologyIndividual;
import org.openflexo.foundation.ontology.OntologyLibrary;
import org.openflexo.foundation.ontology.OntologyObject;
import org.openflexo.foundation.ontology.OntologyObjectProperty;
import org.openflexo.foundation.ontology.dm.OntologyClassInserted;
import org.openflexo.foundation.ontology.dm.OntologyClassRemoved;
import org.openflexo.foundation.ontology.dm.OntologyDataPropertyInserted;
import org.openflexo.foundation.ontology.dm.OntologyDataPropertyRemoved;
import org.openflexo.foundation.ontology.dm.OntologyIndividualInserted;
import org.openflexo.foundation.ontology.dm.OntologyIndividualRemoved;
import org.openflexo.foundation.ontology.dm.OntologyObjectPropertyInserted;
import org.openflexo.foundation.ontology.dm.OntologyObjectPropertyRemoved;
import org.openflexo.foundation.ontology.dm.OntologyObjectRenamed;
import org.openflexo.foundation.ontology.owl.action.CreateDataProperty;
import org.openflexo.foundation.ontology.owl.action.CreateObjectProperty;
import org.openflexo.foundation.ontology.owl.action.CreateOntologyClass;
import org.openflexo.foundation.ontology.owl.action.CreateOntologyIndividual;
import org.openflexo.foundation.ontology.owl.action.DeleteOntologyObjects;
import org.openflexo.foundation.resource.FlexoResourceCenter;
import org.openflexo.foundation.resource.LocalResourceCenterImplementation;
import org.openflexo.foundation.rm.SaveResourceException;
import org.openflexo.toolbox.StringUtils;

import com.hp.hpl.jena.ontology.AnnotationProperty;
import com.hp.hpl.jena.ontology.ComplementClass;
import com.hp.hpl.jena.ontology.DatatypeProperty;
import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.IntersectionClass;
import com.hp.hpl.jena.ontology.ObjectProperty;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.ontology.OntProperty;
import com.hp.hpl.jena.ontology.OntResource;
import com.hp.hpl.jena.ontology.Restriction;
import com.hp.hpl.jena.ontology.UnionClass;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.NodeIterator;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.RDFWriter;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.ResourceFactory;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.util.ResourceUtils;

public abstract class OWLOntology extends OWLObject implements FlexoOntology {

    private static final Logger logger = Logger.getLogger(FlexoOntology.class.getPackage().getName());

    private String name;
    private final String ontologyURI;
    protected OntModel ontModel;
    private final File alternativeLocalFile;
    private final OntologyLibrary _library;
    protected boolean isLoaded = false;
    protected boolean isLoading = false;
    private boolean readOnly = true;

    private final Vector<OWLOntology> importedOntologies;

    private final Hashtable<String, OWLClass> classes;
    private final Hashtable<String, OWLIndividual> individuals;
    private final Hashtable<String, OWLDataProperty> dataProperties;
    private final Hashtable<String, OWLObjectProperty> objectProperties;

    private final Hashtable<OntClass, OWLClass> _classes;
    private final Hashtable<Individual, OWLIndividual> _individuals;
    private final Hashtable<OntProperty, OWLDataProperty> _dataProperties;
    private final Hashtable<OntProperty, OWLObjectProperty> _objectProperties;

    private final Vector<OWLClass> orderedClasses;
    private final Vector<OWLIndividual> orderedIndividuals;
    private final Vector<OWLDataProperty> orderedDataProperties;
    private final Vector<OWLObjectProperty> orderedObjectProperties;

    private OWLClass THING_CONCEPT;

    public OWLOntology(String anURI, File owlFile, OntologyLibrary library) {
        super(null, null);

        logger.info("Register ontology " + anURI + " file: " + owlFile);

        ontologyURI = anURI;
        if (owlFile != null && owlFile.exists()) {
            name = findOntologyName(owlFile);
        }
        if (name == null) {
            name = ontologyURI.substring(ontologyURI.lastIndexOf("/") + 1);
        }
        alternativeLocalFile = owlFile;
        _library = library;

        importedOntologies = new Vector<OWLOntology>();

        classes = new Hashtable<String, OWLClass>();
        individuals = new Hashtable<String, OWLIndividual>();
        dataProperties = new Hashtable<String, OWLDataProperty>();
        objectProperties = new Hashtable<String, OWLObjectProperty>();

        _classes = new Hashtable<OntClass, OWLClass>();
        _individuals = new Hashtable<Individual, OWLIndividual>();
        _dataProperties = new Hashtable<OntProperty, OWLDataProperty>();
        _objectProperties = new Hashtable<OntProperty, OWLObjectProperty>();

        orderedClasses = new Vector<OWLClass>();
        orderedIndividuals = new Vector<OWLIndividual>();
        orderedDataProperties = new Vector<OWLDataProperty>();
        orderedObjectProperties = new Vector<OWLObjectProperty>();
    }

    public static String findOntologyURI(File aFile) {
        String returned = findOntologyURIWithOntologyAboutMethod(aFile);
        if (StringUtils.isNotEmpty(returned) && returned.endsWith("#")) {
            returned = returned.substring(0, returned.lastIndexOf("#"));
        }
        if (StringUtils.isEmpty(returned)) {
            returned = findOntologyURIWithRDFBaseMethod(aFile);
        }
        if (StringUtils.isNotEmpty(returned) && returned.endsWith("#")) {
            returned = returned.substring(0, returned.lastIndexOf("#"));
        }
        if (StringUtils.isEmpty(returned)) {
            logger.warning("Could not find URI for ontology stored in file " + aFile.getAbsolutePath());
        }
        return returned;

    }

    private static String findOntologyURIWithRDFBaseMethod(File aFile) {
        Document document;
        try {
            logger.fine("Try to find URI for " + aFile);
            document = readXMLFile(aFile);
            Element root = getElement(document, "RDF");
            if (root != null) {
                Iterator it = root.getAttributes().iterator();
                while (it.hasNext()) {
                    Attribute at = (Attribute) it.next();
                    if (at.getName().equals("base")) {
                        logger.fine("Returned " + at.getValue());
                        return at.getValue();
                    }
                }
            }
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.fine("Returned null");
        return null;
    }

    private static String findOntologyURIWithOntologyAboutMethod(File aFile) {
        Document document;
        try {
            logger.fine("Try to find URI for " + aFile);
            document = readXMLFile(aFile);
            Element root = getElement(document, "Ontology");
            if (root != null) {
                Iterator it = root.getAttributes().iterator();
                while (it.hasNext()) {
                    Attribute at = (Attribute) it.next();
                    if (at.getName().equals("about")) {
                        logger.fine("Returned " + at.getValue());
                        String returned = at.getValue();
                        if (StringUtils.isNotEmpty(returned)) {
                            return returned;
                        }
                    }
                }
            }
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.fine("Returned null");
        return findOntologyURIWithRDFBaseMethod(aFile);
    }

    public static String findOntologyName(File aFile) {
        if (aFile == null || !aFile.exists() || aFile.length() == 0) {
            if (aFile != null && aFile.length() == 0) {
                aFile.delete();
            }
            return null;
        }

        Document document;
        try {
            logger.fine("Try to find name for " + aFile);
            document = readXMLFile(aFile);
            Element root = getElement(document, "RDF");
            if (root != null) {
                Element ontology = getElement(root, "Ontology");
                if (ontology != null) {
                    Element title = getElement(root, "title");
                    if (title != null) {
                        return title.getValue();
                    }
                    List<Attribute> l = ontology.getAttributes();
                    for (int i = 0; i < l.size(); i++) {
                        Attribute a = l.get(i);
                        if (a.getName().equals("title")) {
                            return a.getValue();
                        }
                    }
                }
            }
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static Document readXMLFile(File f) throws JDOMException, IOException {
        FileInputStream fio = new FileInputStream(f);
        SAXBuilder parser = new SAXBuilder();
        Document reply = parser.build(fio);
        return reply;
    }

    private static Element getElement(Document document, String name) {
        Iterator it = document.getDescendants(new ElementFilter(name));
        if (it.hasNext()) {
            return (Element) it.next();
        } else {
            return null;
        }
    }

    private static Element getElement(Element from, String name) {
        Iterator it = from.getDescendants(new ElementFilter(name));
        if (it.hasNext()) {
            return (Element) it.next();
        } else {
            return null;
        }
    }

    @Override
    public String getClassNameKey() {
        return "flexo_ontology";
    }

    @Override
    public String getURI() {
        return getOntologyURI();
    }

    @Override
    public String getOntologyURI() {
        return ontologyURI;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String aName) {
        String newURI;
        if (getURI().indexOf("#") > -1) {
            newURI = getURI().substring(0, getURI().indexOf("#")) + aName;
        } else {
            newURI = aName;
        }
        logger.warning("Rename ontology " + getURI() + " to " + newURI + " not implemented yet");
    }

    @Override
    protected void _setOntResource(OntResource r) {
        // not relevant
    }

    public OntModel getOntModel() {
        loadWhenUnloaded();
        return ontModel;
    }

    public void setOntModel(OntModel ontModel) {
        this.ontModel = ontModel;
    }

    public File getAlternativeLocalFile() {
        return alternativeLocalFile;
    }

    /**
     * Return a vector of all imported ontologies in the context of this ontology. This method is recursive. Ontologies are imported only
     * once. This ontology is also appened to returned list.
     * 
     * @return
     */
    @Override
    public Vector<OWLOntology> getAllImportedOntologies() {
        Vector<OWLOntology> returned = new Vector<OWLOntology>();
        appendToAllImportedOntologies(this, returned);
        return returned;
    }

    private static void appendToAllImportedOntologies(OWLOntology o, Vector<OWLOntology> v) {
        if (!v.contains(o)) {
            v.add(o);
            for (OWLOntology importedOntology : o.getImportedOntologies()) {
                appendToAllImportedOntologies(importedOntology, v);
            }
        }
    }

    /**
     * Return a vector of imported ontologies in the context of this ontology
     * 
     * @return
     */
    @Override
    public Vector<OWLOntology> getImportedOntologies() {

        loadWhenUnloaded();

        if (getURI().equals(OWL2URIDefinitions.OWL_ONTOLOGY_URI)) {
            // OWL ontology should at least import RDF and RDFS ontologies
            if (!importedOntologies.contains(getOntologyLibrary().getRDFOntology())) {
                importedOntologies.add(getOntologyLibrary().getRDFOntology());
            }
            if (!importedOntologies.contains(getOntologyLibrary().getRDFSOntology())) {
                importedOntologies.add(getOntologyLibrary().getRDFSOntology());
            }
        } else if (getURI().equals(RDFURIDefinitions.RDF_ONTOLOGY_URI)) {
            // RDF ontology should at least import RDFS ontology
            if (!importedOntologies.contains(getOntologyLibrary().getRDFSOntology())) {
                importedOntologies.add(getOntologyLibrary().getRDFSOntology());
            }
        } else if (getURI().equals(RDFSURIDefinitions.RDFS_ONTOLOGY_URI)) {
            // RDFS ontology has no requirement
            if (!importedOntologies.contains(getOntologyLibrary().getRDFOntology())) {
                importedOntologies.add(getOntologyLibrary().getRDFOntology());
            }
        } else {
            // All other ontologies should at least import OWL ontology
            if (!importedOntologies.contains(getOntologyLibrary().getOWLOntology())) {
                importedOntologies.add(getOntologyLibrary().getOWLOntology());
            }
        }

        /*if (importedOntologies.size() == 0) {
           if (getURI().equals(OntologyLibrary.OWL_ONTOLOGY_URI)) {
        importedOntologies.add(getOntologyLibrary().getRDFOntology());
        importedOntologies.add(getOntologyLibrary().getRDFSOntology());
           } else if (getURI().equals(OntologyLibrary.RDF_ONTOLOGY_URI)) {
        importedOntologies.add(getOntologyLibrary().getRDFSOntology());
           } else if (!getURI().equals(OntologyLibrary.RDFS_ONTOLOGY_URI)) {
        importedOntologies.add(getOntologyLibrary().getOWLOntology());
           }
        }*/
        return importedOntologies;
    }

    /**
     * Return the local vision of OWL Thing concept
     * 
     * @return
     */
    @Override
    public OWLClass getThingConcept() {
        return THING_CONCEPT;
    }

    /**
     * Return the root concept class, which is the local vision of OWL Thing concept
     * 
     * @return
     */
    public OWLClass getRootClass() {
        return getThingConcept();
    }

    @Override
    public String toString() {
        return "ImportedOntology:" + getOntologyURI();
    }

    @Override
    public String getFullyQualifiedName() {
        return getOntologyURI();
    }

    public boolean importOntology(String ontologyURI) throws OntologyNotFoundException {
        if (_library.getOntology(ontologyURI) == null) {
            throw new OntologyNotFoundException();
        } else {
            return importOntology(_library.getOntology(ontologyURI));
        }
    }

    /**
     * Import ontology if supplied ontology is not yet imported in this ontology.<br>
     * Return a flag indicating if import was effective (otherwise, it was already done)
     * 
     * @param anOntology
     * @return
     * @throws OntologyNotFoundException
     */
    public boolean importOntology(FlexoOntology anOntology) throws OntologyNotFoundException {
        if (anOntology instanceof OWLOntology == false) {
            if (logger.isLoggable(Level.WARNING)) {
                logger.warning("Tried to import a non-owl ontology to an owl ontology, this is not yet supported.");
            }
        }
        loadWhenUnloaded();

        if (getAllImportedOntologies().contains(anOntology)) {
            return false;
        }

        if (_library.getOntology(anOntology.getOntologyURI()) == null) {
            throw new OntologyNotFoundException();
        } else if (_library.getOntology(anOntology.getOntologyURI()) != anOntology) {
            throw new OntologyNotFoundException();
        }

        String SOURCE = "@prefix rdf:         <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.\n"
                + "@prefix rdfs:        <http://www.w3.org/2000/01/rdf-schema#>.\n"
                + "@prefix owl:         <http://www.w3.org/2002/07/owl#>.\n" + "<" + getOntologyURI()
                + "> a owl:Ontology \n" + "   ; owl:imports <" + anOntology.getOntologyURI() + ">.\n";

        logger.fine("About to load source ontology:");
        logger.fine(SOURCE);
        ontModel.read(new StringReader(SOURCE), getOntologyURI(), "N3");

        importedOntologies.add((OWLOntology) anOntology);

        setChanged();

        return true;
    }

    public static class OntologyNotFoundException extends Exception {

    };

    public static class DuplicatedOntologyException extends Exception {

    };

    private boolean isNamedClass(OntClass ontClass) {
        return !ontClass.isComplementClass() && !ontClass.isUnionClass() && !ontClass.isIntersectionClass()
                && !ontClass.isRestriction() && !ontClass.isEnumeratedClass()
                && StringUtils.isNotEmpty(ontClass.getURI());
    }

    private boolean isNamedResourceOfThisOntology(OntResource ontResource) {
        return StringUtils.isNotEmpty(ontResource.getURI()) && ontResource.getURI().startsWith(getURI());
    }

    private void createConceptsAndProperties() {
        classes.clear();
        individuals.clear();
        dataProperties.clear();
        objectProperties.clear();
        _classes.clear();
        _individuals.clear();
        _dataProperties.clear();
        _objectProperties.clear();

        for (Iterator<OntClass> i = getOntModel().listClasses(); i.hasNext();) {
            OntClass ontClass = i.next();
            if (_classes.get(ontClass) == null && isNamedResourceOfThisOntology(ontClass)) {
                // Only named classes will be appended
                makeNewClass(ontClass);
                if (logger.isLoggable(Level.FINE)) {
                    logger.fine("Made class " + ontClass.getURI());
                }
            }
        }

        for (Iterator<Individual> i = getOntModel().listIndividuals(); i.hasNext();) {
            Individual individual = i.next();
            if (_individuals.get(individual) == null && isNamedResourceOfThisOntology(individual)) {
                OntologyIndividual newIndividual = makeNewIndividual(individual);
                if (logger.isLoggable(Level.FINE)) {
                    logger.fine("Made individual " + individual.getURI());
                }
            }
        }

        for (Iterator<DatatypeProperty> i = getOntModel().listDatatypeProperties(); i.hasNext();) {
            DatatypeProperty ontProperty = i.next();
            if (_dataProperties.get(ontProperty) == null && isNamedResourceOfThisOntology(ontProperty)) {
                makeNewDataProperty(ontProperty);
                if (logger.isLoggable(Level.FINE)) {
                    logger.fine(getURI() + ": made DataProperty" + ontProperty.getURI() + " in " + getURI());
                }
            }
        }

        for (Iterator<ObjectProperty> i = getOntModel().listObjectProperties(); i.hasNext();) {
            ObjectProperty ontProperty = i.next();
            if (_objectProperties.get(ontProperty) == null && isNamedResourceOfThisOntology(ontProperty)) {
                makeNewObjectProperty(ontProperty);
                if (logger.isLoggable(Level.FINE)) {
                    logger.fine(getURI() + ": made ObjectProperty" + ontProperty.getURI() + " in " + getURI());
                }
            }
        }

        // I dont understand why, but on some ontologies (RDF, RDFS and OWL), this is the only way to obtain those properties
        for (Iterator i = ontModel.listAllOntProperties(); i.hasNext();) {
            OntProperty ontProperty = (OntProperty) i.next();
            // Do it if and only if property is not yet existant
            if (getOntologyObject(ontProperty.getURI()) == null) {
                if (ontProperty.canAs(ObjectProperty.class)) {
                    makeNewObjectProperty(ontProperty.as(ObjectProperty.class));
                } else if (ontProperty.canAs(DatatypeProperty.class)) {
                    makeNewDataProperty(ontProperty.as(DatatypeProperty.class));
                } else if (ontProperty.canAs(AnnotationProperty.class)) {
                    AnnotationProperty ap = ontProperty.as(AnnotationProperty.class);
                    if (ap.getRange() != null
                            && ap.getRange().getURI().equals(RDFSURIDefinitions.RDFS_LITERAL_URI)) {
                        makeNewDataProperty(ontProperty);
                    } else if (ap.getRange() != null
                            && ap.getRange().getURI().equals(RDFSURIDefinitions.RDFS_RESOURCE_URI)) {
                        makeNewObjectProperty(ontProperty);
                    }
                } else {
                    // default behaviour: create object property
                    makeNewObjectProperty(ontProperty);
                }
            }

        }

        // I dont understand why, but on some ontologies, this is the only way to obtain those classes
        for (NodeIterator i = ontModel.listObjects(); i.hasNext();) {
            RDFNode node = i.nextNode();
            if (node instanceof Resource && ((Resource) node).canAs(OntClass.class)) {
                OntClass ontClass = ((Resource) node).as(OntClass.class);
                if (_classes.get(ontClass) == null && isNamedResourceOfThisOntology(ontClass)) {
                    // Only named classes will be appended)
                    makeNewClass(ontClass);
                    // logger.info("Made class (2)" + ontClass.getURI());
                }
            }
        }

        /*if (getURI().equals(OntologyLibrary.RDFS_ONTOLOGY_URI)) {
           for (StmtIterator i = getOntModel().listStatements(); i.hasNext();) {
        Statement s = i.nextStatement();
        System.out.println("statement = " + s);
           }
           for (NodeIterator i = ontModel.listObjects(); i.hasNext();) {
        RDFNode node = i.nextNode();
        System.out.println("node = " + node);
           }
           for (NodeIterator i = ontModel.listObjects(); i.hasNext();) {
        RDFNode node = i.nextNode();
        if (node.canAs(Resource.class)) {
           System.out.println("resource = " + node.as(Resource.class));
        }
           }
           for (Iterator i = ontModel.listAllOntProperties(); i.hasNext();) {
        OntProperty ontProperty = (OntProperty) i.next();
        System.out.println("Property: " + ontProperty);
        if (ontProperty.canAs(ObjectProperty.class)) {
           System.out.println("ObjectProperty");
        } else if (ontProperty.canAs(DatatypeProperty.class)) {
           System.out.println("DataProperty");
        } else if (ontProperty.canAs(AnnotationProperty.class)) {
           AnnotationProperty ap = ontProperty.as(AnnotationProperty.class);
           System.out.println("AnnotationProperty " + ap.getRange());
        } else if (ontProperty.canAs(FunctionalProperty.class)) {
           System.out.println("FunctionalProperty");
        }
           }
           System.exit(-1);
        }*/

        if (!getURI().equals(OWL2URIDefinitions.OWL_ONTOLOGY_URI)
                && !getURI().equals(RDFURIDefinitions.RDF_ONTOLOGY_URI)
                && !getURI().equals(RDFSURIDefinitions.RDFS_ONTOLOGY_URI)) {
            // Following will not apply to RDF, RDFS and OWL ontologies
            handleRedefinitionOfConceptsAndProperties();
        }

        // Special case for OWL ontology, register THING
        if (getURI().equals(OWL2URIDefinitions.OWL_ONTOLOGY_URI)) {
            THING_CONCEPT = getClass(OWL2URIDefinitions.OWL_THING_URI);
        }

        if (!getURI().equals(OWL2URIDefinitions.OWL_ONTOLOGY_URI)
                && !getURI().equals(RDFURIDefinitions.RDF_ONTOLOGY_URI)
                && !getURI().equals(RDFSURIDefinitions.RDFS_ONTOLOGY_URI)) {
            // Following will not apply to RDF, RDFS and OWL ontologies
            if (getOntologyLibrary().getOWLOntology() != null) {
                if (!importedOntologies.contains(getOntologyLibrary().getOWLOntology())) {
                    importedOntologies.add(getOntologyLibrary().getOWLOntology());
                }
                THING_CONCEPT = makeThingConcept();
            } else {
                logger.warning("Could not find OWL ontology");
            }
        }

        // SGU / Warning: entering hacking area !!!
        // I don't know what, but i found this way to get some more classes not discovered
        // by classical exploration. This is not satisfying.
        // Please investigate and find the RIGHT way to browse all classes !!!
        for (OWLClass aClass : new ArrayList<OWLClass>(classes.values())) {
            for (Iterator<OntClass> scI = aClass.getOntResource().listSubClasses(); scI.hasNext();) {
                OntClass subClass = scI.next();
                // retrieveOntologyClass(subClass);
                if (_classes.get(subClass) == null && isNamedResourceOfThisOntology(subClass)) {
                    // Only named classes will be appended)
                    makeNewClass(subClass);
                    // logger.info("Made class (3)" + ontClass.getURI());
                }
            }
        }

        logger.info("Done created all concepts, now initialize them");

        for (OWLClass aClass : new ArrayList<OWLClass>(classes.values())) {
            aClass.init();
        }
        for (OWLIndividual anIndividual : new ArrayList<OWLIndividual>(individuals.values())) {
            anIndividual.init();
        }
        for (OWLDataProperty property : new ArrayList<OWLDataProperty>(dataProperties.values())) {
            property.init();
        }
        for (OWLObjectProperty property : new ArrayList<OWLObjectProperty>(objectProperties.values())) {
            property.init();
        }

    }

    private void handleRedefinitionOfConceptsAndProperties() {

        Set<OntClass> redefinedClasses = new HashSet<OntClass>();
        Set<Individual> redefinedIndividuals = new HashSet<Individual>();
        Set<ObjectProperty> redefinedObjectProperties = new HashSet<ObjectProperty>();
        Set<DatatypeProperty> redefinedDatatypeProperties = new HashSet<DatatypeProperty>();

        for (StmtIterator i = getOntModel().listStatements(); i.hasNext();) {
            Statement s = i.nextStatement();
            if (getOntModel().isInBaseModel(s)) {
                // This statement was asserted in this model, so may redefine an other concept defined in imported ontologies
                RDFNode object = s.getObject();
                RDFNode subject = s.getSubject();
                if (object.canAs(OntClass.class)) {
                    redefinedClasses.add(object.as(OntClass.class));
                }
                if (subject.canAs(OntClass.class)) {
                    redefinedClasses.add(subject.as(OntClass.class));
                }
                if (object.canAs(Individual.class)) {
                    redefinedIndividuals.add(object.as(Individual.class));
                    // System.out.println("Redefine individual as object because of statement " + s);
                }
                if (subject.canAs(Individual.class)) {
                    redefinedIndividuals.add(subject.as(Individual.class));
                    // System.out.println("Redefine individual as subject because of statement " + s);
                }
                if (object.canAs(ObjectProperty.class)) {
                    redefinedObjectProperties.add(object.as(ObjectProperty.class));
                }
                if (subject.canAs(ObjectProperty.class)) {
                    redefinedObjectProperties.add(subject.as(ObjectProperty.class));
                }
                if (object.canAs(DatatypeProperty.class)) {
                    redefinedDatatypeProperties.add(object.as(DatatypeProperty.class));
                }
                if (subject.canAs(DatatypeProperty.class)) {
                    redefinedDatatypeProperties.add(subject.as(DatatypeProperty.class));
                }
            }
        }
        for (OntClass ontClass : redefinedClasses) {
            // Thing and Class concepts are handled differently
            if (StringUtils.isNotEmpty(ontClass.getURI())
                    && !OWL2URIDefinitions.OWL_THING_URI.equals(ontClass.getURI())
                    && !OWL2URIDefinitions.OWL_CLASS_URI.equals(ontClass.getURI())
                    && !ontClass.getURI().startsWith("http://www.w3.org/2001/XMLSchema#")
                    && getDeclaredClass(ontClass.getURI()) == null) {
                redefineClass(ontClass);
            }
        }

        // TODO
        /*for (Individual individual : redefinedIndividuals) {
           System.out.println("Ontology " + getURI() + ", redefine individual " + individual);
           redefineIndividual(individual);
        }*/

        for (ObjectProperty ontProperty : redefinedObjectProperties) {
            if (StringUtils.isNotEmpty(ontProperty.getURI())
                    && getDeclaredObjectProperty(ontProperty.getURI()) == null) {
                redefineObjectProperty(ontProperty);
            }
        }

        for (DatatypeProperty ontProperty : redefinedDatatypeProperties) {
            if (StringUtils.isNotEmpty(ontProperty.getURI())
                    && getDeclaredDataProperty(ontProperty.getURI()) == null) {
                redefineDataProperty(ontProperty);
            }
        }
    }

    @Override
    protected void update() {
        updateConceptsAndProperties();
    }

    public void updateConceptsAndProperties() {
        logger.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% " + ontologyURI);
        logger.info("Update ontology " + ontologyURI);

        for (OWLClass aClass : classes.values()) {
            aClass.update();
        }
        for (OWLIndividual anIndividual : individuals.values()) {
            anIndividual.update();
        }
        for (OWLDataProperty property : dataProperties.values()) {
            property.update();
        }
        for (OWLObjectProperty property : objectProperties.values()) {
            property.update();
        }
    }

    private OWLClass makeThingConcept() {
        logger.fine("makeThingConcept() in ontology " + this);
        OWLOntology owlOntology = getOntologyLibrary().getOWLOntology();
        OWLClass thingInOWLOntology = owlOntology.getClass(OWL2URIDefinitions.OWL_THING_URI);
        THING_CONCEPT = makeNewClass(thingInOWLOntology.getOntResource());
        THING_CONCEPT.setOriginalDefinition(thingInOWLOntology);
        return THING_CONCEPT;
    }

    protected OWLClass makeNewClass(OntClass ontClass) {
        if (StringUtils.isNotEmpty(ontClass.getURI())) {
            OWLClass aClass = new OWLClass(ontClass, this);
            classes.put(ontClass.getURI(), aClass);
            _classes.put(ontClass, aClass);
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("Made new class " + ontClass.getURI() + " in " + getOntologyURI());
            }
            // aClass.init();
            needsReordering = true;
            setChanged();
            notifyObservers(new OntologyClassInserted(aClass));
            return aClass;
        } else {
            logger.warning("Unexpected null URI for " + ontClass);
            return null;
        }
    }

    protected OWLClass redefineClass(OntClass ontClass) {
        OWLClass originalDefinition = getClass(ontClass.getURI());
        if (originalDefinition == null) {
            logger.warning("Tried to redefine " + this + " with null originalDefinition");
            return null;
        }
        logger.info("###### REDEFINE class " + ontClass.getURI() + " originalDefinition=" + originalDefinition);
        OWLClass returned = makeNewClass(ontClass);
        returned.setOriginalDefinition(originalDefinition);
        logger.info("Declare class " + returned.getName() + " as a redefinition of class initially asserted in "
                + originalDefinition.getOntology());
        return returned;
    }

    protected OWLClass removeClass(OWLClass aClass) {
        classes.remove(aClass.getURI());
        _classes.remove(aClass.getOntResource());
        needsReordering = true;
        setChanged();
        notifyObservers(new OntologyClassRemoved(aClass));
        return aClass;
    }

    protected void renameClass(OWLClass object, String oldURI, String newURI) {
        if (classes.get(oldURI) == object) {
            classes.remove(oldURI);
            classes.put(newURI, object);
        } else if (classes.get(oldURI) == null) {
            logger.warning(
                    "Inconsistent data in Ontology: rename invoked for non previously-existant ontology class");
            classes.put(newURI, object);
        } else {
            logger.severe(
                    "Inconsistent data in Ontology: rename invoked while found an other class than the one renamed");
        }
        needsReordering = true;
        setChanged();
        notifyObservers(new OntologyObjectRenamed(object, oldURI, newURI));
    }

    protected OWLIndividual makeNewIndividual(Individual individual) {
        if (StringUtils.isNotEmpty(individual.getURI())) {
            OWLIndividual anIndividual = new OWLIndividual(individual, this);
            individuals.put(individual.getURI(), anIndividual);
            _individuals.put(individual, anIndividual);
            logger.fine("Made new individual for " + anIndividual.getName() + " in " + getOntologyURI());
            // anIndividual.init();
            needsReordering = true;
            setChanged();
            notifyObservers(new OntologyIndividualInserted(anIndividual));
            return anIndividual;
        } else {
            logger.warning("Unexpected null URI for " + individual);
            return null;
        }
    }

    protected OWLIndividual redefineIndividual(Individual individual) {
        OWLIndividual originalDefinition = getIndividual(individual.getURI());
        if (originalDefinition == null) {
            logger.warning("Tried to redefine " + this + " with null originalDefinition");
            return null;
        }
        OWLIndividual returned = makeNewIndividual(individual);
        returned.setOriginalDefinition(originalDefinition);
        logger.info("Declare individual " + returned.getName()
                + " as a redefinition of individual initially asserted in " + originalDefinition.getOntology());
        return returned;
    }

    protected OWLIndividual removeIndividual(OWLIndividual anIndividual) {
        individuals.remove(anIndividual.getURI());
        _individuals.remove(anIndividual.getOntResource());
        needsReordering = true;
        setChanged();
        notifyObservers(new OntologyIndividualRemoved(anIndividual));
        return anIndividual;
    }

    protected void renameIndividual(OWLIndividual object, String oldURI, String newURI) {
        if (individuals.get(oldURI) == object) {
            individuals.remove(oldURI);
            individuals.put(newURI, object);
        } else if (individuals.get(oldURI) == null) {
            logger.warning(
                    "Inconsistent data in Ontology: rename invoked for non previously-existant ontology individual");
            individuals.put(newURI, object);
        } else {
            logger.severe(
                    "Inconsistent data in Ontology: rename invoked while found an other individual than the one renamed");
        }
        needsReordering = true;
        setChanged();
        notifyObservers(new OntologyObjectRenamed(object, oldURI, newURI));
    }

    protected OWLDataProperty makeNewDataProperty(OntProperty ontProperty) {
        if (StringUtils.isNotEmpty(ontProperty.getURI())) {
            OWLDataProperty property = new OWLDataProperty(ontProperty, this);
            dataProperties.put(ontProperty.getURI(), property);
            _dataProperties.put(ontProperty, property);
            logger.fine("Made new data property for " + property.getName() + " in " + getOntologyURI());
            // property.init();
            needsReordering = true;
            setChanged();
            notifyObservers(new OntologyDataPropertyInserted(property));
            return property;
        } else {
            logger.warning("Unexpected null URI for " + ontProperty);
            return null;
        }
    }

    protected OWLDataProperty redefineDataProperty(OntProperty ontProperty) {
        OWLDataProperty originalDefinition = getDataProperty(ontProperty.getURI());
        if (originalDefinition == null) {
            logger.warning("Tried to redefine " + this + " with null originalDefinition");
            return null;
        }
        OWLDataProperty returned = makeNewDataProperty(ontProperty);
        returned.setOriginalDefinition(originalDefinition);
        logger.info("Declare data property " + returned.getName()
                + " as a redefinition of data property initially asserted in " + originalDefinition.getOntology());
        return returned;
    }

    protected OWLDataProperty removeDataProperty(OWLDataProperty aProperty) {
        dataProperties.remove(aProperty.getURI());
        _dataProperties.remove(aProperty.getOntResource());
        needsReordering = true;
        setChanged();
        notifyObservers(new OntologyDataPropertyRemoved(aProperty));
        return aProperty;
    }

    protected void renameDataProperty(OWLDataProperty object, String oldURI, String newURI) {
        if (dataProperties.get(oldURI) == object) {
            dataProperties.remove(oldURI);
            dataProperties.put(newURI, object);
        } else if (dataProperties.get(oldURI) == null) {
            logger.warning(
                    "Inconsistent data in Ontology: rename invoked for non previously-existant ontology data property");
            dataProperties.put(newURI, object);
        } else {
            logger.severe(
                    "Inconsistent data in Ontology: rename invoked while found an other data property than the one renamed");
        }
        needsReordering = true;
        setChanged();
        notifyObservers(new OntologyObjectRenamed(object, oldURI, newURI));
    }

    protected OWLObjectProperty makeNewObjectProperty(OntProperty ontProperty) {
        if (StringUtils.isNotEmpty(ontProperty.getURI())) {
            OWLObjectProperty property = new OWLObjectProperty(ontProperty, this);
            objectProperties.put(ontProperty.getURI(), property);
            _objectProperties.put(ontProperty, property);
            logger.fine("Made new object property for " + property.getName() + " in " + getOntologyURI());
            // property.init();
            needsReordering = true;
            setChanged();
            notifyObservers(new OntologyObjectPropertyInserted(property));
            return property;
        } else {
            logger.warning("Unexpected null URI for " + ontProperty);
            return null;
        }
    }

    protected OWLObjectProperty redefineObjectProperty(OntProperty ontProperty) {
        OWLObjectProperty originalDefinition = getObjectProperty(ontProperty.getURI());
        if (originalDefinition == null) {
            logger.warning("Tried to redefine " + this + " with null originalDefinition");
            return null;
        }
        OWLObjectProperty returned = makeNewObjectProperty(ontProperty);
        returned.setOriginalDefinition(originalDefinition);
        logger.info("Declare object property " + returned.getName()
                + " as a redefinition of object property initially asserted in "
                + originalDefinition.getOntology());
        return returned;
    }

    protected OWLObjectProperty removeObjectProperty(OWLObjectProperty aProperty) {
        objectProperties.remove(aProperty.getURI());
        _objectProperties.remove(aProperty.getOntResource());
        needsReordering = true;
        setChanged();
        notifyObservers(new OntologyObjectPropertyRemoved(aProperty));
        return aProperty;
    }

    protected void renameObjectProperty(OWLObjectProperty object, String oldURI, String newURI) {
        if (objectProperties.get(oldURI) == object) {
            objectProperties.remove(oldURI);
            objectProperties.put(newURI, object);
        } else if (objectProperties.get(oldURI) == null) {
            logger.warning(
                    "Inconsistent data in Ontology: rename invoked for non previously-existant ontology object property");
            objectProperties.put(newURI, object);
        } else {
            logger.severe(
                    "Inconsistent data in Ontology: rename invoked while found an other object property than the one renamed");
        }
        needsReordering = true;
        setChanged();
        notifyObservers(new OntologyObjectRenamed(object, oldURI, newURI));
    }

    protected void renameObject(OWLObject<?> object, String oldURI, String newURI) {
        if (object instanceof OWLIndividual) {
            renameIndividual((OWLIndividual) object, oldURI, newURI);
        } else if (object instanceof OWLClass) {
            renameClass((OWLClass) object, oldURI, newURI);
        } else if (object instanceof OWLDataProperty) {
            renameDataProperty((OWLDataProperty) object, oldURI, newURI);
        } else if (object instanceof OWLObjectProperty) {
            renameObjectProperty((OWLObjectProperty) object, oldURI, newURI);
        } else {
            logger.warning("Unexpected object " + object);
        }
    }

    protected OWLObject<?> retrieveOntologyObject(Resource resource) {
        // First try to lookup with resource URI
        if (StringUtils.isNotEmpty(resource.getURI())) {
            OWLObject<?> returned = getOntologyObject(resource.getURI());
            if (returned != null) {
                return returned;
            }
        }
        // Not found, may be we have to create this new concept
        if (resource.canAs(OntClass.class)) {
            return retrieveOntologyClass(resource.as(OntClass.class));
        } else if (resource.canAs(Individual.class)) {
            return retrieveOntologyIndividual(resource.as(Individual.class));
        } else if (resource.canAs(ObjectProperty.class)) {
            return retrieveOntologyObjectProperty(resource.as(ObjectProperty.class));
        } else if (resource.canAs(DatatypeProperty.class)) {
            return retrieveOntologyDataProperty(resource.as(DatatypeProperty.class));
        } else {
            logger.warning("Unexpected resource: " + resource);
            return null;
        }
    }

    protected OWLProperty retrieveOntologyProperty(OntProperty property) {
        if (property.canAs(ObjectProperty.class)) {
            return retrieveOntologyObjectProperty(property.as(ObjectProperty.class));
        } else if (property.canAs(DatatypeProperty.class)) {
            return retrieveOntologyDataProperty(property.as(DatatypeProperty.class));
        } else {
            logger.warning("Unexpected property: " + property);
            return null;
        }
    }

    protected OWLObjectProperty retrieveOntologyObjectProperty(ObjectProperty ontProperty) {

        OWLObjectProperty returned = _objectProperties.get(ontProperty);
        if (returned != null) {
            return returned;
        }

        returned = makeNewObjectProperty(ontProperty);
        returned.init();

        return returned;
    }

    protected OWLDataProperty retrieveOntologyDataProperty(DatatypeProperty ontProperty) {

        OWLDataProperty returned = _dataProperties.get(ontProperty);
        if (returned != null) {
            return returned;
        }

        returned = makeNewDataProperty(ontProperty);
        returned.init();

        return returned;
    }

    protected OWLIndividual retrieveOntologyIndividual(Individual individual) {

        OWLIndividual returned = _individuals.get(individual);
        if (returned != null) {
            return returned;
        }

        // Special case for OWL, RDF and RDFS ontologies, don't create individuals !!!
        if (!getURI().equals(OWL2URIDefinitions.OWL_ONTOLOGY_URI)
                && !getURI().equals(RDFURIDefinitions.RDF_ONTOLOGY_URI)
                && !getURI().equals(RDFSURIDefinitions.RDFS_ONTOLOGY_URI)) {
            // Following will not apply to RDF, RDFS and OWL ontologies
            if (isNamedResourceOfThisOntology(individual)) {
                returned = makeNewIndividual(individual);
                returned.init();
                return returned;
            }
        }

        return null;
    }

    protected OWLClass retrieveOntologyClass(OntClass resource) {

        OWLClass returned = _classes.get(resource);
        if (returned != null) {
            return returned;
        }

        if (isNamedClass(resource) && StringUtils.isNotEmpty(resource.getURI())) {
            returned = getClass(resource.getURI());
            if (returned != null) {
                return returned;
            }
        }

        if (isNamedResourceOfThisOntology(resource)) {
            returned = makeNewClass(resource);
            returned.init();
        }

        else if (resource.isRestriction()) {
            return retrieveRestriction(resource.asRestriction());
        }

        else if (resource.canAs(ComplementClass.class)) {
            returned = new OWLComplementClass(resource.asComplementClass(), getOntology());
        } else if (resource.canAs(UnionClass.class)) {
            returned = new OWLUnionClass(resource.asUnionClass(), getOntology());
        } else if (resource.canAs(IntersectionClass.class)) {
            returned = new OWLIntersectionClass(resource.asIntersectionClass(), getOntology());
        } else {
            // logger.warning("Unexpected class: " + resource);
            return null;
        }

        _classes.put(resource, returned);
        return returned;

    }

    private OntologyRestrictionClass retrieveRestriction(Restriction restriction) {

        OntologyRestrictionClass returned = (OntologyRestrictionClass) _classes.get(restriction);
        if (returned != null) {
            return returned;
        }

        String OWL = getFlexoOntology().getOntModel().getNsPrefixURI("owl");
        Property ON_CLASS = ResourceFactory.createProperty(OWL + OntologyRestrictionClass.ON_CLASS);
        Property ON_DATA_RANGE = ResourceFactory.createProperty(OWL + OntologyRestrictionClass.ON_DATA_RANGE);
        Property QUALIFIED_CARDINALITY = ResourceFactory
                .createProperty(OWL + OntologyRestrictionClass.QUALIFIED_CARDINALITY);
        Property MIN_QUALIFIED_CARDINALITY = ResourceFactory
                .createProperty(OWL + OntologyRestrictionClass.MIN_QUALIFIED_CARDINALITY);
        Property MAX_QUALIFIED_CARDINALITY = ResourceFactory
                .createProperty(OWL + OntologyRestrictionClass.MAX_QUALIFIED_CARDINALITY);

        if (restriction.isSomeValuesFromRestriction()) {
            returned = new SomeValuesFromRestrictionClass(restriction.asSomeValuesFromRestriction(), getOntology());
        } else if (restriction.isAllValuesFromRestriction()) {
            returned = new AllValuesFromRestrictionClass(restriction.asAllValuesFromRestriction(), getOntology());
        } else if (restriction.isHasValueRestriction()) {
            returned = new HasValueRestrictionClass(restriction.asHasValueRestriction(), getOntology());
        } else if (restriction.isCardinalityRestriction()) {
            returned = new CardinalityRestrictionClass(restriction.asCardinalityRestriction(), getOntology());
        } else if (restriction.isMinCardinalityRestriction()) {
            returned = new MinCardinalityRestrictionClass(restriction.asMinCardinalityRestriction(), getOntology());
        } else if (restriction.isMaxCardinalityRestriction()) {
            returned = new MaxCardinalityRestrictionClass(restriction.asMaxCardinalityRestriction(), getOntology());
        } else if (restriction.getProperty(ON_CLASS) != null || restriction.getProperty(ON_DATA_RANGE) != null) {
            if (restriction.getProperty(QUALIFIED_CARDINALITY) != null) {
                returned = new CardinalityRestrictionClass(restriction, getOntology());
            } else if (restriction.getProperty(MIN_QUALIFIED_CARDINALITY) != null) {
                returned = new MinCardinalityRestrictionClass(restriction, getOntology());
            } else if (restriction.getProperty(MAX_QUALIFIED_CARDINALITY) != null) {
                returned = new MaxCardinalityRestrictionClass(restriction, getOntology());
            }
        }

        if (returned != null) {
            _classes.put(restriction, returned);
            return returned;
        } else {
            logger.warning("Unexpected restriction: " + restriction);
            return null;
        }

    }

    /**
     * Return all classes accessible in the context of this ontology.<br>
     * This means that classes are also retrieved from imported ontologies (non-strict mode)
     * 
     * @return
     */
    @Override
    public List<OWLClass> getAccessibleClasses() {
        List<OWLClass> returned = new ArrayList<OWLClass>();
        for (OWLOntology o : getAllImportedOntologies()) {
            returned.addAll(o.getClasses());
        }
        removeOriginalFromRedefinedObjects(returned);
        return returned;
    }

    /**
     * Return all individuals accessible in the context of this ontology.<br>
     * This means that individuals are also retrieved from imported ontologies (non-strict mode)
     * 
     * @return
     */
    @Override
    public List<OWLIndividual> getAccessibleIndividuals() {
        List<OWLIndividual> returned = new ArrayList<OWLIndividual>();
        for (OWLOntology o : getAllImportedOntologies()) {
            returned.addAll(o.getIndividuals());
        }
        removeOriginalFromRedefinedObjects(returned);
        return returned;
    }

    /**
     * Return all object properties accessible in the context of this ontology.<br>
     * This means that properties are also retrieved from imported ontologies (non-strict mode)
     * 
     * @return
     */
    @Override
    public List<OWLObjectProperty> getAccessibleObjectProperties() {
        List<OWLObjectProperty> returned = new ArrayList<OWLObjectProperty>();
        for (OWLOntology o : getAllImportedOntologies()) {
            returned.addAll(o.getObjectProperties());
        }
        removeOriginalFromRedefinedObjects(returned);
        return returned;
    }

    /**
     * Return all data properties accessible in the context of this ontology.<br>
     * This means that properties are also retrieved from imported ontologies (non-strict mode)
     * 
     * @return
     */
    @Override
    public List<OWLDataProperty> getAccessibleDataProperties() {
        List<OWLDataProperty> returned = new ArrayList<OWLDataProperty>();
        for (OWLOntology o : getAllImportedOntologies()) {
            returned.addAll(o.getDataProperties());
        }
        removeOriginalFromRedefinedObjects(returned);
        return returned;
    }

    /**
     * Remove originals from redefined classes<br>
     * Special case: original Thing definition is kept and redefinitions are excluded
     * 
     * @param list
     */
    private void removeOriginalFromRedefinedObjects(List<? extends OWLObject<?>> list) {
        for (OWLObject c : new ArrayList<OWLObject>(list)) {
            if (c.redefinesOriginalDefinition()) {
                if (c instanceof OWLClass && ((OWLClass) c).isThing()) {
                    list.remove(c);
                } else {
                    list.remove(c.getOriginalDefinition());
                }
            }
        }
    }

    @Override
    public Vector<OWLClass> getClasses() {
        if (needsReordering) {
            reorderConceptAndProperties();
        }
        return orderedClasses;
    }

    @Override
    public Vector<OWLIndividual> getIndividuals() {
        if (needsReordering) {
            reorderConceptAndProperties();
        }
        return orderedIndividuals;
    }

    @Override
    public Vector<OWLDataProperty> getDataProperties() {
        if (needsReordering) {
            reorderConceptAndProperties();
        }
        return orderedDataProperties;
    }

    @Override
    public Vector<OWLObjectProperty> getObjectProperties() {
        if (needsReordering) {
            reorderConceptAndProperties();
        }
        return orderedObjectProperties;
    }

    private boolean needsReordering = true;

    private void reorderConceptAndProperties() {
        orderedClasses.clear();
        for (OWLClass aClass : classes.values()) {
            aClass.updateDomainsAndRanges();
            orderedClasses.add(aClass);
        }
        Collections.sort(orderedClasses);

        orderedIndividuals.clear();
        for (OWLIndividual anIndividual : individuals.values()) {
            anIndividual.updateDomainsAndRanges();
            orderedIndividuals.add(anIndividual);
        }
        Collections.sort(orderedIndividuals);

        orderedDataProperties.clear();
        for (OWLDataProperty property : dataProperties.values()) {
            property.updateDomainsAndRanges();
            orderedDataProperties.add(property);
        }
        Collections.sort(orderedDataProperties);

        orderedObjectProperties.clear();
        for (OWLObjectProperty property : objectProperties.values()) {
            property.updateDomainsAndRanges();
            orderedObjectProperties.add(property);
        }
        Collections.sort(orderedObjectProperties);

        needsReordering = false;
    }

    @Override
    public boolean loadWhenUnloaded() {
        if (!isLoaded && !isLoading) {
            isLoading = true;
            // logger.info("Perform load "+getURI());
            load();
            isLoading = false;
            return true;
        } else {
            // logger.info("Skip loading"+getURI());
            return false;
        }
    }

    /* (non-Javadoc)
     * @see org.openflexo.foundation.ontology.IFlexoOntology#isLoaded()
     */
    @Override
    public boolean isLoaded() {
        return isLoaded;
    }

    /* (non-Javadoc)
     * @see org.openflexo.foundation.ontology.IFlexoOntology#isLoading()
     */
    @Override
    public boolean isLoading() {
        return isLoading;
    }

    private static void handleResource(OntResource resource, Hashtable<OntResource, String> renamedResources,
            Hashtable<String, OntResource> renamedURI) {
        for (StmtIterator j = resource.listProperties(); j.hasNext();) {
            Statement s = j.nextStatement();
            Property predicate = s.getPredicate();
            if (predicate.getURI().equals("http://www.w3.org/2000/01/rdf-schema#label")) {
                String baseName = s.getString();
                String newName = baseName;
                int k = 2;
                while (renamedURI.get(newName) != null) {
                    System.out.println("Duplicated URI " + newName);
                    newName = baseName + k;
                    k++;
                }
                renamedResources.put(resource, newName);
                renamedURI.put(newName, resource);
            }
        }
    }

    protected void load() {
        logger.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% " + ontologyURI);
        logger.info("Try to load ontology " + ontologyURI);

        ontModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, _library, null);

        // FIXES add strict to FALSE (XtoF)
        // FIXES OPENFLEXO-39, OPENFLEXO-40, OPENFLEXO-41, OPENFLEXO-42, OPENFLEXO-43, OPENFLEXO-44
        // ontModel.setStrictMode(false);

        // we have a local copy of flexo concept ontology
        if (alternativeLocalFile != null) {
            logger.fine("Alternative local file: " + alternativeLocalFile.getAbsolutePath());
            try {
                ontModel.getDocumentManager().addAltEntry(ontologyURI, alternativeLocalFile.toURL().toString());
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }

        // read the source document
        try {
            logger.info("BEGIN Read " + ontologyURI);
            ontModel.read(ontologyURI);
            logger.info("END read " + ontologyURI);
        } catch (Exception e) {
            logger.warning("Unexpected exception while reading ontology " + ontologyURI);
            logger.warning("Exception " + e.getMessage() + ". See logs for details");
            e.printStackTrace();
        }

        isLoaded = true;

        for (Object o : ontModel.listImportedOntologyURIs()) {
            OWLOntology importedOnt = (OWLOntology) _library.getOntology((String) o);
            logger.info("importedOnt= " + importedOnt);
            if (importedOnt != null) {
                importedOnt.loadWhenUnloaded();
                importedOntologies.add(importedOnt);
            }
        }

        logger.info("For " + ontologyURI + " Imported ontologies = " + getImportedOntologies());

        logger.info("Loaded ontology " + ontologyURI + " search for concepts and properties");

        for (FlexoOntology o : getImportedOntologies()) {
            logger.info("Imported ontology: " + o);
        }

        createConceptsAndProperties();

        logger.info("Finished loading ontology " + ontologyURI);

    }

    public void describe() {
        DescribeClass dc = new DescribeClass();
        DescribeDatatypeProperty dp = new DescribeDatatypeProperty();

        for (Iterator<OntClass> i = getOntModel().listClasses(); i.hasNext();) {
            dc.describeClass(System.out, i.next());
        }

        for (Iterator<ObjectProperty> i = getOntModel().listObjectProperties(); i.hasNext();) {
            ObjectProperty property = i.next();
            System.out.println("Object Property: " + property.getLocalName());
        }

        for (Iterator<DatatypeProperty> i = getOntModel().listDatatypeProperties(); i.hasNext();) {
            dp.describeProperty(System.out, i.next());
        }

    }

    @Override
    public OWLOntology getFlexoOntology() {
        return this;
    }

    @Override
    public void setDescription(String description) {
        // TODO
    }

    @Override
    public OntResource getOntResource() {
        return null;
        // return ontModel.createTypedLiteral(this, XSDDatatype.XSDanyURI);
    }

    @Override
    public Resource getResource() {
        return getOntModel().createResource(getURI());
    }

    @Override
    public void saveToFile(File aFile) {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(aFile);
            RDFWriter writer = ontModel.getWriter("RDF/XML-ABBREV");
            writer.setProperty("xmlbase", getOntologyURI());
            writer.write(ontModel.getBaseModel(), out, getOntologyURI());
            // getOntModel().setNsPrefix("base", getOntologyURI());
            // getOntModel().write(out, "RDF/XML-ABBREV", getOntologyURI()); // "RDF/XML-ABBREV"
            clearIsModified(true);
            logger.info("Wrote " + aFile);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            logger.warning("FileNotFoundException: " + e.getMessage());
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                logger.warning("IOException: " + e.getMessage());
            }
        }
    }

    @Override
    public void save() throws SaveResourceException {
        saveToFile(getAlternativeLocalFile());
    }

    @Override
    public OntologyLibrary getOntologyLibrary() {
        return _library;
    }

    @Override
    public boolean isSuperConceptOf(OntologyObject concept) {
        return false;
    }

    /**
     * Return a vector of Ontology class, which correspond to all classes necessary to see all classes and individuals belonging to current
     * ontology
     * 
     * @param context
     * @return
     */
    @Deprecated
    public Vector<OWLClass> getRootClasses() {
        Vector<OWLClass> topLevelClasses = new Vector<OWLClass>();
        for (OWLClass aClass : getClasses()) {
            addTopLevelClass(aClass, topLevelClasses);
        }
        for (OWLIndividual anIndividual : getIndividuals()) {
            addTopLevelClass(anIndividual, topLevelClasses);
        }
        return topLevelClasses;
    }

    @Deprecated
    private static void addTopLevelClass(OWLClass aClass, Vector<OWLClass> topLevelClasses) {
        // System.out.println("addTopLevelClass " + aClass + " for " + topLevelClasses);
        if (aClass.getSuperClasses().size() == 0) {
            if (!topLevelClasses.contains(aClass)) {
                topLevelClasses.add(aClass);
            }
            return;
        }
        for (OWLClass superClass : aClass.getSuperClasses()) {
            if (superClass != aClass) {
                addTopLevelClass(superClass, topLevelClasses);
            }
        }
    }

    @Deprecated
    private static void addTopLevelClass(OWLIndividual anIndividual, Vector<OWLClass> topLevelClasses) {
        for (OWLClass superClass : anIndividual.getSuperClasses()) {
            addTopLevelClass(superClass, topLevelClasses);
        }
    }

    /**
     * Return a vector of Ontology properties, which correspond to all properties necessary to see all properties belonging to current
     * ontology
     * 
     * @param context
     * @return
     */
    @Deprecated
    public Vector<OWLProperty> getRootProperties() {
        Vector<OWLProperty> topLevelProperties = new Vector<OWLProperty>();
        for (OWLProperty aProperty : getObjectProperties()) {
            addTopLevelProperty(aProperty, topLevelProperties);
        }
        for (OWLProperty aProperty : getDataProperties()) {
            addTopLevelProperty(aProperty, topLevelProperties);
        }
        return topLevelProperties;
    }

    @Deprecated
    private void addTopLevelProperty(OWLProperty aProperty, Vector<OWLProperty> topLevelProperties) {
        if (aProperty.getSuperProperties().size() == 0) {
            if (!topLevelProperties.contains(aProperty)) {
                topLevelProperties.add(aProperty);
            }
            return;
        }
        for (OWLProperty superProperty : aProperty.getSuperProperties()) {
            addTopLevelProperty(superProperty, topLevelProperties);
        }
    }

    @Override
    public boolean getIsReadOnly() {
        return readOnly;
    }

    public void setIsReadOnly(boolean readOnly) {
        this.readOnly = readOnly;
    }

    /**
     * Return true if URI is valid regarding its unicity (no one other object has same URI)
     * 
     * @param uri
     * @return
     */
    public boolean testValidURI(String name) {
        return getOntologyLibrary().testValidURI(getURI(), name);
    }

    public String makeURI(String name) {
        return getURI() + "#" + name;
    }

    public void assumeOntologyImportForReference(OWLObject<?> object) {
        if (!getImportedOntologies().contains(object.getFlexoOntology())) {
            logger.info("Import ontology:" + object.getFlexoOntology());
            try {
                importOntology(object.getFlexoOntology());
            } catch (OntologyNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    /**
     * Creates an new individual with specified name, and with specified type
     * 
     * @param name
     * @param type
     * @return
     * @throws DuplicateURIException
     */
    @Override
    public OWLIndividual createOntologyIndividual(String name, OntologyClass type) throws DuplicateURIException {
        if (type instanceof OWLClass) {
            assumeOntologyImportForReference((OWLClass) type);
            OntModel ontModel = getOntModel();
            String uri = makeURI(name);
            if (testValidURI(name)) {
                Individual individual = ontModel.createIndividual(uri, ((OWLClass) type).getOntResource());
                OWLIndividual returned = makeNewIndividual(individual);
                returned.init();
                return returned;
            } else {
                throw new DuplicateURIException(uri);
            }
        }
        logger.warning("Type is not an OWLClass");
        return null;
    }

    /**
     * Creates a new class with specified name, and with specified superClass
     * 
     * @param name
     * @param father
     * @return
     * @throws DuplicateURIException
     */
    @Override
    public OWLClass createOntologyClass(String name) throws DuplicateURIException {
        return createOntologyClass(name, null);
    }

    /**
     * Creates a new class with specified name, and with specified superClass
     * 
     * @param name
     * @param father
     * @return
     * @throws DuplicateURIException
     */
    @Override
    public OWLClass createOntologyClass(String name, OntologyClass father) throws DuplicateURIException {
        if (father instanceof OWLClass) {
            assumeOntologyImportForReference((OWLClass) father);
            OntModel ontModel = getOntModel();
            String uri = makeURI(name);
            if (testValidURI(name)) {
                OntClass aClass = ontModel.createClass(uri);
                if (father != null) {
                    aClass.addSuperClass(((OWLClass) father).getOntResource());
                }
                OWLClass returned = makeNewClass(aClass);
                returned.init();
                return returned;
            } else {
                throw new DuplicateURIException(uri);
            }
        }
        logger.warning("Type is not an OWLClass");
        return null;
    }

    /**
     * Creates an new data property with specified name, super property, domain and range
     * 
     * @param name
     * @param father
     * @return
     * @throws DuplicateURIException
     */
    @Override
    public OntologyObjectProperty createObjectProperty(String name, OntologyObjectProperty superProperty,
            OntologyClass domain, OntologyClass range) throws DuplicateURIException {
        // TODO implement this
        logger.warning("createObjectProperty() not implemented yet");
        return null;
    }

    /**
     * Creates an new data property with specified name, super property, domain and datatype
     * 
     * @param name
     * @param father
     * @return
     * @throws DuplicateURIException
     */
    @Override
    public OntologyDataProperty createDataProperty(String name, OntologyDataProperty superProperty,
            OntologyClass domain, OntologicDataType dataType) throws DuplicateURIException {
        // TODO implement this
        logger.warning("createDataProperty() not implemented yet");
        return null;
    }

    public OntologyRestrictionClass createRestriction(OWLClass subjectClass, OWLProperty property,
            OntologyRestrictionClass.RestrictionType type, int cardinality, OWLClass objectClass) {
        if (subjectClass != null) {
            assumeOntologyImportForReference(subjectClass);
        }
        if (objectClass != null) {
            assumeOntologyImportForReference(objectClass);
        }
        if (property != null) {
            assumeOntologyImportForReference(property);
        }

        OntModel ontModel = getOntModel();

        Restriction restriction = null;
        String OWL = getFlexoOntology().getOntModel().getNsPrefixURI("owl");
        Property ON_CLASS = ResourceFactory.createProperty(OWL + "onClass");

        switch (type) {
        case Some:
            restriction = ontModel.createSomeValuesFromRestriction(null, property.getOntProperty(),
                    objectClass.getOntResource());
            break;
        case Only:
            restriction = ontModel.createAllValuesFromRestriction(null, property.getOntProperty(),
                    objectClass.getOntResource());
            break;
        case Exact:
            Property QUALIFIED_CARDINALITY = ResourceFactory.createProperty(OWL + "qualifiedCardinality");
            restriction = ontModel.createRestriction(property.getOntProperty());
            restriction.addProperty(ON_CLASS, objectClass.getOntResource());
            restriction.addLiteral(QUALIFIED_CARDINALITY, cardinality);
            break;
        case Min:
            Property MIN_QUALIFIED_CARDINALITY = ResourceFactory.createProperty(OWL + "minQualifiedCardinality");
            restriction = ontModel.createRestriction(property.getOntProperty());
            restriction.addProperty(ON_CLASS, objectClass.getOntResource());
            restriction.addLiteral(MIN_QUALIFIED_CARDINALITY, cardinality);
            break;
        case Max:
            Property MAX_QUALIFIED_CARDINALITY = ResourceFactory.createProperty(OWL + "maxQualifiedCardinality");
            restriction = ontModel.createRestriction(property.getOntProperty());
            restriction.addProperty(ON_CLASS, objectClass.getOntResource());
            restriction.addLiteral(MAX_QUALIFIED_CARDINALITY, cardinality);
            break;

        default:
            break;
        }

        if (restriction != null) {
            return getOntology().retrieveRestriction(restriction);
        }

        setIsModified();

        logger.warning("Could not create restriction for " + property.getURI());
        return null;
    }

    public OntologyClass newOntologyClass(FlexoEditor editor) {
        CreateOntologyClass action = CreateOntologyClass.actionType.makeNewAction(this, null, editor).doAction();
        return action.getNewClass();
    }

    public OntologyIndividual newOntologyIndividual(FlexoEditor editor) {
        CreateOntologyIndividual action = CreateOntologyIndividual.actionType.makeNewAction(this, null, editor)
                .doAction();
        return action.getNewIndividual();
    }

    public OntologyObjectProperty newOntologyObjectProperty(FlexoEditor editor) {
        CreateObjectProperty action = CreateObjectProperty.actionType.makeNewAction(this, null, editor).doAction();
        return action.getNewProperty();
    }

    public OntologyDataProperty newCreateDataProperty(FlexoEditor editor) {
        CreateDataProperty action = CreateDataProperty.actionType.makeNewAction(this, null, editor).doAction();
        return action.getNewProperty();
    }

    public OWLObject<?> deleteOntologyObject(OWLObject<?> o, FlexoEditor editor) {
        DeleteOntologyObjects.actionType.makeNewAction(o, null, editor).doAction();
        return o;
    }

    @Override
    public boolean isOntology() {
        return true;
    }

    /**
     * Retrieve an ontology object from its URI, in the context of current ontology.<br>
     * The current ontology defines the scope, in which to lookup returned object. This method does NOT try to lookup object from other
     * ontologies. If you want to do this, try using method in OntologyLibrary.
     * 
     * @param objectURI
     * @return
     */
    @Override
    public OWLObject<?> getOntologyObject(String objectURI) {

        if (logger.isLoggable(Level.FINE)) {
            logger.fine("retrieve OntologyObject " + objectURI);
        }

        if (objectURI == null) {
            return null;
        }

        if (objectURI.endsWith("#")) {
            String potentialOntologyURI = objectURI.substring(0, objectURI.lastIndexOf("#"));
            OWLOntology returned = (OWLOntology) getOntologyLibrary().getOntology(ontologyURI);
            if (returned != null) {
                return returned;
            }
        }

        if (objectURI.equals(getURI())) {
            return this;
        }

        OWLObject<?> returned = null;

        returned = getClass(objectURI);
        if (returned != null) {
            return returned;
        }
        returned = getIndividual(objectURI);
        if (returned != null) {
            return returned;
        }
        returned = getObjectProperty(objectURI);
        if (returned != null) {
            return returned;
        }
        returned = getDataProperty(objectURI);
        if (returned != null) {
            return returned;
        }

        // logger.warning("Cannot find OntologyObject " + objectURI);
        return null;
    }

    @Override
    public OWLClass getClass(String classURI) {
        if (classURI == null) {
            return null;
        }
        OWLClass returned = getDeclaredClass(classURI);
        if (returned != null) {
            return returned;
        }

        for (OWLOntology o : getAllImportedOntologies()) {
            returned = o.getDeclaredClass(classURI);
            if (returned != null) {
                return returned;
            }
        }
        return null;
    }

    public OWLClass getDeclaredClass(String classURI) {
        if (classURI == null) {
            return null;
        }
        return classes.get(classURI);
    }

    @Override
    public OWLIndividual getIndividual(String individualURI) {
        if (individualURI == null) {
            return null;
        }
        OWLIndividual returned = getDeclaredIndividual(individualURI);
        if (returned != null) {
            return returned;
        }
        for (OWLOntology o : getAllImportedOntologies()) {
            returned = o.getDeclaredIndividual(individualURI);
            if (returned != null) {
                return returned;
            }
        }
        return null;
    }

    public OWLIndividual getDeclaredIndividual(String individualURI) {
        if (individualURI == null) {
            return null;
        }
        return individuals.get(individualURI);
    }

    @Override
    public OWLObjectProperty getObjectProperty(String propertyURI) {
        if (propertyURI == null) {
            return null;
        }
        OWLObjectProperty returned = getDeclaredObjectProperty(propertyURI);
        if (returned != null) {
            return returned;
        }
        for (OWLOntology o : getAllImportedOntologies()) {
            returned = o.getDeclaredObjectProperty(propertyURI);
            if (returned != null) {
                return returned;
            }
        }
        return null;
    }

    public OWLObjectProperty getDeclaredObjectProperty(String propertyURI) {
        if (propertyURI == null) {
            return null;
        }
        return objectProperties.get(propertyURI);
    }

    /**
     * Retrieve a data property from its URI, in the context of current ontology.<br>
     * The current ontology defines the scope, in which to lookup returned object. This method does NOT try to lookup object from other
     * ontologies. If you want to do this, try using method in OntologyLibrary.
     * 
     * @param objectURI
     * @return
     */
    @Override
    public OWLDataProperty getDataProperty(String propertyURI) {
        if (propertyURI == null) {
            return null;
        }
        OWLDataProperty returned = getDeclaredDataProperty(propertyURI);
        if (returned != null) {
            return returned;
        }
        for (OWLOntology o : getAllImportedOntologies()) {
            returned = o.getDeclaredDataProperty(propertyURI);
            if (returned != null) {
                return returned;
            }
        }
        return null;
    }

    public OWLDataProperty getDeclaredDataProperty(String propertyURI) {
        if (propertyURI == null) {
            return null;
        }
        return dataProperties.get(propertyURI);
    }

    @Override
    public OWLProperty getProperty(String objectURI) {
        OWLProperty returned = getObjectProperty(objectURI);
        if (returned != null) {
            return returned;
        }
        returned = getDataProperty(objectURI);
        if (returned != null) {
            return returned;
        }
        return null;
    }

    public static void main(String[] args) {
        File f = new File(
                "/Users/sylvain/Library/OpenFlexo/FlexoResourceCenter/Ontologies/www.bolton.ac.uk/Archimate_from_Ecore.owl");
        String uri = findOntologyURI(f);
        System.out.println("uri: " + uri);
        System.out.println("uri: " + findOntologyName(f));
        FlexoResourceCenter resourceCenter = LocalResourceCenterImplementation
                .instanciateTestLocalResourceCenterImplementation(
                        new File("/Users/sylvain/Library/OpenFlexo/FlexoResourceCenter"));
        resourceCenter.retrieveBaseOntologyLibrary();
        // ImportedOntology o = ImportedOntology.createNewImportedOntology(uri, f, resourceCenter.retrieveBaseOntologyLibrary());
        // o.load();
        /*try {
           o.save();
        } catch (SaveResourceException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
        }*/
        /*System.out.println("ontologies:" + o.getImportedOntologies());
        System.out.println("classes:" + o.getClasses());
        System.out.println("properties:" + o.getObjectProperties());*/
    }

    public static void main2(String[] args) {
        Hashtable<OntResource, String> renamedResources = new Hashtable<OntResource, String>();
        Hashtable<String, OntResource> renamedURI = new Hashtable<String, OntResource>();

        OntModel ontModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
        String ontologyURI = "file:/tmp/UML2.owl";
        ontModel.read(ontologyURI);
        for (Iterator<OntClass> i = ontModel.listClasses(); i.hasNext();) {
            OntClass aClass = i.next();
            handleResource(aClass, renamedResources, renamedURI);
        }
        for (Iterator<ObjectProperty> i = ontModel.listObjectProperties(); i.hasNext();) {
            ObjectProperty aProperty = i.next();
            handleResource(aProperty, renamedResources, renamedURI);
        }
        for (Iterator<DatatypeProperty> i = ontModel.listDatatypeProperties(); i.hasNext();) {
            DatatypeProperty aProperty = i.next();
            handleResource(aProperty, renamedResources, renamedURI);
        }

        for (OntResource r : renamedResources.keySet()) {
            String oldURI = r.getURI();
            String newURI = r.getURI().substring(0, r.getURI().indexOf("#")) + "#" + renamedResources.get(r);
            System.out.println("Rename " + oldURI + " to " + newURI);
            ResourceUtils.renameResource(r, newURI);
        }

        FileOutputStream out = null;
        try {
            out = new FileOutputStream(new File("/tmp/Prout.owl"));
            ontModel.write(out);
            logger.info("Wrote " + out);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            logger.warning("FileNotFoundException: " + e.getMessage());
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                logger.warning("IOException: " + e.getMessage());
            }
        }

    }

}