Log in Help
Print
Homereleasesgate-5.1-beta2-build3402-ALLpluginsOntologysrcgatecreoleontologyimplsesame 〉 OntologyServiceImplSesame.java
 
/*
 *  Copyright (c) 1998-2009, The University of Sheffield.
 *
 *  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 11600 2009-10-13 17:13:22Z johann_p $
 */
package gate.creole.ontology.impl.sesame;

// 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.RDFProperty;
import gate.creole.ontology.impl.*;
import gate.util.ClosableIterator;

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.List;
import java.util.Set;


import java.util.logging.Level;
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.model.impl.BNodeImpl;
import org.openrdf.model.impl.URIImpl;
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(
      "http://gate.ac.uk/dummyuri/OWLIM3OntologyPlugin/#DataContext");
  private static final org.openrdf.model.URI SYSTEM_IMPORT_CONTEXT_URI =
      new org.openrdf.model.impl.URIImpl(
      "http://gate.ac.uk/dummyuri/OWLIM3OntologyPlugin/#SystemImportContext");


  // ***************************************************************************
  // **** CONSTANTS for prepared queries and the assiciated query variables
  // ***************************************************************************


  private Logger logger;

  protected SesameManager sesameManager;

  private RepositoryConnection repositoryConnection;

  public final AbstractOntologyImplSesame ontology;
  private String ontologyUrl;



  /**
   * Constructor
   */
  public OntologyServiceImplSesame(AbstractOntologyImplSesame o) {
    super();
    ontology = o;
    logger = Logger.getLogger(this.getClass().getName());
  }

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

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

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

  /**
   * 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
   */
  void createManagedRepository(URL repoLoc, String repositoryID, URL configFileURL) {
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("id", repositoryID);
    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 = sesameManager.getRepositoryConnection();
    try {
      repositoryConnection.setAutoCommit(true);
    } catch (RepositoryException ex) {
      sesameManager.disconnect();
      throw new GateOntologyException("Could not set autocommit");
    }
    init();
  }

  /**
   * Conect 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 repositoryURL
   * @param repositoryID
   */
  void connectToRepository(URL repositoryURL, String repositoryID) {
    sesameManager = new SesameManager();
    logger.debug("Service: calling connectToRepository for id " + repositoryID);
    sesameManager.connectToRepository(repositoryURL, repositoryID);
    repositoryConnection = sesameManager.getRepositoryConnection();
    try {
      repositoryConnection.setAutoCommit(true);
    } catch (RepositoryException ex) {
      sesameManager.disconnect();
      throw new GateOntologyException("Could not set autocommit");
    }
    init();
  }

  /**
   * 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();
  }

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

  public void readOntologyData(File selectedFile, String baseURI,
      OntologyFormat ontologyFormat, boolean asImport) {
    org.openrdf.model.URI contextURI;
    if (!asImport) {
      contextURI = DATA_CONTEXT_URI;
    } 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 = DATA_CONTEXT_URI;
    } 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 = DATA_CONTEXT_URI;
    } 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, DATA_CONTEXT_URI, IMPORT_CONTEXT_URI);
      } else {
        repositoryConnection.export(writer, DATA_CONTEXT_URI);
      }
    } 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, DATA_CONTEXT_URI, IMPORT_CONTEXT_URI);
      } else {
        repositoryConnection.export(writer, DATA_CONTEXT_URI);
      }
    } 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 allows adding version information to the repository.
   *
   * @param versionInfo
   */
  public void setVersion(String versionInfo) {
    addUULStatement(this.ontologyUrl, OWL.VERSIONINFO.toString(), versionInfo, null);
  }

  /**
   * 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) {
    addUUUStatement(theURI.toString(), RDF.TYPE.toString(), OWL.ONTOLOGY.toString());
  }



  // ***************************************************************************
  // **** CLASS RELATED METHODS
  // ***************************************************************************
  /**
   * The method allows adding a class to repository.
   *
   * @param classURI
   */
  public void addClass(String classURI, byte classType) {
    switch (classType) {
      case OConstants.OWL_CLASS:
        addUUUStatement(classURI, RDF.TYPE.toString(), OWL.CLASS.toString());
        return;
      default:
        addUUUStatement(classURI, RDF.TYPE.toString(), OWL.RESTRICTION.toString());
        return;
    }
  }

  /**
   * 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!
  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);
    //}
    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());
        }
      }
      ClosableIterator<OInstance> instIt =
          getInstancesIterator(string2ONodeID(classURI), Closure.DIRECT_CLOSURE);
      //for (int i = 0; i < individuals.length; i++) {
      while(instIt.hasNext()) {
        removeUUUStatement(instIt.next().toString(), RDF.TYPE.toString(), classURI);
        for (int j = 0; j < superClasses.length; j++) {
          addUUUStatement(instIt.next().toString(), RDF.TYPE.toString(), superClasses[j].getUri());
        }
      }
    }
    try {
      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.
   *
   * @return
   */
  public boolean hasClass(String classURI)
  {
    //System.out.println("Checking for class: "+classURI);
    try {
      // TODO: make two versions: one taking ONodeID and one String
      boolean hasOWLClass = 
          repositoryConnection.hasStatement(string2SesameResource(classURI),
          RDF.TYPE, OWL.CLASS, true);
      if (!hasOWLClass) {
        boolean hasRDFSClass = 
            repositoryConnection.hasStatement(string2SesameResource(classURI),
            RDF.TYPE, RDFS.CLASS, true);
        //System.out.println("OWL class not found, RDFS class "+hasRDFSClass);
        return hasRDFSClass;
      } else {
        //System.out.println("OWL class found");
        return true;
      }
    } catch (RepositoryException ex) {
      throw new GateOntologyException("Could not do hasStatement for class "+classURI);
    }
  }

  public boolean containsURI(OURI theURI) {
    try {
      return
          repositoryConnection.hasStatement(oNodeID2SesameResource(theURI), null, null, true) ||
          repositoryConnection.hasStatement(null, (URI) oNodeID2SesameResource(theURI), null, true) ||
          repositoryConnection.hasStatement(null, null, oNodeID2SesameResource(theURI), true);
    } catch (RepositoryException ex) {
      throw new GateOntologyException("Problem when looking up URI "+theURI,ex);
    }
  }


  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(
            repositoryConnection, 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(repositoryConnection,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(repositoryConnection,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(repositoryConnection,query,QueryLanguage.SERQL);
    boolean hasResult = result.hasNext();
    result.close();
    return hasResult;
  }

  protected UtilTupleQueryIterator performSerqlQuery(String serqlQuery) {
    return 
        new UtilTupleQueryIterator(repositoryConnection,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(String theClassURI1,
      String theClassURI2)
  {

    String queryRep1 =  string2Turtle(theClassURI1);
    String queryRep2 =  string2Turtle(theClassURI2);

    String query =
        "SELECT * FROM {" + queryRep1 + "} owl:equivalentClass {" + queryRep2 + "}";
    return hasSerqlQueryResultRows(query);
  }

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

  /**
   * 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();
      // 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(anAnnProp.toString().intern())) {
          type = OConstants.SYMMETRIC_PROPERTY;
        } else if (isTransitiveProperty(anAnnProp.toString().intern())) {
          type = OConstants.TRANSITIVE_PROPERTY;
        }

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

        list.add(new Property(type, anAnnProp.toString()));
      }
    }
    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();
      // 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(anAnnProp.toString().intern())) {
          type = OConstants.SYMMETRIC_PROPERTY;
        } else if (isTransitiveProperty(anAnnProp.toString().intern())) {
          type = OConstants.TRANSITIVE_PROPERTY;
        }

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

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

        list.add(new Property(type, anAnnProp.toString()));
      }
    }
    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()) {
      String propString = result.nextFirstAsString();
      if (isAnnotationProperty(propString) || isDatatypeProperty(propString) || isObjectProperty(propString) || isTransitiveProperty(propString) || isSymmetricProperty(propString)) {
        continue;
      }
      list.add(new Property(OConstants.RDF_PROPERTY, propString));
    }
    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(String aPropertyURI)
  {
    String query =
        "Select * FROM {X} rdf:type {<" + OWL.ANNOTATIONPROPERTY + ">} WHERE X=<" + aPropertyURI + ">";
    return hasSerqlQueryResultRows(query);
  }

  /**
   * Adds a new annotation property value and specifies the language.
   * 
   * @param theAnnotationProperty
   *          the annotation property
   * @param value
   *          the value containing some value
   */
  public void addAnnotationPropertyValue(String theResourceURI, String 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);
    }
    addUULStatement(theResourceURI, theAnnotationPropertyURI, value, language);
  }

  /**
   * Gets the list of annotation property values
   * 
   * @param theResourceURI
   * @param theAnnotationPropertyURI
   * @return
   */
  public PropertyValue[] getAnnotationPropertyValues(String theResourceURI, String 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;
    }

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

    UtilTupleQueryIterator result = performSerqlQuery(query);
    while (result.hasNext()) {
      // TODO: how to process a literal here? Is the string representation
      // we get identical with literal.getLabel()?
      PropertyValue pv;
      Literal literal = (Literal) result.nextFirstAsValue();
      //Literal literal = (Literal)iter.getValue(i, 0);
      //pv = new PropertyValue(literal.getLanguage(), literal.getLabel());
      pv = new PropertyValue(literal.getLanguage(), literal.getLabel());
      list.add(pv);
    }
    return listToPropertyValueArray(list);
  }

  /**
   * Gets the annotation property for the given resource uri.
   * 
   * @param repositoryID
   * @param theResourceURI
   * @param theAnnotationPropertyURI
   * @param language
   * @return
   */
  public String getAnnotationPropertyValue(String theResourceURI, String theAnnotationPropertyURI, 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: !!! use toTurtle
    Resource r2 = getResource(theResourceURI);
    String queryRep21 = "<" + theResourceURI + ">";
    if (r2 instanceof BNode) {
      queryRep21 = "_:" + theResourceURI;
    }

    String query =
        "Select Y from {X} <" + theAnnotationPropertyURI + "> {Y} WHERE X=" + queryRep21 + " AND isLiteral(Y) AND lang(Y) LIKE \"" + language + "\"";

    UtilTupleQueryIterator result = performSerqlQuery(query);
    Literal literal = null;
    if (result.hasNext()) {
      literal = (Literal) result.nextFirstAsValue();
    }
    result.close();
    if (literal != null) {
      return literal.getLabel();
    } else {
      return null;
    }
  }

  /**
   * For the current resource, the method removes the given literal for the
   * given property.
   * 
   * @param theAnnotationProperty
   * @param literal
   */
  public void removeAnnotationPropertyValue(String theResourceURI, String 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);
    }
    startTransaction(null);
    removeUULStatement(theResourceURI, theAnnotationPropertyURI, value,
        language);
    endTransaction(null);
  }

  /**
   * Removes all values for a named property.
   * 
   * @param theProperty
   *          the property
   */
  public void removeAnnotationPropertyValues(String theResourceURI, String theAnnotationPropertyURI)
  {
    try {
      // 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);
      }
      startTransaction(null);
      repositoryConnection.remove(
          getResource(theResourceURI),
          makeSesameURI(theAnnotationPropertyURI), null);
      endTransaction(null);
    } catch (Exception e) {
      throw new GateOntologyException(
          "Error while removing annotation property values " + e.getMessage(), e);
    }
  }

  // **************
  // 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(String aPropertyURI,
      String[] domainClassesURIs, String[] rangeClassesTypes)
      throws GateOntologyException {
    addUUUStatement(aPropertyURI, RDF.TYPE.toString(), RDF.PROPERTY.toString());

    if (domainClassesURIs != null) {
      for (int i = 0; i < domainClassesURIs.length; i++) {
        addUUUStatement(aPropertyURI, RDFS.DOMAIN.toString(), domainClassesURIs[i]);
      }
    }
    if (rangeClassesTypes != null) {
      for (int i = 0; i < rangeClassesTypes.length; i++) {
        addUUUStatement(aPropertyURI, RDFS.RANGE.toString(), rangeClassesTypes[i]);
      }
    }
  }

  /**
   * returns if the given property is an RDF property
   * 
   * @param aPropertyURI
   * @return Done
   */
  public boolean isRDFProperty(String aPropertyURI)
  {
    boolean found =
        isAnnotationProperty(aPropertyURI) || isDatatypeProperty(aPropertyURI) || isObjectProperty(aPropertyURI) || isTransitiveProperty(aPropertyURI) || isSymmetricProperty(aPropertyURI);
    if (!found) {
      String query =
          "Select * FROM {X} rdf:type {<" + RDF.PROPERTY.toString() + ">} WHERE X=<" + aPropertyURI + ">";
      return hasSerqlQueryResultRows(query);
    } 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(String aPropertyURI,
      String[] domainClassesURIs, String dataTypeURI)
 {
    addUUUStatement(aPropertyURI, RDF.TYPE.toString(), OWL.DATATYPEPROPERTY.toString());
    addUUUStatement(aPropertyURI, RDFS.RANGE.toString(), dataTypeURI);

    if (domainClassesURIs != null) {
      for (int i = 0; i < domainClassesURIs.length; i++) {
        addUUUStatement(aPropertyURI, RDFS.DOMAIN.toString(), domainClassesURIs[i]);
      }
    }
  }

  /**
   * Returns the datatype uri specified for the given datatype property.
   * 
   * @param theDatatypePropertyURI
   * @return
   * @throws GateOntologyException
   */
  public String getDatatype(String theDatatypePropertyURI)
  {
    // isAnnotationProperty also checks for the correct repository so no
    // need to give a call to it
    if (!isDatatypeProperty(theDatatypePropertyURI)) {
      throw new GateOntologyException(
          "Invalid DatatypeProperty :" + theDatatypePropertyURI);
    }

    String query =
        "Select Z from {<" + theDatatypePropertyURI + ">} 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 domainAndRangeClassesURIs
   *          Done
   */
  public void addSymmetricProperty(String aPropertyURI,
      String[] domainAndRangeClassesURIs)
  {
    if (debug) {
      logger.debug("addSymmetricProperty");
    }
    addUUUStatement(aPropertyURI, RDF.TYPE.toString(), OWL.SYMMETRICPROPERTY.toString());
    if (domainAndRangeClassesURIs != null) {
      for (int i = 0; i < domainAndRangeClassesURIs.length; i++) {
        addUUUStatement(aPropertyURI, RDFS.DOMAIN.toString(), domainAndRangeClassesURIs[i]);
        addUUUStatement(aPropertyURI, RDFS.RANGE.toString(), domainAndRangeClassesURIs[i]);
      }
    }
  }

  /**
   * Checkes whether the two properties are Equivalent.
   * 
   * @param aPropertyURI
   * @return
   * @throws GateOntologyException
   */
  public boolean isEquivalentPropertyAs(String aPropertyURI1, String aPropertyURI2)
  {
    String query =
        "Select * FROM {<" + aPropertyURI1 + ">} " + OWL.EQUIVALENTPROPERTY + " {<" + aPropertyURI2 + ">}";
    return hasSerqlQueryResultRows(query);
  }

  /**
   * 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(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(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(String theInstanceURI1, String theInstanceURI2)
  {
    String query =
        "Select * from {<" + theInstanceURI1 + ">} owl:differentFrom {<" + theInstanceURI2 + ">}";
    return hasSerqlQueryResultRows(query);
  }

  /**
   * Checkes whether the two individuals are same.
   * 
   * @param individualURI1
   * @param invidualURI2
   * @return
   */
  public boolean isSameIndividualAs(String theInstanceURI1, String theInstanceURI2)
  {
    String query =
        "Select * from {<" + theInstanceURI1 + ">} owl:sameAs {<" + theInstanceURI2 + ">}";
    return hasSerqlQueryResultRows(query);
  }

  // *************
  // Instances and properties
  // **************
  /**
   * adds the RDF Property value on the specified instance
   * 
   * @param anInstanceURI
   * @param anRDFPropertyURI
   * @param aResourceURI
   */
  public void addRDFPropertyValue(String anInstanceURI,
      String anRDFPropertyURI, String aResourceURI)
  {
    addUUUStatement(anInstanceURI, anRDFPropertyURI, aResourceURI);
  }

  /**
   * Removes the specified RDF Property Value
   * 
   * @param anInstanceURI
   * @param anRDFPropertyURI
   * @param aResourceURI
   */
  public void removeRDFPropertyValue(String anInstanceURI,
      String anRDFPropertyURI, String aResourceURI)
  {
    startTransaction(null);
    removeUUUStatement(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);
  }

  /**
   * 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(String anInstanceURI, String aDatatypePropertyURI, String datatypeURI,
      String value)
  {
    if (!isDatatypeProperty(aDatatypePropertyURI)) {
      throw new GateOntologyException(
          "No datatype property exists with URI :" + aDatatypePropertyURI);
    }
    addUUDStatement(anInstanceURI, aDatatypePropertyURI, value,
        datatypeURI);
  }

  /**
   * Removes the provided value for the given instance.
   * 
   * @param anInstanceURI
   * @param aDatatypePropertyURI
   * @param datatypeURI
   * @param value
   */
  public void removeDatatypePropertyValue(String anInstanceURI, String aDatatypePropertyURI, String datatypeURI,
      String value)
  {
    if (!isDatatypeProperty(aDatatypePropertyURI)) {
      throw new GateOntologyException(
          "No datatype property exists with URI :" + aDatatypePropertyURI);
    }
    startTransaction(null);
    removeUUDStatement(anInstanceURI, aDatatypePropertyURI,
        value, datatypeURI);
    endTransaction(null);
  }

  /**
   * Gets a list of values for the given Property.
   * 
   * @param anInstanceURI
   * @param aDatatypePropertyURI
   * @return
   */
  public PropertyValue[] getDatatypePropertyValues(String anInstanceURI, String aDatatypePropertyURI)
  {
    if (!isDatatypeProperty(aDatatypePropertyURI)) {
      throw new GateOntologyException(
          "No datatype property exists with URI :" + aDatatypePropertyURI);
    }

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

    List<PropertyValue> list = new ArrayList<PropertyValue>();
    String query =
        "Select DISTINCT Y from {X} <" + aDatatypePropertyURI + "> {Y} WHERE X=" + queryRep21 + " AND isLiteral(Y)";

    UtilTupleQueryIterator result = performSerqlQuery(query);
    while (result.hasNext()) {
      PropertyValue pv;
      Literal literal = (Literal) result.nextFirstAsValue();
      String datatype = "http://www.w3.org/2001/XMLSchema#string";
      if (literal.getDatatype() != null) {
        datatype = literal.getDatatype().toString();
      }
      pv = new PropertyValue(datatype, literal.getLabel());
      list.add(pv);
    }
    return listToPropertyValueArray(list);
  }

  /**
   * Removes all property values set on the provided instance for the current
   * property.
   * 
   * @param anInstanceURI
   * @param aDatatypePropertyURI
   */
  public void removeDatatypePropertyValues(String anInstanceURI, String aDatatypePropertyURI)
  {
    if (!isDatatypeProperty(aDatatypePropertyURI)) {
      throw new GateOntologyException(
          "No datatype property exists with URI :" + aDatatypePropertyURI);
    }
    startTransaction(null);
    removeUUUStatement(anInstanceURI, aDatatypePropertyURI, 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(String sourceInstanceURI, String anObjectPropertyURI,
      String theValueInstanceURI) {
    try {
      if (!repositoryConnection.hasStatement(
          getResource(anObjectPropertyURI),
          makeSesameURI(RDF.TYPE.toString()),
          getResource(OWL.OBJECTPROPERTY.toString()),
          true)) {
        throw new GateOntologyException(
            "No object property exists with URI :" + anObjectPropertyURI);
      }
    } catch (Exception e) {
      throw new GateOntologyException("Could not check for statement", e);
    }
    addUUUStatement(sourceInstanceURI, anObjectPropertyURI, theValueInstanceURI);
  }

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

    startTransaction(null);
    removeUUUStatement(sourceInstanceURI, anObjectPropertyURI,
        theValueInstanceURI);
    endTransaction(null);
  }

  /**
   * Gets a list of values for the given Property (Object, Symmetric and
   * Transitive).
   * 
   * @param sourceInstanceURI
   * @param anObjectPropertyURI
   * @return
   */
  public String[] getObjectPropertyValues(String sourceInstanceURI, String 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;
    }

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

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

  /**
   * Removes all property values set for the current property (Object, Symmetric
   * and Transitive).
   * 
   * @param sourceInstanceURI
   * @param anObjectPropertyURI
   */
  public void removeObjectPropertyValues(String sourceInstanceURI, String anObjectPropertyURI)
  {
    if (!isObjectProperty(anObjectPropertyURI)) {
      throw new GateOntologyException(
          "No object property exists with URI :" + anObjectPropertyURI);
    }
    startTransaction(null);
    removeUUUStatement(sourceInstanceURI, anObjectPropertyURI, null);
    endTransaction(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)
  {
    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)
  {
    addUUUStatement(subClassURI, RDFS.SUBCLASSOF.toString(), superClassURI);
  }

  /**
   * Removes the subclass relationship
   * 
   * @param superClassURI
   * @param subClassURI
   */
  public void removeSubClass(String superClassURI,
      String subClassURI) {
    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(
          repositoryConnection, 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(
          repositoryConnection, query, ql_getSubClassesAllFor);
      return new UtilResourceQueryIterator<OClass>(
          this, qp_getSubClassesAllFor, OClass.class);

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


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



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

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

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

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

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

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

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

    return listToResourceInfoArray(list);
  }

  /**
   * Sets the classes as disjoint
   * 
   * @param class1URI
   * @param class2URI
   */
  public void setDisjointClassWith(String class1URI,
      String class2URI)
  {
    addUUUStatement(class1URI, OWL.DISJOINTWITH.toString(), class2URI);
  }

  /**
   * Sets the classes as same classes
   * 
   * @param class1URI
   * @param class2URI
   */
  public void setEquivalentClassAs(String class1URI,
      String class2URI) {
    addUUUStatement(class1URI, OWL.EQUIVALENTCLASS.toString(), class2URI);
  }

  /**
   * returns an array of classes which are marked as disjoint for the given
   * class
   * 
   * @param classURI
   * @return
   */
  public String[] getDisjointClasses(String aClassURI)
  {
    Resource r1 = getResource(aClassURI);
    // TODO: !!!! turtle
    String queryRep1 = "<" + aClassURI + ">";
    if (r1 instanceof BNode) {
      queryRep1 = "_:" + aClassURI;
    }

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

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

  /**
   * 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);
    // }
    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);
        }
      }
    }
    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)
  {
    addUUUStatement(aPropertyURI, RDF.TYPE.toString(), OWL.OBJECTPROPERTY.toString());
    if (domainClassesURIs != null) {
      for (int i = 0; i < domainClassesURIs.length; i++) {
        addUUUStatement(aPropertyURI, RDFS.DOMAIN.toString(), domainClassesURIs[i]);
      }
    }
    if (rangeClassesTypes != null) {
      for (int i = 0; i < rangeClassesTypes.length; i++) {
        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)
  {
    addUUUStatement(aPropertyURI, RDF.TYPE.toString(), OWL.TRANSITIVEPROPERTY.toString());
    if (domainClassesURIs != null) {
      for (int i = 0; i < domainClassesURIs.length; i++) {
        addUUUStatement(aPropertyURI, RDFS.DOMAIN.toString(), domainClassesURIs[i]);
      }
    }
    if (rangeClassesTypes != null) {
      for (int i = 0; i < rangeClassesTypes.length; i++) {
        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 Property[] getRDFProperties()
  {
    List<Property> list = new ArrayList<Property>();
    String query =
        "Select distinct X FROM {X} rdf:type {<" + RDF.PROPERTY + ">}";

    UtilTupleQueryIterator result = performSerqlQuery(query);
    while (result.hasNext()) {
      String propString = result.nextFirstAsString();
      if (isAnnotationProperty(propString) || isDatatypeProperty(propString) || isObjectProperty(propString) || isTransitiveProperty(propString) || isSymmetricProperty(propString)) {
        continue;
      }
      list.add(new Property(OConstants.RDF_PROPERTY, propString));
    }
    result.close();
    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[] 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>();
    // TODOD: !!!!!!
    // TODO: get all rdf properties, object properties, symmetric properties
    // etc where the URI fragment identifier matches the name
    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 ResourceInfo[] getDomain(String aPropertyURI)
  {
    if (isAnnotationProperty(aPropertyURI)) {
      throw new GateOntologyException(
          "AnnotationProperties do no specify any domain or range");
    }

    String query =
        "select distinct Y from {<" + aPropertyURI + ">} rdfs:domain {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);
  }

  /**
   * Given a property, this method returns its range
   * 
   * @param aPropertyURI
   * @return
   */
  public ResourceInfo[] getRange(String aPropertyURI)
  {
    if (isAnnotationProperty(aPropertyURI)) {
      throw new GateOntologyException(
          "AnnotationProperties do no specify any domain or range");
    }
    if (isDatatypeProperty(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(String aPropertyURI)
  {
    String query =
        "Select * FROM {X} rdf:type {<" + OWL.FUNCTIONALPROPERTY + ">} WHERE X=<" + aPropertyURI + ">";
    return hasSerqlQueryResultRows(query);
  }

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

  /**
   * returns if the given property is inverse functional property
   * 
   * @param aPropertyURI
   * @return
   */
  public boolean isInverseFunctional(String aPropertyURI)
  {
    String query =
        "Select * FROM {X} rdf:type {<" + OWL.INVERSEFUNCTIONALPROPERTY + ">} WHERE X=<" + aPropertyURI + ">";
    return hasSerqlQueryResultRows(query);
  }

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

  /**
   * returns if the given property is a symmetric property
   * 
   * @param aPropertyURI
   * @return
   */
  public boolean isSymmetricProperty(String aPropertyURI)
  {
    String query =
        "Select * FROM {X} rdf:type {<" + OWL.SYMMETRICPROPERTY + ">} WHERE X=<" + aPropertyURI + ">";
    return hasSerqlQueryResultRows(query);
  }

  /**
   * returns if the given property is a transitive property
   * 
   * @param aPropertyURI
   * @return
   */
  public boolean isTransitiveProperty(String aPropertyURI)
  {
    String query =
        "Select * FROM {X} rdf:type {<" + OWL.TRANSITIVEPROPERTY + ">} WHERE X=<" + aPropertyURI + ">";
    return hasSerqlQueryResultRows(query);
  }

  /**
   * returns if the given property is a datatype property
   * 
   * @param aPropertyURI
   * @return
   */
  public boolean isDatatypeProperty(String aPropertyURI)
  {
    String query =
        "Select * FROM {X} rdf:type {<" + OWL.DATATYPEPROPERTY + ">} WHERE X=<" + aPropertyURI + ">";
    return hasSerqlQueryResultRows(query);
  }

  /**
   * returns if the given property is an object property
   * 
   * @param aPropertyURI
   * @return
   */
  public boolean isObjectProperty(String aPropertyURI)
  {
    String query =
        "Select * FROM {X} rdf:type {<" + OWL.OBJECTPROPERTY + ">} WHERE X=<" + aPropertyURI + ">";
    return hasSerqlQueryResultRows(query);
  }

  // *************************************
  // Relations among properties
  // *************************************
  /**
   * Sets two properties as same
   * 
   * @param property1URI
   * @param property2URI
   */
  public void setEquivalentPropertyAs(String property1URI,
      String property2URI)
  {
    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)
  {
    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)
  {
    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)
  {
    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)
  {
    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)
  {
    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)
  {
    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");
    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);
    }
    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 ";
    query = query.replaceAll("yyy1", "\"*"+name+"\"");
    //System.out.println("Query for instances: "+query);
    UtilTupleQueryIterator q = new UtilTupleQueryIterator(repositoryConnection,
        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(repositoryConnection, 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(repositoryConnection, 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
   */
  public void setDifferentIndividualFrom(String individual1URI, String individual2URI) throws GateOntologyException {
    if (debug) {
      logger.debug("setDifferentIndividualFrom");
    }
    addUUUStatement(individual1URI, OWL.DIFFERENTFROM.toString(), 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");
    }
    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(String restrictionURI,
      String propertyURI)
  {
    addUUUStatement(restrictionURI, OWL.ONPROPERTY.toString(), 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();
      removeUUUStatement(whatValueURI, l.getLabel(), l.getDatatype().toString());
    }
    addUUDStatement(restrictionURI, whatValueURI, value,
        datatypeURI);
  }

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

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

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

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

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

  }

  /**
   * Sets the cardinality value for the given restriction uri.
   * 
   * @param restrictionURI
   * @param restrictionType
   *          - either of the following constants from the OConstants -
   *          ALL_VALUES_FROM_RESTRICTION, SOME_VALUES_FROM_RESTRICTION, and
   *          HAS_VALUE_RESTRICTION
   * @param value
   * @return
   */
  public void setRestrictionValue(String restrictionURI,
      byte restrictionType, String value)
  {
    String whatValueURI = null;
    switch (restrictionType) {
      case OConstants.ALL_VALUES_FROM_RESTRICTION:
        whatValueURI = OWL.ALLVALUESFROM.toString();
        break;
      case OConstants.HAS_VALUE_RESTRICTION:
        whatValueURI = OWL.HASVALUE.toString();
        break;
      case OConstants.SOME_VALUES_FROM_RESTRICTION:
        whatValueURI = OWL.SOMEVALUESFROM.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();
        toDelete = stmt;
      }
    } catch (Exception e) {
      throw new GateOntologyException(e);
    }

    if (toDelete != null) {
      String objectString = toDelete.getObject().toString();
      removeUUUStatement(restrictionURI, whatValueURI, objectString);
    }
    addUUUStatement(restrictionURI, whatValueURI, 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;
    }
  }


  /**
   * The method is useful for adding statements into the graph. All three values
   * must exist in repository. These values are cast in Resources and then added
   * into the graph of repository.
   * 
   * @param subjectURI
   * @param predicateURI
   * @param objectURI
   */
  public void addStatement(String subjectURI,
      String predicateURI, String objectURI)
  {
    try {
      startTransaction(null);
      Resource s = subjectURI != null ? getResource(subjectURI) : null;
      URI p =
          predicateURI != null
          ? repositoryConnection.getValueFactory().createURI(predicateURI)
          : null;
      Resource o = objectURI != null ? getResource(objectURI) : null;
      repositoryConnection.add(s, p, o);
      endTransaction(null);
    } catch (Exception e) {
      throw new GateOntologyException(
          "error while adding statement into the repository where subject:" + subjectURI + " predicate:" + predicateURI + " objectURI:" + objectURI, e);
    }
  }

  /**
   * The method is useful for removing statements from the graph of repository.
   * All three values must exist in repository. these values are cast in
   * Resources and then removed from teh graph of repository.
   * 
   * @param subjectURI
   * @param predicateURI
   * @param objectURI
   */
  public void removeStatement(String subjectURI,
      String predicateURI, String objectURI)
  {
    try {
      startTransaction(null);
      Resource s = subjectURI != null ? getResource(subjectURI) : null;
      URI p =
          predicateURI != null
          ? repositoryConnection.getValueFactory().createURI(predicateURI)
          : null;
      Resource o = objectURI != null ? getResource(objectURI) : null;
      repositoryConnection.remove(s, p, o);
      endTransaction(null);
    } catch (Exception e) {
      throw new GateOntologyException(
          "error while removing statement from the repository where subject:" + subjectURI + " predicate:" + predicateURI + " objectURI:" + objectURI, e);
    }

  }

  // ***************************************************************************
  // *********************** Other Utility Methods
  // **************************************************************************
  private 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, DATA_CONTEXT_URI);
      endTransaction(null);
    } catch (Exception e) {
      throw new GateOntologyException(
          "error while adding statement into the repository where subject:" + subject + " predicate:" + predicate + " objectURI:" + object, e);
    }
  }

  private void addUULStatement(String subject, String predicate, String object,
      String language) throws GateOntologyException {
    if (debug) {
      logger.debug("addUULStatement for " + subject + " / " + predicate + " / " + object);
    }
    try {
      startTransaction(null);
      Resource s = subject != null ? getResource(subject) : null;
      URI p =
          predicate != null ? repositoryConnection.getValueFactory().createURI(predicate) : null;
      Literal o = null;
      if (language == null) {
        o =
            object != null ? repositoryConnection.getValueFactory().createLiteral(object) : null;
      } else {
        o =
            object != null
            ? repositoryConnection.getValueFactory().createLiteral(object, language)
            : null;
      }
      repositoryConnection.add(s, p, o, DATA_CONTEXT_URI);
      endTransaction(null);
    } catch (Exception e) {
      throw new GateOntologyException(
          "error while adding statement into the repository where subject:" + subject + " predicate:" + predicate + " objectURI:" + object, e);
    }
  }

  public void addStatement(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, DATA_CONTEXT_URI);
      endTransaction(null);
    } catch (Exception e) {
      throw new GateOntologyException(
          "error while adding statement into the repository where subject:" + subject + " predicate:" + predicate + " objectURI:" + object, e);
    }
  }

  public 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, DATA_CONTEXT_URI);
      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
  private 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);
    }
  }

  private 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);
    }
  }

  public 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 removeStatement(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;
  }

  /**
   * This method tells whether the resource is imported or added as an explicit
   * statement.
   * 
   * @param resourceURI
   * @return
   */

  // JP: seems what is meant here is "implicit" not "imported"
  public boolean isImplicitResource(String resourceURI)
  {
    try {
      return !repositoryConnection.hasStatement(getResource(resourceURI),
          makeSesameURI(RDF.TYPE.toString()), null, false);
    } catch (Exception e) {
      throw new GateOntologyException(e);
    }
  }

  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 {
    byte type = OConstants.ANNOTATION_PROPERTY;
    if (isAnnotationProperty(uri)) {
      type = OConstants.ANNOTATION_PROPERTY;
    } else if (isObjectProperty(uri)) {
      type = OConstants.OBJECT_PROPERTY;
    } else if (isDatatypeProperty(uri)) {
      type = OConstants.DATATYPE_PROPERTY;
    } else if (isTransitiveProperty(uri)) {
      type = OConstants.TRANSITIVE_PROPERTY;
    } else if (isSymmetricProperty(uri)) {
      type = OConstants.SYMMETRIC_PROPERTY;
    } else if (isRDFProperty(uri)) {
      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(String 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);
    }
    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);
    }
    return writer;
  }

  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;
  }

  private Resource string2SesameResource(String uriString) {
    if(uriString.startsWith("_:")) {
      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 new URIImpl(uriString);
      } else {
        return new BNodeImpl(uriString);
      }
    }
  }
  private Resource oNodeID2SesameResource(ONodeID id) {
    if(id.isAnonymousResource()) {
      // TODO: does this and should this include the _: part?
      return new BNodeImpl(id.getResourceName());
    } else {
      return new URIImpl(id.toString());
    }
  }

  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);
    }
  }



  // 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(repositoryConnection,
          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(repositoryConnection,
          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: 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;



}