LearnPAd/learnpad

View on GitHub
lp-ontology-recommender/src/main/resources/gate/plugins/Ontology/src/gate/creole/ontology/impl/sesame/OntologyServiceImplSesame.java

Summary

Maintainability
F
3 wks
Test Coverage
/*
 *  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 18239 2014-08-11 05:19:20Z johann_p $
 */
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
    logger.warn("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)
  {
    logger.debug("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);
      }
    }
  }
  
  


}