LearnPAd/learnpad

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

Summary

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

import gate.DataStore;
import gate.Gate;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openrdf.model.vocabulary.XMLSchema;

import gate.creole.AbstractLanguageResource;
import gate.creole.ResourceData;
import gate.creole.ontology.AllValuesFromRestriction;
import gate.creole.ontology.AnnotationProperty;
import gate.creole.ontology.AnonymousClass;
import gate.creole.ontology.CardinalityRestriction;
import gate.creole.ontology.DataType;
import gate.creole.ontology.DatatypeProperty;
import gate.creole.ontology.GateOntologyException;
import gate.creole.ontology.HasValueRestriction;
import gate.creole.ontology.InvalidValueException;
import gate.creole.ontology.Literal;
import gate.creole.ontology.MaxCardinalityRestriction;
import gate.creole.ontology.MinCardinalityRestriction;
import gate.creole.ontology.OBNodeID;
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.OInstance;
import gate.creole.ontology.OResource;
import gate.creole.ontology.OURI;
import gate.creole.ontology.ONodeID;
import gate.creole.ontology.ObjectProperty;
import gate.creole.ontology.Ontology;
import gate.creole.ontology.OntologyModificationListener;
import gate.creole.ontology.RDFProperty;
import gate.creole.ontology.SomeValuesFromRestriction;
import gate.creole.ontology.SymmetricProperty;
import gate.creole.ontology.TransitiveProperty;
import gate.persist.PersistenceException;
import gate.util.ClosableIterator;
import java.io.InputStream;
import gate.util.GateRuntimeException;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.Comparator;
import java.util.Random;
import org.apache.log4j.Logger;
import org.openrdf.model.BNode;

/**
 * This class provides implementation of most of the methods of Ontology
 * interface. This implementation is based on the OntologyService (a SAIL) that stores
 * data in repository using SESAME.
 * 
 * @author Niraj Aswani
 * @author Johann Petrak
 * 
 */
