gate.creole.ontology.impl.sesame.OntologyServiceImplSesame.java Source code

Java tutorial

Introduction

Here is the source code for gate.creole.ontology.impl.sesame.OntologyServiceImplSesame.java

Source

/*
 *  Copyright (c) 1995-2012, The University of Sheffield. See the file
 *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
 *
 *  This file is part of GATE (see http://gate.ac.uk/), and is free
 *  software, licenced under the GNU Library General Public License,
 *  Version 2, June 1991 (in the distribution as file licence.html,
 *  and also available at http://gate.ac.uk/gate/licence.html).
 *
 *  $Id: OntologyServiceImplSesame.java 17080 2013-11-12 19:29:34Z markagreenwood $
 */
package gate.creole.ontology.impl.sesame;

// TODO: re-enable transactions, if possible so that we can make 

//   api methods  complete fully or not at all. For this, move the transaction
//   start and end calls into the abstract ontology code.
//   Also, consider adding start/endTransaction to the Ontology API: that 
//   -> if startTransaction is called on the API level all transaction 
//   calls on the implementation level are ignored until endTransaction is 
//   called on the API level. That we we ensure minimum atomic consistency
//   but make it possible to get larger atomic actions.
// TODO: we still get two different kinds of bnodeids: the old one without
//  _: and the new one with _:
// Figure out where the version without the prefix comes from and make
// all methods use the same convention!
// TODO: !!!!
// - replace generic Exception with something better
// - make replacement for repositoryConnection.isClass and repositoryConnection.isProperty
// - handle "system namespaces/URIs" etc better: have one array of these
// URIS declared somewhere and derive all the constants and tests from there.
// Have that array defined in the ontology namespace!
//
// !!!! Change all the return types used by GOS to either OResource objects
// or ONodeID or NodeIDorLiteral
// Create a class NodeIDorLiteral that *contains* either a NodeID or a
// Literal value. Use that class to pass back search results. Since this
// could be useful in the API, define that interface in the API!
// (For now and during testing, define in package impl)
//
// oneOf restrictions are simply returned as some anonymous class for now!
// check if it makes sense to actually use transactions somewhere? at the
// moment, by default the repositoryconnection is in autocommit mode and
// each modification is automatically commited.

import gate.creole.ontology.GateOntologyException;
import gate.creole.ontology.LiteralOrONodeID;
import gate.creole.ontology.OClass;
import gate.creole.ontology.OConstants;
import gate.creole.ontology.OConstants.Closure;
import gate.creole.ontology.OConstants.OntologyFormat;
import gate.creole.ontology.OURI;
import gate.creole.ontology.OBNodeID;
import gate.creole.ontology.OConstants.QueryLanguage;
import gate.creole.ontology.OInstance;
import gate.creole.ontology.ONodeID;
import gate.creole.ontology.OResource;
import gate.creole.ontology.OntologyTripleStore;
import gate.creole.ontology.RDFProperty;
import gate.creole.ontology.impl.*;
import gate.util.ClosableIterator;
import gate.util.GateRuntimeException;

import java.io.File;
import java.util.Vector;
import java.util.Collection;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.openrdf.model.BNode;
import org.openrdf.model.Literal;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.query.MalformedQueryException;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.rio.RDFWriter;
import org.openrdf.rio.n3.N3Writer;
import org.openrdf.rio.ntriples.NTriplesWriter;
import org.openrdf.rio.rdfxml.RDFXMLWriter;
import org.openrdf.rio.turtle.TurtleWriter;
import org.openrdf.model.vocabulary.RDFS;
import org.openrdf.model.vocabulary.OWL;
import org.openrdf.rio.RDFFormat;
import org.openrdf.model.Resource;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import org.openrdf.model.Value;
import org.openrdf.query.BindingSet;
import org.openrdf.query.TupleQueryResult;

/**
 * Implementation of the GATE Ontology Services. This class provides an
 * implementation of each and every service defined under the OntologyService interface.
 * 
 * @author Niraj Aswani
 * @author Johann Petrak
 */
public class OntologyServiceImplSesame implements OntologyService {

    // ***************************************************************************
    // **** CONSTANTS ************************************************************
    // ***************************************************************************

    private static final org.openrdf.model.URI IMPORT_CONTEXT_URI = new org.openrdf.model.impl.URIImpl(
            "http://gate.ac.uk/dummyuri/OWLIM3OntologyPlugin/#ImportContext");
    private static final org.openrdf.model.URI DATA_CONTEXT_URI = new org.openrdf.model.impl.URIImpl(
            AbstractOntologyImplSesame.TRIPLE_CONTEXT_DATA);
    private static final org.openrdf.model.URI SYSTEM_IMPORT_CONTEXT_URI = new org.openrdf.model.impl.URIImpl(
            "http://gate.ac.uk/dummyuri/OWLIM3OntologyPlugin/#SystemImportContext");

    private org.openrdf.model.URI contextURI = DATA_CONTEXT_URI;

    public void setContextURIString(String uriString) {
        contextURI = repositoryConnection.getValueFactory().createURI(uriString);
        ontologyTripleStore.setContextURI(contextURI);
    }

    public String getContextURIString() {
        return contextURI.toString();
    }

    public org.openrdf.model.URI getContextURI() {
        return contextURI;
    }

    private Logger logger;

    protected SesameManager sesameManager;

    private RepositoryConnection repositoryConnection;

    public final AbstractOntologyImplSesame ontology;
    private String ontologyUrl;

    private OntologyTripleStoreImpl ontologyTripleStore;

    /**
     * This is the constructor that is used from one of the factory methods
     * that create an OntologyServiceImplSesame object. Only the factory
     * methods can be used to create an instance. The factory method is 
     * responsible for initializing all the delegate datastructures correctly:
     * an instance of SesameManager and an instance of OntologyTripleStoreImpl.
     * The OntologyTripleStoreImpl instance in turn uses the SesameManager 
     * instance internally to access the Sesame repository connection. 
     */
    private OntologyServiceImplSesame(AbstractOntologyImplSesame o, SesameManager sm) {
        super();
        ontology = o;
        sesameManager = sm;
        repositoryConnection = sesameManager.getRepositoryConnection();
        ontologyTripleStore = new OntologyTripleStoreImpl(o, sesameManager, contextURI);
        logger = Logger.getLogger(this.getClass().getName());
    }

    private OntologyServiceImplSesame() {
        ontology = null;
        throw new GateRuntimeException("Default constructor of OntologyServiceImpleSesame must not be used!");
    }

    // ********** CREATION, INITIALIZATION, SHUTDOWN

    // OntologyServiceImplSesame Objects can only be created through one of 
    // the static factory methods. If an instance of this class is returned
    // by the factory method (i.e. no exception is thrown) then the instance
    // is guaranteed to have its internal datastructures initialized. This means
    // that once such an instance exists, the SesameManager and RepositoryConnection
    // objects are initialized too ... until shutdown is called or something
    // unexpected happens (e.g. a connection to a HTTP repository is lost).

    /**
     * Create an unmanaged repository in the given data directory from the
     * given configuration data string.
     * 
     * @param dataDir
     * @param configData
     */
    public static OntologyServiceImplSesame createForRepository(AbstractOntologyImplSesame ontology, File dataDir,
            String configData) {
        SesameManager sesameManager = new SesameManager();
        sesameManager.createUnmanagedRepository(dataDir, configData);
        RepositoryConnection rc = sesameManager.getRepositoryConnection();
        try {
            rc.setAutoCommit(true);
        } catch (RepositoryException ex) {
            sesameManager.disconnect();
            throw new GateOntologyException("Could not set autocommit");
        }
        OntologyServiceImplSesame osi = new OntologyServiceImplSesame(ontology, sesameManager);
        osi.init();
        return osi;
    }

    /**
     * Create a managed repository at the given repository location, which could
     * either be a directory or a sesame server, with the given repository ID
     * from theconfiguration file at the given URL. The configuration fiel should
     * be a configuration file template with the template variable "id" which
     * will be replaced with the repository ID.
     * 
     * @param repoLoc
     * @param repositoryID
     * @param configFileURL
     */
    static OntologyServiceImplSesame createForManagedRepository(AbstractOntologyImplSesame ontology, URL repoLoc,
            String repositoryID, URL configFileURL) {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("id", repositoryID);
        SesameManager sesameManager = new SesameManager();
        String configData;
        try {
            InputStream is = configFileURL.openStream();
            configData = IOUtils.toString(is);
            IOUtils.closeQuietly(is);
        } catch (IOException ex) {
            throw new GateOntologyException("Cannot read config file " + configFileURL, ex);
        }
        sesameManager.connectToLocation(repoLoc);
        Set<String> repositories = sesameManager.getRepositories();
        if (repositories.contains(repositoryID)) {
            sesameManager.disconnect();
            throw new GateOntologyException("Repository with this ID already exists: " + repositoryID);
        }
        configData = SesameManager.substituteConfigTemplate(configData, map);
        //logger.debug("Config file is: \n" + configData);
        sesameManager.createRepository(configData);
        RepositoryConnection repositoryConnection = sesameManager.getRepositoryConnection();
        try {
            repositoryConnection.setAutoCommit(true);
        } catch (RepositoryException ex) {
            sesameManager.disconnect();
            throw new GateOntologyException("Could not set autocommit");
        }
        OntologyServiceImplSesame osi = new OntologyServiceImplSesame(ontology, sesameManager);
        osi.init();
        return osi;
    }

    /**
     * Connect to the repository with the given repository ID
     * at the given repository URL location, which could
     * be either a directory or a sesame server.
     *
     * @param ontology 
     * @param repositoryURL
     * @param repositoryID
     * @return  
     */
    public static OntologyServiceImplSesame createForRepositoryConnection(AbstractOntologyImplSesame ontology,
            URL repositoryURL, String repositoryID) {
        SesameManager sesameManager = new SesameManager();
        sesameManager.connectToRepository(repositoryURL, repositoryID);
        RepositoryConnection repositoryConnection = sesameManager.getRepositoryConnection();
        try {
            repositoryConnection.setAutoCommit(true);
        } catch (RepositoryException ex) {
            sesameManager.disconnect();
            throw new GateOntologyException("Could not set autocommit");
        }
        OntologyServiceImplSesame osi = new OntologyServiceImplSesame(ontology, sesameManager);
        osi.init();
        return osi;
    }

    /**
     * Initialize the ontology service. This methods prepares the ontology service
     * for use. It must be called right after the repository has been created
     * or has been connected to.
     */
    private void init() {
        // once we have created a repository or connected to a repository,
        // do all the init stuff for which we need the repository
        // connection: mainly prepare queries.
        initQueries("default");
    }

    /**
     * Shutdown the repository. This must be done before the the object of this
     * class is destroyed!
     */
    public void shutdown() {
        sesameManager.disconnect();
    }

    public OntologyTripleStore getOntologyTripleStore() {
        return ontologyTripleStore;
    }

    public SesameManager getSesameManager() {
        return sesameManager;
    }

    // ***************************************************************************
    // *** METHODS RELATED TO THE ONTOLOGY AS A WHOLE
    // ***************************************************************************

    // *************** IMPORT / EXPORT *******************************************

    // TODO: Sesame does not support getting the base uri or default namespace
    // as of version 2.3.1 so we have no chance to figure those out ...
    // This was for debugging ...
    //
    // Latest news is that in version 2.3.3 there will be support to get
    // the default namespace after loading, but not to get the base uri,
    // if there is a base URI declared in the RDF element.
    // Also the code for version 2.3.3 shows that a repository's default namespace
    // will be set from the first file loaded and after that, never overwritten
    // by a loaded file.
    // In order to get this right in the future we need to define more precisely
    // the semantics of ontology.setDefaultNamespace and probably also change the
    // semantics:
    //  - should setting the default namespace actually set it in the repository?
    //    pro: more consistent with expectation
    //    con: not possible if repository is read-only but even for read-only
    //      repositories, we want the functionality of what setDefaultNamespace
    //      was used so far: provide a default URI prefix.
    //  - related: should what we set be saved? If we only set the default
    //    namespace for the writer, we can do this for read-only repositories.
    //  - compromise: set it for the repository but catch the exception if
    //    the repository is R/O and just issue a warning. Always handle for the
    //    writer.
    // Also, if a repository is read, we should set the Ontology default namespace
    // from the definition in the file (but only from the first file). So
    // we could always set our ontology default NS after reading from the
    // repository. Except if the user has already *set* the default namespace.
    // In that case, the reverse should be done: after reading, the repositories
    // DNS gets overwritten by the user's.
    // The Base URI optionally passed as a parameter should be used, if given
    //   - as a parameter for the Sesame file reader
    //   - if neither the user nor the file has a DNS to set the DNS
    // Eventually we might want to make general NS handling available in the
    // Ontology interface by adding a createURIForName(nsabbrev,name) and a
    // OURI.getResourceName(nsabbrev) method?
    // Also review the documentation and comments (and code) to distinguish
    // properly between default namespace and base URI!!
    /*
     //  for later/debugging
    private void handleDefaultNSafterLoad() {
      if(defaultnshasbeensetbyuser) {
        // check if this would be necessary at all if we already set
        // the DNS on the repository?
        try {
    repositoryConnection.setNamesapce("",ontology.getDefaultNamespace())
        } catch(repoisreadonly) {
    logwarning
        }
      } else {
        repoDNS = repositoryConnection.getNamespace("");
        // not the normal method invoked by the user which sets the repo DNS too
        ontology.justSetTgheNamespace(repoDNS);
      }
     * 
     */

    public void readOntologyData(File selectedFile, String baseURI, OntologyFormat ontologyFormat,
            boolean asImport) {
        org.openrdf.model.URI contextURI;
        if (!asImport) {
            contextURI = getContextURI();
        } else {
            contextURI = IMPORT_CONTEXT_URI;
        }
        try {
            repositoryConnection.add(selectedFile, baseURI, ontologyFormat2RDFFormat(ontologyFormat), contextURI);
        } catch (Exception ex) {
            throw new GateOntologyException(
                    "Could not load/import ontology data from file " + selectedFile.getAbsolutePath(), ex);
        }
    }

    public void readOntologyData(InputStream is, String baseURI, OntologyFormat ontologyFormat, boolean asImport) {
        org.openrdf.model.URI contextURI;
        if (!asImport) {
            contextURI = getContextURI();
        } else {
            contextURI = IMPORT_CONTEXT_URI;
        }
        try {
            repositoryConnection.add(is, baseURI, ontologyFormat2RDFFormat(ontologyFormat), contextURI);
        } catch (Exception ex) {
            throw new GateOntologyException("Could not load/import ontology data from input stream ", ex);
        }
    }

    public void readOntologyData(Reader ir, String baseURI, OntologyFormat ontologyFormat, boolean asImport) {
        org.openrdf.model.URI contextURI;
        if (!asImport) {
            contextURI = getContextURI();
        } else {
            contextURI = IMPORT_CONTEXT_URI;
        }
        try {
            repositoryConnection.add(ir, baseURI, ontologyFormat2RDFFormat(ontologyFormat), contextURI);
        } catch (Exception ex) {
            throw new GateOntologyException("Could not load/import ontology data from reader ", ex);
        }
    }

    public void writeOntologyData(Writer out, OntologyFormat ontologyFormat, boolean includeImports) {
        RDFWriter writer = getRDFWriter4Format(out, ontologyFormat);
        try {
            if (includeImports) {
                repositoryConnection.export(writer, getContextURI(), IMPORT_CONTEXT_URI);
            } else {
                repositoryConnection.export(writer, getContextURI());
            }
        } catch (Exception ex) {
            throw new GateOntologyException("Could not write ontology data", ex);
        }
    }

    public void writeOntologyData(OutputStream out, OntologyFormat ontologyFormat, boolean includeImports) {
        RDFWriter writer = getRDFWriter4Format(out, ontologyFormat);
        try {
            if (includeImports) {
                repositoryConnection.export(writer, getContextURI(), IMPORT_CONTEXT_URI);
            } else {
                repositoryConnection.export(writer, getContextURI());
            }
        } catch (Exception ex) {
            throw new GateOntologyException("Could not write ontology data", ex);
        }
    }

    public void loadSystemImport(File selectedFile, String baseURI, OntologyFormat ontologyFormat) {
        org.openrdf.model.URI contextURI = SYSTEM_IMPORT_CONTEXT_URI;
        try {
            repositoryConnection.add(selectedFile, baseURI, ontologyFormat2RDFFormat(ontologyFormat), contextURI);
        } catch (Exception ex) {
            throw new GateOntologyException("Could not import system file " + selectedFile.getAbsolutePath(), ex);
        }
    }

    // *************** OTHER METHODS RELATED TO THE ONTOLOGY AS A WHOLE **********

    /**
     * The method removes all data from the ontology, including imports and
     * the system imports.
     */
    public void cleanOntology() throws GateOntologyException {
        try {
            repositoryConnection.clear();
        } catch (Exception sue) {
            throw new GateOntologyException("error while cleaning repository:", sue);
        }
    }

    /**
     * From all the data and imports so far loaded, gather the set of
     * all ontology import URIs.
     *
     * @return
     */
    public Set<String> getImportURIStrings() {
        Set<String> uris = new HashSet<String>();
        RepositoryResult<Statement> result;
        try {
            // TODO: should we remove "system" import URIs here?
            // I tend to not do this here, instead ignore them in the resolveImports
            // method ...
            result = repositoryConnection.getStatements(null, OWL.IMPORTS, null, false);
            while (result.hasNext()) {
                String v = result.next().getObject().stringValue();
                uris.add(v);
            }
        } catch (RepositoryException ex) {
            throw new GateOntologyException("Problem getting the import statements", ex);
        }
        return uris;
    }

    public Set<OURI> getOntologyURIs() {
        // apparently, this can return several ontology URIs, of which only
        // the one that is not object of an owl:priorVersion property is the
        // the one we want?

        // TODO: this just checks if the URI found is equal to one of the
        // import uri strings as present in the ontology, but does not check
        // against the actual import URI as it will be created from those
        // improt URI strings by replacing relative URI references.
        // Not sure how to really deal with this for now .... JP
        Set<OURI> theURIs = new HashSet<OURI>();

        Set<String> importURIs = getImportURIStrings();

        qp_getOntologyURIs.evaluate();
        while (qp_getOntologyURIs.hasNext()) {
            String someURI = qp_getOntologyURIs.nextFirstAsString();
            OURI u = new OURIImpl(someURI);
            if (!importURIs.contains(u.toString())) {
                theURIs.add(u);
            }
        }
        return theURIs;
    }