public abstract class AbstractOntologyImpl
    extends AbstractLanguageResource
    implements Ontology {

  
  // a couple of useful constant OURIs that we need often in the ontology
  // service impl and elsewhere
  
  // RDF 
  public OURI OURI_RDF_PROPERTY = createOURI(OConstants.RDF.PROPERTY.toString());
  public OURI OURI_RDF_TYPE = createOURI(OConstants.RDF.TYPE.toString());
  // RDFS
  public OURI OURI_RDFS_COMMENT = createOURI(OConstants.RDFS.COMMENT.toString());
  public OURI OURI_RDFS_CLASS = createOURI(OConstants.RDFS.CLASS.toString());
  public OURI OURI_RDFS_DOMAIN = createOURI(OConstants.RDFS.DOMAIN.toString());
  public OURI OURI_RDFS_LABEL = createOURI(OConstants.RDFS.LABEL.toString());
  public OURI OURI_RDFS_RANGE = createOURI(OConstants.RDFS.RANGE.toString());
  public OURI OURI_RDFS_SUBCLASSOF = createOURI(OConstants.RDFS.SUBCLASSOF.toString());
  // OWL
  public OURI OURI_OWL_ALLVALUESFROM = createOURI(OConstants.OWL.ALLVALUESFROM.toString());
  public OURI OURI_OWL_ANNOTATIONPROPERTY = createOURI(OConstants.OWL.ANNOTATIONPROPERTY.toString());
  public OURI OURI_OWL_CLASS = createOURI(OConstants.OWL.CLASS.toString());
  public OURI OURI_OWL_DATATYPEPROPERTY = createOURI(OConstants.OWL.DATATYPEPROPERTY.toString());
  public OURI OURI_OWL_DIFFERENTFROM = createOURI(OConstants.OWL.DIFFERENTFROM.toString());
  public OURI OURI_OWL_EQUIVALENTCLASS = createOURI(OConstants.OWL.EQUIVALENTCLASS.toString());
  public OURI OURI_OWL_EQUIVALENTPROPERTY = createOURI(OConstants.OWL.EQUIVALENTPROPERTY.toString());
  public OURI OURI_OWL_FUNCTIONALPROPERTY = createOURI(OConstants.OWL.FUNCTIONALPROPERTY.toString());
  public OURI OURI_OWL_HASVALUE = createOURI(OConstants.OWL.HASVALUE.toString());
  public OURI OURI_OWL_INVERSEFUNCTIONALPROPERTY = createOURI(OConstants.OWL.INVERSEFUNCTIONALPROPERTY.toString());
  public OURI OURI_OWL_MAXCARDINALITY = createOURI(OConstants.OWL.MAXCARDINALITY.toString());
  public OURI OURI_OWL_MINCARDINALITY = createOURI(OConstants.OWL.MINCARDINALITY.toString());
  public OURI OURI_OWL_OBJECTPROPERTY = createOURI(OConstants.OWL.OBJECTPROPERTY.toString());
  public OURI OURI_OWL_ONPROPERTY = createOURI(OConstants.OWL.ONPROPERTY.toString());
  public OURI OURI_OWL_ONTOLOGY = createOURI(OConstants.OWL.ONTOLOGY.toString());
  public OURI OURI_OWL_RESTRICTION = createOURI(OConstants.OWL.RESTRICTION.toString());
  public OURI OURI_OWL_SAMEAS = createOURI(OConstants.OWL.SAMEAS.toString());
  public OURI OURI_OWL_SOMEVALUESFROM = createOURI(OConstants.OWL.SOMEVALUESFROM.toString());
  public OURI OURI_OWL_SYMMETRICPROPERTY = createOURI(OConstants.OWL.SYMMETRICPROPERTY.toString());
  public OURI OURI_OWL_TRANSITIVEPROPERTY = createOURI(OConstants.OWL.TRANSITIVEPROPERTY.toString());
  public OURI OURI_OWL_VERSIONINFO = createOURI(OConstants.OWL.VERSIONINFO.toString());
  
  
  
  
  /**
   * The ontology import URIs that were already processed for this ontology.
   * NOTE: this contains both the URIs from imports and the ontology URIs
   * from loading ontology data in order to prevent that an ontology that
   * was loaded gets again loaded as an import. Having an ontology loaded
   * both normally and as an import will cause things to break in absurd
   * and unpredictable ways!!!
   */
  protected Set<String> knownImportURIs = new HashSet<String>();
  
  protected List<OURI> loadedOntologyURIs = new ArrayList<OURI>();

  /**
   * instance of the OntologyService
   */
  protected OntologyService ontologyService;

  /**
   * Main URL of the ontology. This is the URL that was used to load
   * the first ontology data. If not known, this is null.
   */
  protected URL ontologyURL;


  /**
   * Default Namespace
   */
  protected String defaultNameSpace;

  /**
   * Parameter that keeps track of if the ontology is modified
   */
  protected boolean isModified;

  /**
   * A List of ontology modification listeners
   */
  protected transient List<OntologyModificationListener> modificationListeners;



  /**
   * Map where the key is a resource name and value is a list of resources with
   * that name.
   */
  //protected Map<String, List<OResource>> resourceNamesToOResourcesMap;

  protected static int anonymousNodeCounter = 0;

  protected static String restrictionPrefix = "Restriction";

  /**
   * This field controls whether new ontology entities will have their
   * label set to the entity resource name automatically.
   * The behavior has changed from the old to the new implementation: the
   * old implementation always set the label, the new implementation does
   * not do that for the new LRs. However, to provide better temporary backwards
   * compatibility, the backwards compatibility LR sets this to true and
   * does create the labels automatically.
   */
  protected boolean doSetAutoLabel = false;

  private Logger logger;

  protected Random randomGenerator;

  /**
   * Constructor
   */
  public AbstractOntologyImpl() {
    logger = Logger.getLogger(this.getClass().getName());
    //TODO: get rid of this!
    //urisToOResouceMap = new HashMap<String, OResource>();
    //resourceNamesToOResourcesMap = new HashMap<String, List<OResource>>();
    knownImportURIs.add("http://www.w3.org/2000/01/rdf-schema");
    randomGenerator = new Random();
  }


  public String getAutoGeneratedRestrictionName() {
    anonymousNodeCounter++;
    String toReturn = restrictionPrefix + anonymousNodeCounter;
    return toReturn;
  }

  public void cleanOntology() {
    ontologyService.cleanOntology();
  }

  @Deprecated
  public String getOntologyData(byte format) {
    throw new UnsupportedOperationException("Method not supported in this implementation");
  }

  @Deprecated
  public void writeOntologyData(OutputStream out, byte format) {
    throw new UnsupportedOperationException("Method not supported in this implementation");
  }

  @Deprecated
  public void writeOntologyData(Writer out, byte format) {
    throw new UnsupportedOperationException("Not supported any more in this implementation");
  }

  public URL getURL() {
    return ontologyURL;
  }

  public void setURL(URL aUrl) {
    this.ontologyURL = aUrl;
  }

  public void setDefaultNameSpace(String theURI) {
    defaultNameSpace = theURI;
    if(defaultNameSpace != null &&
       !defaultNameSpace.endsWith("#") &&
       !defaultNameSpace.endsWith("/")) {
      throw new GateOntologyException(
          "The default name space (base URI) must end with '#' or '/': "+
          theURI);
    }
  }

  public String getDefaultNameSpace() {
    return this.defaultNameSpace;
  }

  public void setVersion(String theVersion) {
    AnnotationProperty pr = (AnnotationProperty)Utils.createOProperty(
      this, ontologyService, 
      OConstants.OWL.VERSIONINFO, OConstants.ANNOTATION_PROPERTY);
    setOntologyAnnotation(pr, new Literal(theVersion));
  }

  public String getVersion() {
    return ontologyService.getVersion();
  }

  public OClass addOClass(OURI aURI, byte classType) {
    OClass existing = this.getOClass(aURI);
    if(existing != null) {
      Utils.warning(aURI + " already exists");
      return existing;
    }
    ontologyService.addClass(aURI);
    OClass oClass =
      Utils.createOClass(this, ontologyService, aURI.toString(),
        classType);

    fireOntologyResourceAdded(oClass);
    if(doSetAutoLabel) {
      oClass.setLabel(aURI.getResourceName(), null);
    }
    return oClass;
  }

  public OClass addOClass(OURI aURI) {
    return addOClass(aURI, OConstants.OWL_CLASS);
  }

  public OClass getOClass(ONodeID theClassURI) {
    if(ontologyService.hasClass(theClassURI)) {
      byte classType =
        ontologyService.getClassType(theClassURI.toString());
      return Utils.createOClass(this, ontologyService,
        theClassURI.toString(), classType);
    }
    return null;
  }

  public void removeOClass(OClass theClass) {

    if(!containsOClass(theClass.getONodeID())) {
      Utils.warning("Cannot remove the class "+theClass.getONodeID().toString() + " - does not exist");
      return;
    }

    String[] deletedResources =
      ontologyService.removeClass(theClass.getONodeID().toString(),
        true);
    fireOntologyResourcesRemoved(deletedResources);
  }

  public boolean containsOClass(ONodeID theURI) {
    return ontologyService.hasClass(theURI);
  }

  public boolean containsOClass(OClass theClass) {
    return ontologyService.hasClass(theClass.getONodeID());
  }

  public Set<OClass> getOClasses(boolean top) {
    return ontologyService.getClasses(top);
  }

  public ClosableIterator<OClass> getOClassesIterator(boolean top) {
    return ontologyService.getClassesIterator(top);
  }


  public int getDistance(OClass class1, OClass class2) {

    if(!containsOClass(class1.getONodeID())) {
      Utils.warning(class1.getONodeID().toString() + " does not exist");
      return -1;
    }

    if(!containsOClass(class2.getONodeID())) {
      Utils.warning(class2.getONodeID() + " does not exist");
      return -1;
    }

    int result = 0;
    OClass c;
    ArrayList<Set<OClass>> supers1 = class1.getSuperClassesVSDistance();
    ArrayList<Set<OClass>> supers2 = class2.getSuperClassesVSDistance();
    for(int i1 = 0; i1 < supers1.size(); i1++) {
      if(supers1.get(i1).contains(class2)) {
        result = i1 + 1;
        break;
      }
    }
    for(int i2 = 0; i2 < supers2.size(); i2++) {
      if(supers2.get(i2).contains(class1)) {
        result = i2 + 1;
        break;
      }
    }
    if(0 == result) {
      for(int i1 = 0; i1 < supers1.size(); i1++) {
        for(int i2 = 0; i2 < supers2.size(); i2++) {
          Set<OClass> s1 = supers1.get(i1);
          Set<OClass> s2 = supers2.get(i2);
          Iterator<OClass> i3 = s1.iterator();
          while(i3.hasNext()) {
            c = i3.next();
            if(s2.contains(c)) {
              result = i1 + i2 + 2;
              i1 = supers1.size();
              i2 = supers2.size();
              break;
            }
          }
        }
      }
    }
    return result;
  }

  public OInstance addOInstance(OURI theInstanceURI, OClass theClass) {
    if(!containsOClass(theClass.getONodeID())) {
      Utils.error(theClass.getONodeID() + " does not exist");
      return null;
    }

    // TODO: how to properly not use the map here?
    OResource anInst = null; //getOResourceFromMap(theInstanceURI.toString());
    // if(anInst != null && !(anInst instanceof OInstance)) {
    //   Utils.error(anInst.getURI().toString() + " already exists but "
    //    + " is not an ontology instance!");
    //  return null;
    //}

    /*
    if(anInst != null &&
      ((OInstance)anInst).getOClasses(OConstants.TRANSITIVE_CLOSURE)
        .contains(theClass)) {
      Utils.warning(theInstanceURI.toString()
        + " is already registered as an instanceof "
        + theClass.getURI().toString());
      return (OInstance)anInst;
    }
     * */

    OInstance existing = getOInstance(theInstanceURI);
    if(existing != null) {
      Utils.warning("instance "+theInstanceURI+" already exists");
      return existing;
    }

    ontologyService.addIndividual(theClass.getONodeID().toString(),
      theInstanceURI.toString());
    OInstance oInst =
      Utils.createOInstance(this, ontologyService,
        theInstanceURI.toString());
    fireOntologyResourceAdded(oInst);
    if(doSetAutoLabel) {
      oInst.setLabel(theInstanceURI.getResourceName(), null);
    }
    return oInst;
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#removeOInstance(gate.creole.ontology.OInstance
   * )
   */
  public void removeOInstance(OInstance theInstance) {
    if(!containsOInstance((OURI)theInstance.getOURI())) {
      Utils.warning(theInstance.getOURI() + " does not exist");
      return;
    }

    String[] deletedResources =
      ontologyService.removeIndividual(theInstance.getOURI().toString());
    fireOntologyResourcesRemoved(deletedResources);
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#getOInstances()
   */
  public Set<OInstance> getOInstances() {
//    String[] oInsts = ontologyService.getIndividuals();
//    Set<OInstance> set = new HashSet<OInstance>();
//    for(int i = 0; i < oInsts.length; i++) {
//      set.add(Utils.createOInstance(this, this.ontologyService,
//        oInsts[i]));
//    }
//    return set;
    Set<OInstance> theInstances = new HashSet<OInstance>();
    ClosableIterator<OInstance> ii =
        ontologyService.getInstancesIterator(null, null);
    while(ii.hasNext()) {
      OInstance i = ii.next();
      //System.out.println("Adding to result: "+i);
      theInstances.add(i);
    }
    return theInstances;
  }

  public ClosableIterator<OInstance> getOInstancesIterator() {
    return ontologyService.getInstancesIterator(null, null);
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#getOInstances(gate.creole.ontology.OClass,
   * boolean)
   */
  public Set<OInstance> getOInstances(OClass theClass, byte closure) {
    //throw new UnsupportedOperationException("Method not supported any more with these parameters");
    Closure theClosure = closure == OConstants.DIRECT_CLOSURE ?
      Closure.DIRECT_CLOSURE : Closure.TRANSITIVE_CLOSURE;
    return getOInstances(theClass,theClosure);
  }
  
  public Set<OInstance> getOInstances(OClass theClass, Closure closure) {
//    String[] oInsts =
//      ontologyService.getIndividuals(theClass.getONodeID()
//        .toString(), closure);
//    Set<OInstance> set = new HashSet<OInstance>();
//
//    if(!containsOClass(theClass.getONodeID())) {
//      Utils.warning("GetOInstances: "+theClass.getONodeID() + " does not exist");
//      return set;
//    }
//
//    for(int i = 0; i < oInsts.length; i++) {
//      set.add(Utils.createOInstance(this, this.ontologyService,
//        oInsts[i]));
//    }
//    return set;
    Set<OInstance> theInstances = new HashSet<OInstance>();
    ClosableIterator<OInstance> ii =
        ontologyService.getInstancesIterator(theClass.getONodeID(), closure);
    while(ii.hasNext()) {
      OInstance i = ii.next();
      //System.out.println("Adding to result: "+i);
      theInstances.add(i);
    }
    return theInstances;
  }

  public ClosableIterator<OInstance>
      getOInstancesIterator(OClass theClass, Closure closure) {
    return ontologyService.getInstancesIterator(theClass.getONodeID(), closure);
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#getOInstance(gate.creole.ontology.URI)
   */
  // TODO: extremely bad performance, do this differnetly!
  public OInstance getOInstance(OURI theInstanceURI) {
//    // TODO: properly remove map
//    OResource resource = null; //= getOResourceFromMap(theInstanceURI.toString());
//    //if(resource != null) return (OInstance)resource;
//    List<String> individuals =
//      Arrays.asList(ontologyService.getIndividuals());
//    if(individuals.contains(theInstanceURI.toString())) { return Utils
//      .createOInstance(this, ontologyService, theInstanceURI
//        .toString()); }
//    return null;
    if(ontologyService.hasInstance(theInstanceURI, null, null)) {
      return Utils.createOInstance(this, ontologyService, theInstanceURI.toString());
    } else {
      return null;
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#containsOInstance(gate.creole.ontology.OInstance
   * )
   */
  public boolean containsOInstance(OInstance theInstance) {
    return containsOInstance(theInstance.getOURI());
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#containsOInstance(gate.creole.ontology.URI)
   */
  // TODO: !!!! extremely bad performance, do this differently!
  public boolean containsOInstance(OURI theInstanceURI) {
//    List<String> individuals =
//      Arrays.asList(ontologyService.getIndividuals());
//    return individuals.contains(theInstanceURI.toString());
    return ontologyService.hasInstance(theInstanceURI, null, null);
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#addRDFProperty(gate.creole.ontology.URI,
   * java.util.Set, java.util.Set)
   */

  // TODO: this should really take a set of OClasses instead of a set of
  // OResources ... 
  public RDFProperty addRDFProperty(OURI aPropertyURI, Set<OResource> domain,
    Set<OResource> range) {
    // TODO: check if the property already exists or if the URI is 
    // used for something other than a property
    
    if(domain == null) {
      domain = new HashSet<OResource>();
    }
    if(range == null) {
      range = new HashSet<OResource>();
    }
    String[] domainURIs = new String[domain.size()];
    String[] rangeURIs = new String[range.size()];
    Iterator<OResource> iter = domain.iterator();
    int counter = 0;
    while(iter.hasNext()) {
      domainURIs[counter] = iter.next().getONodeID().toString();
    }
    iter = range.iterator();
    counter = 0;
    while(iter.hasNext()) {
      rangeURIs[counter] = iter.next().getONodeID().toString();
    }
    ontologyService.addRDFProperty(aPropertyURI,
      domain, range);
    RDFProperty rp =
      Utils.createOProperty(this, ontologyService, aPropertyURI
        .toString(), OConstants.RDF_PROPERTY);
    fireOntologyResourceAdded(rp);

    return rp;
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#getRDFProperties()
   */
  public Set<RDFProperty> getRDFProperties() {
    return ontologyService.getRDFProperties();
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#isRDFProperty(gate.creole.ontology.URI)
   */
  public boolean isRDFProperty(OURI thePropertyURI) {
    return ontologyService.isRDFProperty(thePropertyURI);
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#addAnnotationProperty(gate.creole.ontology
   * .URI)
   */
  public AnnotationProperty addAnnotationProperty(OURI aPropertyURI) {
    // TODO: properly remove map
    /*
    OResource res = getOResourceFromMap(aPropertyURI.toString());
    if(res != null) {
      if(res instanceof AnnotationProperty) {
        Utils.warning(aPropertyURI.toString() + " already exists");
        return (AnnotationProperty)res;
      }
      else {
        Utils.error(aPropertyURI.toString()
          + " already exists but it is not an AnnotationProperty");
        return null;
      }
    }
     * */
    RDFProperty exists = getProperty(aPropertyURI);
    if(exists != null) {
      if(exists instanceof AnnotationProperty) {
        Utils.warning(aPropertyURI.toString() + " already exists");
        return (AnnotationProperty)exists;
      }
      Utils.warning(aPropertyURI.toString() + " already exists but is not an annotation property");
      return null;
    }


    ontologyService.addAnnotationProperty(aPropertyURI);
    AnnotationProperty ap =
      (AnnotationProperty)Utils.createOProperty(this,
        ontologyService, aPropertyURI.toString(), OConstants.ANNOTATION_PROPERTY);
    fireOntologyResourceAdded(ap);
    if(doSetAutoLabel) {
      ap.setLabel(aPropertyURI.getResourceName(), null);
    }
    return ap;
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#getAnnotationProperties()
   */
  public Set<AnnotationProperty> getAnnotationProperties() {
    Property[] properties =
      ontologyService.getAnnotationProperties();
    Set<AnnotationProperty> set = new HashSet<AnnotationProperty>();
    for(int i = 0; i < properties.length; i++) {
      set.add((AnnotationProperty)Utils.createOProperty(
        this, ontologyService, properties[i].getUri(),
        properties[i].getType()));
    }
    return set;
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#isAnnotationProperty(gate.creole.ontology
   * .URI)
   */
  public boolean isAnnotationProperty(OURI thePropertyURI) {
    return ontologyService.isAnnotationProperty(thePropertyURI);
  }

  public DatatypeProperty addDatatypeProperty(OURI aPropertyURI,
    Set<OClass> domain, DataType aDatatype) {
    if(domain == null) {
      domain = new HashSet<OClass>();
    }
    RDFProperty exists = getProperty(aPropertyURI);
    if(exists != null) {
      if(exists instanceof DatatypeProperty) {
        Utils.warning(aPropertyURI.toString() + " already exists");
        String[] domainURIs = new String[domain.size()];
        Iterator<OClass> iter = domain.iterator();
        int counter = 0;
        while(iter.hasNext()) {
         domainURIs[counter] = iter.next().getONodeID().toString();
        }
        if(domainURIs.length > 0) {
          ontologyService.addDataTypeProperty(aPropertyURI,
            domain, aDatatype.getXmlSchemaURIString());
        }
        return (DatatypeProperty)exists;
      }
      Utils.warning(aPropertyURI.toString() + " already exists but is not a datatype property");
      return null;
    }

    String[] domainURIs = new String[domain.size()];
    Iterator<OClass> iter = domain.iterator();
    int counter = 0;
    while(iter.hasNext()) {
      domainURIs[counter] = iter.next().getONodeID().toString();
    }
    ontologyService.addDataTypeProperty(aPropertyURI,
      domain, aDatatype.getXmlSchemaURIString());
    DatatypeProperty dp =
      (DatatypeProperty)Utils.createOProperty(this,
        ontologyService, aPropertyURI.toString(), OConstants.DATATYPE_PROPERTY);
    fireOntologyResourceAdded(dp);

    if(doSetAutoLabel) {
      dp.setLabel(aPropertyURI.getResourceName(), null);
    }

    return dp;
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#getDatatypeProperties()
   */
  public Set<DatatypeProperty> getDatatypeProperties() {
    Property[] properties =
      ontologyService.getDatatypeProperties();
    Set<DatatypeProperty> set = new HashSet<DatatypeProperty>();
    for(int i = 0; i < properties.length; i++) {
      set.add((DatatypeProperty)Utils.createOProperty(
        this, ontologyService, properties[i].getUri(), properties[i].getType()));
    }
    return set;
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#isDatatypeProperty(gate.creole.ontology.URI)
   */
  public boolean isDatatypeProperty(OURI thePropertyURI) {
    return ontologyService.isDatatypeProperty(thePropertyURI);
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#addObjectProperty(gate.creole.ontology.URI,
   * java.util.Set, java.util.Set)
   */
    public ObjectProperty addObjectProperty(OURI aPropertyURI, Set<OClass> domain,
          Set<OClass> range) {
    if (domain == null) {
      domain = new HashSet<OClass>();
    }
    if (range == null) {
      range = new HashSet<OClass>();
    }
    RDFProperty exists = getProperty(aPropertyURI);
    if (exists != null) {
      if (exists instanceof ObjectProperty) {
        Utils.warning(aPropertyURI.toString() + " already exists");
        String[] domainURIs = new String[domain.size()];
        String[] rangeURIs = new String[range.size()];
        Iterator<OClass> iter = domain.iterator();
        int counter = 0;
        while (iter.hasNext()) {
          domainURIs[counter] = iter.next().getONodeID().toString();
          counter++;
        }
        iter = range.iterator();
        counter = 0;
        while (iter.hasNext()) {
          rangeURIs[counter] = iter.next().getONodeID().toString();
          counter++;
        }
        if (domainURIs.length > 0 || rangeURIs.length > 0) {
          ontologyService.addObjectProperty(aPropertyURI.toString(),
                  domainURIs, rangeURIs);
        }

        return (ObjectProperty) exists;
      }
      Utils.warning(aPropertyURI.toString() + " already exists but is not an object property");
      return null;
    }

    String[] domainURIs = new String[domain.size()];
    String[] rangeURIs = new String[range.size()];
    Iterator<OClass> iter = domain.iterator();
    int counter = 0;
    while (iter.hasNext()) {
      domainURIs[counter] = iter.next().getONodeID().toString();
      counter++;
    }
    iter = range.iterator();
    counter = 0;
    while (iter.hasNext()) {
      rangeURIs[counter] = iter.next().getONodeID().toString();
      counter++;
    }
    ontologyService.addObjectProperty(aPropertyURI.toString(),
            domainURIs, rangeURIs);
    ObjectProperty op =
            (ObjectProperty) Utils.createOProperty(this,
            ontologyService, aPropertyURI.toString(), OConstants.OBJECT_PROPERTY);
    fireOntologyResourceAdded(op);

    if (doSetAutoLabel) {
      op.setLabel(aPropertyURI.getResourceName(), null);
    }

    return op;
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#getObjectProperties()
   */
  public Set<ObjectProperty> getObjectProperties() {
    Property[] properties = ontologyService.getObjectProperties();
    Set<ObjectProperty> set = new HashSet<ObjectProperty>();
    for(int i = 0; i < properties.length; i++) {
      set.add((ObjectProperty)Utils.createOProperty(
        this, ontologyService, properties[i].getUri(), properties[i].getType()));
    }
    return set;
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#isObjectProperty(gate.creole.ontology.URI)
   */
  public boolean isObjectProperty(OURI thePropertyURI) {
    return ontologyService.isObjectProperty(thePropertyURI);
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#addSymmetricProperty(gate.creole.ontology
   * .URI, java.util.Set)
   */
  public SymmetricProperty addSymmetricProperty(OURI aPropertyURI,
    Set<OClass> domainAndRange) {
    if(domainAndRange == null) {
      domainAndRange = new HashSet<OClass>();
    }

    RDFProperty exists = getProperty(aPropertyURI);
    if(exists != null) {
      if(exists instanceof SymmetricProperty) {
        Utils.warning(aPropertyURI.toString() + " already exists");
        String[] domainURIs = new String[domainAndRange.size()];
        Iterator<OClass> iter = domainAndRange.iterator();
        int counter = 0;
        while(iter.hasNext()) {
         domainURIs[counter] = iter.next().getONodeID().toString();
         counter++;
        }
        if(domainURIs.length > 0) {
          ontologyService.addSymmetricProperty(
            aPropertyURI, domainAndRange);
        }
        return (SymmetricProperty)exists;
      }
      Utils.warning(aPropertyURI.toString() + " already exists but is not a symmetric property");
      return null;
    }

    String[] domainURIs = new String[domainAndRange.size()];
    Iterator<OClass> iter = domainAndRange.iterator();
    int counter = 0;
    while(iter.hasNext()) {
      domainURIs[counter] = iter.next().getONodeID().toString();
      counter++;
    }
    ontologyService.addSymmetricProperty(
      aPropertyURI, domainAndRange);
    SymmetricProperty sp =
      (SymmetricProperty)Utils.createOProperty(this,
        ontologyService, aPropertyURI.toString(), OConstants.SYMMETRIC_PROPERTY);
    fireOntologyResourceAdded(sp);

    if(doSetAutoLabel) {
      sp.setLabel(aPropertyURI.getResourceName(), null);
    }

    return sp;
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#getSymmetricProperties()
   */
  public Set<SymmetricProperty> getSymmetricProperties() {
    Property[] properties =
      ontologyService.getSymmetricProperties();
    Set<SymmetricProperty> set = new HashSet<SymmetricProperty>();
    for(int i = 0; i < properties.length; i++) {
      set.add((SymmetricProperty)Utils.createOProperty(
        this, ontologyService, properties[i].getUri(), properties[i].getType()));
    }
    return set;
  }

  public boolean isSymmetricProperty(OURI thePropertyURI) {
    return ontologyService.isSymmetricProperty(thePropertyURI);
  }

  public TransitiveProperty addTransitiveProperty(OURI aPropertyURI,
    Set<OClass> domain, Set<OClass> range) {
    if(domain == null) {
      domain = new HashSet<OClass>();
    }
    if(range == null) {
      range = new HashSet<OClass>();
    }
    RDFProperty exists = getProperty(aPropertyURI);
    if(exists != null) {
      if(exists instanceof TransitiveProperty) {
        Utils.warning(aPropertyURI.toString() + " already exists");
        String[] domainURIs = new String[domain.size()];
        String[] rangeURIs = new String[range.size()];
        Iterator<OClass> iter = domain.iterator();
        int counter = 0;
        while (iter.hasNext()) {
          domainURIs[counter] = iter.next().getONodeID().toString();
          counter++;
        }
        iter = range.iterator();
        counter = 0;
        while (iter.hasNext()) {
          rangeURIs[counter] = iter.next().getONodeID().toString();
          counter++;
        }
        if(domainURIs.length > 0 || rangeURIs.length > 0) {
          ontologyService.addTransitiveProperty(aPropertyURI.toString(),
                  domainURIs, rangeURIs);
        }
        return (TransitiveProperty)exists;
      }
      Utils.warning(aPropertyURI.toString() + " already exists but is not as transitive property");
      return null;
    }


    String[] domainURIs = new String[domain.size()];
    String[] rangeURIs = new String[range.size()];
    Iterator<OClass> iter = domain.iterator();
    int counter = 0;
    while(iter.hasNext()) {
      domainURIs[counter] = iter.next().getONodeID().toString();
      counter++;
    }
    iter = range.iterator();
    counter = 0;
    while(iter.hasNext()) {
      rangeURIs[counter] = iter.next().getONodeID().toString();
      counter++;
    }
    ontologyService.addTransitiveProperty(aPropertyURI
      .toString(), domainURIs, rangeURIs);
    TransitiveProperty tp =
      (TransitiveProperty)Utils.createOProperty(this,
        ontologyService, aPropertyURI.toString(), OConstants.TRANSITIVE_PROPERTY);
    fireOntologyResourceAdded(tp);

    if(doSetAutoLabel) {
      tp.setLabel(aPropertyURI.getResourceName(), null);
    }

    return tp;
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#getTransitiveProperties()
   */
  public Set<TransitiveProperty> getTransitiveProperties() {
    Property[] properties =
      ontologyService.getTransitiveProperties();
    Set<TransitiveProperty> set = new HashSet<TransitiveProperty>();
    for(int i = 0; i < properties.length; i++) {

      set.add((TransitiveProperty)Utils.createOProperty(
        this, ontologyService, properties[i].getUri(),
        properties[i].getType()));
    }
    return set;
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#isTransitiveProperty(gate.creole.ontology
   * .URI)
   */
  public boolean isTransitiveProperty(OURI thePropertyURI) {
    return ontologyService.isTransitiveProperty(thePropertyURI);
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#getPropertyDefinitions()
   */
  public Set<RDFProperty> getPropertyDefinitions() {
    Set<RDFProperty> set = new HashSet<RDFProperty>();
    set.addAll(getAnnotationProperties());
    set.addAll(getDatatypeProperties());
    set.addAll(getObjectProperties());
    set.addAll(getRDFProperties());
    return set;
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#getProperty(gate.creole.ontology.URI)
   */
  public RDFProperty getProperty(OURI thePropertyURI) {
    Property property =
      ontologyService.getPropertyFromOntology(thePropertyURI
        .toString());
    if(property == null) return null;
    return Utils.createOProperty(this, ontologyService,
      thePropertyURI.toString(), property.getType());
  }
  
  public AnnotationProperty getAnnotationProperty(OURI theURI) {
    if(ontologyService.isAnnotationProperty(theURI)) {
      return (AnnotationProperty) Utils.createOProperty(this,ontologyService,
          theURI.toString(), OConstants.ANNOTATION_PROPERTY);
    } else {
      return null;
    }
  }
  public DatatypeProperty getDatatypeProperty(OURI theURI) {
    if(ontologyService.isDatatypeProperty(theURI)) {
      return (DatatypeProperty) Utils.createOProperty(this,ontologyService,
          theURI.toString(), OConstants.DATATYPE_PROPERTY);
    } else {
      return null;
    }
  }
  public ObjectProperty getObjectProperty(OURI theURI) {
    if(ontologyService.isObjectProperty(theURI)) {
      return (ObjectProperty) Utils.createOProperty(this,ontologyService,
          theURI.toString(), OConstants.OBJECT_PROPERTY);
    } else {
      return null;
    }
  }



  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#removeProperty(gate.creole.ontology.RDFProperty
   * )
   */
  public void removeProperty(RDFProperty theProperty) {
    // TODO: properly remove map
    /*
    OResource res = getOResourceFromMap(theProperty.getURI().toString());
    if(res == null) {
      Utils.warning(theProperty.getURI().toString() + " does not exist");
      return;
    }
     * */

    String[] deletedResources =
      ontologyService.removePropertyFromOntology(theProperty
        .getOURI().toString(), true);
    fireOntologyResourcesRemoved(deletedResources);
  }

  /**
   * Adds a new MinCardinality Restriction to the ontology. It automatically
   * creates a randon anonymous class, which it uses to denote the restriction.
   * The default datatype is set to NonNegativeIntegerNumber
   * 
   * @param onProperty
   *          - Specifies the property for which the restriction is being set.
   * @param minCardinalityValue
   *          - generally a numeric number.
   * @return
   * @throws InvalidValueException
   *           - if a value is not compatible with the nonNegativeIntegerNumber
   *           datatype.
   */
  public MinCardinalityRestriction addMinCardinalityRestriction(
    RDFProperty onProperty, String minCardinalityValue)
    throws InvalidValueException {
    String restId = getAutoGeneratedRestrictionName();
    DataType datatype =
      OntologyUtilities.getDataType(XMLSchema.NON_NEGATIVE_INTEGER.toString());

    OBNodeID bnode = createOBNodeID(restId);
    ontologyService.addRestriction(bnode);

    ontologyService.setOnPropertyValue(bnode, onProperty.getOURI());

    if(!datatype.isValidValue(minCardinalityValue)) {
      throw new InvalidValueException(minCardinalityValue
        + " is not valid for datatype " + datatype.getXmlSchemaURIString());
    }

    ontologyService.setPropertyValue(restId,
      OConstants.MIN_CARDINALITY_RESTRICTION, minCardinalityValue, datatype
        .getXmlSchemaURIString());

    MinCardinalityRestriction mcr =
      (MinCardinalityRestriction)Utils.createOClass(
        this, ontologyService, restId, OConstants.MIN_CARDINALITY_RESTRICTION);

    fireOntologyResourceAdded(mcr);
    return mcr;
  }

  /**
   * Adds a new MaxCardinality Restriction to the ontology. It automatically
   * creates a randon anonymous class, which it uses to denote the restriction.
   * The default datatype is set to NonNegativeIntegerNumber
   * 
   * @param onProperty
   *          - Specifies the property for which the restriction is being set.
   * @param maxCardinalityValue
   *          - generally a numeric number.
   * @return
   * @throws InvalidValueException
   *           - if a value is not compatible with the nonNegativeIntegerNumber
   *           datatype.
   */
  public MaxCardinalityRestriction addMaxCardinalityRestriction(
    RDFProperty onProperty, String maxCardinalityValue)
    throws InvalidValueException {
    String restId = getAutoGeneratedRestrictionName();
    DataType datatype =
      OntologyUtilities.getDataType(XMLSchema.NON_NEGATIVE_INTEGER.toString());

    OBNodeID bnode = createOBNodeID(restId);
    ontologyService.addRestriction(bnode);

    ontologyService.setOnPropertyValue(bnode, onProperty.getOURI());

    if(!datatype.isValidValue(maxCardinalityValue)) {
      throw new InvalidValueException(maxCardinalityValue
        + " is not valid for datatype " + datatype.getXmlSchemaURIString());
    }

    ontologyService.setPropertyValue(restId,
      OConstants.MAX_CARDINALITY_RESTRICTION, maxCardinalityValue, datatype
        .getXmlSchemaURIString());

    MaxCardinalityRestriction mcr =
      (MaxCardinalityRestriction)Utils.createOClass(
        this, ontologyService, restId, OConstants.MAX_CARDINALITY_RESTRICTION);
    fireOntologyResourceAdded(mcr);
    return mcr;
  }

  /**
   * Adds a new Cardinality Restriction to the ontology. It automatically
   * creates a randon anonymous class, which it uses to denote the restriction.
   * The default datatype is set to NonNegativeIntegerNumber
   * 
   * @param onProperty
   *          - Specifies the property for which the restriction is being set.
   * @param cardinalityValue
   *          - generally a numeric number.
   * @return
   * @throws InvalidValueException
   *           - if a value is not compatible with the nonNegativeIntegerNumber
   *           datatype.
   */
  public CardinalityRestriction addCardinalityRestriction(
    RDFProperty onProperty, String cardinalityValue)
    throws InvalidValueException {
    String restId = getAutoGeneratedRestrictionName();
    DataType datatype =
      OntologyUtilities.getDataType(XMLSchema.NON_NEGATIVE_INTEGER.toString());

    OBNodeID bnode = createOBNodeID(restId);
    ontologyService.addRestriction(bnode);

    ontologyService.setOnPropertyValue(bnode, onProperty.getOURI());

    if(!datatype.isValidValue(cardinalityValue))
      throw new InvalidValueException(cardinalityValue
        + " is not valid for datatype " + datatype.getXmlSchemaURIString());

    ontologyService.setPropertyValue(restId,
      OConstants.CARDINALITY_RESTRICTION, cardinalityValue, datatype
        .getXmlSchemaURIString());

    CardinalityRestriction cr =
      (CardinalityRestriction)Utils.createOClass(this,
        ontologyService, restId, OConstants.CARDINALITY_RESTRICTION);

    fireOntologyResourceAdded(cr);
    return cr;
  }

  /**
   * Adds a new HasValue Restriction to the ontology. It automatically creates a
   * randon anonymous class, which it uses to denote the restriction.
   * 
   * @param onProperty
   *          - Specifies the property for which the restriction is being set.
   * @param hasValue
   *          - a resource or a literal used as a value for hasValue element of
   *          the restriction.
   * @return
   */
  public HasValueRestriction addHasValueRestriction(RDFProperty onProperty,
    OResource hasValue) {

    String restId = getAutoGeneratedRestrictionName();

    OBNodeID bnode = createOBNodeID(restId);
    ontologyService.addRestriction(bnode);

    ontologyService.setOnPropertyValue(bnode, onProperty.getOURI());

    // TODO: this was the original code here which obviously intended to 
    // make this work correctly for both instances and literal values.
    // However, OResource never could actually be a Literal, so this would
    // never yield a literal value!
    //String valueString =
    //  hasValue instanceof Literal
    //   ? ((Literal)hasValue).getValue()
    //    : ((OResource)hasValue).getONodeID().toString();
    ontologyService.setRestrictionValue(bnode,
      OURI_OWL_HASVALUE, hasValue.getONodeID());

    HasValueRestriction hvr =
      (HasValueRestriction)Utils.createOClass(this,
        ontologyService, restId, OConstants.HAS_VALUE_RESTRICTION);
    fireOntologyResourceAdded(hvr);
    return hvr;
  }

  /**
   * Adds a new AllValuesFrom Restriction to the ontology. It automatically
   * creates a randon anonymous class, which it uses to denote the restriction.
   * 
   * @param onProperty
   *          - Specifies the property for which the restriction is being set.
   * @param hasValue
   *          - a resource used as a value for hasValue element of the
   *          restriction.
   * @return
   */
  public AllValuesFromRestriction addAllValuesFromRestriction(
    RDFProperty onProperty, OResource hasValue) {
    String restId = getAutoGeneratedRestrictionName();

    OBNodeID bnode = createOBNodeID(restId);
    ontologyService.addRestriction(bnode);

    ontologyService.setOnPropertyValue(bnode, onProperty.getOURI());

    ontologyService.setRestrictionValue(bnode,
      OURI_OWL_ALLVALUESFROM, hasValue.getONodeID());

    AllValuesFromRestriction avfr =
      (AllValuesFromRestriction)Utils.createOClass(
        this, ontologyService, restId, OConstants.ALL_VALUES_FROM_RESTRICTION);
    fireOntologyResourceAdded(avfr);
    return avfr;
  }

  public AllValuesFromRestriction addAllValuesFromRestriction(
    ObjectProperty onProperty, OClass hasValue) {
    String restId = getAutoGeneratedRestrictionName();

    OBNodeID bnode = createOBNodeID(restId);
    ontologyService.addRestriction(bnode);

    ontologyService.setOnPropertyValue(bnode, onProperty.getOURI());

    ontologyService.setRestrictionValue(bnode,
      OURI_OWL_ALLVALUESFROM, hasValue.getONodeID());

    AllValuesFromRestriction avfr =
      (AllValuesFromRestriction)Utils.createOClass(
        this, ontologyService, restId, OConstants.ALL_VALUES_FROM_RESTRICTION);
    fireOntologyResourceAdded(avfr);
    return avfr;
  }

  /**
   * Adds a new AllValuesFrom Restriction to the ontology. It automatically
   * creates a randon anonymous class, which it uses to denote the restriction.
   * 
   * @param onProperty
   *          - Specifies the property for which the restriction is being set.
   * @param hasValue
   *          - a resource used as a value for hasValue element of the
   *          restriction.
   * @return
   */
  public SomeValuesFromRestriction addSomeValuesFromRestriction(
    RDFProperty onProperty, OResource hasValue) {
    String restId = getAutoGeneratedRestrictionName();

    OBNodeID bnode = createOBNodeID(restId);
    ontologyService.addRestriction(bnode);

    ontologyService.setOnPropertyValue(bnode, onProperty.getOURI());

    ontologyService.setRestrictionValue(bnode,
      OURI_OWL_SOMEVALUESFROM, hasValue.getONodeID());

    SomeValuesFromRestriction svfr =
      (SomeValuesFromRestriction)Utils.createOClass(
        this, ontologyService, restId, OConstants.SOME_VALUES_FROM_RESTRICTION);
    fireOntologyResourceAdded(svfr);
    return svfr;
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#setModified(boolean)
   */
  public void setModified(boolean isModified) {
    this.isModified = isModified;
  }

  /*
   * (non-Javadoc)
   * 
   * @see gate.creole.ontology.Ontology#isModified()
   */
  @Override
  public boolean isModified() {
    return this.isModified;
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#addOntologyModificationListener(gate.creole
   * .ontology.OntologyModificationListener)
   */
  public synchronized void addOntologyModificationListener(
    OntologyModificationListener oml) {
    List<OntologyModificationListener> newListeners =
      new ArrayList<OntologyModificationListener>();
    if(this.modificationListeners != null) {
      newListeners.addAll(this.modificationListeners);
    }
    newListeners.add(oml);
    this.modificationListeners = newListeners;
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * gate.creole.ontology.Ontology#removeOntologyModificationListener(gate.creole
   * .ontology.OntologyModificationListener)
   */
  public synchronized void removeOntologyModificationListener(
    OntologyModificationListener oml) {
    if(this.modificationListeners == null
      || !this.modificationListeners.contains(oml)) {
      return;
    }
    else {
      List<OntologyModificationListener> newListeners =
        new ArrayList<OntologyModificationListener>();
      for(OntologyModificationListener l : this.modificationListeners) {
        if(l != oml) {
          newListeners.add(l);
        }
      }
      this.modificationListeners = newListeners;
    }
  }

  /**
   * A method to invoke when a resource's property value is changed
   * 
   * @param resource
   * @param eventType
   */
  public void fireResourcePropertyValueChanged(OResource resource,
    RDFProperty property, Object value, int eventType) {
    List<OntologyModificationListener> listeners = this.modificationListeners;
    if(listeners != null) {
      for(OntologyModificationListener l : listeners) {
        l.resourcePropertyValueChanged(this, resource, property, value,
          eventType);
      }
    }
  }

  /**
   * A method to invoke when a resource's property value is changed
   * 
   * @param resource
   * @param eventType
   */
  public void fireResourceRelationChanged(OResource resource1,
    OResource resource2, int eventType) {
    List<OntologyModificationListener> listeners = this.modificationListeners;
    if(listeners != null) {
      for(OntologyModificationListener l : listeners) {
        l.resourceRelationChanged(this, resource1, resource2, eventType);
      }
    }
  }

  public void fireOntologyReset() {
    List<OntologyModificationListener> listeners = this.modificationListeners;
    if(listeners != null) {
      for(OntologyModificationListener l : listeners) {
        l.ontologyReset(this);
      }
    }
  }

  /**
   * A Method to invoke an event for newly added ontology resource
   * 
   * @param resource
   */
  public void fireOntologyResourceAdded(OResource resource) {
    List<OntologyModificationListener> listeners = this.modificationListeners;
    if(listeners != null) {
      for(OntologyModificationListener l : listeners) {
        l.resourceAdded(this, resource);
      }
    }
  }

  /**
   * A Method to invoke an event for a removed ontology resource
   * 
   * @param resource
   */
  public void fireOntologyResourcesRemoved(String[] resources) {
    // we need to delete this resource from our maps
    //for(int i = 0; i < resources.length; i++) {
    //  removeOResourceFromMap(resources[i]);
    //}

    List<OntologyModificationListener> listeners = this.modificationListeners;
    if(listeners != null) {
      for(OntologyModificationListener l : listeners) {
        l.resourcesRemoved(this, resources);
      }
    }
  }

  /**
   * Dummy implementation - this method is not supported any more.
   */
  public boolean transationStarted() {
    throw new UnsupportedOperationException("Not supported any more in this implementation");
  }

  /**
   * Dummy implementation - this method is not supported any more.
   * To get the sesame repository for a sesame ontology, the ontology
   * object should get cast to a gate.creole.contology.impl.sesame.OntologyLR
   * object and getSesameRepositoryConnection() to get the connection which
   * can be used to get the repository object.
   */
  public Object getSesameRepository() {
    throw new UnsupportedOperationException("Not supported any more in this implementation");
  }

  /**
   * Dummy implementation - this method is not supported any more.
   */
  public String getSesameRepositoryID() {
    throw new UnsupportedOperationException("Not supported in this implementation");
  }

  /**
   * Dummy implementation - this method is deprecated and only kept as long
   * as it will be used in the gate.gui.ontology package. It is strongly
   * recommended to replace all occurrences of this method by one of the 
   * methods that gets a specific ontology entity (e.g. OInstance, Oclass).
   */
  public OResource getOResourceFromMap(String uri) {
    throw new UnsupportedOperationException("getResourceFromMap not supported any more");
  }

  /**
   * Dummy implementation - this method is not supported any more.
   */
  public void addOResourceToMap(String uri, OResource resource) {
    throw new UnsupportedOperationException("addOResourceToMap not supported any more");
  }
  
  /**
   * Dummy implementation - this method is not supported any more.
   */
  public void removeOResourceFromMap(String uri) {
    throw new UnsupportedOperationException("removeOResourceFromMap not supported any more");
  }


  public void cleanup() {
  }


  /**
   * Try to return the only OResource with the given resource name.
   * If there is no such resource return null. If there is more than 
   * one OResource where the fragment identifier of the URI matches the
   * given resource name, return an arbitrary one and output a warning.
   * 
   * @param resourceName
   * @return an OResource object that matches the name or null, if none found
   */
  // NOTE: this should stay deprecated as it can return a random of several
  // matching resources. 
  public OResource getOResourceByName(String resourceName) {
    //System.err.println("getOResourceByName called");
    //new GateOntologyException("NO USE").printStackTrace();
    List<OResource> resources = getOResourcesByName(resourceName);
    if(resources != null && !resources.isEmpty()) {
      if(resources.size() > 1) {
        System.err
          .print("Warning : there are more than one resources matching with the name "
            + resourceName);
      }
      return resources.get(0);
    }
    return null;
  }

  /**
   * Find all OResources for the given resource name. These can be OResources
   * with different URI but identical fragment identifier. If the ontology
   * is not OWL-Lite (which is not officially supported by this implementation)
   * this could also be an URI that can be represented by different subtypes
   * of OResource, e.g. an entity which is both an instance and a class
   * (which is possible in OWL-Full).
   * 
   * @param resourceName
   * @return a list of OResource objects that have the given resource name.
   */
  // NOTE: this method should get un-deprecated but strongly discouraged as
  // it is rather slow and the type of the requested resource should usually
  // be known beforehand.
  public List<OResource> getOResourcesByName(String resourceName) {
    List<OResource> toReturn = new ArrayList<OResource>();
    Set<OClass> classes = getOClassesByName(resourceName);
    toReturn.addAll(classes);
    classes = null;
    Set<OInstance> instances = getOInstancesByName(resourceName);
    toReturn.addAll(instances);
    instances = null;
    Set<RDFProperty> properties = getPropertiesByName(resourceName);
    toReturn.addAll(properties);
    properties = null;
    return toReturn;
  }

  public Set<OClass> getOClassesByName(String resourceName) {
    // TODO: normalize/check resourceName: quotes, spaces etc must be escaped!
    return ontologyService.getClassesByName(encodeResourceName(resourceName));
  }

  public Set<OInstance> getOInstancesByName(String resourceName) {
    // TODO: normalize/check resourceName: quotes, spaces etc must be escaped!
    return ontologyService.getInstancesByName(encodeResourceName(resourceName));
  }

  public Set<RDFProperty> getPropertiesByName(String resourceName) {
    // TODO: normalize/check resourceName: quotes, spaces etc must be escaped!
    return ontologyService.getPropertiesByName(encodeResourceName(resourceName));
  }

  protected String encodeResourceName(String resourceName) {
    // TODO: replace blanks by %20, quotes, <, >, #(?), ampersand?
    return resourceName;
  }

  /**
   * This method returns a list of OResources from the ontology. Please note
   * that deleting an instance from this list (e.g. list.remove(int/Object))
   * does not delete the resource from an ontology. One must use appropriate
   * method from the Ontology interface to delete such resources.
   * 
   * @return
   */
  public List<OResource> getAllResources() {
    //Utils.warnDeprecation("getAllResources");
    // TODO: would love to make this Unsupported but at the moment
    // it is still used by the ontology editor.
    Set<OClass> cs = getOClasses(false);
    Set<OInstance> is = getOInstances();
    Set<RDFProperty> rs = getPropertyDefinitions();
    List<OResource> toReturn = new ArrayList<OResource>();
    for(OClass c : cs) {
      toReturn.add(c);
    }
    for(OInstance i : is) {
      toReturn.add(i);
    }
    for(RDFProperty r : rs) {
      toReturn.add(r);
    }
    //Iterator<String> keys = resourceNamesToOResourcesMap.keySet().iterator();
    //while(keys.hasNext()) {
    //  toReturn.addAll(resourceNamesToOResourcesMap.get(keys.next()));
    //}
    return toReturn;
    //throw new UnsupportedOperationException("getAllResources not supported any more");
  }

  /**
   * Tries to save the ontology at the provided File
   */
  public void store(File newOntology) throws IOException {
    throw new UnsupportedOperationException("Method not supported in this implementation");
  }

  /**
   * This method given a property (either an annotation or datatype), retrieves
   * a list of resources which have the provided literal set as a value.
   * 
   * @param aProperty
   * @param aValue
   * @return
   */
  public List<OResource> getOResourcesWith(RDFProperty aProperty, Literal aValue) {
    List<OResource> toReturn = new ArrayList<OResource>();

    int propType = 1;

    if(aProperty instanceof AnnotationProperty) {
      propType = 1;
    }
    else if(aProperty instanceof DatatypeProperty) {
      propType = 2;
    }
    else {
      return toReturn;
    }

    // here the first thing is to obtain all the resources
    List<OResource> resources = getAllResources();

    // and on each resource we need to check if it has the above
    // property set on it
    for(OResource aResource : resources) {
      switch(propType){
        case 1:
          if(aResource.hasAnnotationPropertyWithValue(
            (AnnotationProperty)aProperty, aValue)) { toReturn.add(aResource); }
          break;
        case 2:
          if(aResource instanceof OInstance
            && ((OInstance)aResource).hasDatatypePropertyWithValue(
              (DatatypeProperty)aProperty, aValue)) { toReturn.add(aResource); }
          break;
      }
    }
    return toReturn;
  }

  /**
   * This method given a property (either object, transitive, symmetric or rdf),
   * retrieves a list of resources which have the provided resource set as a
   * value.
   * 
   * @param aProperty
   * @param aValue
   * @return
   */
  public List<OResource> getOResourcesWith(RDFProperty aProperty,
    OResource aValue) {
    List<OResource> toReturn = new ArrayList<OResource>();

    int propType = 1;

    if(aProperty instanceof ObjectProperty) {
      propType = 1;
    }
    else if(!(aProperty instanceof DatatypeProperty)) {
      propType = 2;
    }
    else {
      return toReturn;
    }

    // here the first thing is to obtain all the resources
    List<OResource> resources = getAllResources();

    // and on each resource we need to check if it has the above
    // property set on it
    for(OResource aResource : resources) {
      switch(propType){
        case 1:
          if(aResource instanceof OInstance
            && aValue instanceof OInstance
            && ((OInstance)aResource).hasObjectPropertyWithValue(
              (ObjectProperty)aProperty, (OInstance)aValue)) {
            toReturn.add(aResource);
          }
          break;
        case 2:
          if(aResource instanceof OInstance
            && ((OInstance)aResource)
              .hasRDFPropertyWithValue(aProperty, aValue)) {
            toReturn.add(aResource);
          }
          break;
      }
    }
    return toReturn;
  }

  // NOTE: we provide an implementation for this in the sesame implementation
  // package that overwrites this method 
  @Deprecated
  public String executeQuery(String serqlQuery) {
    throw new UnsupportedOperationException("Not supported in this implementation");
  }

  public void resolveImports(Map<String, String> importMappings) {
    boolean haveUnresolvedImports = true;
    // make sure we have a map, even if empty
    if (importMappings == null) {
      importMappings = new HashMap<String, String>();
    }
    // get the global substitution patterns from the map: everything that
    // starts with "*" will be replaced in any import URI that starts with
    // this.
    List<String> patterns = new ArrayList<String>();
    for (String from : importMappings.keySet()) {
      if (from.startsWith("*")) {
        //System.out.println("Adding pattern: " + from);
        patterns.add(from.substring(1));
      }
    }
    // now sort by decreasing length of the replacement patter
    Collections.sort(patterns,
        new Comparator<String>() {

          public int compare(String s1, String s2) {
            if (s1.length() == s2.length()) {
              return s1.compareTo(s2);
            } else if (s1.length() < s2.length()) {
              return 1;
            } else {
              return -1;
            }
          }
        });
    // Go through all the import URIs and if we have not seen the URI yet,
    // load or ignore according to the map. Repeat until no more unseen
    // import URIs are left
    while (haveUnresolvedImports) {
      // get all the imports mentioned in the ontology repository
      // this includes the ones we already have processed
      Set<OURI> importURIs = getImportURIs();
      // lets see if we find anything new to load in this iteration
      int loaded = 0;
      OUTER:
      for (OURI anURI : importURIs) {
        String URIString = anURI.toString();
        // if we find an URI that we have not processed yet
        if (!this.knownImportURIs.contains(URIString)) {
          // lets see if we have a specific mapping for it
          if (importMappings.containsKey(URIString)) {
            String mapped = importMappings.get(URIString);
            // if the mapping contains something, try to interpret that
            // as an URL and load from there, otherwise do not actually
            // import anything
            if (mapped != null &&
                // !mapped.isEmpty()  - does not work in Java 1.5
                (mapped.length() != 0)) {
              URL location;
              try {
                location = new URL(mapped);
              } catch (MalformedURLException ex) {
                throw new GateOntologyException(
                    "Problem creating an URL from the mapping " + mapped +
                    " for ontology import " + anURI, ex);

              }
              InputStream is;
              try {
                is = location.openStream();
              } catch (IOException ex) {
                throw new GateOntologyException(
                    "Problem opening the URL " + location + " from the mapping " + mapped +
                    " for ontology import " + anURI, ex);

              }
              try {
                System.out.println("Loading import for " + URIString + " from " + location);
                readOntologyData(is, anURI.toString(), OntologyFormat.RDFXML, true);
              } catch (Exception ex) {
                throw new GateOntologyException(
                    "Problem loading ontology from URL " + location, ex);
              }
              try {
                is.close();
              } catch (IOException ex) {
                throw new GateOntologyException("Problem closing the stream for URL " +
                    location + " from the mapping " + mapped +
                    " for ontology import " + anURI, ex);
              }
              loaded++;
            } else {
              System.out.println("Ignoring import for " + URIString);
            }
            knownImportURIs.add(anURI.toString());
            continue OUTER;
          }

          // we get here only if we did not find a specific mapping
          // lets see if we have a pattern that matches
          for (String pattern : patterns) {
            if (URIString.startsWith(pattern)) {
              //System.out.println("Processing URI: " + URIString);
              //System.out.println("Found matching pattern: " + pattern);
              // substitute the pattern in the uri with the mapping, or
              // ignore the URI if the mapping is empty
              String subst = importMappings.get("*" + pattern);
              //System.out.println("Found replacement " + subst);
              if (subst.length() == 0) {
                knownImportURIs.add(anURI.toString());
                continue OUTER;
              } else {
                // substitute the part of the URI that matches with
                // the replacement part
                knownImportURIs.add(anURI.toString());
                URIString = URIString.replaceFirst("\\Q" + pattern + "\\E", subst);
                //System.out.println("URI String after replacement: " + URIString);
                anURI = createOURI(URIString);
                //System.out.println("Replaced, new URI is: " + anURI.toString());
              }
            }
          }
          // no process either the original URI or the one we got after
          // making the substitution
          URL location;
          try {
            location = new URL(anURI.toString());
          } catch (MalformedURLException ex) {
            throw new GateOntologyException(
                "Problem creating an URL from the ontology import URI " + anURI, ex);

          }
          InputStream is;
          try {
            URLConnection conn = location.openConnection();
            conn.addRequestProperty("accept", 
                "application/rdf+xml,application/xml;q=0.5,*/*;q=0.1");
            is = conn.getInputStream();
          } catch (IOException ex) {
            throw new GateOntologyException(
                "Problem opening the URL " + location +
                " from the ontology import URI " + anURI, ex);

          }
          try {
            System.out.println("Loading import for " + URIString + " from " + location);
            readOntologyData(is, anURI.toString(), OntologyFormat.RDFXML, true);
          } catch (Exception ex) {
            throw new GateOntologyException(
                "Problem loading ontology from URL " + location, ex);
          }
          try {
            is.close();
          } catch (IOException ex) {
            throw new GateOntologyException(
                "Problem closing the stream for URL " +
                location +
                " for ontology import URI " + anURI, ex);
          }


          loaded++;
          // remember that we have already processed this URI
          knownImportURIs.add(anURI.toString());
        }
      }
      // if nothing was loaded, there will be no more import URIs to process
      if (loaded == 0) {
        haveUnresolvedImports = false;
      }
    }
  }

  public Set<OURI> getImportURIs() {
    Set<OURI> set = new HashSet<OURI>();
    Set<String> ss = ontologyService.getImportURIStrings();
    for (String s : ss) {
      OURI theOURI = createOURI(s);
      set.add(theOURI);
      //System.out.println("Converted import URI string "+s+" to OURI "+theOURI.toString());
    }
    return set;
  }

  // TODO: maybe we implement this at a later time if it is needed and
  // useful, at the moment, only the first URL loaded is returned by getURL
  //public List<URL> getURLs(boolean includeImports) {
  //  throw new UnsupportedOperationException("Needs to get implemented in AbstractOntologyImpl.getURLs");
  //}


  public void startTransaction() {
    throw new UnsupportedOperationException("Not supported in this implementation");
  }

  public void commitTransaction() {
    throw new UnsupportedOperationException("Not supported in this implementation");
  }

  /**
   * Return an URL that is related to the source of the ontology.
   * This needs to be implemented by all implementing LRs so the factory
   * can determine a name based on the source of the ontology. If the ontology
   * is empty or the source otherwise unknown, null can be returned.
   * This is not part of the public ontology API but used internally by
   * the GATE Factory.
   * 
   * @return a URL of the source of the ontology
   */
  public abstract java.net.URL getSourceURL();


  protected File pluginDir = null;

  public File getPluginDir() {
    if (pluginDir == null) {
      ResourceData myResourceData =
          Gate.getCreoleRegister().get("gate.creole.ontology.impl.sesame.OWLIMOntology");
      java.net.URL creoleXml = myResourceData.getXmlFileUrl();
      pluginDir = gate.util.Files.fileFromURL(creoleXml).getParentFile();
    }
    return pluginDir;
  }


  public Map<String, String> loadImportMappingsFile(java.net.URL mappingsURL) {
    Map<String, String> mappings = new HashMap<String, String>();
    try {
      // open file and read line by line, each line should have
      // two tab-separated strings, which will be trimmed and added
      // to the map
      InputStream is = mappingsURL.openStream();
      DataInputStream dis = new DataInputStream(is);
      BufferedReader br = new BufferedReader(new InputStreamReader(dis));
      String strLine;
      while ((strLine = br.readLine()) != null) {
        if(strLine.matches("^\\s*#.*") ||
           strLine.matches("^\\s*$")) {
          continue;
        }
        String[] s = strLine.split("[\\t\\s]+", 2);
        if (s.length == 2) {
          String theMapping = s[1];
          theMapping = theMapping.trim();
          if(!theMapping.startsWith("http:") &&
             !theMapping.startsWith("file:") &&
             !theMapping.startsWith("/")) {
            String mappingsDir = mappingsURL.toString();
            // remove everything after the last "/" and append the relative name
            mappingsDir = mappingsDir.substring(0,mappingsDir.lastIndexOf("/"));
            theMapping = mappingsDir+"/"+theMapping;
          } else if(theMapping.startsWith("/")) {
            String mappingsURIString = "file://"+theMapping;
          }
          mappings.put(s[0].trim(), theMapping);
        } else {
          mappings.put(strLine.trim(),"");
        }
      }
      is.close();
    } catch (IOException ex) {
      throw new GateRuntimeException("Error reading mappings file ", ex);
    }
    return mappings;
  }

  // ************************* helper methods and utilities

  // add the ontology URI of an ontology just loaded to the known imports
  // this should get called by any method that LOADS an ontology and
  // it should find exactly one new ontology URI
  // If more than one URI has been found they will all get added to the known
  // import URIs and to the loaded ontology URIs for now ...
  // the method returns the new URIs actually found.
  protected Set<OURI> addOntologyURIs() {
    Set<OURI> ouris = ontologyService.getOntologyURIs();
    Set<OURI> newuris = new HashSet<OURI>();
    for (OURI u : ouris) {
      if(!loadedOntologyURIs.contains(u)) { 
        loadedOntologyURIs.add(u);
        knownImportURIs.add(u.toString());
        newuris.add(u);
      }
    }
    return newuris;
  }

  public List<OURI> getOntologyURIs() {
    return loadedOntologyURIs;
  }

  public AnonymousClass addAnonymousClass() {
    throw new UnsupportedOperationException("Still to be implemented!");
  }

  
  public OURI createOURI(String uriString) {
    return new OURIImpl(uriString);
  }

  public OBNodeID createOBNodeID(String id) {
    return new OBNodeIDImpl(id);
  }


  public OURI createOURIForName(String resourceName) {
    // TODO: check and normalize resourceName
    String baseURI = getDefaultNameSpace();
    if(baseURI == null) {
      throw new GateOntologyException("Cannot create OURI, no system name space (base URI) set");
    }
    return new OURIImpl(baseURI+resourceName);
  }

  public OURI createOURIForName(String resourceName, String baseURI) {
    // TODO: check and normalize resource name, maybe also URI, or do the
    // latter in the OURI constructor?
    return new OURIImpl(baseURI+resourceName);
  }

  public OURI generateOURI(String resourceName) {
    String baseURI = getDefaultNameSpace();
    if(baseURI == null) {
      throw new GateOntologyException("No default name space set, cannot generate OURI");
    }
    return generateOURI(resourceName, baseURI);
  }

  public OURI generateOURI(String resourceName, String baseURI) {
    if(resourceName == null) {
      resourceName = "";
    }
    // TODO: check and normalize resource name so it is a valid part of an IRI

    // now append a generated suffix .. if the OURI already exists, retry with
    // a different suffix until we get a really new OURI.
    while(true) {
      String rn  = 
        resourceName +
        Long.toString(System.currentTimeMillis(),36) +
        Integer.toString(Math.abs(randomGenerator.nextInt(1296)),36);
      OURI uri = createOURIForName(rn);
      if (!ontologyService.containsURI(uri)) {
        return uri;
      }
    }
  }
  
  public List<Literal> getOntologyAnnotationValues(AnnotationProperty ann) {
    Set<OURI> ontouris = ontologyService.getOntologyURIs();
    if(ontouris.size() != 1) {
      throw new GateOntologyException(
          "Can only get ontology annotation values if there is a single ontology uri but there are "+
          ontouris.size()+": "+ontouris);
    }
    OURI ouri = ontouris.iterator().next();
    return ontologyService.getAnnotationPropertyValues(
            ouri, ann.getOURI());
  }

  public void setOntologyAnnotation(AnnotationProperty ann, Literal val)  {
    Set<OURI> ontouris = ontologyService.getOntologyURIs();
    if(ontouris.size() != 1) {
      throw new GateOntologyException(
          "Can only set ontology annotation values if there is a single ontology uri but there are "+
          ontouris.size()+": "+ontouris);
    }
    OURI ouri = ontouris.iterator().next();
    RDFProperty res = getProperty(ann.getOURI());
    if(res == null) {
      Utils
              .error(ann.getOURI().toTurtle()
                      + " does not exist");
      return;
    }

    if(!(res instanceof AnnotationProperty)) {
      Utils.error(ann.getOURI().toTurtle()
              + " is not an annotation property");
      return;
    }

    ontologyService.addAnnotationPropertyValue(ouri,
            ann.getOURI(), val.getValue(),
            val.getLanguage() != null
                    ? val.getLanguage().getLanguage()
                    : null);
  }

  public void setOntologyURI(OURI theURI) {
    // TODO: check if already have one or more URIs, if yes, remove them(?)
    Set<OURI> uris = ontologyService.getOntologyURIs();
    if(uris.size() == 0) {
      ontologyService.setOntologyURI(theURI);
    } else if(uris.size() == 1) {
      OURI existing = uris.iterator().next();
      if(existing.equals(theURI)) {
        throw new GateOntologyException("Ontology URI already set to "+existing.toTurtle());
      }
    } else {
      throw new GateOntologyException("Ontology has already several URIS: "+uris);
    }
  }

  public OURI getOntologyURI() {
    Set<OURI> uris = ontologyService.getOntologyURIs();
    if(uris.size() == 0) {
      return null;
    } else if(uris.size() == 1) {
      return uris.iterator().next();
    } else {
      throw new GateOntologyException("More than one ontology URI found: "+uris);
    }
  }

  @Override
  public void setDataStore(DataStore dataStore) throws PersistenceException {
    throw new PersistenceException("This ontology LR cannot be saved to a datastore");
  } // setDataStore(DS)

}