    /**
     * The method returns the version information of the repository.
     *
     * @return
     */
    public String getVersion() throws GateOntologyException {
        try {
            RepositoryResult<Statement> iter = repositoryConnection.getStatements(getResource(this.ontologyUrl),
                    makeSesameURI(OWL.VERSIONINFO.toString()), null, true);
            while (iter.hasNext()) {
                Statement stmt = iter.next();
                return stmt.getObject().toString();
            }
        } catch (Exception e) {
            throw new GateOntologyException("Problem getting the ontology version: ", e);
        }
        return null;
    }

    public void setOntologyURI(OURI theURI) {
        ontologyTripleStore.addTriple(theURI, ontology.OURI_RDF_TYPE, ontology.OURI_OWL_ONTOLOGY);
    }

    // ***************************************************************************
    // **** CLASS RELATED METHODS
    // ***************************************************************************
    /**
     * The method allows adding a class to repository.
     *
     * @param classURI
     */
    public void addClass(OURI classURI) {
        ontologyTripleStore.addTriple(classURI, ontology.OURI_RDF_TYPE, ontology.OURI_OWL_CLASS);
    }

    public void addRestriction(OBNodeID classURI) {
        ontologyTripleStore.addTriple(classURI, ontology.OURI_RDF_TYPE, ontology.OURI_OWL_RESTRICTION);
    }

    /**
     * Given a class to delete, it removes it from the repository.
     *
     * @param classURI
     * @param removeSubTree
     *          - if set to true, removes all its subclasses and instances as
     *          well, otherwise shifts all subclasses and instances to its parent
     *          node
     * @return a list of other resources, which got removed as a result of this
     *         deletion
     */
    // TODO: !!! "its instances:" what if instances also belong to other classes
    // that do not get removed?
    // TODO: subclasses: what if a subclass also is a subclass of some other
    // class that does not get removed?
    // test/clarify in API!
    // TODO: !!! This is a complex method, add a tester for it and
    // work on getting rid of all string methods
    public String[] removeClass(String classURI, boolean removeSubTree) throws GateOntologyException {
        logger.debug("removeClass");
        //System.out.println("removeClass: "+classURI);
        ResourceInfo[] superClasses = getSuperClasses(classURI, OConstants.Closure.DIRECT_CLOSURE);

        List<String> deletedResources = new ArrayList<String>();
        // TODO: JP !!!! need a different way to check for explicit !!
        //if(removeUUUStatement(classURI, RDF.TYPE.toString(), null) == 0) {
        //  throw new GateOntologyException(classURI + " is not an explicit resource");
        //}
        //else {
        //  currentEventsLog.addEvent(new OEvent(classURI, RDF.TYPE.toString(), null, false));
        //  deletedResources.add(classURI);
        //}
        // TODO: !! replace !!
        removeUUUStatement(classURI, RDF.TYPE.toString(), null);
        deletedResources.add(classURI);

        try {
            startTransaction(null);
            repositoryConnection.remove(getResource(classURI), makeSesameURI(RDFS.SUBCLASSOF.toString()), null);
            endTransaction(null);
        } catch (Exception sue) {
            throw new GateOntologyException("error while removing a class:" + classURI, sue);
        }

        // this should happen only if removeSubTree is set to true
        if (removeSubTree) {
            //ResourceInfo[] subClasses =
            //    getSubClassesOld(classURI, OConstants.Closure.DIRECT_CLOSURE);
            Set<OClass> subClasses = getSubClasses(string2ONodeID(classURI), OConstants.Closure.DIRECT_CLOSURE);
            //for (int i = 0; i < subClasses.length; i++) {
            for (OClass subclass : subClasses) {
                String[] removedResources =
                        //removeClass(subClasses[i].getUri(), true);
                        removeClass(subclass.getONodeID().toString(), true);
                deletedResources.addAll(Arrays.asList(removedResources));
            }
            ClosableIterator<OInstance> instIt = getInstancesIterator(string2ONodeID(classURI),
                    Closure.DIRECT_CLOSURE);
            while (instIt.hasNext()) {
                String[] removedResources = removeIndividual(instIt.next().toString());
                deletedResources.addAll(Arrays.asList(removedResources));
            }
        } else {
            //ResourceInfo[] subClasses =
            //    getSubClassesOld(classURI, OConstants.Closure.DIRECT_CLOSURE);
            Set<OClass> subClasses = getSubClasses(string2ONodeID(classURI), OConstants.Closure.DIRECT_CLOSURE);
            //for (int i = 0; i < subClasses.length; i++) {
            for (OClass subclass : subClasses) {
                //removeSubClass(classURI, subClasses[i].getUri());
                removeSubClass(classURI, subclass.getONodeID().toString());
                for (int j = 0; j < superClasses.length; j++) {
                    //addSubClass(superClasses[j].getUri(), subClasses[i].getUri());
                    addSubClass(superClasses[j].getUri(), subclass.getONodeID().toString());
                }
            }
            // get all the direct instances of the class to be removed
            ClosableIterator<OInstance> instIt = getInstancesIterator(string2ONodeID(classURI),
                    Closure.DIRECT_CLOSURE);
            //for (int i = 0; i < individuals.length; i++) {
            while (instIt.hasNext()) {
                OInstance inst = instIt.next();
                // remove the triple that says that that instance is of type class
                ontologyTripleStore.removeTriple(inst.getONodeID(), ontology.createOURI(RDF.TYPE.toString()),
                        ontology.createOURI(classURI));
                //removeUUUStatement(instIt.next().toString(), RDF.TYPE.toString(), classURI);
                // instead add a triple for each superclass of class 
                for (int j = 0; j < superClasses.length; j++) {
                    //addUUUStatement(inst.toString(), RDF.TYPE.toString(), superClasses[j].getUri());
                    ontologyTripleStore.addTriple(inst.getONodeID(), ontology.createOURI(RDF.TYPE.toString()),
                            ontology.createOURI(superClasses[j].getUri()));
                }
            }
        }
        try {
            // The following deletes all the properties that have the deleted
            // class as either a domain or range.
            // TODO: is that the logical thing to do? How about just removing the
            // domain or range restriction? Especially if we do not remove the 
            // instance subtree, then we still can reasonably have relationships?
            startTransaction(null);
            RepositoryResult<Statement> iter = repositoryConnection.getStatements(null,
                    makeSesameURI(RDFS.DOMAIN.toString()), getResource(classURI), true);
            endTransaction(null);
            while (iter.hasNext()) {
                Statement stmt = iter.next();
                Resource resource = stmt.getSubject();
                String[] removedResources = removePropertyFromOntology(resource.toString(), removeSubTree);
                deletedResources.addAll(Arrays.asList(removedResources));
            }
            startTransaction(null);
            iter = repositoryConnection.getStatements(null, makeSesameURI(RDFS.RANGE.toString()),
                    getResource(classURI), true);
            endTransaction(null);
            while (iter.hasNext()) {
                Statement stmt = iter.next();
                Resource resource = stmt.getSubject();
                String[] removedResources = removePropertyFromOntology(resource.toString(), removeSubTree);
                deletedResources.addAll(Arrays.asList(removedResources));
            }
        } catch (Exception e) {
            throw new GateOntologyException(e);
        }

        // finaly remove all statements concerning this resource
        try {
            startTransaction(null);
            repositoryConnection.remove(getResource(classURI), null, null);
            if (!(getResource(classURI) instanceof BNode)) {
                repositoryConnection.remove((Resource) null, makeSesameURI(classURI), null);
            }
            repositoryConnection.remove((Resource) null, null, getResource(classURI));

            endTransaction(null);
        } catch (Exception sue) {
            throw new GateOntologyException("error while removing a class:" + classURI, sue);
        }

        Collections.reverse(deletedResources);
        //System.out.println("deletedResources is: "+deletedResources);
        return listToArray(deletedResources);
    }

    /**
     * The method returns if the current repository has a class with URI that
     * matches with the class parameter.
     *
     * @param classURI 
     * @return
     */
    public boolean hasClass(ONodeID classURI) {
        boolean hasOWLClass = ontologyTripleStore.hasTriple(classURI, ontology.OURI_RDF_TYPE,
                ontology.OURI_OWL_CLASS);
        if (!hasOWLClass) {
            boolean hasRDFSClass = ontologyTripleStore.hasTriple(classURI, ontology.OURI_RDF_TYPE,
                    ontology.OURI_RDFS_CLASS);
            return hasRDFSClass;
        } else {
            return true;
        }
    }

    public boolean containsURI(OURI theURI) {
        return ontologyTripleStore.hasTriple(theURI, null, (ONodeID) null)
                || ontologyTripleStore.hasTriple(null, theURI, (ONodeID) null)
                || ontologyTripleStore.hasTriple(null, null, theURI);
    }

    public Set<OClass> getClasses(boolean topOnly) {
        Set<OClass> theClasses = new HashSet<OClass>();
        ClosableIterator<OClass> ci = getClassesIterator(topOnly);
        while (ci.hasNext()) {
            theClasses.add(ci.next());
        }
        return theClasses;
    }

    public ClosableIterator<OClass> getClassesIterator(boolean top) {
        if (top) {
            return new UtilResourceQueryIterator<OClass>(this, qp_getClassesTopAll, OClass.class);
        } else {
            return new UtilResourceQueryIterator<OClass>(this, qp_getClassesAllAll, OClass.class);
        }
    }

    public Set<OClass> getClassesByName(String name) {
        String query;
        Set<OClass> classes = new HashSet<OClass>();

        UtilTupleQueryIterator q;
        String qs = qs_getClassesByNameNoW3.replaceAll("yyy1", "\"[/#]" + name + "\\$\"");
        q = new UtilTupleQueryIterator(sesameManager, qs, ql_getClassesByNameNoW3);
        while (q.hasNext()) {
            Vector<Value> tuple = q.nextAsValue();
            Value t1 = tuple.get(0);
            String uristring = ((org.openrdf.model.URI) t1).toString();
            OURI ourURI = ontology.createOURI(uristring);
            classes.add(new OClassImpl(ourURI, ontology, this));
        }
        q.close();
        return classes;
    }

    private OClass createRestrictionFromURI(String uriString, String bnodeID) {
        OBNodeID uri = new OBNodeIDImpl(bnodeID);
        return createRestrictionFromURI(uriString, uri);
    }

    private OClass createRestrictionFromURI(String uriString, ONodeID uri) {
        if (uriString.equals("http://www.w3.org/2002/07/owl#cardinality")) {
            return new CardinalityRestrictionImpl(uri, ontology, this);
        } else if (uriString.equals("http://www.w3.org/2002/07/owl#allValuesFrom")) {
            return new AllValuesFromRestrictionImpl(uri, ontology, this);
        } else if (uriString.equals("http://www.w3.org/2002/07/owl#minCardinality")) {
            return new MinCardinalityRestrictionImpl(uri, ontology, this);
        } else if (uriString.equals("http://www.w3.org/2002/07/owl#maxCardinality")) {
            return new MaxCardinalityRestrictionImpl(uri, ontology, this);
        } else if (uriString.equals("http://www.w3.org/2002/07/owl#someValuesFrom")) {
            return new SomeValuesFromRestrictionImpl(uri, ontology, this);
        } else if (uriString.equals("http://www.w3.org/2002/07/owl#hasValue")) {
            return new HasValueRestrictionImpl(uri, ontology, this);
        } else if (uriString.equals("http://www.w3.org/2002/07/owl#oneOf")) {
            System.out.println("Warning: restriction oneOf not yet implemented in createRestrictionFromURI" + uri);
            return new AnonymousClassImpl(uri, ontology, this);
        }
        throw new GateOntologyException("createRestrictionFromURI not for this yet: " + uriString);
    }

    /**
     * Returns if the given class is a topOnly class.
     *
     * @param classURI
     * @return
     */
    public boolean isTopClass(String classURI) {
        // TODO: maybe this can be done more efficiently?
        return getSuperClasses(classURI, OConstants.Closure.DIRECT_CLOSURE).length == 0;
    }

    /**
     * Returns whether the theSuperClass is indeed a super class of the
     * theSubClassURI.
     * 
     * @param theSuperClassURI
     * @param theSubClassURI
     * @param direct
     * @return
     */
    public boolean isSuperClassOf(String theSuperClassURI, String theSubClassURI, Closure direct) {
        Resource r = getResource(theSubClassURI);
        String queryRep = string2Turtle(theSubClassURI);

        String query = "";
        query = "Select distinct SUPER FROM {" + queryRep + "} rdfs:subClassOf {SUPER}" + " WHERE SUPER!="
                + queryRep + " AND SUPER != ALL ( " + " select distinct B FROM {B} owl:equivalentClass {" + queryRep
                + "} )";

        List<String> list = new ArrayList<String>();
        addSerqlQueryResultToCollection(query, list);

        if (direct == OConstants.Closure.DIRECT_CLOSURE) {
            Set<String> toDelete = new HashSet<String>();
            for (int i = 0; i < list.size(); i++) {
                String string = list.get(i);
                if (toDelete.contains(string)) {
                    continue;
                }
                queryRep = string2Turtle(string);

                query = "Select distinct SUPER FROM {" + queryRep + "} rdfs:subClassOf {SUPER}" + " WHERE SUPER!="
                        + queryRep + " AND SUPER != ALL ( " + " select distinct B FROM {B} owl:equivalentClass {"
                        + queryRep + "})";

                addSerqlQueryResultToCollection(query, toDelete);

            }
            list.removeAll(toDelete);
        }

        // here if the list contains the uri of the super class
        // we return true;
        return list.contains(theSuperClassURI);
    }

    protected void addSerqlQueryResultToCollection(String query, Collection<String> coll) {
        addSerqlQueryResultToCollection(query, coll, false);
    }

    protected void addSerqlQueryResultToCollection(String query, Collection<String> coll, boolean internIt) {
        UtilTupleQueryIterator result = new UtilTupleQueryIterator(sesameManager, query, QueryLanguage.SERQL);
        //UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            if (internIt) {
                coll.add(result.nextFirstAsString().intern());
            } else {
                String tmp = result.nextFirstAsString();
                //System.out.println("Adding to collection: "+tmp);
                coll.add(tmp);
            }
        }
        result.close();
    }

    protected void addSerqlQueryResultValuesToCollection(String query, Collection<Value> coll) {
        UtilTupleQueryIterator result = new UtilTupleQueryIterator(sesameManager, query, QueryLanguage.SERQL);
        //UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            coll.add(result.nextFirstAsValue());
        }
        result.close();
    }

    protected boolean hasSerqlQueryResultRows(String query) {
        //UtilTupleQueryIterator result = performSerqlQuery(query);
        UtilTupleQueryIterator result = new UtilTupleQueryIterator(sesameManager, query, QueryLanguage.SERQL);
        boolean hasResult = result.hasNext();
        result.close();
        return hasResult;
    }

    protected UtilTupleQueryIterator performSerqlQuery(String serqlQuery) {
        return new UtilTupleQueryIterator(sesameManager, serqlQuery, QueryLanguage.SERQL);
    }

    /**
     * Returns whether the theSubClass is indeed a sub class of the
     * theSuperClassURI.
     * 
     * @param theSuperClassURI
     * @param theSubClassURI
     * @param direct
     * @return
     */
    public boolean isSubClassOf(String theSuperClassURI, String theSubClassURI, Closure direct) {
        return isSuperClassOf(theSuperClassURI, theSubClassURI, direct);
    }

    /**
     * Given a property URI, this method returns an object of Property
     * 
     * @param repositoryID
     * @param thePropertyURI
     * @return
     * @throws GateOntologyException
     */
    public Property getPropertyFromOntology(String thePropertyURI) {
        // here we need to check which type of property it is
        return createPropertyObject(thePropertyURI);
    }

    /**
     * Checks whether the two classes defined as same in the ontology.
     * 
     * @param theClassURI1
     * @param theClassURI2
     * @return
     * @throws Exception
     */
    public boolean isEquivalentClassAs(ONodeID theClassURI1, ONodeID theClassURI2) {
        return ontologyTripleStore.hasTriple(theClassURI1, ontology.OURI_OWL_EQUIVALENTCLASS, theClassURI2);
    }

    // *******************************************************************
    // property methods
    // *******************************************************************
    // **************
    // Annotation Property
    // ************
    /**
     * Creates a new AnnotationProperty.
     * 
     * @param aPropertyURI
     *          URI of the property to be added into the ontology. Done
     */
    public void addAnnotationProperty(OURI aPropertyURI) throws GateOntologyException {
        //addUUUStatement(aPropertyURI, RDF.TYPE.toString(), OWL.ANNOTATIONPROPERTY.toString());
        ontologyTripleStore.addTriple(aPropertyURI, ontology.OURI_RDF_TYPE, ontology.OURI_OWL_ANNOTATIONPROPERTY);
    }

    /**
     * This method returns a set of all properties where the current resource has
     * been specified as one of the domain resources. Please note that this method
     * is different from the getAllSetProperties() method which returns a set of
     * properties set on the resource. For each property in the ontology, this
     * method checks if the current resource is valid domain. If so, the property
     * is said to be applicable, and otherwise not..
     * 
     * @param theResourceURI 
     * @return
     */
    public Property[] getPropertiesWithResourceAsDomain(String theResourceURI) {

        List<Property> list = new ArrayList<Property>();

        HashSet<String> toCheck = new HashSet<String>();
        try {
            if (repositoryConnection.hasStatement(string2SesameResource(theResourceURI), RDF.TYPE, OWL.CLASS, true // TODO: include inferred: true or false here?
            )) {

                String queryRep1 = string2Turtle(theResourceURI);
                String queryRep = "{" + queryRep1 + "}";

                String query = "Select distinct SUPER FROM " + queryRep + " rdfs:subClassOf {SUPER}"
                        + " WHERE SUPER!=" + queryRep1 + " AND SUPER != ALL ( "
                        + " select distinct B FROM {B} owl:equivalentClass " + queryRep + ")";

                addSerqlQueryResultToCollection(query, toCheck);

                toCheck.add(theResourceURI);
            } else if (repositoryConnection.hasStatement(string2SesameResource(theResourceURI), RDF.TYPE,
                    RDF.PROPERTY, true)) {

                String queryRep1 = string2Turtle(theResourceURI);
                String queryRep = "{" + queryRep1 + "}";

                String query = "Select distinct SUPER FROM " + queryRep + " rdfs:subPropertyOf {SUPER}"
                        + " WHERE SUPER!=" + queryRep1 + " AND SUPER != ALL ( "
                        + " select distinct B FROM {B} owl:equivalentProperty " + queryRep + ")";

                addSerqlQueryResultToCollection(query, toCheck);

                toCheck.add(theResourceURI);
            } else {
                // it is an instance
                String queryRep1 = string2Turtle(theResourceURI);
                String query = "Select DISTINCT B from {X} rdf:type {B} WHERE X=" + queryRep1;

                addSerqlQueryResultToCollection(query, toCheck, true);

            }
        } catch (Exception e) {
            throw new GateOntologyException("Error getting statements", e);
        }

        String query = "Select distinct X FROM {X} rdf:type {<" + OWL.ANNOTATIONPROPERTY + ">}";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            String anAnnProp = result.nextFirstAsString();
            list.add(new Property(OConstants.ANNOTATION_PROPERTY, anAnnProp));
        }
        result.close();

        boolean allowSystemStatements = this.returnSystemStatements;
        this.returnSystemStatements = true;
        Property[] props = listToPropertyArray(list);
        this.returnSystemStatements = allowSystemStatements;

        // now we obtain all datatype properties
        list = new ArrayList<Property>();
        query = "Select X FROM {X} rdf:type {<" + OWL.DATATYPEPROPERTY + ">}";

        //iter = performQuery(query);
        result = performSerqlQuery(query);
        while (result.hasNext()) {
            String anAnnProp = result.nextFirstAsString();
            // for each property we obtain its domain and search for the
            // resourceURI in it
            query = "select distinct Y from {<" + anAnnProp + ">} rdfs:domain {Y}";
            Set<String> set = new HashSet<String>();
            addSerqlQueryResultToCollection(query, set, true);

            if (set.isEmpty()) {
                list.add(new Property(OConstants.DATATYPE_PROPERTY, anAnnProp.toString()));
            }

            set = new HashSet<String>(reduceToMostSpecificClasses(set));

            set.retainAll(toCheck);
            if (!set.isEmpty()) {
                list.add(new Property(OConstants.DATATYPE_PROPERTY, anAnnProp.toString()));
            }
        }
        result.close();

        query = "Select X FROM {X} rdf:type {<" + OWL.OBJECTPROPERTY + ">}";

        result = performSerqlQuery(query);
        while (result.hasNext()) {
            String anAnnProp = result.nextFirstAsString();
            OURI annOURI = ontology.createOURI(anAnnProp);
            // for each property we obtain its domain and search for the
            // resourceURI in it
            query = "select distinct Y from {<" + anAnnProp + ">} rdfs:domain {Y}";
            Set<String> set = new HashSet<String>();
            addSerqlQueryResultToCollection(query, set, true);

            set = new HashSet<String>(reduceToMostSpecificClasses(set));

            byte type = OConstants.OBJECT_PROPERTY;

            if (set.isEmpty()) {
                if (isSymmetricProperty(annOURI)) {
                    type = OConstants.SYMMETRIC_PROPERTY;
                } else if (isTransitiveProperty(annOURI)) {
                    type = OConstants.TRANSITIVE_PROPERTY;
                }

                list.add(new Property(type, anAnnProp));
                continue;
            }
            set.retainAll(toCheck);
            if (!set.isEmpty()) {
                if (isSymmetricProperty(annOURI)) {
                    type = OConstants.SYMMETRIC_PROPERTY;
                } else if (isTransitiveProperty(annOURI)) {
                    type = OConstants.TRANSITIVE_PROPERTY;
                }

                list.add(new Property(type, anAnnProp));
            }
        }
        result.close();
        Property[] props1 = listToPropertyArray(list);
        Property[] toProps = new Property[props.length + props1.length];
        for (int i = 0; i < props.length; i++) {
            toProps[i] = props[i];
        }

        for (int i = 0; i < props1.length; i++) {
            toProps[props.length + i] = props1[i];
        }

        return toProps;

    }

    /**
     * This method returns a set of all properties where the current resource has
     * been specified as one of the range resources. Please note that this method
     * is different from the getAllSetProperties() method which returns a set of
     * properties set on the resource. For each property in the ontology, this
     * method checks if the current resource is valid range. If so, the property
     * is said to be applicable, and otherwise not.
     * 
     * @return
     */
    public Property[] getPropertiesWithResourceAsRange(String theResourceURI) {
        List<Property> list = new ArrayList<Property>();

        HashSet<String> toCheck = new HashSet<String>();
        try {
            if (repositoryConnection.hasStatement(getResource(theResourceURI), makeSesameURI(RDF.TYPE.toString()),
                    getResource(OWL.CLASS.toString()), true)) {

                String queryRep = string2Turtle(theResourceURI);
                String query = "Select distinct SUPER FROM {" + queryRep + "} rdfs:subClassOf {SUPER}"
                        + " WHERE SUPER!=" + queryRep + " AND SUPER != ALL ( "
                        + " select distinct B FROM {B} owl:equivalentClass {" + queryRep + "} )";

                addSerqlQueryResultToCollection(query, toCheck);

                toCheck.add(theResourceURI);
            } else if (repositoryConnection.hasStatement(getResource(theResourceURI),
                    makeSesameURI(RDF.TYPE.toString()), getResource(RDF.PROPERTY.toString()), true)) {

                String queryRep = string2Turtle(theResourceURI);
                String query = "Select distinct SUPER FROM {" + queryRep + "} rdfs:subPropertyOf {SUPER}"
                        + " WHERE SUPER!=" + queryRep + " AND SUPER != ALL ( "
                        + " select distinct B FROM {B} owl:equivalentProperty {" + queryRep + "})";

                addSerqlQueryResultToCollection(query, toCheck);

                toCheck.add(theResourceURI);
            } else {
                // it is an instance
                String query = "Select DISTINCT B from {X} rdf:type {B} WHERE X=<" + theResourceURI + ">";

                addSerqlQueryResultToCollection(query, toCheck, true);
            }
        } catch (Exception e) {
            throw new GateOntologyException("Could not get statements", e);
        }

        String query = "Select distinct X FROM {X} rdf:type {<" + OWL.ANNOTATIONPROPERTY + ">}";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            String anAnnProp = result.nextFirstAsString();
            list.add(new Property(OConstants.ANNOTATION_PROPERTY, anAnnProp));
        }
        result.close();

        boolean allowSystemStatements = this.returnSystemStatements;
        this.returnSystemStatements = true;
        Property[] props = listToPropertyArray(list);
        this.returnSystemStatements = allowSystemStatements;

        // now we obtain all datatype properties
        list = new ArrayList<Property>();
        query = "Select X FROM {X} rdf:type {<" + OWL.OBJECTPROPERTY + ">}";

        result = performSerqlQuery(query);
        while (result.hasNext()) {
            String anAnnProp = result.nextFirstAsString();
            OURI annOURI = ontology.createOURI(anAnnProp);
            // for each property we obtain its domain and search for the
            // resourceURI in it
            query = "select distinct Y from {<" + anAnnProp + ">} rdfs:range {Y}";
            Set<String> set = new HashSet<String>();
            addSerqlQueryResultToCollection(query, set, true);

            set = new HashSet<String>(reduceToMostSpecificClasses(set));

            byte type = OConstants.OBJECT_PROPERTY;

            if (set.isEmpty()) {
                if (isSymmetricProperty(annOURI)) {
                    type = OConstants.SYMMETRIC_PROPERTY;
                } else if (isTransitiveProperty(annOURI)) {
                    type = OConstants.TRANSITIVE_PROPERTY;
                }

                list.add(new Property(type, anAnnProp.toString()));
            }

            set.retainAll(toCheck);
            if (!set.isEmpty()) {
                if (isSymmetricProperty(annOURI)) {
                    type = OConstants.SYMMETRIC_PROPERTY;
                } else if (isTransitiveProperty(annOURI)) {
                    type = OConstants.TRANSITIVE_PROPERTY;
                }

                list.add(new Property(type, anAnnProp));
            }
        }
        result.close();
        Property[] props1 = listToPropertyArray(list);
        Property[] toProps = new Property[props.length + props1.length];
        for (int i = 0; i < props.length; i++) {
            toProps[i] = props[i];
        }

        for (int i = 0; i < props1.length; i++) {
            toProps[props.length + i] = props1[i];
        }

        return toProps;
    }

    /**
     * Gets the annotation properties set on the specified resource
     * 
     * @param theResourceURI
     * @return
     */
    public Property[] getAnnotationProperties(String theResourceURI) {
        List<Property> list = new ArrayList<Property>();

        String queryRep = string2Turtle(theResourceURI);

        String query = "Select DISTINCT X FROM {X} rdf:type {<" + OWL.ANNOTATIONPROPERTY
                + ">} WHERE EXISTS (SELECT * FROM {" + queryRep + "} X {Z})";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            list.add(new Property(OConstants.ANNOTATION_PROPERTY, result.nextFirstAsString()));
        }
        result.close();
        boolean allowSystemStatements = this.returnSystemStatements;
        this.returnSystemStatements = true;
        Property[] props = listToPropertyArray(list);
        this.returnSystemStatements = allowSystemStatements;
        return props;
    }

    /**
     * Gets the RDF properties set on the specified resource
     * 
     * @param theResourceURI
     * @return
     */
    public Property[] getRDFProperties(String theResourceURI) {
        List<Property> list = new ArrayList<Property>();

        String queryRep = string2Turtle(theResourceURI);
        String query = "Select distinct X FROM {X} rdf:type {<" + RDF.PROPERTY.toString()
                + ">} WHERE EXISTS (SELECT * FROM {" + queryRep + "} X {Z})";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            LiteralOrONodeID tmp = result.nextFirst();
            OURI propuri = (OURI) tmp.getONodeID();
            if (isAnnotationProperty(propuri) || isDatatypeProperty(propuri) || isObjectProperty(propuri)
                    || isTransitiveProperty(propuri) || isSymmetricProperty(propuri)) {
                continue;
            }
            list.add(new Property(OConstants.RDF_PROPERTY, propuri.toString()));
        }
        result.close();
        return listToPropertyArray(list);
    }

    /**
     * Gets the datatype properties set on the specified resource
     * 
     * @param theResourceURI
     * @return
     */
    public Property[] getDatatypeProperties(String theResourceURI) {
        List<Property> list = new ArrayList<Property>();
        String queryRep = string2Turtle(theResourceURI);
        String query = "Select distinct X FROM {X} rdf:type {<" + OWL.DATATYPEPROPERTY
                + ">} WHERE EXISTS (SELECT * FROM {" + queryRep + "} X {Z})";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            String anAnnProp = result.nextFirstAsString();
            list.add(new Property(OConstants.DATATYPE_PROPERTY, anAnnProp));
        }
        result.close();
        return listToPropertyArray(list);
    }

    /**
     * Gets the object properties set on the specified resource
     * 
     * @param theResourceURI
     * @return
     */
    public Property[] getObjectProperties(String theResourceURI) {
        List<Property> list = new ArrayList<Property>();
        String queryRep = string2Turtle(theResourceURI);
        String query = "Select distinct X FROM {X} rdf:type {<" + OWL.OBJECTPROPERTY
                + ">} WHERE EXISTS (SELECT * FROM {" + queryRep + "} X {Z})";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            String anAnnProp = result.nextFirstAsString();
            list.add(new Property(OConstants.OBJECT_PROPERTY, anAnnProp));
        }
        result.close();
        return listToPropertyArray(list);
    }

    /**
     * Gets the transitive properties set on the specified resource
     * 
     * @param theResourceURI
     * @return
     */
    public Property[] getTransitiveProperties(String theResourceURI) {
        List<Property> list = new ArrayList<Property>();
        String queryRep = string2Turtle(theResourceURI);
        String query = "Select distinct X FROM {X} rdf:type {<" + OWL.TRANSITIVEPROPERTY
                + ">} WHERE EXISTS (SELECT * FROM {" + queryRep + "} X {Z})";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            String anAnnProp = result.nextFirstAsString();
            list.add(new Property(OConstants.TRANSITIVE_PROPERTY, anAnnProp));
        }
        result.close();
        return listToPropertyArray(list);
    }

    /**
     * Gets the symmetric properties set on the specified resource
     * 
     * @param theResourceURI
     * @return
     */
    public Property[] getSymmetricProperties(String theResourceURI) {
        List<Property> list = new ArrayList<Property>();
        String queryRep = string2Turtle(theResourceURI);
        String query = "Select distinct X FROM {X} rdf:type {<" + OWL.SYMMETRICPROPERTY
                + ">} WHERE EXISTS (SELECT * FROM {" + queryRep + "} X {Z})";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            String anAnnProp = result.nextFirstAsString();
            list.add(new Property(OConstants.SYMMETRIC_PROPERTY, anAnnProp));
        }
        result.close();
        return listToPropertyArray(list);
    }

    /**
     * returns if the given property is an Annotation property
     * 
     * @param aPropertyURI
     * @return Done
     */
    public boolean isAnnotationProperty(OURI aPropertyURI) {
        return ontologyTripleStore.hasTriple(aPropertyURI, ontology.OURI_RDF_TYPE,
                ontology.OURI_OWL_ANNOTATIONPROPERTY);
    }

    /**
     * Adds a new annotation property value and specifies the language.
     * 
     * @param value
     *          the value containing some value
     */
    public void addAnnotationPropertyValue(ONodeID theResourceURI, OURI theAnnotationPropertyURI, String value,
            String language) {
        // isAnnotationProperty also checks for the correct repository so no
        // need to give a call to it
        if (!isAnnotationProperty(theAnnotationPropertyURI)) {
            throw new GateOntologyException(
                    "No annotation property found with the URI :" + theAnnotationPropertyURI);
        }
        // TODO: !! replace !!
        ontologyTripleStore.addTriple(theResourceURI, theAnnotationPropertyURI,
                new gate.creole.ontology.Literal(value, sesameManager.lang2locale(language)));
    }

    /**
     * Gets the list of annotation property values
     * 
     * @param theResourceURI
     * @param theAnnotationPropertyURI
     * @return
     */
    // TODO: make sure all values for annotation properties that are not literals
    // are filtered out and ignored.
    public List<gate.creole.ontology.Literal> getAnnotationPropertyValues(ONodeID theResourceURI,
            OURI theAnnotationPropertyURI) {
        // isAnnotationProperty also checks for the correct repository so no
        // need to give a call to it
        if (!isAnnotationProperty(theAnnotationPropertyURI)) {
            throw new GateOntologyException(
                    "No annotation property found with the URI :" + theAnnotationPropertyURI);
        }

        //Resource r2 = getResource(theResourceURI);
        //String queryRep21 = "<" + theResourceURI + ">";
        //if (r2 instanceof BNode) {
        //  queryRep21 = "_:" + theResourceURI;
        //}
        String queryRep21 = theResourceURI.toTurtle();

        List<gate.creole.ontology.Literal> list = new ArrayList<gate.creole.ontology.Literal>();
        String query = "Select DISTINCT Y from {X} <" + theAnnotationPropertyURI + "> {Y} WHERE X=" + queryRep21
                + " AND isLiteral(Y)";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            LiteralOrONodeID theValue = result.nextFirst();
            if (theValue.isLiteral()) {
                gate.creole.ontology.Literal literal = theValue.getLiteral();
                list.add(literal);
            }
        }
        return list;
    }

    /**
     * For the current resource, the method removes the given literal for the
     * given property.
     * 
     * @param theResourceURI 
     * @param theAnnotationPropertyURI 
     * @param value 
     * @param language  
     */
    public void removeAnnotationPropertyValue(ONodeID theResourceURI, OURI theAnnotationPropertyURI,
            gate.creole.ontology.Literal value) {
        if (!isAnnotationProperty(theAnnotationPropertyURI)) {
            throw new GateOntologyException(
                    "No annotation property found with the URI :" + theAnnotationPropertyURI);
        }
        ontologyTripleStore.removeTriple(theResourceURI, theAnnotationPropertyURI, value);
    }

    /**
     * Removes all values for a named property.
     * 
     * @param theResourceURI 
     * @param theAnnotationPropertyURI 
     */
    public void removeAnnotationPropertyValues(ONodeID theResourceURI, OURI theAnnotationPropertyURI) {
        if (!isAnnotationProperty(theAnnotationPropertyURI)) {
            throw new GateOntologyException(
                    "No annotation property found with the URI :" + theAnnotationPropertyURI);
        }
        ontologyTripleStore.removeTriple(theResourceURI, theAnnotationPropertyURI, (ONodeID) null);
    }

    // **************
    // RDFProperties
    // *************
    /**
     * The method adds a generic property specifiying domain and range for the
     * same. All classes specified in domain and range must exist.
     * 
     * @param aPropertyURI
     * @param domainClassesURIs
     * @param rangeClassesTypes
     *          Done
     */
    public void addRDFProperty(OURI aPropertyURI, Set<OResource> domain, Set<OResource> range)
            throws GateOntologyException {
        ontologyTripleStore.addTriple(aPropertyURI, ontology.OURI_RDF_TYPE, ontology.OURI_RDF_PROPERTY);

        if (domain != null) {
            for (OResource d : domain) {
                ontologyTripleStore.addTriple(aPropertyURI, ontology.OURI_RDFS_DOMAIN, d.getONodeID());
            }
        }
        if (range != null) {
            for (OResource r : range) {
                ontologyTripleStore.addTriple(aPropertyURI, ontology.OURI_RDFS_RANGE, r.getONodeID());
            }
        }
    }

    /**
     * returns if the given property is an RDF property
     * 
     * @param aPropertyURI
     * @return Done
     */
    public boolean isRDFProperty(OURI aPropertyURI) {
        boolean found = isAnnotationProperty(aPropertyURI) || isDatatypeProperty(aPropertyURI)
                || isObjectProperty(aPropertyURI) || isTransitiveProperty(aPropertyURI)
                || isSymmetricProperty(aPropertyURI);
        if (!found) {
            return ontologyTripleStore.hasAssertedTriple(aPropertyURI, ontology.OURI_RDF_TYPE,
                    ontology.OURI_RDF_PROPERTY);
        } else {
            return false;
        }
    }

    // **************
    // Datatype Properties
    // *************
    /**
     * The method adds a data type property specifiying domain and range for the
     * same. All classes specified in domain and range must exist.
     * 
     * @param aPropertyURI
     * @param domainClassesURIs
     * @param dataTypeURI
     *          Done
     */
    public void addDataTypeProperty(OURI aPropertyURI, Set<OClass> domain, String dataTypeURI) {
        ontologyTripleStore.addTriple(aPropertyURI, ontology.OURI_RDF_TYPE, ontology.OURI_OWL_DATATYPEPROPERTY);

        ontologyTripleStore.addTriple(aPropertyURI, ontology.OURI_RDFS_RANGE, ontology.createOURI(dataTypeURI));

        if (domain != null) {
            for (OClass d : domain) {
                ontologyTripleStore.addTriple(aPropertyURI, ontology.OURI_RDFS_DOMAIN, d.getONodeID());
            }
        }
    }

    /**
     * Returns the datatype uri specified for the given datatype property.
     * <p>
     * Note: this will return the first datatype URI found and ignore 
     * all others if there are more than one.
     * 
     * @param theDatatypePropertyURI
     * @return
     * @throws GateOntologyException
     */
    public String getDatatype(OURI theDatatypePropertyURI) {
        if (!isDatatypeProperty(theDatatypePropertyURI)) {
            throw new GateOntologyException("Invalid DatatypeProperty :" + theDatatypePropertyURI);
        }

        String query = "Select Z from {" + theDatatypePropertyURI.toTurtle() + "} rdfs:range" + " {Z}";
        UtilTupleQueryIterator result = performSerqlQuery(query);

        String toReturn = null;
        if (result.hasNext()) {
            toReturn = result.nextFirstAsString();
        }
        result.close();
        if (OntologyUtilities.getDataType(toReturn) != null) {
            return toReturn;
        }
        return "http://www.w3.org/2001/XMLSchema#string";
    }

    // **************
    // Symmetric Properties
    // *************
    /**
     * The method adds a symmetric property specifying domain and range for the
     * same. All classes specified in domain and range must exist.
     * 
     * @param aPropertyURI
     * @param domainAndRangeClasses 
     */
    public void addSymmetricProperty(OURI aPropertyURI, Set<OClass> domainAndRangeClasses) {
        logger.debug("addSymmetricProperty");
        ontologyTripleStore.addTriple(aPropertyURI, ontology.OURI_RDF_TYPE, ontology.OURI_OWL_SYMMETRICPROPERTY);
        if (domainAndRangeClasses != null) {
            for (OClass domainAndRangeClass : domainAndRangeClasses) {
                ontologyTripleStore.addTriple(aPropertyURI, ontology.OURI_RDFS_DOMAIN,
                        domainAndRangeClass.getONodeID());
                ontologyTripleStore.addTriple(aPropertyURI, ontology.OURI_RDFS_RANGE,
                        domainAndRangeClass.getONodeID());
            }
        }
    }

    /**
     * Checkes whether the two properties are Equivalent.
     * 
     * @param aPropertyURI
     * @return
     * @throws GateOntologyException
     */
    public boolean isEquivalentPropertyAs(OURI aPropertyURI1, OURI aPropertyURI2) {
        return ontologyTripleStore.hasTriple(aPropertyURI1, ontology.OURI_OWL_EQUIVALENTPROPERTY, aPropertyURI2);
    }

    /**
     * for the given property, the method returns all its super properties
     * 
     * @param aPropertyURI
     * @param direct
     * @return
     */
    public Property[] getSuperProperties(String aPropertyURI, Closure direct) {
        String queryRep = string2Turtle(aPropertyURI);

        String query = "";
        query = "Select distinct SUPER FROM {" + queryRep + "} rdfs:subPropertyOf {SUPER}" + " WHERE SUPER!="
                + queryRep + " AND SUPER != ALL ( " + " select distinct B FROM {B} owl:equivalentProperty {"
                + queryRep + "} )";

        List<String> list = new ArrayList<String>();
        addSerqlQueryResultToCollection(query, list);

        if (direct == OConstants.Closure.DIRECT_CLOSURE) {
            Set<String> toDelete = new HashSet<String>();
            for (int i = 0; i < list.size(); i++) {
                String string = list.get(i);
                if (toDelete.contains(string)) {
                    continue;
                }
                queryRep = string2Turtle(string);
                query = "Select distinct SUPER FROM {" + queryRep + "} rdfs:subPropertyOf {SUPER}"
                        + " WHERE SUPER!=" + queryRep + " AND SUPER != ALL ( "
                        + " select distinct B FROM {B} owl:equivalentProperty {" + queryRep + "} )";

                addSerqlQueryResultToCollection(query, toDelete);
            }
            list.removeAll(toDelete);
        }

        ArrayList<Property> properties = new ArrayList<Property>();
        for (int i = 0; i < list.size(); i++) {
            byte type = getPropertyType(ontology.createOURI(list.get(i)));
            properties.add(new Property(type, list.get(i)));
        }

        return listToPropertyArray(properties);
    }

    /**
     * for the given property, the method returns all its sub properties
     * 
     * @param aPropertyURI
     * @param direct
     * @return
     */
    public Property[] getSubProperties(String aPropertyURI, Closure direct) {

        String queryRep = string2Turtle(aPropertyURI);
        String query = "";
        query =
                // OLD "Select distinct SUB FROM {SUB} rdfs:subPropertyOf " + queryRep + " WHERE SUB!=" + queryRep1 + " MINUS " + " select distinct B FROM {B} owl:equivalentProperty " + queryRep;
                "Select distinct SUB FROM {SUB} rdfs:subPropertyOf {" + queryRep + "} WHERE SUB!=" + queryRep
                        + " AND SUB !=ALL( select distinct B FROM {B} owl:equivalentProperty {" + queryRep + "} )";

        List<String> list = new ArrayList<String>();
        addSerqlQueryResultToCollection(query, list);

        if (direct == OConstants.Closure.DIRECT_CLOSURE) {
            Set<String> toDelete = new HashSet<String>();
            for (int i = 0; i < list.size(); i++) {
                String string = list.get(i);
                if (toDelete.contains(string)) {
                    continue;
                }
                queryRep = string2Turtle(string);
                query = "Select distinct SUB FROM {SUB} rdfs:subPropertyOf {" + queryRep + "} WHERE SUB!="
                        + queryRep + " AND SUB != ALL ( " + " select distinct B FROM {B} owl:equivalentProperty {"
                        + queryRep + "} )";

                addSerqlQueryResultToCollection(query, toDelete);
            }
            list.removeAll(toDelete);
        }

        ArrayList<Property> properties = new ArrayList<Property>();
        for (int i = 0; i < list.size(); i++) {
            byte type = getPropertyType(ontology.createOURI(list.get(i)));
            properties.add(new Property(type, list.get(i)));
        }

        return listToPropertyArray(properties);
    }

    /**
     * Checkes whether the two properties have a super-sub relation.
     * 
     * @param aSuperPropertyURI
     * @param aSubPropertyURI
     * @param direct
     * @return
     */
    public boolean isSuperPropertyOf(String aSuperPropertyURI, String aSubPropertyURI, Closure direct) {
        String queryRep = string2Turtle(aSuperPropertyURI);
        String query = "";
        query = "Select distinct SUPER FROM {" + queryRep + "} rdfs:subPropertyOf {SUPER}" + " WHERE SUPER!="
                + queryRep + " AND SUPER != ALL ( " + " select distinct B FROM {B} owl:equivalentProperty {"
                + queryRep + "} )";

        List<String> list = new ArrayList<String>();
        addSerqlQueryResultToCollection(query, list);

        if (direct == OConstants.Closure.DIRECT_CLOSURE) {
            Set<String> toDelete = new HashSet<String>();
            for (int i = 0; i < list.size(); i++) {
                String string = list.get(i);
                if (toDelete.contains(string)) {
                    continue;
                }
                queryRep = string2Turtle(string);
                query = "Select distinct SUPER FROM {" + queryRep + "} rdfs:subPropertyOf {SUPER}"
                        + " WHERE SUPER!=" + queryRep + " AND SUPER != ALL ( "
                        + " select distinct B FROM {B} owl:equivalentProperty {" + queryRep + "} )";

                addSerqlQueryResultToCollection(query, toDelete);
            }
            list.removeAll(toDelete);
        }

        return list.contains(aSuperPropertyURI);
    }

    /**
     * Checkes whether the two properties have a super-sub relation.
     * 
     * @param aSuperPropertyURI
     * @param aSubPropertyURI
     * @param direct
     * @return
     */
    public boolean isSubPropertyOf(String aSuperPropertyURI, String aSubPropertyURI, Closure direct) {
        return isSuperPropertyOf(aSuperPropertyURI, aSubPropertyURI, direct);
    }

    /**
     * Returns whether the individual1 is different from the individual2.
     * 
     * @param theInstanceURI1
     * @param theInstanceURI2
     * @return
     */
    public boolean isDifferentIndividualFrom(OURI theInstanceURI1, OURI theInstanceURI2) {
        return ontologyTripleStore.hasTriple(theInstanceURI1, ontology.OURI_OWL_DIFFERENTFROM, theInstanceURI2);
    }

    /**
     * Checkes whether the two individuals are same.
     * 
     * @param individualURI1
     * @param invidualURI2
     * @return
     */
    public boolean isSameIndividualAs(OURI theInstanceURI1, OURI theInstanceURI2) {
        return ontologyTripleStore.hasTriple(theInstanceURI1, ontology.OURI_OWL_SAMEAS, theInstanceURI2);
    }

    // *************
    // Instances and properties
    // **************
    /**
     * adds the RDF Property value on the specified instance
     * 
     * @param anInstanceURI
     * @param anRDFPropertyURI
     * @param aResourceURI
     */
    public void addRDFPropertyValue(ONodeID anInstanceURI, OURI anRDFPropertyURI, ONodeID aResourceURI) {
        ontologyTripleStore.addTriple(anInstanceURI, anRDFPropertyURI, aResourceURI);
    }

    /**
     * Removes the specified RDF Property Value
     * 
     * @param anInstanceURI
     * @param anRDFPropertyURI
     * @param aResourceURI
     */
    public void removeRDFPropertyValue(ONodeID anInstanceURI, OURI anRDFPropertyURI, ONodeID aResourceURI) {
        startTransaction(null);
        ontologyTripleStore.removeTriple(anInstanceURI, anRDFPropertyURI, aResourceURI);
        endTransaction(null);
    }

    /**
     * gets the rdf property values for the specified instance.
     * 
     * @param anInstanceURI
     * @param anRDFPropertyURI
     * @return resource URIs
     */
    public ResourceInfo[] getRDFPropertyValues(String anInstanceURI, String anRDFPropertyURI) {
        Resource r = getResource(anInstanceURI);
        // TODO: !!! turtle
        String queryRep2 = "<" + anInstanceURI + ">";
        if (r instanceof BNode) {
            queryRep2 = "_:" + anInstanceURI;
        }

        List<String> list = new ArrayList<String>();
        String query = "Select DISTINCT Y from {X} <" + anRDFPropertyURI + "> {Y} WHERE X=" + queryRep2;

        addSerqlQueryResultToCollection(query, list);
        return listToResourceInfoArray(list);
    }

    public List<LiteralOrONodeID> getRDFPropertyLiteralOrONodeIDs(ONodeID anInstanceURI, OURI anRDFPropertyURI) {

        List<LiteralOrONodeID> list = new LinkedList<LiteralOrONodeID>();
        String query = "Select DISTINCT Y from {" + anInstanceURI.toTurtle() + "} " + anRDFPropertyURI.toTurtle()
                + " {Y}";

        UtilTupleQueryIterator qit = new UtilTupleQueryIterator(sesameManager, query,
                OConstants.QueryLanguage.SERQL);
        while (qit.hasNext()) {
            list.add(qit.nextFirst());
        }
        return list;
    }

    /**
     * Removes all the RDF Property values from the given instance.
     * 
     * @param anInstanceURI
     * @param anRDFPropertyURI
     */
    public void removeRDFPropertyValues(String anInstanceURI, String anRDFPropertyURI) {
        try {
            repositoryConnection.remove(getResource(anInstanceURI), makeSesameURI(anRDFPropertyURI), null);
        } catch (Exception sue) {
            throw new GateOntologyException("Error while removing RDF Property Values " + sue.getMessage(), sue);
        }
    }

    // ******************
    // DataType Properties
    // *****************
    /**
     * Adds the value for the given Property.
     * 
     * @param anInstanceURI
     * @param aDatatypePropertyURI
     * @param datatypeURI
     * @param value
     */
    public void addDatatypePropertyValue(OURI anInstanceURI, OURI aDatatypePropertyURI,
            gate.creole.ontology.Literal value) {
        if (!isDatatypeProperty(aDatatypePropertyURI)) {
            throw new GateOntologyException("No datatype property exists with URI :" + aDatatypePropertyURI);
        }
        ontologyTripleStore.addTriple(anInstanceURI, aDatatypePropertyURI, value);
    }

    /**
     * Removes the provided value for the given instance.
     * 
     * @param anInstanceURI
     * @param aDatatypePropertyURI
     * @param datatypeURI
     * @param value
     */
    public void removeDatatypePropertyValue(OURI anInstanceURI, OURI aDatatypePropertyURI,
            gate.creole.ontology.Literal value) {
        if (!isDatatypeProperty(aDatatypePropertyURI)) {
            throw new GateOntologyException("No datatype property exists with URI :" + aDatatypePropertyURI);
        }
        ontologyTripleStore.removeTriple(anInstanceURI, aDatatypePropertyURI, value);
    }

    /**
     * Gets a list of values for the given Property.
     * 
     * @param anInstanceURI
     * @param aDatatypePropertyURI
     * @return
     */
    public List<gate.creole.ontology.Literal> getDatatypePropertyValues(OURI anInstanceURI,
            OURI aDatatypePropertyURI) {
        if (!isDatatypeProperty(aDatatypePropertyURI)) {
            throw new GateOntologyException("No datatype property exists with URI :" + aDatatypePropertyURI);
        }

        //Resource r2 = getResource(anInstanceURI);
        //String queryRep21 = "<" + anInstanceURI + ">";
        //if (r2 instanceof BNode) {
        //  queryRep21 = "_:" + anInstanceURI;
        //}

        List<gate.creole.ontology.Literal> list = new ArrayList<gate.creole.ontology.Literal>();
        String query = "Select DISTINCT Y from {X} " + aDatatypePropertyURI.toTurtle() + " {Y} WHERE X="
                + anInstanceURI.toTurtle() + " AND isLiteral(Y)";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            LiteralOrONodeID lo = result.nextFirst();
            if (lo.isLiteral()) {
                list.add(lo.getLiteral());
            }
        }
        return list;
    }

    /**
     * Removes all property values set on the provided instance for the current
     * property.
     * 
     * @param anInstanceURI
     * @param aDatatypePropertyURI
     */
    public void removeDatatypePropertyValues(ONodeID anInstanceURI, OURI aDatatypePropertyURI) {
        if (!isDatatypeProperty(aDatatypePropertyURI)) {
            throw new GateOntologyException("No datatype property exists with URI :" + aDatatypePropertyURI);
        }
        startTransaction(null);
        ontologyTripleStore.removeTriple(anInstanceURI, aDatatypePropertyURI, (gate.creole.ontology.Literal) null);
        endTransaction(null);
    }

    // ******************
    // Object, Symmetric and Transitive Properties
    // *****************
    /**
     * Adds the value for the given property (Object, Symmetric and Transitive).
     * 
     * @param sourceInstanceURI
     * @param anObjectPropertyURI
     * @param theValueInstanceURI
     */
    public void addObjectPropertyValue(ONodeID sourceInstanceURI, OURI anObjectPropertyURI,
            OURI theValueInstanceURI) {
        ontologyTripleStore.addTriple(sourceInstanceURI, anObjectPropertyURI, theValueInstanceURI);
    }

    /**
     * Remove the provided value for the given property (Object, Symmetric and
     * Transitive).
     * 
     * @param sourceInstanceURI
     * @param anObjectPropertyURI
     * @param theValueInstanceURI
     */
    public void removeObjectPropertyValue(OURI sourceInstanceURI, OURI anObjectPropertyURI,
            OURI theValueInstanceURI) {
        if (!isObjectProperty(anObjectPropertyURI)) {
            throw new GateOntologyException("No object property exists with URI :" + anObjectPropertyURI);
        }
        ontologyTripleStore.removeTriple(sourceInstanceURI, anObjectPropertyURI, theValueInstanceURI);
    }

    /**
     * Gets a list of values for the given Property (Object, Symmetric and
     * Transitive).
     * 
     * @param sourceInstanceURI
     * @param anObjectPropertyURI
     * @return
     */
    public List<OInstance> getObjectPropertyValues(OURI sourceInstanceURI, OURI anObjectPropertyURI) {
        if (!isObjectProperty(anObjectPropertyURI) && !isTransitiveProperty(anObjectPropertyURI)
                && !isSymmetricProperty(anObjectPropertyURI)) {
            throw new GateOntologyException(
                    "No object/transitive/symmetric property exists with URI :" + anObjectPropertyURI);
        }

        //Resource r = getResource(sourceInstanceURI);
        //String queryRep2 = "<" + sourceInstanceURI + ">";
        //if (r instanceof BNode) {
        //  queryRep2 = "_:" + sourceInstanceURI;
        //}
        String queryRep1 = anObjectPropertyURI.toTurtle();
        String queryRep2 = sourceInstanceURI.toTurtle();

        List<OInstance> list = new ArrayList<OInstance>();
        String query = "Select DISTINCT Y from {X} " + queryRep1 + " {Y} WHERE X=" + queryRep2;

        UtilTupleQueryIterator result = new UtilTupleQueryIterator(sesameManager, query, QueryLanguage.SERQL);
        while (result.hasNext()) {
            LiteralOrONodeID val = result.nextFirst();
            if (val.isONodeID()) {
                ONodeID on = val.getONodeID();
                if (!on.isAnonymousResource()) {
                    list.add(Utils.createOInstance(ontology, this, val.toString()));
                }
            }
        }
        result.close();
        return list;
    }

    /**
     * Removes all property values set for the current property (Object, Symmetric
     * and Transitive).
     * 
     * @param sourceInstanceURI
     * @param anObjectPropertyURI
     */
    public void removeObjectPropertyValues(OURI sourceInstanceURI, OURI anObjectPropertyURI) {
        if (!isObjectProperty(anObjectPropertyURI)) {
            throw new GateOntologyException("No object property exists with URI :" + anObjectPropertyURI);
        }
        ontologyTripleStore.removeTriple(sourceInstanceURI, anObjectPropertyURI, (ONodeID) null);
    }

    /**
     * Returns if the given property is a topOnly property.
     * 
     * @param classURI
     * @return
     */
    public boolean isTopProperty(String aPropertyURI) {
        return getSuperProperties(aPropertyURI, OConstants.Closure.DIRECT_CLOSURE).length == 0;
    }

    //****************************************************************************
    // relations among classes
    //****************************************************************************
    /**
     * The method creates a new class with the URI as specified in className and
     * adds it as a subClassOf the parentClass. It also adds the provided comment
     * on the subClass.
     * 
     * @param superClassURI
     * @param subClassURI
     */
    public void addSubClass(String superClassURI, String subClassURI) {
        // TODO: !! replace !!
        addUUUStatement(subClassURI, RDFS.SUBCLASSOF.toString(), superClassURI);
    }

    /**
     * The method creates a new class with the URI as specified in className and
     * adds it as a superClassOf the parentClass. It also adds the provided
     * comment on the subClass.
     * 
     * @param superClassURI
     * @param subClassURI
     */
    public void addSuperClass(String superClassURI, String subClassURI) {
        // TODO: !! replace !!
        addUUUStatement(subClassURI, RDFS.SUBCLASSOF.toString(), superClassURI);
    }

    /**
     * Removes the subclass relationship
     * 
     * @param superClassURI
     * @param subClassURI
     */
    public void removeSubClass(String superClassURI, String subClassURI) {
        // TODO: !! replace !!
        removeUUUStatement(subClassURI, RDFS.SUBCLASSOF.toString(), superClassURI);
    }

    /**
     * Removes the superclass relationship
     * 
     * @param superClassURI
     * @param subClassURI
     */
    public void removeSuperClass(String superClassURI, String subClassURI) {
        removeUUUStatement(subClassURI, RDFS.SUBCLASSOF.toString(), superClassURI);
    }

    public ClosableIterator<OClass> getSubClassesIterator(ONodeID forClass, Closure closure) {
        if (closure == Closure.DIRECT_CLOSURE) {
            // better would be to just do a setbinding for a prepared query,
            // but there is a bug in OWLIM that prevents this to work with this query
            String query = qs_getSubClassesDirectFor;
            query = query.replaceAll("yyy1", forClass.toTurtle());
            UtilTupleQueryIterator qp_getSubClassesDirectFor = new UtilTupleQueryIterator(sesameManager, query,
                    ql_getSubClassesDirectFor);
            return new UtilResourceQueryIterator<OClass>(this, qp_getSubClassesDirectFor, OClass.class);
        } else {
            String query = qs_getSubClassesAllFor;
            query = query.replaceAll("yyy1", forClass.toTurtle());
            UtilTupleQueryIterator qp_getSubClassesAllFor = new UtilTupleQueryIterator(sesameManager, query,
                    ql_getSubClassesAllFor);
            return new UtilResourceQueryIterator<OClass>(this, qp_getSubClassesAllFor, OClass.class);

        }
    }

    public Set<OClass> getSubClasses(ONodeID superClassURI, Closure direct) {
        Set<OClass> ret = new HashSet<OClass>();
        ClosableIterator<OClass> it = getSubClassesIterator(superClassURI, direct);
        while (it.hasNext()) {
            ret.add(it.next());
        }
        return ret;
    }

    public OClass getRestrictionForONodeID(ONodeID node) {
        OClass theClass = null;
        if (node.isAnonymousResource()) {
            qp_getRestrictionTypeFor.setBinding("yyy1", new LiteralOrONodeIDImpl(node));
            String nodeID = node.toTurtle();
            LiteralOrONodeID r = null;
            int i = 0;
            while (qp_getRestrictionTypeFor.hasNext()) {
                i++;
                r = qp_getRestrictionTypeFor.nextFirst();
            }
            if (i == 0) {
                // no restriction property found, must be some other anonymous class
                theClass = Utils.createOClass(ontology, this, node.toString(), OConstants.ANNONYMOUS_CLASS);
            } else if (i == 1) {
                // make the apropriate restriction 
                theClass = createRestrictionFromURI(r.toString(), nodeID.toString());
            } else {
                // oddd
                System.out.println("getRestrictionForONodeIDs: Got more than one restriction type for: " + nodeID);
                theClass = Utils.createOClass(ontology, this, node.toString(), OConstants.ANNONYMOUS_CLASS);
            }
            return theClass;
        } else {
            throw new GateOntologyException(
                    "getRestrictionForONodeIDs: called for non-anonymous class: " + node.toTurtle());
        }
    }

    /**
     * This method returns all super classes of the given class
     * 
     * @param subClassURI
     * @param direct
     * @return
     */
    public ResourceInfo[] getSuperClasses(String subClassURI, Closure direct) throws GateOntologyException {

        String queryRep1 = string2Turtle(subClassURI);
        String queryRep = "{" + queryRep1 + "}";

        String query = "";
        query = "Select distinct SUPER FROM " + queryRep + " rdfs:subClassOf {SUPER}" + " WHERE SUPER!=" + queryRep1
                + " AND SUPER != ALL ( " + " select distinct B FROM {B} owl:equivalentClass " + queryRep + ")";

        List<String> list = new ArrayList<String>();
        addSerqlQueryResultToCollection(query, list);

        if (direct == OConstants.Closure.DIRECT_CLOSURE) {
            Set<String> toDelete = new HashSet<String>();
            for (int i = 0; i < list.size(); i++) {
                String string = list.get(i);
                if (toDelete.contains(string)) {
                    continue;
                }
                queryRep1 = string2Turtle(string);
                queryRep = "{" + queryRep1 + "}";

                query = "Select distinct SUPER FROM " + queryRep + " rdfs:subClassOf {SUPER}" + " WHERE SUPER!="
                        + queryRep1 + " AND SUPER != ALL ( " + " select distinct B FROM {B} owl:equivalentClass "
                        + queryRep + ")";

                addSerqlQueryResultToCollection(query, toDelete);
            }
            list.removeAll(toDelete);
        }

        return listToResourceInfoArray(list);
    }

    /**
     * Sets the classes as same classes
     * 
     * @param class1URI
     * @param class2URI
     */
    public void setEquivalentClassAs(ONodeID class1URI, ONodeID class2URI) {
        ontologyTripleStore.addTriple(class1URI, ontology.OURI_OWL_EQUIVALENTCLASS, class2URI);
    }

    /**
     * returns an array of classes which are equivalent as the given class
     * 
     * @param aClassURI
     * @return
     */
    public ResourceInfo[] getEquivalentClasses(String aClassURI) {
        String queryRep1 = string2Turtle(aClassURI);

        String query = "Select distinct B FROM {A}" + " owl:equivalentClass {B} WHERE A!=B AND A=" + queryRep1;

        List<String> list = new ArrayList<String>();
        addSerqlQueryResultToCollection(query, list);
        return listToResourceInfoArray(list);
    }

    /**
     * Removes the given property
     * 
     * @param aPropertyURI
     * @param removeSubTree
     *          - if set to true, removes all its subproperties, otherwise shifts
     *          subproperties to its parent property
     * @return a list of URIs of resources deleted as a result of deleting this
     *         property.
     */
    public String[] removePropertyFromOntology(String aPropertyURI, boolean removeSubTree) {
        List<String> deletedResources = new ArrayList<String>();
        // TODO: have to check for explicit property in some other way, this
        // does not work anymore!
        //if(removeUUUStatement(aPropertyURI, RDF.TYPE.toString(), null) == 0) {
        //  throw new GateOntologyException(aPropertyURI
        //    + " is not an explicit Property");
        // }
        // else {
        //   currentEventsLog
        //     .addEvent(new OEvent(aPropertyURI, RDF.TYPE.toString(), null, false));
        //   deletedResources.add(aPropertyURI);
        // }
        // TODO: !! replace !!
        removeUUUStatement(aPropertyURI, RDF.TYPE.toString(), null);
        deletedResources.add(aPropertyURI);
        try {
            startTransaction(null);
            // removing all values set for the current property
            repositoryConnection.remove((Resource) null, makeSesameURI(aPropertyURI), null);
            repositoryConnection.remove(getResource(aPropertyURI), makeSesameURI(RDFS.SUBPROPERTYOF.toString()),
                    null);
            endTransaction(null);
        } catch (Exception sue) {
            throw new GateOntologyException("error while removing a property:" + aPropertyURI, sue);
        }

        // this should happen only if removeSubTree is set to true
        if (removeSubTree) {
            Property[] subProps = getSubProperties(aPropertyURI, OConstants.Closure.DIRECT_CLOSURE);
            for (int i = 0; i < subProps.length; i++) {
                try {
                    if (repositoryConnection.hasStatement(getResource(subProps[i].getUri()),
                            makeSesameURI(RDF.TYPE.toString()), null, false)) {
                        continue;
                    }
                    String[] removedResources = removePropertyFromOntology(subProps[i].getUri(), true);
                    deletedResources.addAll(Arrays.asList(removedResources));
                } catch (RepositoryException e) {
                    throw new GateOntologyException("Error finding statement ", e);
                }
            }
        }
        // TODO: !! replace !!
        removeUUUStatement(aPropertyURI, null, null);
        removeUUUStatement(null, aPropertyURI, null);
        removeUUUStatement(null, null, aPropertyURI);
        return listToArray(deletedResources);
    }

    /**
     * The method adds an object property specifiying domain and range for the
     * same. All classes specified in domain and range must exist.
     * 
     * @param aPropertyURI
     * @param domainClassesURIs
     * @param rangeClassesTypes
     */
    public void addObjectProperty(String aPropertyURI, String[] domainClassesURIs, String[] rangeClassesTypes) {
        // TODO: !! replace !!
        addUUUStatement(aPropertyURI, RDF.TYPE.toString(), OWL.OBJECTPROPERTY.toString());
        if (domainClassesURIs != null) {
            for (int i = 0; i < domainClassesURIs.length; i++) {
                // TODO: !! replace !!
                addUUUStatement(aPropertyURI, RDFS.DOMAIN.toString(), domainClassesURIs[i]);
            }
        }
        if (rangeClassesTypes != null) {
            for (int i = 0; i < rangeClassesTypes.length; i++) {
                // TODO: !! replace !!
                addUUUStatement(aPropertyURI, RDFS.RANGE.toString(), rangeClassesTypes[i]);
            }
        }
    }

    /**
     * The method adds a transitive property specifiying domain and range for the
     * same. All classes specified in domain and range must exist.
     * 
     * @param aPropertyURI
     * @param domainClassesURIs
     * @param rangeClassesTypes
     */
    public void addTransitiveProperty(String aPropertyURI, String[] domainClassesURIs, String[] rangeClassesTypes) {
        // TODO: !! replace !!
        addUUUStatement(aPropertyURI, RDF.TYPE.toString(), OWL.TRANSITIVEPROPERTY.toString());
        if (domainClassesURIs != null) {
            for (int i = 0; i < domainClassesURIs.length; i++) {
                // TODO: !! replace !!
                addUUUStatement(aPropertyURI, RDFS.DOMAIN.toString(), domainClassesURIs[i]);
            }
        }
        if (rangeClassesTypes != null) {
            for (int i = 0; i < rangeClassesTypes.length; i++) {
                // TODO: !! replace !!
                addUUUStatement(aPropertyURI, RDFS.RANGE.toString(), rangeClassesTypes[i]);
            }
        }
    }

    /**
     * The method returns an array of properties. Property is a complex structure,
     * which contains name, comment, information about its domain and range.
     * 
     * @return
     */
    public Set<RDFProperty> getRDFProperties() {
        Set<RDFProperty> set = new HashSet<RDFProperty>();
        String query = "Select distinct X FROM {X} rdf:type {<" + RDF.PROPERTY + ">}";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            LiteralOrONodeID value = result.nextFirst();
            if (value.isONodeID()) {
                ONodeID valueONodeID = value.getONodeID();
                if (!valueONodeID.isAnonymousResource()) {
                    OURI ouri = (OURI) valueONodeID;
                    if (isAnnotationProperty(ouri) || isDatatypeProperty(ouri) || isObjectProperty(ouri)
                            || isTransitiveProperty(ouri) || isSymmetricProperty(ouri)) {
                        continue;
                    }
                    set.add(Utils.createOProperty(ontology, this, ouri.toString(), OConstants.RDF_PROPERTY));
                } // not anonymous
            } // an onodeid
        } // while
        result.close();
        return set;
    }

    /**
     * The method returns an array of properties. Property is a complex structure,
     * which contains name, comment, information about its domain and range.
     * 
     * @return
     */
    public Property[] getObjectProperties() {
        List<Property> list = new ArrayList<Property>();
        String query = "Select distinct X FROM {X} rdf:type {<" + OWL.OBJECTPROPERTY + ">}";

        logger.debug("=== searching for object properties");
        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            Value anAnnProp = result.nextFirstAsValue();
            logger.debug("Got an object property: " + anAnnProp);
            list.add(new Property(OConstants.OBJECT_PROPERTY, anAnnProp.toString()));
        }
        result.close();

        query = "Select distinct X FROM {X} rdf:type {<" + OWL.SYMMETRICPROPERTY + ">}";

        logger.debug("=== searching for symmetric properties");
        result = performSerqlQuery(query);
        while (result.hasNext()) {
            Value anAnnProp = result.nextFirstAsValue();
            logger.debug("Got a symmetric property: " + anAnnProp);
            list.add(new Property(OConstants.SYMMETRIC_PROPERTY, anAnnProp.toString()));
        }

        query = "Select distinct X FROM {X} rdf:type {<" + OWL.TRANSITIVEPROPERTY + ">}";

        result = performSerqlQuery(query);
        while (result.hasNext()) {
            Value anAnnProp = result.nextFirstAsValue();
            logger.debug("Got a transitive property: " + anAnnProp);
            list.add(new Property(OConstants.TRANSITIVE_PROPERTY, anAnnProp.toString()));
        }
        logger.debug("Returning from  OSI getObjectProperties");
        return listToPropertyArray(list);
    }

    /**
     * The method returns an array of properties. Property is a complex structure,
     * which contains name, comment, information about its domain and range.
     * 
     * @return
     */
    public Property[] getSymmetricProperties() {
        List<Property> list = new ArrayList<Property>();
        String query = "Select distinct X FROM {X} rdf:type {<" + OWL.SYMMETRICPROPERTY + ">}";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            Value anAnnProp = result.nextFirstAsValue();
            list.add(new Property(OConstants.SYMMETRIC_PROPERTY, anAnnProp.toString()));
        }
        return listToPropertyArray(list);
    }

    /**
     * The method returns an array of properties. Property is a complex structure,
     * which contains name, comment, information about its domain and range.
     * 
     * @return
     */
    public Property[] getTransitiveProperties() {
        List<Property> list = new ArrayList<Property>();
        String query = "Select distinct X FROM {X} rdf:type {<" + OWL.TRANSITIVEPROPERTY + ">}";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            Value anAnnProp = result.nextFirstAsValue();
            list.add(new Property(OConstants.TRANSITIVE_PROPERTY, anAnnProp.toString()));
        }
        return listToPropertyArray(list);
    }

    /**
     * The method returns an array of properties. Property is a complex structure,
     * which contains name, comment, information about its domain and range.
     * 
     * @return
     */
    public Property[] getDatatypeProperties() {
        List<Property> list = new ArrayList<Property>();
        String query = "Select distinct X FROM {X} rdf:type {<" + OWL.DATATYPEPROPERTY + ">}";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            Value anAnnProp = result.nextFirstAsValue();
            list.add(new Property(OConstants.DATATYPE_PROPERTY, anAnnProp.toString()));
        }
        return listToPropertyArray(list);
    }

    /**
     * The method returns an array of properties. Property is a complex structure,
     * which contains name, comment, information about its domain and range.
     * 
     * @return
     */
    public Property[] getAnnotationProperties() {
        List<Property> list = new ArrayList<Property>();
        String query = "Select distinct X FROM {X} rdf:type {<" + OWL.ANNOTATIONPROPERTY + ">}";

        UtilTupleQueryIterator result = performSerqlQuery(query);
        while (result.hasNext()) {
            Value anAnnProp = result.nextFirstAsValue();
            list.add(new Property(OConstants.ANNOTATION_PROPERTY, anAnnProp.toString()));
        }

        boolean allowSystemStatements = this.returnSystemStatements;
        this.returnSystemStatements = true;
        Property[] props = listToPropertyArray(list);
        this.returnSystemStatements = allowSystemStatements;
        return props;
    }

    public Set<RDFProperty> getPropertiesByName(String name) {
        Set<RDFProperty> properties = new HashSet<RDFProperty>();
        // TODO: filter out system properties
        // TODO: should this include rdf properties (filter out even more sys props)
        //       and annotation properties?
        String queryd = "Select distinct X from {X} rdf:type {T} " + "  WHERE T = <" + OWL.DATATYPEPROPERTY
                + "> AND " + "       ( X LIKE yyy1 OR X LIKE yyy2 )";
        String queryo = "Select distinct X from {X} rdf:type {T} " + "  WHERE  T = <" + OWL.OBJECTPROPERTY
                + "> AND " + "       ( X LIKE yyy1 OR X LIKE yyy2 ) ";
        queryd = queryd.replaceAll("yyy1", "\"*#" + name + "\"");
        queryd = queryd.replaceAll("yyy2", "\"*/" + name + "\"");
        queryo = queryo.replaceAll("yyy1", "\"*#" + name + "\"");
        queryo = queryo.replaceAll("yyy2", "\"*/" + name + "\"");
        UtilTupleQueryIterator q = new UtilTupleQueryIterator(sesameManager, queryo,
                OConstants.QueryLanguage.SERQL);
        while (q.hasNext()) {
            Value v = q.nextFirstAsValue();
            properties.add(Utils.createOProperty(ontology, this, v.toString(), OConstants.OBJECT_PROPERTY));
        }
        q = new UtilTupleQueryIterator(sesameManager, queryd, OConstants.QueryLanguage.SERQL);
        while (q.hasNext()) {
            Value v = q.nextFirstAsValue();
            properties.add(Utils.createOProperty(ontology, this, v.toString(), OConstants.DATATYPE_PROPERTY));
        }

        return properties;
    }

    /**
     * Given a property, this method returns its domain
     * 
     * @param aPropertyURI
     * @return
     */
    // TODO: return ONodeIDs or Classes, make reducing to most
    // specific classes optional
    public Set<OResource> getDomain(OURI aPropertyURI) {
        if (isAnnotationProperty(aPropertyURI)) {
            throw new GateOntologyException("AnnotationProperties do no specify any domain or range");
        }
        // TODO: check if we can directly search for the most specific 
        // classes using SPARQL 1.1 here!
        // If not, avoid the use of ResourceInfo!
        String query = "select distinct Y from {" + aPropertyURI.toTurtle() + "} rdfs:domain {Y}";
        UtilTupleQueryIterator result = performSerqlQuery(query);
        Set<OResource> set = new HashSet<OResource>();
        List<ResourceInfo> list = new ArrayList<ResourceInfo>();
        while (result.hasNext()) {
            String classString = result.nextFirstAsString();
            byte classType = getClassType(classString);
            if (classType == OConstants.ANNONYMOUS_CLASS) {
                continue;
            }
            //set.add(Utils.createOClass(ontology, this, classString, classType));
            list.add(new ResourceInfo(classString, classType));
        }
        result.close();
        ResourceInfo[] res = reduceToMostSpecificClasses(list);
        for (ResourceInfo r : res) {
            set.add(Utils.createOClass(ontology, this, r.getUri(), r.getClassType()));
        }
        return set;
    }

    /**
     * Given a property, this method returns its range
     * 
     * @param aPropertyURI
     * @return
     */
    public ResourceInfo[] getRange(String aPropertyURI) {
        // TODO: make the whole method use OURI instead of String and ResourceInfo
        if (isAnnotationProperty(ontology.createOURI(aPropertyURI))) {
            throw new GateOntologyException("AnnotationProperties do no specify any domain or range");
        }
        if (isDatatypeProperty(ontology.createOURI(aPropertyURI))) {
            throw new GateOntologyException("Please use getDatatype(String theDatatypeProerptyURI) method instead");
        }

        String query = "Select distinct Y from {<" + aPropertyURI + ">} rdfs:range {Y}";
        UtilTupleQueryIterator result = performSerqlQuery(query);
        List<ResourceInfo> list = new ArrayList<ResourceInfo>();
        while (result.hasNext()) {
            String classString = result.nextFirstAsString();
            byte classType = getClassType(classString);
            if (classType == OConstants.ANNONYMOUS_CLASS) {
                continue;
            }
            list.add(new ResourceInfo(classString, classType));
        }
        result.close();
        return reduceToMostSpecificClasses(list);
    }

    /**
     * Returns if the provided property is functional
     * 
     * @param aPropertyURI
     * @return
     */
    public boolean isFunctional(OURI aPropertyURI) {
        return ontologyTripleStore.hasTriple(aPropertyURI, ontology.OURI_RDF_TYPE,
                ontology.OURI_OWL_FUNCTIONALPROPERTY);
    }

    /**
     * sets the current property as functional
     * 
     * @param aPropertyURI
     * @param isFunctional
     */
    public void setFunctional(String aPropertyURI, boolean isFunctional) {
        if (isFunctional) {
            // TODO: !! replace !!
            addUUUStatement(aPropertyURI, RDF.TYPE.toString(), OWL.FUNCTIONALPROPERTY.toString());
        } else {
            // TODO: !! replace !!
            removeUUUStatement(aPropertyURI, RDF.TYPE.toString(), OWL.FUNCTIONALPROPERTY.toString());
        }
    }

    /**
     * returns if the given property is inverse functional property
     * 
     * @param aPropertyURI
     * @return
     */
    public boolean isInverseFunctional(OURI aPropertyURI) {
        return ontologyTripleStore.hasTriple(aPropertyURI, ontology.OURI_RDF_TYPE,
                ontology.OURI_OWL_INVERSEFUNCTIONALPROPERTY);
    }

    /**
     * Sets the current property as inverse functional property
     * 
     * @param aPropertyURI
     * @param isInverseFunctional
     */
    public void setInverseFunctional(String aPropertyURI, boolean isInverseFunctional) {
        if (isInverseFunctional) {
            // TODO: !! replace !!
            addUUUStatement(aPropertyURI, RDF.TYPE.toString(), OWL.INVERSEFUNCTIONALPROPERTY.toString());
        } else {
            // TODO: !! replace !!
            removeUUUStatement(aPropertyURI, RDF.TYPE.toString(), OWL.INVERSEFUNCTIONALPROPERTY.toString());
        }
    }

    /**
     * returns if the given property is a symmetric property
     * 
     * @param aPropertyURI
     * @return
     */
    public boolean isSymmetricProperty(OURI aPropertyURI) {
        return ontologyTripleStore.hasTriple(aPropertyURI, ontology.OURI_RDF_TYPE,
                ontology.OURI_OWL_SYMMETRICPROPERTY);
    }

    /**
     * returns if the given property is a transitive property
     * 
     * @param aPropertyURI
     * @return
     */
    public boolean isTransitiveProperty(OURI aPropertyURI) {
        return ontologyTripleStore.hasTriple(aPropertyURI, ontology.OURI_RDF_TYPE,
                ontology.OURI_OWL_TRANSITIVEPROPERTY);
    }

    /**
     * returns if the given property is a datatype property
     * 
     * @param aPropertyURI
     * @return
     */
    public boolean isDatatypeProperty(OURI aPropertyURI) {
        return ontologyTripleStore.hasTriple(aPropertyURI, ontology.OURI_RDF_TYPE,
                ontology.OURI_OWL_DATATYPEPROPERTY);
    }

    /**
     * returns if the given property is an object property
     * 
     * @param aPropertyURI
     * @return
     */
    public boolean isObjectProperty(OURI aPropertyURI) {
        return ontologyTripleStore.hasTriple(aPropertyURI, ontology.OURI_RDF_TYPE,
                ontology.OURI_OWL_OBJECTPROPERTY);
    }

    // *************************************
    // Relations among properties
    // *************************************
    /**
     * Sets two properties as same
     * 
     * @param property1URI
     * @param property2URI
     */
    public void setEquivalentPropertyAs(String property1URI, String property2URI) {
        // TODO: !! replace !!
        addUUUStatement(property1URI, OWL.EQUIVALENTPROPERTY.toString(), property2URI);
    }

    /**
     * For the given property, this method returns all properties marked as
     * Equivalent as it
     * 
     * @param aPropertyURI
     * @return
     */
    public Property[] getEquivalentPropertyAs(String aPropertyURI) {
        String query = "Select DISTINCT Y FROM {X} owl:equivalentProperty {Y} WHERE X=<" + aPropertyURI + ">";
        UtilTupleQueryIterator result = performSerqlQuery(query);
        List<Property> list = new ArrayList<Property>();
        while (result.hasNext()) {
            list.add(createPropertyObject(result.nextFirstAsString()));
        }
        return listToPropertyArray(list);
    }

    /**
     * For the given properties, this method registers the super, sub relation
     * 
     * @param superPropertyURI
     * @param subPropertyURI
     */
    public void addSuperProperty(String superPropertyURI, String subPropertyURI) {
        // TODO: !! replace !!
        addUUUStatement(subPropertyURI, RDFS.SUBPROPERTYOF.toString(), superPropertyURI);
    }

    /**
     * For the given properties, this method removes the super, sub relation
     * 
     * @param superPropertyURI
     * @param subPropertyURI
     */
    public void removeSuperProperty(String superPropertyURI, String subPropertyURI) {
        // TODO: !! replace !!
        removeUUUStatement(subPropertyURI, RDFS.SUBPROPERTYOF.toString(), superPropertyURI);
    }

    /**
     * For the given properties, this method registers the super, sub relation
     * 
     * @param superPropertyURI
     * @param subPropertyURI
     */
    public void addSubProperty(String superPropertyURI, String subPropertyURI) {
        // TODO: !! replace !!
        addUUUStatement(subPropertyURI, RDFS.SUBPROPERTYOF.toString(), superPropertyURI);
    }

    /**
     * For the given properties, this method removes the super, sub relation
     * 
     * @param superPropertyURI
     * @param subPropertyURI
     */
    public void removeSubProperty(String superPropertyURI, String subPropertyURI) {
        // TODO: !! replace !!
        removeUUUStatement(subPropertyURI, RDFS.SUBPROPERTYOF.toString(), superPropertyURI);
    }

    /**
     * for the given property, the method returns all its super properties
     * 
     * @param aPropertyURI
     * @param direct
     * @return
     */
    public Property[] getSuperProperties(String aPropertyURI, boolean direct) {
        return this.getSuperProperties(aPropertyURI,
                direct ? OConstants.Closure.DIRECT_CLOSURE : OConstants.Closure.TRANSITIVE_CLOSURE);
    }

    /**
     * for the given property, the method returns all its sub properties
     * 
     * @param aPropertyURI
     * @param direct
     * @return
     */
    public Property[] getSubProperties(String aPropertyURI, boolean direct) {
        return this.getSubProperties(aPropertyURI,
                direct ? OConstants.Closure.DIRECT_CLOSURE : OConstants.Closure.TRANSITIVE_CLOSURE);
    }

    /**
     * for the given property, the method returns all its inverse properties
     * 
     * @param aPropertyURI
     * @return
     */
    public Property[] getInverseProperties(String aPropertyURI) {
        String query = "Select DISTINCT Y FROM {X} owl:inverseOf {Y} WHERE X=<" + aPropertyURI + ">";
        UtilTupleQueryIterator result = performSerqlQuery(query);
        List<Property> list = new ArrayList<Property>();
        while (result.hasNext()) {
            list.add(createPropertyObject(result.nextFirstAsString()));
        }
        result.close();
        return listToPropertyArray(list);
    }

    /**
     * property1 is set as inverse of property 2
     * 
     * @param propertyURI1
     * @param propertyURI2
     */
    public void setInverseOf(String propertyURI1, String propertyURI2) {
        // TODO: !! replace !!
        addUUUStatement(propertyURI1, OWL.INVERSEOF.toString(), propertyURI2);
    }

    // *******************************************************************
    // *************************** Instance Methods **********************
    // *******************************************************************
    /**
     * The method adds a new instance (literal) into the repository. It then
     * creates a statement indicating membership relation with the provided class.
     * 
     * @param superClassURI
     * @param individualURI
     */
    public void addIndividual(String superClassURI, String individualURI) {
        // TODO: !! replace !!
        addUUUStatement(individualURI, RDF.TYPE.toString(), superClassURI);
    }

    /**
     * The method removes the provided instance from the repository.
     * 
     * @param individual
     * @return
     */
    public String[] removeIndividual(String individualURI) {
        // TODO: JP we have to check for explicit individual in some other way
        // here since removeUUUStatement cannot return the number of removed
        // eny more
        // Do a query to assert this?

        //int no = removeUUUStatement(individualURI, RDF.TYPE.toString(), null);
        //if(no == 0)
        //  throw new GateOntologyException(individualURI
        //    + " is not an explicit Individual");
        // TODO: !! replace !!
        removeUUUStatement(individualURI, RDF.TYPE.toString(), null);

        // we need to go though all ontology resources of the ontology
        // check if they have property with value the current resource
        // we need to delete it

        // TODO: !!!! is this not redundand with respect to what we do below?
        // (which is remove any triples that contain this URI anywhere?)
        // NOTE that removing all triples with this URI will fail for OWL-DL
        // if we just want to remove the occurrences of this individual as
        // individual but it is also a class!
        List<Property> properties = new ArrayList<Property>();
        properties.addAll(Arrays.asList(getObjectProperties()));
        try {
            startTransaction(null);
            for (int i = 0; i < properties.size(); i++) {
                repositoryConnection.remove((Resource) null, makeSesameURI(properties.get(i).getUri()),
                        getResource(individualURI));
            }
            endTransaction(null);
        } catch (Exception sue) {
            throw new GateOntologyException("error while removing individual:" + individualURI, sue);
        }
        // TODO: !! replace !!
        removeUUUStatement(individualURI, null, null);
        removeUUUStatement(null, null, individualURI);
        removeUUUStatement(null, individualURI, null);
        return new String[] { individualURI };
    }

    /**
     * The method returns all member instances of the provided class. It returns
     * only the direct instances if the boolean parameter direct is set to true.
     * 
     * @param superClassURI
     * @param direct
     */
    public String[] getIndividuals(String superClassURI, Closure direct) {
        String queryRep = string2Turtle(superClassURI);

        // A -> B -> I1

        String query = "";
        if (direct == OConstants.Closure.DIRECT_CLOSURE) {
            query = "Select distinct X from {X} serql:directType {" + queryRep + "}";
        } else {
            query = "Select distinct X from {X} rdf:type {" + queryRep + "}";
        }
        //System.out.println("getIndividuals query: "+query);
        List<String> list = new ArrayList<String>();
        addSerqlQueryResultToCollection(query, list);
        return listToArray(list);
    }

    public ClosableIterator<OInstance> getInstancesIterator(ONodeID aClass, OConstants.Closure closure) {
        // if aClass is null: all instances
        // if aClass is not null: instances of that class either 
        //   direct or transitive
        // once we have that, remove  unneeded classes and re-implement
        // getOInstance and has OInstance in abstractOntologyimpl
        UtilResourceQueryIterator ret = null;
        if (aClass == null) {
            ret = new UtilResourceQueryIterator<OInstance>(this, qp_getInstancesAll, OInstance.class);
        } else if (closure == OConstants.Closure.DIRECT_CLOSURE) {
            ret = new UtilResourceQueryIterator<OInstance>(this, qp_getInstancesDirectFor, OInstance.class);
            ret.setBinding("yyy1", new LiteralOrONodeIDImpl(aClass));

        } else {
            ret = new UtilResourceQueryIterator<OInstance>(this, qp_getInstancesAllFor, OInstance.class);
            ret.setBinding("yyy1", new LiteralOrONodeIDImpl(aClass));
        }
        return ret;
    }

    public Set<OInstance> getInstances(ONodeID aClass, OConstants.Closure closure) {
        //System.out.println("Running service.getInstances()");
        Set<OInstance> theInstances = new HashSet<OInstance>();
        ClosableIterator<OInstance> ii = getInstancesIterator(aClass, closure);
        while (ii.hasNext()) {
            OInstance i = ii.next();
            //System.out.println("Adding to result: "+i);
            theInstances.add(i);
        }
        return theInstances;
    }

    // public ClosableIterator<OInstance> getInstancesIterator() {
    //   //System.out.print("Creating ResourceQueryIt fir "+qp_getInstancesAll);
    //   return new UtilResourceQueryIterator<OInstance>(
    //       this, qp_getInstancesAll, OInstance.class);
    // }

    public Set<OInstance> getInstancesByName(String name) {
        Set<OInstance> instances = new HashSet<OInstance>();
        String query = "Select distinct X from {X} rdf:type {Y} "
                + "  rdf:type {<http://www.w3.org/2002/07/owl#Class>} "
                + "WHERE Y != <http://www.w3.org/2002/07/owl#Thing> AND " + "  ( X LIKE yyy1 OR X LIKE yyy2 )";
        query = query.replaceAll("yyy1", "\"*#" + name + "\"");
        query = query.replaceAll("yyy2", "\"*/" + name + "\"");
        //System.out.println("Query for instances: "+query);
        UtilTupleQueryIterator q = new UtilTupleQueryIterator(sesameManager, query, OConstants.QueryLanguage.SERQL);
        while (q.hasNext()) {
            Value v = q.nextFirstAsValue();
            OInstance i = Utils.createOInstance(ontology, this, v.toString());
            instances.add(i);
        }
        return instances;
    }

    // OURI must be not null, ONodeID can be null in that cas closure can be null too
    public boolean hasInstance(OURI theURI, ONodeID theClass, OConstants.Closure closure) {
        boolean ret = false;
        if (theClass == null) {
            qp_hasInstance.setBinding("yyy1", new LiteralOrONodeIDImpl(theURI));
            if (qp_hasInstance.hasNext()) {
                ret = true;
                qp_hasInstance.close();
            }
        } else if (closure == OConstants.Closure.DIRECT_CLOSURE) {
            //      qp_hasInstanceDirectFor.setBinding("yyy1", new LiteralOrONodeIDImpl(theURI));
            //      qp_hasInstanceDirectFor.setBinding("yyy2", new LiteralOrONodeIDImpl(theClass));
            String query = qs_hasInstanceDirectFor;
            query = query.replaceAll("yyy1", theURI.toTurtle());
            query = query.replaceAll("yyy2", theClass.toTurtle());
            UtilTupleQueryIterator qp_hasInstanceDirectFor = new UtilTupleQueryIterator(sesameManager, query,
                    ql_hasInstanceDirectFor);
            if (qp_hasInstanceDirectFor.hasNext()) {
                ret = true;
                qp_hasInstanceDirectFor.close();
            }
        } else {
            //      qp_hasInstanceAllFor.setBinding("yyy1", new LiteralOrONodeIDImpl(theURI));
            //      qp_hasInstanceAllFor.setBinding("yyy2", new LiteralOrONodeIDImpl(theClass));
            String query = qs_hasInstanceAllFor;
            query = query.replaceAll("yyy1", theURI.toTurtle());
            query = query.replaceAll("yyy2", theClass.toTurtle());
            UtilTupleQueryIterator qp_hasInstanceAllFor = new UtilTupleQueryIterator(sesameManager, query,
                    ql_hasInstanceAllFor);
            if (qp_hasInstanceAllFor.hasNext()) {
                ret = true;
                qp_hasInstanceAllFor.close();
            }
        }
        return ret;
    }

    /**
     * For the given individual, the method returns a set of classes for which the
     * individual is registered as instance of
     * 
     * @param individualURI
     */
    public ResourceInfo[] getClassesOfIndividual(String individualURI, Closure direct)
            throws GateOntologyException {
        if (debug) {
            logger.debug("getClassesOfIndividual");
        }
        String query = "";
        if (direct == OConstants.Closure.DIRECT_CLOSURE) {
            query = "Select DISTINCT B from {X} serql:directType {B} WHERE X=<" + individualURI + ">";
        } else {
            query = "Select DISTINCT B from {X} rdf:type {B} WHERE X=<" + individualURI + ">";
        }

        List<String> list = new ArrayList<String>();
        addSerqlQueryResultToCollection(query, list);
        return listToResourceInfoArray(list);
    }

    // *******************************************************************
    // relations among individuals
    // *******************************************************************
    /**
     * individual1 is sets as different individual from individual2
     * 
     * @param individual1URI
     * @param individual2URI
     * @throws GateOntologyException  
     */
    public void setDifferentIndividualFrom(ONodeID individual1URI, ONodeID individual2URI)
            throws GateOntologyException {
        logger.debug("setDifferentIndividualFrom");
        ontologyTripleStore.addTriple(individual1URI, ontology.OURI_OWL_DIFFERENTFROM, individual2URI);
    }

    /**
     * for the given individual, the method returns all individuals registered as
     * different from the given individual
     * 
     * @param individualURI
     * @return
     */
    public String[] getDifferentIndividualFrom(String individualURI) throws GateOntologyException {
        String query = "Select distinct B from {X} owl:differentFrom {B} WHERE X=<" + individualURI + ">";
        List<String> list = new ArrayList<String>();
        addSerqlQueryResultToCollection(query, list);
        return listToArray(list);
    }

    /**
     * individual1 is set as same as the individual2
     * 
     * @param individual1URI
     * @param individual2URI
     */
    public void setSameIndividualAs(String individual1URI, String individual2URI) throws GateOntologyException {
        if (debug) {
            logger.debug("setSameIndividualAs");
        }
        // TODO: !! replace !!
        addUUUStatement(individual1URI, OWL.SAMEAS.toString(), individual2URI);
    }

    /**
     * for the given individual, the method returns all individuals which are
     * registered as same as the provided individual
     * 
     * @param inidividualURI
     * @return
     */
    public String[] getSameIndividualAs(String individualURI) {
        String query = "select distinct B from {X} owl:sameAs {B} WHERE X=<" + individualURI + "> AND X!=B";
        List<String> list = new ArrayList<String>();
        addSerqlQueryResultToCollection(query, list);
        return listToArray(list);
    }

    // ***********************************************
    // ********* Restrictions ***********************
    // ***********************************************
    /**
     * This method given a restriction uri returns the value for the onProperty
     * element.
     * 
     * @param restrictionURI
     * @return
     * @throws GateOntologyException
     */
    public Property getOnPropertyValue(String restrictionURI) {
        String queryRep = string2Turtle(restrictionURI);

        String query = "Select distinct B from {X} owl:onProperty {B} WHERE X=" + queryRep;
        //System.out.println("Query="+query);
        UtilTupleQueryIterator result = performSerqlQuery(query);
        String val = null;
        if (result.hasNext()) {
            // here we need to check which type of property it is
            val = result.nextFirstAsString();
        }
        result.close();
        if (val != null) {
            return createPropertyObject(val);
        } else {
            return null;
        }
    }

    /**
     * This method sets the value for onProperty element on the given restriction.
     * 
     * @param repositoryId
     * @param restrictionURI
     * @param propertyURI
     * @throws GateOntologyException
     */
    public void setOnPropertyValue(ONodeID restrictionURI, OURI propertyURI) {
        ontologyTripleStore.addTriple(restrictionURI, ontology.OURI_OWL_ONPROPERTY, propertyURI);
    }

    /**
     * Gets the datatype uri specified on the given restriction uri.
     * 
     * @param repositoryID
     * @param restrictionURI
     * @return
     * @throws GateOntologyException
     */
    public PropertyValue getPropertyValue(String restrictionURI, byte restrictionType) {
        org.openrdf.model.URI whatValueURI = null;
        switch (restrictionType) {
        case OConstants.CARDINALITY_RESTRICTION:
            whatValueURI = OWL.CARDINALITY;
            break;
        case OConstants.MAX_CARDINALITY_RESTRICTION:
            whatValueURI = OWL.MAXCARDINALITY;
            break;
        case OConstants.MIN_CARDINALITY_RESTRICTION:
            whatValueURI = OWL.MINCARDINALITY;
            break;
        default:
            throw new GateOntologyException(
                    "Invalid restriction type :" + restrictionType + " for the " + restrictionURI);
        }

        try {
            RepositoryResult<Statement> iter = repositoryConnection.getStatements(getResource(restrictionURI),
                    whatValueURI, null, true);
            if (iter.hasNext()) {
                Value v = iter.next().getObject();
                if (v instanceof Literal) {
                    return new PropertyValue(((Literal) v).getDatatype().toString(), ((Literal) v).getLabel());
                }
            } else {
                throw new GateOntologyException(
                        "Could not find restriction value for " + restrictionURI + "/" + whatValueURI);
            }
        } catch (Exception e) {
            throw new GateOntologyException(e);
        }
        return null;
    }

    /**
     * Sets the datatype uri for the given restriction uri.
     * 
     * @param restrictionURI
     * @param datatypeURI
     */
    public void setPropertyValue(String restrictionURI, byte restrictionType, String value, String datatypeURI) {
        String whatValueURI = null;
        switch (restrictionType) {
        case OConstants.CARDINALITY_RESTRICTION:
            whatValueURI = OWL.CARDINALITY.toString();
            break;
        case OConstants.MAX_CARDINALITY_RESTRICTION:
            whatValueURI = OWL.MAXCARDINALITY.toString();
            break;
        case OConstants.MIN_CARDINALITY_RESTRICTION:
            whatValueURI = OWL.MINCARDINALITY.toString();
            break;
        default:
            throw new GateOntologyException(
                    "Invalid restriction type :" + restrictionType + " for the restriction " + restrictionURI);
        }
        Statement toDelete = null;
        try {
            RepositoryResult<Statement> iter = repositoryConnection.getStatements(getResource(restrictionURI),
                    makeSesameURI(whatValueURI), null, true);
            if (iter.hasNext()) {
                Statement stmt = iter.next();
                Value v = stmt.getObject();
                if (v instanceof Literal) {
                    if (((Literal) v).getDatatype().toString().intern() == datatypeURI.intern()) {
                        toDelete = stmt;
                    }
                }
            }
        } catch (Exception e) {
            throw new GateOntologyException(e);
        }

        if (toDelete != null) {
            Literal l = (Literal) toDelete.getObject();
            // TODO: !! replace !!
            removeUUUStatement(whatValueURI, l.getLabel(), l.getDatatype().toString());
        }
        // TODO: !! replace !!
        addUUDStatement(restrictionURI, whatValueURI, value, datatypeURI);
    }

    /**
     * Gets the cardinality value specified on the given restriction uri.
     * 
     * @param restrictionURI
     * @param restrictionType
     *          - either of the following constants from the OConstants -
     *          ALL_VALUES_FROM_RESTRICTION, SOME_VALUES_FROM_RESTRICTION, and
     *          HAS_VALUE_RESTRICTION
     * @return
     */
    public ResourceInfo getRestrictionValue(String restrictionURI, byte restrictionType) {
        System.out.println("getRestrictionValue for " + restrictionURI);
        URI whatValueURI = null;
        switch (restrictionType) {
        case OConstants.ALL_VALUES_FROM_RESTRICTION:
            whatValueURI = OWL.ALLVALUESFROM;
            break;
        case OConstants.HAS_VALUE_RESTRICTION:
            whatValueURI = OWL.HASVALUE;
            break;
        case OConstants.SOME_VALUES_FROM_RESTRICTION:
            whatValueURI = OWL.SOMEVALUESFROM;
            break;
        default:
            throw new GateOntologyException(
                    "Invalid restriction type:" + restrictionType + " for the restriction " + restrictionURI);
        }
        String resourceURI;
        try {
            RepositoryResult<Statement> iter = repositoryConnection
                    .getStatements(string2SesameResource(restrictionURI), whatValueURI, null, true);
            if (iter.hasNext()) {
                resourceURI = iter.next().getObject().toString();
                Resource res = getResource(resourceURI);
                boolean isRestriction = repositoryConnection.hasStatement(res, RDF.TYPE, OWL.RESTRICTION, true);
                byte classType = OConstants.OWL_CLASS;
                if (isRestriction) {
                    if (repositoryConnection.hasStatement(res, OWL.HASVALUE, null, true)) {
                        classType = OConstants.HAS_VALUE_RESTRICTION;
                    } else if (repositoryConnection.hasStatement(res, OWL.SOMEVALUESFROM, null, true)) {
                        classType = OConstants.SOME_VALUES_FROM_RESTRICTION;
                    } else if (repositoryConnection.hasStatement(res, OWL.ALLVALUESFROM, null, true)) {
                        classType = OConstants.ALL_VALUES_FROM_RESTRICTION;
                    } else if (repositoryConnection.hasStatement(res, OWL.CARDINALITY, null, true)) {
                        classType = OConstants.CARDINALITY_RESTRICTION;
                    } else if (repositoryConnection.hasStatement(res, OWL.MINCARDINALITY, null, true)) {
                        classType = OConstants.MIN_CARDINALITY_RESTRICTION;
                    } else if (repositoryConnection.hasStatement(res, OWL.MAXCARDINALITY, null, true)) {
                        classType = OConstants.MAX_CARDINALITY_RESTRICTION;
                    }
                }

                if (classType == OConstants.OWL_CLASS) {
                    if (res instanceof BNode) {
                        classType = OConstants.ANNONYMOUS_CLASS;
                    } else {
                        // check if it is an instance
                        if (isIndividual(resourceURI)) {
                            classType = OConstants.INSTANCE;
                        }
                    }
                }

                return new ResourceInfo(resourceURI, classType);
            }
        } catch (Exception e) {
            throw new GateOntologyException("Problem getting restriction value for " + restrictionURI, e);
        }
        return null;
    }

    /**
     * tells if the given URI is registered as an individual
     * @param individualURI
     * @return
     */
    public boolean isIndividual(String individualURI) {

        String query = "Select X from {<" + individualURI
                + ">} rdf:type {X} rdf:type {<http://www.w3.org/2002/07/owl#Class>}";
        return hasSerqlQueryResultRows(query);

    }

    /**
     * Sets the cardinality value for the given restriction uri.
     * 
     * @param restrictionURI
     * @param restrictionType
     *          - either of the following constants from the OConstants -
     *          ALL_VALUES_FROM_RESTRICTION, SOME_VALUES_FROM_RESTRICTION, and
     *          HAS_VALUE_RESTRICTION
     * @param value
     * @return
     */
    public void setRestrictionValue(ONodeID restrictionURI, OURI restrictionTypeURI, ONodeID value) {
        // TODO: should we check the restrictionTypeURI? SHould be one of
        // ALLVALUESFROM, HASVALUE, SOMEVALUESFROM (even though HASVALUE is 
        // not part of owl-lite)

        // if we have already such a restriction with some value ...
        if (ontologyTripleStore.hasTriple(restrictionURI, restrictionTypeURI, (ONodeID) null)) {
            // remove the triples for the old value before adding the new value
            // TODO: check if removing all triples with any value is correct here 
            // (originally the code explicitly only removed the triple with the 
            // specific value found for the object)
            ontologyTripleStore.removeTriple(restrictionURI, restrictionTypeURI, (ONodeID) null);
        }
        // add the new value
        ontologyTripleStore.addTriple(restrictionURI, restrictionTypeURI, value);
    }

    public void setRestrictionValue(ONodeID restrictionURI, OURI restrictionTypeURI,
            gate.creole.ontology.Literal value) {
        // TODO: should we check the restrictionTypeURI? SHould be one of
        // ALLVALUESFROM, HASVALUE, SOMEVALUESFROM (even though HASVALUE is 
        // not part of owl-lite)

        // if we have already such a restriction with some value ...
        if (ontologyTripleStore.hasTriple(restrictionURI, restrictionTypeURI, (ONodeID) null)) {
            // remove the triples for the old value before adding the new value
            // TODO: check if removing all triples with any value is correct here 
            // (originally the code explicitly only removed the triple with the 
            // specific value found for the object)
            ontologyTripleStore.removeTriple(restrictionURI, restrictionTypeURI, (ONodeID) null);
        }
        // add the new value
        ontologyTripleStore.addTriple(restrictionURI, restrictionTypeURI, value);
    }

    /**
     * This method tells what type of restriction the given uri refers to. If the
     * given URI is not a restriction, the method returns -1. Otherwise one of the
     * following values from the OConstants class. OWL_CLASS,
     * CARDINALITY_RESTRICTION, MIN_CARDINALITY_RESTRICTION,
     * MAX_CARDINALITY_RESTRICTION, HAS_VALUE_RESTRICTION,
     * ALL_VALUES_FROM_RESTRICTION.
     * 
     * @param restrictionURI
     * @return
     */
    // TODO: !!! how does this relate to getRestrictionForONodeID
    public byte getClassType(String restrictionURI) {

        Resource res = getResource(restrictionURI);
        logger.debug("Converted to resource: " + res);
        String rep1 = "<" + restrictionURI + ">";
        if (res instanceof BNode) {
            logger.debug("is an instance of Bnode: " + res);
            rep1 = restrictionURI;
        }

        if (res instanceof BNode) {
            logger.debug("is an instance of Bnode: " + res);
            String query = "select * from {" + rep1 + "} owl:hasValue {B}";
            if (hasSerqlQueryResultRows(query)) {
                return OConstants.HAS_VALUE_RESTRICTION;
            }

            query = "select * from {" + rep1 + "} owl:someValuesFrom {B}";
            if (hasSerqlQueryResultRows(query)) {
                return OConstants.SOME_VALUES_FROM_RESTRICTION;
            }

            query = "select * from {" + rep1 + "} owl:allValuesFrom {B}";
            if (hasSerqlQueryResultRows(query)) {
                return OConstants.ALL_VALUES_FROM_RESTRICTION;
            }

            query = "select * from {" + rep1 + "} owl:cardinality {B}";
            if (hasSerqlQueryResultRows(query)) {
                return OConstants.CARDINALITY_RESTRICTION;
            }

            query = "select * from {" + rep1 + "} owl:minCardinality {B}";
            if (hasSerqlQueryResultRows(query)) {
                return OConstants.MIN_CARDINALITY_RESTRICTION;
            }

            query = "select * from {" + rep1 + "} owl:maxCardinality {B}";
            if (hasSerqlQueryResultRows(query)) {
                return OConstants.MAX_CARDINALITY_RESTRICTION;
            }
        }

        if (res instanceof BNode) {
            logger.debug("is an instance of Bnode: " + res);
            return OConstants.ANNONYMOUS_CLASS;
        } else {
            logger.debug("is an ordinary class: " + res);
            return OConstants.OWL_CLASS;
        }
    }

    // ***************************************************************************
    // *********************** Other Utility Methods
    // **************************************************************************
    void addUUUStatement(String subject, String predicate, String object) {
        try {
            startTransaction(null);
            Resource s = subject != null ? getResource(subject) : null;
            URI p = predicate != null ? repositoryConnection.getValueFactory().createURI(predicate) : null;
            Resource o = object != null ? getResource(object) : null;
            repositoryConnection.add(s, p, o, getContextURI());
            endTransaction(null);
        } catch (Exception e) {
            throw new GateOntologyException("error while adding statement into the repository where subject:"
                    + subject + " predicate:" + predicate + " objectURI:" + object, e);
        }
    }

    void addUUDStatement(String subject, String predicate, String object, String datatype) {
        try {
            startTransaction(null);
            Resource s = subject != null ? getResource(subject) : null;
            URI p = predicate != null ? repositoryConnection.getValueFactory().createURI(predicate) : null;
            URI d = repositoryConnection.getValueFactory().createURI(datatype);
            Literal l = object != null ? repositoryConnection.getValueFactory().createLiteral(object, d) : null;
            repositoryConnection.add(s, p, l, getContextURI());
            endTransaction(null);
        } catch (Exception e) {
            throw new GateOntologyException("error while adding statement into the repository where subject:"
                    + subject + " predicate:" + predicate + " objectURI:" + object, e);
        }
    }

    // NOTE: this originally returned the number of removed statements, but
    // this does not work any more with Sesame2
    void removeUUUStatement(String subject, String predicate, String object) {
        try {
            startTransaction(null);
            Resource s = subject != null ? getResource(subject) : null;
            URI p = predicate != null ? repositoryConnection.getValueFactory().createURI(predicate) : null;
            Resource o = object != null ? getResource(object) : null;
            //int no = repositoryConnection.remove(s, p, o);
            // TODO: should we restrict removal to the DATA context?
            repositoryConnection.remove(s, p, o);
            endTransaction(null);
            //return no;
        } catch (Exception e) {
            throw new GateOntologyException("error while removing statement from the repository where subject:"
                    + subject + " predicate:" + predicate + " objectURI:" + object, e);
        }
    }

    void removeUULStatement(String subject, String predicate, String object, String language) {
        try {
            startTransaction(null);
            Resource s = subject != null ? getResource(subject) : null;
            URI p = predicate != null ? repositoryConnection.getValueFactory().createURI(predicate) : null;
            Literal l = null;
            if (language == null) {
                l = object != null ? repositoryConnection.getValueFactory().createLiteral(object) : null;
            } else {
                l = object != null ? repositoryConnection.getValueFactory().createLiteral(object, language) : null;
            }
            repositoryConnection.remove(s, p, l);
            endTransaction(null);
        } catch (Exception e) {
            throw new GateOntologyException("error while removing statement from the repository where subject:"
                    + subject + " predicate:" + predicate + " objectURI:" + object, e);
        }
    }

    void removeUUDStatement(String subject, String predicate, String object, String datatype) {
        try {
            startTransaction(null);
            Resource s = subject != null ? getResource(subject) : null;
            URI p = predicate != null ? repositoryConnection.getValueFactory().createURI(predicate) : null;
            URI d = repositoryConnection.getValueFactory().createURI(datatype);
            Literal l = object != null ? repositoryConnection.getValueFactory().createLiteral(object) : null;

            repositoryConnection.remove(s, p, l);

            l = object != null ? repositoryConnection.getValueFactory().createLiteral(object, d) : null;
            repositoryConnection.remove(s, p, l);
            endTransaction(null);
        } catch (Exception e) {
            throw new GateOntologyException("error while removing statement from the repository where subject:"
                    + subject + " predicate:" + predicate + " objectURI:" + object, e);
        }
    }

    public void startTransaction(String repositoryID) {
    }

    public void endTransaction(String repositoryID) throws GateOntologyException {
    }

    private Property[] listToPropertyArray(List<Property> list) {
        if (list == null) {
            return null;
        }
        ArrayList<Property> subList = new ArrayList<Property>();
        for (int i = 0; i < list.size(); i++) {
            if (hasSystemNameSpace(list.get(i).getUri())) {
                continue;
            }
            subList.add(list.get(i));
        }
        Property[] props = new Property[subList.size()];
        for (int i = 0; i < subList.size(); i++) {
            props[i] = subList.get(i);
        }
        return props;
    }

    private PropertyValue[] listToPropertyValueArray(List<PropertyValue> subList) {
        if (subList == null) {
            return null;
        }
        PropertyValue[] props = new PropertyValue[subList.size()];
        for (int i = 0; i < subList.size(); i++) {
            props[i] = subList.get(i);
        }
        return props;
    }

    private ResourceInfo[] listToResourceInfoArray(List<String> list) {
        if (list == null) {
            return null;
        }
        ArrayList<ResourceInfo> subList = new ArrayList<ResourceInfo>();
        for (int i = 0; i < list.size(); i++) {
            String resourceURI = list.get(i);
            if (hasSystemNameSpace(resourceURI)) {
                continue;
            }
            byte classType = getClassType(resourceURI);
            if (classType == OConstants.ANNONYMOUS_CLASS) {
                continue;
            }
            subList.add(new ResourceInfo(list.get(i).toString(), classType));
        }

        ResourceInfo[] strings = new ResourceInfo[subList.size()];
        for (int i = 0; i < subList.size(); i++) {
            strings[i] = subList.get(i);
        }
        return strings;
    }

    private String[] listToArray(List<String> list) {
        if (list == null) {
            return null;
        }
        ArrayList<String> subList = new ArrayList<String>();
        for (int i = 0; i < list.size(); i++) {
            if (hasSystemNameSpace(list.get(i))) {
                continue;
            }
            subList.add(list.get(i));
        }
        String[] strings = new String[subList.size()];
        for (int i = 0; i < subList.size(); i++) {
            strings[i] = subList.get(i);
        }
        return strings;
    }

    private org.openrdf.model.URI makeSesameURI(String string) {
        Resource rs = repositoryConnection.getValueFactory().createURI(string);
        return (URI) rs;
    }

    private Resource getResource(String string) {
        Resource rs = null; // resourcesMap.get(string);
        // TODO: !!!!!
        if (string.startsWith("_:") || (!string.startsWith("_:") && !string.contains(":"))) {
            if (string.startsWith("_:")) {
                string = string.substring(2);
            }
            rs = repositoryConnection.getValueFactory().createBNode(string);
            logger.debug("Created BNode resource for " + rs);
            //resourcesMap.put(string, rs);
        } else {
            logger.debug("Creating resource for " + string);
            rs = repositoryConnection.getValueFactory().createURI(string);
            logger.debug("Created URI resource for " + string);
            //resourcesMap.put(string, rs);
        }
        logger.debug("Created resource " + rs);
        return rs;
    }

    // TODO: get rid of this and use ontology objects directly!
    private Property createPropertyObject(String uri) throws GateOntologyException {
        OURI ouri = ontology.createOURI(uri);
        byte type = OConstants.ANNOTATION_PROPERTY;
        if (isAnnotationProperty(ouri)) {
            type = OConstants.ANNOTATION_PROPERTY;
        } else if (isObjectProperty(ouri)) {
            type = OConstants.OBJECT_PROPERTY;
        } else if (isDatatypeProperty(ouri)) {
            type = OConstants.DATATYPE_PROPERTY;
        } else if (isTransitiveProperty(ouri)) {
            type = OConstants.TRANSITIVE_PROPERTY;
        } else if (isSymmetricProperty(ouri)) {
            type = OConstants.SYMMETRIC_PROPERTY;
        } else if (isRDFProperty(ouri)) {
            type = OConstants.RDF_PROPERTY;
        } else {
            return null;
        }
        return new Property(type, uri);
    }

    /**
     * This method is used to obtain the most specific classes
     * 
     * @param values
     * @return
     */
    private ResourceInfo[] reduceToMostSpecificClasses(List<ResourceInfo> values) {
        if (values == null || values.isEmpty()) {
            return new ResourceInfo[0];
        }
        List<String> classes = new ArrayList<String>();
        for (int i = 0; i < values.size(); i++) {
            classes.add(values.get(i).getUri());
        }
        outer: for (int i = 0; i < classes.size(); i++) {
            String c = classes.get(i);
            // if the class's children appear in list, it is not the most
            // specific class

            String queryRep = string2Turtle(c);
            String query = "select distinct A FROM {A} rdfs:subClassOf {" + queryRep + "} WHERE A!=" + queryRep
                    + " AND A != ALL ( " + " select distinct B FROM {B} owl:equivalentClass {" + queryRep + "} )";

            List<String> list = new ArrayList<String>();
            addSerqlQueryResultToCollection(query, list);

            for (int j = 0; j < list.size(); j++) {
                if (classes.contains(list.get(j))) {
                    classes.remove(i);
                    values.remove(i);
                    i--;
                    continue outer;
                }
            }
        }
        return values.toArray(new ResourceInfo[0]);
    }

    /**
     * This method is used to obtain the most specific classes
     * 
     * @param values
     * @return
     */
    private List<String> reduceToMostSpecificClasses(Set<String> values) {
        if (values == null || values.isEmpty()) {
            return new ArrayList<String>();
        }
        List<String> classes = new ArrayList<String>(values);
        outer: for (int i = 0; i < classes.size(); i++) {
            String c = classes.get(i);
            // if the class's children appear in list, it is not the most
            // specific class

            String queryRep = string2Turtle(c);
            String query = "select distinct A FROM {A} rdfs:subClassOf {" + queryRep + "} WHERE A!=" + queryRep
                    + " AND A!= ALL ( " + " select distinct B FROM {B} owl:equivalentClass {" + queryRep + "} )";

            List<String> list = new ArrayList<String>();
            addSerqlQueryResultToCollection(query, list);

            for (int j = 0; j < list.size(); j++) {
                if (classes.contains(list.get(j))) {
                    classes.remove(i);
                    i--;
                    continue outer;
                }
            }
        }
        return classes;
    }

    private byte getPropertyType(OURI aPropertyURI) throws GateOntologyException {
        if (isDatatypeProperty(aPropertyURI)) {
            return OConstants.DATATYPE_PROPERTY;
        } else if (isTransitiveProperty(aPropertyURI)) {
            return OConstants.TRANSITIVE_PROPERTY;
        } else if (isSymmetricProperty(aPropertyURI)) {
            return OConstants.SYMMETRIC_PROPERTY;
        } else if (isObjectProperty(aPropertyURI)) {
            return OConstants.OBJECT_PROPERTY;
        } else if (isAnnotationProperty(aPropertyURI)) {
            return OConstants.ANNOTATION_PROPERTY;
        } else {
            return OConstants.RDF_PROPERTY;
        }
    }

    private PropertyValue[] getPropertyValues(String aResourceURI, String aPropertyURI)
            throws GateOntologyException {
        Resource r = getResource(aResourceURI);
        String rep1 = "<" + aResourceURI + ">";
        String rep2 = "{" + rep1 + "}";
        if (r instanceof BNode) {
            rep1 = "_:" + aResourceURI;
            rep2 = "{" + rep1 + "}";
        }
        String query = "Select DISTINCT Y from " + rep2 + " <" + aPropertyURI + "> {Y}";
        UtilTupleQueryIterator result = performSerqlQuery(query);
        List<PropertyValue> list = new ArrayList<PropertyValue>();
        while (result.hasNext()) {
            list.add(new PropertyValue(String.class.getName(), result.nextFirstAsString()));
        }
        result.close();
        return listToPropertyValueArray(list);
    }

    String executeQuery(String serqlQuery) {
        //logger.info("executeQuery: "+serqlQuery);
        TupleQueryResult res = null;
        String ret = "";
        String msg = "Error executing query: " + serqlQuery;
        try {
            res = repositoryConnection.prepareTupleQuery(org.openrdf.query.QueryLanguage.SERQL, serqlQuery)
                    .evaluate();
            // TODO: convert to string that is compatible what the old Sesame1 to string
            // method did!
            // code taken from Sesame1    org.openrdf.sesame.query.QueryResultsTable.toString()
            StringBuffer buf = new StringBuffer();
            List<String> bindings = res.getBindingNames();
            //System.out.println("Found bindings: "+bindings);
            String[] _columnNames = bindings.toArray(new String[0]);
            //System.out.println("Found columns names: "+_columnNames);
            if (_columnNames != null) {
                for (int i = 0; i < _columnNames.length; i++) {
                    if (i > 0) {
                        buf.append("\t| ");
                    }
                    buf.append(_columnNames[i]);
                }
                buf.append('\n');

                int dashCount = buf.length() + 7 * (_columnNames.length - 1);
                for (int i = 0; i < dashCount; i++) {
                    buf.append('-');
                }
                buf.append('\n');
            }

            Vector<Value> columns = new Vector<Value>(bindings.size());
            for (int j = 0; j < bindings.size(); j++) {
                columns.add(null);
            }
            //for (int i = 0; i < _rowList.size(); i++) {
            while (res.hasNext()) {
                BindingSet bs = res.next();
                int i = 0;
                for (String name : bindings) {
                    columns.set(i++, bs.getValue(name));
                    //System.out.println("Found columns: "+columns);
                }
                //List columns = (List)_rowList.get(i);

                for (int j = 0; j < columns.size(); j++) {
                    if (j > 0) {
                        buf.append("\t| ");
                    }
                    buf.append(columns.get(j).stringValue());
                }
                buf.append('\n');
            }

            ret = buf.toString();

        } catch (QueryEvaluationException ex) {
            throw new GateOntologyException(msg, ex);
        } catch (RepositoryException ex) {
            throw new GateOntologyException(msg, ex);
        } catch (MalformedQueryException ex) {
            throw new GateOntologyException(msg, ex);
        } finally {
            if (res != null) {
                try {
                    res.close();
                } catch (QueryEvaluationException ex) {
                    throw new GateOntologyException(msg, ex);
                }
            }
        }
        //logger.info("executeQuery returns:\n"+ret+"\n");
        return ret;
    }

    // ***************************************************************************
    // *** UTILITY FUNCTIONS
    // ***************************************************************************

    public RepositoryConnection getRepositoryConnection() {
        return repositoryConnection;
    }

    // TODO: is returnSystemStatements still relevant?
    // if yes, check how often and where actually used
    // This should probably become part of the query anyways.
    // Try to get rid and move entirely to UtilConvert
    private boolean hasSystemNameSpace(String uri) {
        if (returnSystemStatements) {
            return false;
        }
        Boolean val = new Boolean(Utils.hasSystemNameSpace(uri));
        return val.booleanValue();
    }

    private RDFWriter getRDFWriter4Format(OutputStream out, OntologyFormat ontologyFormat) {
        RDFWriter writer = null;
        switch (ontologyFormat) {
        case N3:
            writer = new N3Writer(out);
            break;
        case NTRIPLES:
            writer = new NTriplesWriter(out);
            break;
        case TURTLE:
            writer = new TurtleWriter(out);
            break;
        case RDFXML:
            writer = new RDFXMLWriter(out);
            break;
        default:
            throw new GateOntologyException("Unsupported ontology format: " + ontologyFormat);
        }
        addDefaultNamespaceHandler(writer);
        return writer;
    }

    private RDFWriter getRDFWriter4Format(Writer out, OntologyFormat ontologyFormat) {
        RDFWriter writer = null;
        switch (ontologyFormat) {
        case N3:
            writer = new N3Writer(out);
            break;
        case NTRIPLES:
            writer = new NTriplesWriter(out);
            break;
        case TURTLE:
            writer = new TurtleWriter(out);
            break;
        case RDFXML:
            writer = new RDFXMLWriter(out);
            break;
        default:
            throw new GateOntologyException("Unsupported ontology format: " + ontologyFormat);
        }
        addDefaultNamespaceHandler(writer);
        return writer;
    }

    private void addDefaultNamespaceHandler(RDFWriter writer) {
        if (ontology.getDefaultNameSpace() != null) {
            //System.out.println("Trying to set default namespace URI on writing to "+ontology.getDefaultNameSpace());
            try {
                writer.handleNamespace("", ontology.getDefaultNameSpace());
            } catch (org.openrdf.rio.RDFHandlerException ex) {
                throw new GateOntologyException("Could not set default namespace for export " + ex);
            }
        } else {
            //System.out.println("Default namespace is not set!");
            logger.debug("No default namespace set when writing ontology");
        }
    }

    private RDFFormat ontologyFormat2RDFFormat(OntologyFormat format) {
        switch (format) {
        case RDFXML:
            return RDFFormat.RDFXML;
        case N3:
            return RDFFormat.N3;
        case NTRIPLES:
            return RDFFormat.NTRIPLES;
        case TURTLE:
            return RDFFormat.TURTLE;
        default:
            throw new GateOntologyException("Unsupported ontology format: " + format);
        }
    }

    private String string2Turtle(String queryRep1) {
        if (!queryRep1.startsWith("_:") && !queryRep1.startsWith("<")) {
            if (queryRep1.contains(":")) {
                queryRep1 = "<" + queryRep1 + ">";
            } else {
                queryRep1 = "_:" + queryRep1;
            }
        }
        return queryRep1;
    }

    // The query language of the query is determined automatically: if the
    // query string contains "USING NAMESPACE" it is SERQL, if it contains
    // "PREFIX" at the beginning of a line it is SPARQL. If neither applies,
    // an exception is thrown.
    UtilTupleQueryIterator qp_getClassesTopAll;
    UtilTupleQueryIterator qp_getClassesAllAll;
    UtilTupleQueryIterator qp_getOntologyURIs;
    UtilTupleQueryIterator qp_getInstancesAll;
    UtilTupleQueryIterator qp_getInstancesAllFor;
    UtilTupleQueryIterator qp_getInstancesDirectFor;
    UtilTupleQueryIterator qp_hasInstance;
    // Unfortunately, the prepared queries do not work properly with
    // setBinding, we need to do String substitution!
    //UtilTupleQueryIterator qp_hasInstanceAllFor;
    //UtilTupleQueryIterator qp_hasInstanceDirectFor;
    String qs_hasInstanceAllFor;
    QueryLanguage ql_hasInstanceAllFor;
    String qs_hasInstanceDirectFor;
    QueryLanguage ql_hasInstanceDirectFor;

    UtilTupleQueryIterator qp_getRestrictionTypeFor;

    // Unfortunately, the prepared queries do not work properly with
    // setBinding, we need to do String substitution!
    //UtilTupleQueryIterator qp_getSubClassesAllFor;
    //UtilTupleQueryIterator qp_getSubClassesDirectFor;
    String qs_getSubClassesAllFor;
    QueryLanguage ql_getSubClassesAllFor;
    String qs_getSubClassesDirectFor;
    QueryLanguage ql_getSubClassesDirectFor;

    String qs_getClassesByNameNoW3;
    QueryLanguage ql_getClassesByNameNoW3;
    //UtilTupleQueryIterator qp_getClassesByNameNoW3;
    File queriesDir;

    private void initQueries(String querySet) {
        queriesDir = new File(((AbstractOntologyImpl) ontology).getPluginDir(), "queries");
        queriesDir = new File(queriesDir, querySet);
        if (!queriesDir.exists()) {
            throw new GateOntologyException("Queries directory not found: " + queriesDir.getAbsolutePath());
        }

        qp_getClassesTopAll = getPreparedTupleQueryFromFile("getClassesTopAll");
        qp_getClassesAllAll = getPreparedTupleQueryFromFile("getClassesAllAll");
        qp_getOntologyURIs = getPreparedTupleQueryFromFile("getOntologyURIs");
        qp_getInstancesAll = getPreparedTupleQueryFromFile("getInstancesAll");
        qp_getInstancesDirectFor = getPreparedTupleQueryFromFile("getInstancesDirectFor");
        qp_getInstancesAllFor = getPreparedTupleQueryFromFile("getInstancesAllFor");
        qp_hasInstance = getPreparedTupleQueryFromFile("hasInstance");
        //qp_hasInstanceAllFor      = getPreparedTupleQueryFromFile("hasInstanceAllFor");
        //qp_hasInstanceDirectFor   = getPreparedTupleQueryFromFile("hasInstanceDirectFor");
        qs_hasInstanceAllFor = getQueryStringFromFile("hasInstanceAllFor");
        ql_hasInstanceAllFor = determineQueryLanguage(qs_hasInstanceAllFor);
        qs_hasInstanceDirectFor = getQueryStringFromFile("hasInstanceDirectFor");
        ql_hasInstanceDirectFor = determineQueryLanguage(qs_hasInstanceDirectFor);
        qp_getRestrictionTypeFor = getPreparedTupleQueryFromFile("getRestrictionTypeFor");

        qs_getSubClassesAllFor = getQueryStringFromFile("getSubClassesAllFor");
        ql_getSubClassesAllFor = determineQueryLanguage(qs_getSubClassesAllFor);
        qs_getSubClassesDirectFor = getQueryStringFromFile("getSubClassesDirectFor");
        ql_getSubClassesDirectFor = determineQueryLanguage(qs_getSubClassesDirectFor);

        qs_getClassesByNameNoW3 = getQueryStringFromFile("getClassesByNameNoW3");
        ql_getClassesByNameNoW3 = determineQueryLanguage(qs_getClassesByNameNoW3);

    }

    private UtilTupleQueryIterator getPreparedTupleQueryFromFile(String filename) {
        String queryString = null;
        try {
            queryString = FileUtils.readFileToString(new File(queriesDir, filename));
        } catch (IOException ex) {
            throw new GateOntologyException("Could not read query file: " + filename, ex);
        }
        QueryLanguage queryLanguage = determineQueryLanguage(queryString);
        return new UtilTupleQueryIterator(sesameManager, queryString, queryLanguage);
    }

    private String getQueryStringFromFile(String filename) {
        String queryString = null;
        try {
            queryString = FileUtils.readFileToString(new File(queriesDir, filename));
        } catch (IOException ex) {
            throw new GateOntologyException("Could not read query file: " + filename, ex);
        }
        return queryString;
    }

    private UtilBooleanQuery getPreparedBooleanQueryFromFile(String filename) {
        String queryString = null;
        try {
            queryString = FileUtils.readFileToString(new File(queriesDir, filename));
        } catch (IOException ex) {
            throw new GateOntologyException("Could not read query file: " + filename, ex);
        }
        QueryLanguage queryLanguage = determineQueryLanguage(queryString);
        return new UtilBooleanQuery(sesameManager, queryString, queryLanguage);

    }

    private QueryLanguage determineQueryLanguage(String query) {
        if (query.contains("USING NAMESPACE")) {
            return QueryLanguage.SERQL;
        } else if (query.contains("PREFIX ")) {
            return QueryLanguage.SPARQL;
        } else {
            throw new GateOntologyException("Could not determine query language for: " + query);
        }
    }

    // ***************************************************************************
    // **** STUFF TO GET RID OF EVENTUALLY
    // ***************************************************************************

    /**
     * Debug parameter, if set to true, shows various messages when different
     * methods are invoked
     */
    private boolean debug = true;

    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    public boolean getDebug() {
        return debug;
    }

    // TODO: make it a constructor parameter or something that is settable
    // if this service creates triples using the DATA or META graph URI.
    // That way, the same repository can be used for both meta and data if
    // we create to ontology objects with different graph URIs.

    // TODO: STUFF TO GET RID OF
    // TODO: get rid of this or make semantics available to API?
    // If it is just internal, make this local to whatever method and
    // context where it is relevant
    private boolean returnSystemStatements = false;

    // at some point we should never need this as all our URIs already should
    // be ONodeIDs or OURIs
    @Deprecated
    private ONodeID string2ONodeID(String uri) {
        if (uri.startsWith("_:")) {
            return new OBNodeIDImpl(uri);
        } else if (uri.contains(":")) {
            return new OURIImpl(uri);
        } else {
            return new OBNodeIDImpl(uri);
        }
    }

    @Deprecated
    private Resource string2SesameResource(String uriString) {
        if (uriString.startsWith("_:")) {
            return repositoryConnection.getValueFactory().createBNode(uriString.substring(2));
            //return new BNodeImpl(uriString.substring(2));
        } else {
            // we can still get bnodeids from old methods where the initial _: is missing
            // we assume that if the string contains a colon it must be a proper
            // URI, otherwise it must be a Bnodeid
            if (uriString.contains(":")) {
                return repositoryConnection.getValueFactory().createURI(uriString);
                //return new URIImpl(uriString);
            } else {
                return repositoryConnection.getValueFactory().createBNode(uriString);
                //return new BNodeImpl(uriString);
            }
        }
    }

}