Package jade.content.onto

Source Code of jade.content.onto.Ontology

/**
* ***************************************************************
* JADE - Java Agent DEvelopment Framework is a framework to develop
* multi-agent systems in compliance with the FIPA specifications.
* Copyright (C) 2000 CSELT S.p.A.
*
* GNU Lesser General Public License
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation,
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA  02111-1307, USA.
* **************************************************************
*/
package jade.content.onto;

import java.util.Hashtable;
import java.util.Enumeration;

import jade.content.Concept;
import jade.content.abs.AbsAggregate;
import jade.content.abs.AbsHelper;
import jade.content.abs.AbsObject;
import jade.content.schema.ConceptSlotFunctionSchema;
import jade.content.schema.ObjectSchema;
import jade.content.schema.AgentActionSchema;
import jade.content.schema.ConceptSchema;
import jade.content.schema.PredicateSchema;

import jade.util.leap.Serializable;
import jade.util.Logger;

//#J2ME_EXCLUDE_BEGIN
import java.io.PrintStream;

import java.util.Iterator;
import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;

import jade.content.schema.Facet;
import jade.content.schema.facets.CardinalityFacet;
import jade.content.schema.facets.DefaultValueFacet;
import jade.content.schema.facets.PermittedValuesFacet;
import jade.content.schema.facets.RegexFacet;
//#J2ME_EXCLUDE_END

/**
* An application-specific ontology describes the elements that agents
* can use within content of messages. It defines a vocabulary and
* relationships between the elements in such a vocabulary.
* The relationships can be:
* <ul>
* <li>structural, e.g., the predicate <code>fatherOf</code> accepts two
*     parameters, a father and a set of children;
* <li>semantic, e.g., a concept of class <code>Man</code> is also of class
*     <code>Person</code>.
* </ul>
* Application-specific ontologies are implemented through objects
* of class <code>Ontology</code>.<br>
* An ontology is characterized by:
* <ul>
* <li>one name;
* <li>one (or more) base ontology that it extends;
* <li>a set of <i>element schemas</i>.
* </ul>
* Element schemas are objects describing the structure of concepts, actions,
* and predicates that are allowed in messages. For example,
* <code>People</code> ontology contains an element schema called
* <code>Person</code>. This schema states that a <code>Person</code> is
* characterized by a <code>name</code> and by an <code>address</code>:
* <code>
* ConceptSchema personSchema = new ConceptSchema(PERSON);
* personSchema.addSlot(NAME,    stringSchema);
* personSchema.addSlot(ADDRESS, addressSchema, ObjectSchema.OPTIONAL);
* </code>
* where <code>PERSON<code>, <code>NAME</code> and <code>ADDRESS</code> are
* string constants. When you register your schema with the ontology, such
* constants become part of the vocabulary of the ontology.<br>
* Schemas that describe concepts support inheritance. You can define the
* concept <code>Man</code> as a refinement of the concept <code>Person</code>:
* <code>
* ConceptSchema manSchema = new ConceptSchema(MAN);
* manSchema.addSuperSchema(personSchema);
* </code>
* Each element schema can be associated with a Java class to map elements of
* the ontology that comply with a schema with Java objects of that class. The
* following is a class that might be associated with the <code>Person</code>
* schema:
* <code>
* public class Person extends Concept {
*       private String  name    = null;
*       private Address address =  null;
*
*       public void setName(String name) {
*               this.name = name;
*       }
*
*       public void setAddress(Address address) {
*               this.address = address;
*       }
*
*       public String getName() {
*               return name;
*       }
*
*       public Address getAddress() {
*               return address;
*       }
* }
* </code>
* When sending/receiving messages you can represent your content in terms of
* objects belonging to classes that the ontology associates with schemas.<br>
* As the previous example suggests, you cannot use objects of class
* <code>Person</code> when asking for the value of some attribute, e.g., when
* asking for the value of <code>address</code>. Basically, the problem is that
* you cannot 'assign' a variable to an attribute of an object, i.e.
* you cannot write something like:
* <code>person.setName(new Variable("X"))</code>.<br>
* In order to solve this problem, you can describe your content in terms of
* <i>abstract descriptors</i>. An abstract descriptor is an
* object that reifies an element of the ontology.
* The following is the creation of an abstract
* descriptor for a concept of type <code>Man</code>:
* <code>
* AbsConcept absMan = new AbsConcept(MAN);
* absMan.setSlot(NAME,    "John");
* absMan.setSlot(ADDRESS, absAddress);
* </code>
* where <code>absAddress</code> is the abstract descriptor for John's
* address:
* <code>
* AbsConcept absAddress = new AbsConcept(ADDRESS);
* absAddress.setSlot(CITY, "London");
* </code>
* Objects of class <code>Ontology</code> allows you to:
* <ul>
* <li>register schemas with associated (i) a mandatory term of the
*     vocabulary e.g. <code>NAME</code> and (ii) an optional Java class,
*     e.g. <code>Person</code>;
* <li>retrieve the registered information through various keys.
* </ul>
* The framework already provides the <code>BasicOntology</code> ontology
* that provides all basic elements, i.e. primitive data types, aggregate
* types, etc.
* Application-specific ontologies should be implemented extending it.

* @see jade.content.Concept
* @see jade.content.abs.AbsConcept
* @see jade.content.schema.ConceptSchema
* @see jade.content.onto.BasicOntology
* @author Federico Bergenti - Universita` di Parma
* @author Giovanni Caire - TILAB
*/
public class Ontology implements Serializable {
  private static final String DEFAULT_INTROSPECTOR_CLASS = "jade.content.onto.ReflectiveIntrospector";
  private Ontology[]   base = new Ontology[0];
  private String       name = null;
  private Introspector introspector = null;

  private Hashtable elements = new Hashtable(); // Maps type-names to schemas
  private Hashtable classes  = new Hashtable(); // Maps type-names to java classes
  private Hashtable schemas  = new Hashtable(); // Maps java classes to schemas
 
  // We use an Hashtable as if it was a Set
  private Hashtable conceptSlots;
 
  private Logger logger = Logger.getMyLogger(this.getClass().getName());

  // This is required for compatibility with CLDC MIDP where XXX.class
  // is not supported
  private static Class absObjectClass = null;
  static {
    try {
      absObjectClass = Class.forName("jade.content.abs.AbsObject");
    }
    catch (Exception e) {
      // Should never happen
      e.printStackTrace();
    }
  }

  /**
   * Construct an Ontology object with a given <code>name</code>
   * that extends a given ontology.
   * The <code>ReflectiveIntrospector</code> is used by default to
   * convert between Java objects and abstract descriptors.
   * @param name The identifier of the ontology.
   * @param base The base ontology.
   */
  public Ontology(String name, Ontology base) {
    this(name, base, null);
    try {
      introspector = (Introspector) Class.forName(DEFAULT_INTROSPECTOR_CLASS).newInstance();
    }
    catch (Exception e) {
      throw new RuntimeException("Class "+DEFAULT_INTROSPECTOR_CLASS+"for default Introspector not found");
    }
  }

  /**
   * Construct an Ontology object with a given <code>name</code>
   * that uses a given Introspector to
   * convert between Java objects and abstract descriptors.
   * @param name The identifier of the ontology.
   * @param introspector The introspector.
   */
  public Ontology(String name, Introspector introspector) {
    this(name, new Ontology[0], introspector);
  }

  /**
   * Construct an Ontology object with a given <code>name</code>
   * that extends a given ontology and that uses a given Introspector to
   * convert between Java objects and abstract descriptors.
   * @param name The identifier of the ontology.
   * @param base The base ontology.
   * @param introspector The introspector.
   */
  public Ontology(String name, Ontology base, Introspector introspector) {
    this(name, (base != null ? new Ontology[]{base} : new Ontology[0]), introspector);
  }

  /**
   * Construct an Ontology object with a given <code>name</code>
   * that extends a given set of ontologies and that uses a given Introspector to
   * convert between Java objects and abstract descriptors.
   * @param name The identifier of the ontology.
   * @param base The base ontology.
   * @param introspector The introspector.
   */
  public Ontology(String name, Ontology[] base, Introspector introspector) {
    this.name = name;
    this.introspector = introspector;
    this.base = (base != null ? base : new Ontology[0]);
  }

  /**
   * Retrieves the name of this ontology.
   * @return the name of this ontology.
   */
  public String getName() {
    return name;
  }

  public Introspector getIntrospector() {
    return introspector;
  }

  /**
   * Adds a schema to this ontology
   * @param schema The schema to add
   * @throws OntologyException
   */
  public void add(ObjectSchema schema) throws OntologyException {
    add(schema, null);
  }


  /**
   * Adds a schema to the ontology and associates it to the class
   * <code>javaClass</code>
   * @param schema the schema.
   * @param javaClass the concrete class.
   * @throws OntologyException
   */
  public void add(ObjectSchema schema, Class javaClass) throws OntologyException {
    if (schema.getTypeName() == null) {
      throw new OntologyException("Invalid schema identifier");
    }

    String s = schema.getTypeName().toLowerCase();
    elements.put(s, schema);

    if (javaClass != null) {
      classes.put(s, javaClass);
      if (!absObjectClass.isAssignableFrom(javaClass)) {
        if (introspector != null) {
          introspector.checkClass(schema, javaClass, this);
        }
        schemas.put(javaClass, schema);
      }
      else {
        // If the java class is an abstract descriptor check the
        // coherence between the schema and the abstract descriptor
        if (!javaClass.isInstance(schema.newInstance())) {
          throw new OntologyException("Java class "+javaClass.getName()+" can't represent instances of schema "+schema);
        }
      }
    }
  }

  /**
   * Retrieves the schema of element <code>name</code> in this ontology.
   * The search is extended to the base ontologies if the schema is not
   * found.
   * @param name the name of the schema in the vocabulary.
   * @return the schema or <code>null</code> if the schema is not found.
   * @throws OntologyException
   */
  public ObjectSchema getSchema(String name) throws OntologyException {
    if (name == null) {
      throw new OntologyException("Null schema identifier");
    }

    ObjectSchema ret = (ObjectSchema) elements.get(name.toLowerCase());
       
    if (ret == null) {
      // Check if a ConceptSlotFunctionSchema must be returned
      if ("BC-Ontology".equals(getName())) {
        System.out.println("Searching for schema "+name);
      }
      if (conceptSlots != null && conceptSlots.containsKey(name)) {
        return new ConceptSlotFunctionSchema(name);
      }
     
      if(logger.isLoggable(Logger.FINE))
        logger.log(Logger.FINE,"Ontology "+getName()+". Schema for "+name+" not found");
      for (int i = 0; i < base.length; ++i) {
        if (base[i] == null) {
          if(logger.isLoggable(Logger.FINE))
            logger.log(Logger.FINE,"Base ontology # "+i+" for ontology "+getName()+" is null");
        }
        else {
          ret = base[i].getSchema(name);
          if (ret != null) {
            break;
          }
        }
      }
    }
    return ret;
  }

  /**
   * Retrieves the schema associated to a given class in this ontology.
   * The search is extended to the base ontologies if the schema is not
   * found.
   * @param clazz the class whose associated schema must be retrieved.
   * @return the schema associated to the given class or <code>null</code> if the schema is not found.
   * @throws OntologyException
   */
  public ObjectSchema getSchema(Class clazz) throws OntologyException {
    if (clazz == null) {
      throw new OntologyException("Null class");
    }
    ObjectSchema ret = (ObjectSchema) schemas.get(clazz);
    if (ret == null) {
      if(logger.isLoggable(Logger.FINE))
        logger.log(Logger.FINE,"Ontology "+getName()+". Schema for class "+clazz+" not found");
      for (int i = 0; i < base.length; ++i) {
        if (base[i] == null) {
          if(logger.isLoggable(Logger.FINE))
            logger.log(Logger.FINE,"Base ontology # "+i+" for ontology "+getName()+" is null");
        }
        else {
          ret = base[i].getSchema(clazz);
          if (ret != null) {
            break;
          }
        }
      }
    }
    return ret;
  }

  /**
   * Converts an abstract descriptor to a Java object of the proper class.
   * @param abs the abstract descriptor.
   * @return the object
   * @throws UngroundedException if the abstract descriptor contains a
   * variable
   * @throws OntologyException if some mismatch with the schema is found
   * @see #fromObject(Object)
   */
  public Object toObject(AbsObject abs) throws OntologyException, UngroundedException {
    if (abs == null) {
      return null;
    }

    try {
      return toObject(abs, abs.getTypeName().toLowerCase(), this);
    }
    catch (UnknownSchemaException use) {
      // If we get this exception here, the schema is globally unknown
      // (i.e. is unknown in the reference ontology and all its base
      // ontologies) --> throw a generic OntologyException
      throw new OntologyException("No schema found for type "+abs.getTypeName());
    }
    catch (OntologyException oe) {
      // This exception may have been thrown due to the fact that the Abs descriptor is
      // ungrounded. In this case an UngroundedException must be thrown.
      // Note that we don't check ungrouding before to speed up performances
      if (!abs.isGrounded()) {
        throw new UngroundedException();
      }
      else {
        throw oe;
      }
    }
  }

  /**
   * Converts a Java object into a proper abstract descriptor.
   * @param obj the object
   * @return the abstract descriptor.
   * @throws OntologyException if some mismatch with the schema is found
   * @see #toObject(AbsObject)
   */
  public AbsObject fromObject(Object obj) throws OntologyException {
    if (obj == null) {
      return null;
    }
   
    try {
      return fromObject(obj, this);
    }
    catch (UnknownSchemaException use) {
      // If we get this exception here, the schema is globally unknown
      // (i.e. is unknown in the reference ontology and all its base
      // ontologies) --> throw a generic OntologyException
      throw new OntologyException("No schema found for class "+obj.getClass().getName());
    }
   
  }

  /**
   * Retrieves the concrete class associated with element <code>name</code>
   * in this ontology. The search is extended to the base ontologies
   * @param name the name of the schema.
   * @return the Java class or null if no schema called <code>name</code>
   * is found or if no class is associated to that schema.
   * @throws OntologyException if name is null
   */
  public Class getClassForElement(String name) throws OntologyException {
    if (name == null) {
      throw new OntologyException("Null schema identifier");
    }

    Class ret = (Class) classes.get(name.toLowerCase());

    if (ret == null) {
      for (int i = 0; i < base.length; ++i) {
        ret = base[i].getClassForElement(name);
        if (ret != null) {
          return ret;
        }
      }
    }
    return ret;
  }
 
  /**
   * Retrieves the ontology actually containing the definition of a given schema.
   * This can be the ontology itself or one of its super-ontologies. 
   * @param lcName The lower-case version of the name of the schema whose defining ontology must be retrieved
   * @return The ontology actually containing the definition of schema <code>lcName</code> or null if such schema
   * is not defined neither in this ontology nor in one of its super-ontologies
   */
  private Ontology getDefiningOntology(String lcName) {
    Ontology definingOntology = null;
    if (elements.containsKey(lcName)) {
      definingOntology = this;
    }
    else {
      for (int i = 0; i < base.length; ++i) {
        definingOntology = base[i].getDefiningOntology(lcName);
        if (definingOntology != null) {
          break;
        }
      }
    }
    return definingOntology;
  }

  //#APIDOC_EXCLUDE_BEGIN
  /**
   * Converts an abstract descriptor to a Java object of the proper class.
   * @param abs the abstract descriptor.
   * @param lcType the type of the abstract descriptor to be translated
   * aconverted into lower case. This is passed as parameters to avoid
   * making the conversion to lower case for each base ontology.
   * @param globalOnto The ontology this ontology is part of (i.e. the
   * ontology that extends this ontology).
   * @return the object
   * @throws UnknownSchemaException If no schema for the abs descriptor
   * to be translated is defined in this ontology.
   * @throws UngroundedException if the abstract descriptor contains a
   * variable
   * @throws OntologyException if some mismatch with the schema is found      * ontology. In this case UnknownSchema
   */
  protected Object toObject(AbsObject abs, String lcType, Ontology globalOnto) throws UnknownSchemaException, UngroundedException, OntologyException {
    if(logger.isLoggable(Logger.FINE))
      logger.log(Logger.FINE,"Ontology "+getName()+". Translating ABS descriptor "+abs);

    // Retrieve the schema
    ObjectSchema schema = (ObjectSchema) elements.get(lcType);
    if (schema != null) {
      if(logger.isLoggable(Logger.FINE))
        logger.log(Logger.FINE,"Ontology "+getName()+". Schema for type "+abs.getTypeName()+" found locally: "+schema);

      // Retrieve the java class
      Class javaClass = (Class) classes.get(lcType);
      if (javaClass == null) {
        throw new OntologyException("No java class associated to type "+abs.getTypeName());
      }
      if(logger.isLoggable(Logger.FINE))
        logger.log(Logger.FINE,"Ontology "+getName()+". Class for type "+abs.getTypeName()+" = "+javaClass.getName());

      // If the Java class is an Abstract descriptor --> just return abs
      if (absObjectClass.isAssignableFrom(javaClass)) {
        return abs;
      }

      try {
        // Try to manage as special type
        Object obj = null;
        try {
          obj = internalizeSpecialType(abs, schema, javaClass, globalOnto);
        } catch(NotASpecialType nasp) {
          // Manage as structure slot
          obj = javaClass.newInstance()
          internalize(abs, obj, schema, globalOnto);
        }
        return obj;
      }
      catch (OntologyException oe) {
        // Let the exception pass through
        throw oe;
      }
      catch (InstantiationException ie) {
        throw new OntologyException("Class "+javaClass+" can't be instantiated", ie);
      }
      catch (IllegalAccessException iae) {
        throw new OntologyException("Class "+javaClass+" does not have an accessible constructor", iae);
      }
    }

    // If we get here --> This ontology is not able to translate abs
    // --> Try to convert it using the base ontologies
    for (int i = 0; i < base.length; ++i) {
      try {
        return base[i].toObject(abs, lcType, globalOnto);
      }
      catch (UnknownSchemaException use) {
        // Try the next one
      }
    }

    throw new UnknownSchemaException();
  }

  private Object internalizeSpecialType(AbsObject abs, ObjectSchema schema, Class javaClass, Ontology globalOnto) throws OntologyException {
    if (introspector == null) {
      throw new NotASpecialType();
    }
   
    return introspector.internalizeSpecialType(abs, schema, javaClass, globalOnto);
  }
 
  /**
   * Internalize (abs --> obj) the slots defined in <code>schema</code> and its super-schemas
   */
  protected void internalize(AbsObject abs, Object obj, ObjectSchema schema, Ontology globalOnto) throws OntologyException {
    // Let the proper ontology manage slots defined in super schemas if any
    ObjectSchema[] superSchemas = schema.getSuperSchemas();
    for (int i = 0; i < superSchemas.length; ++i) {
      ObjectSchema superSchema = superSchemas[i];
      Ontology definingOntology = getDefiningOntology(superSchema.getTypeName().toLowerCase());
      if (definingOntology != null) {
        definingOntology.internalize(abs, obj, superSchema, globalOnto);
      }
    }
   
    // Finally manage "local" slots through the introspector
    if (introspector != null) {
      String[] names = schema.getOwnNames();
      for (int i = 0; i < names.length; ++i) {
        String slotName = names[i];
        AbsObject absSlotValue = abs.getAbsObject(slotName);
        if (absSlotValue != null) {
          Object slotValue = null;
          if (absSlotValue.getAbsType() == AbsObject.ABS_AGGREGATE) {
            // Manage as aggregate
            slotValue = introspector.internalizeAggregate(slotName, (AbsAggregate)absSlotValue, schema, globalOnto);
          } else {
            // Manage as normal slot
            slotValue = globalOnto.toObject(absSlotValue);
          }

          if (slotValue != null) {
            introspector.setSlotValue(slotName, slotValue, obj, schema);
          }
        }
      }
    } 
  }

  /**
   * Converts a Java object into a proper abstract descriptor.
   * @param obj the object
   * @param globalOnto The ontology this ontology is part of (i.e. the
   * ontology that extends this ontology).
   * @return the abstract descriptor.
   * @throws UnknownSchemaException If no schema for the object to be
   * translated is defined in this ontology.
   * @throws OntologyException if some mismatch with the schema is found
   */
  protected AbsObject fromObject(Object obj, Ontology globalOnto) throws UnknownSchemaException, OntologyException {

    // If obj is already an abstract descriptor --> just return it
    if (obj instanceof AbsObject) {
      return (AbsObject) obj;
    }

    // Retrieve the Java class
    Class javaClass = obj.getClass();
    if(logger.isLoggable(Logger.FINE))
      logger.log(Logger.FINE,"Ontology "+getName()+". Translating object of class "+javaClass);

    // Retrieve the schema
    ObjectSchema schema = (ObjectSchema) schemas.get(javaClass);
    if (schema != null) {
      if(logger.isLoggable(Logger.FINE))
        logger.log(Logger.FINE,"Ontology "+getName()+". Schema for class "+javaClass+" found locally: "+schema);

      // Try to manage as special type
      AbsObject abs = null;
      try {
        abs = externalizeSpecialType(obj, schema, javaClass, globalOnto);
      } catch(NotASpecialType nasp) {
        // Manage as structure slot
        abs = schema.newInstance();
        externalize(obj, abs, schema, globalOnto);
      }
      return abs;
    }

    // If we get here --> This ontology is not able to translate obj
    // --> Try to convert it using the base ontologies
    for (int i = 0; i < base.length; ++i) {
      try {
        return base[i].fromObject(obj, globalOnto);
      }
      catch (UnknownSchemaException use) {
        // Try the next one
      }
    }

    throw new UnknownSchemaException();
  }

  private AbsObject externalizeSpecialType(Object obj, ObjectSchema schema, Class javaClass, Ontology globalOnto) throws OntologyException {
    if (introspector == null) {
      throw new NotASpecialType();
    }
    return introspector.externalizeSpecialType(obj, schema, javaClass, globalOnto);
  }

  /**
   * Externalize (obj --> abs) the slots defined in <code>schema</code> and its super-schemas
   */
  protected void externalize(Object obj, AbsObject abs, ObjectSchema schema, Ontology globalOnto) throws OntologyException {
    // Let the proper ontology manage slots defined in super schemas if any
    ObjectSchema[] superSchemas = schema.getSuperSchemas();
    for (int i = 0; i < superSchemas.length; ++i) {
      ObjectSchema superSchema = superSchemas[i];
      Ontology definingOntology = getDefiningOntology(superSchema.getTypeName().toLowerCase());
      if (definingOntology != null) {
        definingOntology.externalize(obj, abs, superSchema, globalOnto);
      }
    }
   
    // Finally manage "local" slots through the introspector
    if (introspector != null) {
      String[] names = schema.getOwnNames();
      for (int i = 0; i < names.length; ++i) {
        String slotName = names[i];
        Object slotValue = introspector.getSlotValue(slotName, obj, schema);
        if (slotValue != null) {
          // Try to manage as aggregate
          AbsObject absSlotValue = null;
          try {
            absSlotValue = introspector.externalizeAggregate(slotName, slotValue, schema, globalOnto);
          } catch(NotAnAggregate naa) {
            // Manage as normal slot
            absSlotValue = globalOnto.fromObject(slotValue);
          }
         
          if (absSlotValue != null) {
            AbsHelper.setAttribute(abs, slotName, absSlotValue);
          }
        }
      }
    }
  }
 
  /**
   * Set the value of slot <code>slotName</code> as <code>slotValue</code> to object <code>obj</code>
   */
  public void setSlotValue(String slotName, Object slotValue, Object obj) throws OntologyException {
    Class javaClass = obj.getClass();
    ObjectSchema schema = (ObjectSchema) schemas.get(javaClass);
    if (schema != null) {
      setSlotValue(slotName, slotValue, obj, schema);
      return;
    }

    // The schema must be defined in a super-ontology --> let it do the job
    for (int i = 0; i < base.length; ++i) {
      try {
        base[i].setSlotValue(slotName, slotValue, obj);
        return;
      }
      catch (UnknownSchemaException use) {
        // Try the next one
      }
    }
   
    throw new UnknownSchemaException();
  }
 
  private void setSlotValue(String slotName, Object slotValue, Object obj, ObjectSchema schema) throws OntologyException {
    if (schema.isOwnSlot(slotName)) {
      // The slot is defined in "schema" --> use the Introspector of the ontology actually defining "schema"
      Ontology definingOntology = getDefiningOntology(schema.getTypeName().toLowerCase());
      definingOntology.introspector.setSlotValue(slotName, slotValue, obj, schema);
      return;
    }
    else {
      // The slot must be defined in a super-schema
      ObjectSchema[] superSchemas = schema.getSuperSchemas();
      for (int i = 0; i < superSchemas.length; ++i) {
        try {
          setSlotValue(slotName, slotValue, obj, superSchemas[i]);
          return;
        }
        catch (UnknownSlotException use) {
          // Try next super-schema
        }
      }
    }
    throw new UnknownSlotException(slotName);
  }
 
  /**
   * Retrieve the value of slot <code>slotName</code> from object <code>obj</code>
   */
  public Object getSlotValue(String slotName, Object obj) throws OntologyException {
    Class javaClass = obj.getClass();
    ObjectSchema schema = (ObjectSchema) schemas.get(javaClass);
    if (schema != null) {
      return getSlotValue(slotName, obj, schema);
    }

    // The schema must be defined in a super-ontology --> let it do the job
    for (int i = 0; i < base.length; ++i) {
      try {
        return base[i].getSlotValue(slotName, obj);
      }
      catch (UnknownSchemaException use) {
        // Try the next one
      }
    }
   
    throw new UnknownSchemaException();
  }

  private Object getSlotValue(String slotName, Object obj, ObjectSchema schema) throws OntologyException {
    if (schema.isOwnSlot(slotName)) {
      // The slot is defined in "schema" --> use the Introspector of the ontology actually defining "schema"
      Ontology definingOntology = getDefiningOntology(schema.getTypeName().toLowerCase());
      return definingOntology.introspector.getSlotValue(slotName, obj, schema);
    }
    else {
      // The slot must be defined in a super-schema
      ObjectSchema[] superSchemas = schema.getSuperSchemas();
      for (int i = 0; i < superSchemas.length; ++i) {
        try {
          return getSlotValue(slotName, obj, superSchemas[i]);
        }
        catch (UnknownSlotException use) {
          // Try next super-schema
        }
      }
    }
    throw new UnknownSlotException(slotName);
  }
  //#APIDOC_EXCLUDE_END


  /////////////////////////
  // Utility static methods
  /////////////////////////

  /**
   * Check whether a given object is a valid term.
   * If it is an Aggregate (i.e. a <code>List</code>) it also check
   * the elements.
   * @throws OntologyException if the given object is not a valid term
   */
  public static void checkIsTerm(Object obj) throws OntologyException {
    // FIXME: This method is likely to be removed as it does not add any value and creates problems
    // when using the Serializable Ontology
    /*if (obj instanceof String ||
          obj instanceof Boolean ||
          obj instanceof Integer ||
          obj instanceof Long ||
          //#MIDP_EXCLUDE_BEGIN
          obj instanceof Float ||
          obj instanceof Double ||
          //#MIDP_EXCLUDE_END
          obj instanceof Date ||
          obj instanceof Term) {
        return;
      }
      if (obj instanceof List) {
        Iterator it = ((List) obj).iterator();
        while (it.hasNext()) {
          checkIsTerm(it.next());
        }
        return;
      }

      // If we reach this point the object is not a term
      throw new OntologyException("Object "+obj+" of class "+obj.getClass().getName()+" is not a term");
     */
  }

  public String toString() {
    return getClass().getName()+"-"+name;
  }


  //#J2ME_EXCLUDE_BEGIN
  /**
   * Retrieve the names of the concepts defined in this ontology only (excluding extended ontologies).
   * It should be noticed that an agent-action is itself a concept and therefore the returned list
   * also includes names of agent-actions defined in this ontology.
   * <br>
   * <b>NOT available in J2ME</b>
   * <br>
   * @return the names of the concepts defined in this ontology only (excluding extended ontologies)
   */
  public List getOwnConceptNames(){
    return getOwnElementNames(ConceptSchema.class);
  }
 
  /**
   * Retrieve the names of all concepts defined in this ontology (including extended ontologies).
   * It should be noticed that an agent-action is itself a concept and therefore the returned list
   * also includes names of agent-actions defined in this ontology.
   * <br>
   * <b>NOT available in J2ME</b>
   * <br>
   * @return the names of all concepts defined in this ontology (including extended ontologies)
   */
  public List getConceptNames(){
    Set names = getElementNames(ConceptSchema.class);
    List l = new ArrayList();
    l.addAll(names);
    return l;
  }

  /**
   * Retrieve the names of the agent actions defined in this ontology only (excluding extended ontologies).
   * <br>
   * <b>NOT available in J2ME</b>
   * <br>
   * @return the names of the agent actions defined in this ontology only (excluding extended ontologies)
   */
  public List getOwnActionNames(){
    return getOwnElementNames(AgentActionSchema.class);
  }
 
  /**
   * Retrieve the names of all agent actions defined in this ontology (including extended ontologies).
   * <br>
   * <b>NOT available in J2ME</b>
   * <br>
   * @return the names of all agent actions defined in this ontology (including extended ontologies)
   */
  public List getActionNames(){
    Set names = getElementNames(AgentActionSchema.class);
    List l = new ArrayList();
    l.addAll(names);
    return l;
  }

  /**
   * Retrieve the names of the predicates defined in this ontology only (excluding extended ontologies).
   * <br>
   * <b>NOT available in J2ME</b>
   * <br>
   * @return the names of the predicates defined in this ontology only (excluding extended ontologies)
   */
  public List getOwnPredicateNames(){
    return getOwnElementNames(PredicateSchema.class);
  }
 
  /**
   * Retrieve the names of all predicatess defined in this ontology (including extended ontologies).
   * <br>
   * <b>NOT available in J2ME</b>
   * <br>
   * @return the names of all predicatess defined in this ontology (including extended ontologies)
   */
  public List getPredicateNames(){
    Set names = getElementNames(PredicateSchema.class);
    List l = new ArrayList();
    l.addAll(names);
    return l;
  }
 
  private List getOwnElementNames(Class c) {
    List names = new ArrayList();
    for (Enumeration e = elements.keys(); e.hasMoreElements();){
      String key  = (String)e.nextElement();
      ObjectSchema objSchema = (ObjectSchema) elements.get(key);
      if (c.isAssignableFrom(objSchema.getClass())) {
        names.add(objSchema.getTypeName());
      }
    }
    return names;
  }

  private Set getElementNames(Class c){
    // We use a Set to avoid duplicating names in case an element is overridden
    Set names = new HashSet();
    names.addAll(getOwnElementNames(c));
    for (int i = 0; i < base.length; ++i) {
      Ontology o = base[i];
      // Do not consider elements defined in the BasicOntology and in the SerializableOntology
      if ((o != null) && (o.getClass() != BasicOntology.class) && (o.getClass() != SerializableOntology.class)) {
        names.addAll(o.getElementNames(c));
      }
    }
    return names;
 
  //#J2ME_EXCLUDE_END
 
  //#MIDP_EXCLUDE_BEGIN
  /**
   * Create a ConceptSlotFunction for a given slot of a given Concept.
   * The ConceptSlotFunction class allows treating the slots of an ontological concept as functions.
   * For instance, if an ontology defines a concept <code>Person</code> with a slot <code>name</code> and a slot <code>age</code>,
   * it is possible to create expression such as<br>
   * (= (age (Person :name John)) 41) <br>
   * (> (age (Person :name John)) (age (Person :name Bill)))<br>
   * (iota ?x (= (age (Person :name John)) ?x))
   * <br>
   * <b>NOT available in MIDP</b>
   * <br>
   * @param slotName The name of the slot
   * @param c The concept a ConceptSlotFunction must be created for. This concept must have a slot called <code>slotName</code>
   * @return A ConceptSlotFunction for the given slotName of the given Concept 
   * @see ConceptSlotFunction
   * @see useConceptSlotsAsFunctions()
   * @since JADE 3.7
   */
  public ConceptSlotFunction createConceptSlotFunction(String slotName, Concept c) throws OntologyException {
    // Scan the ontology hierarchy and get the ontology where concept c is defined.
    // Then create a ConceptSlotFunction refering to that ontology
    ObjectSchema schema = (ObjectSchema) schemas.get(c.getClass());
    if (schema != null) {
      if (conceptSlots != null) {
        if (schema.containsSlot(slotName)) {
          return new ConceptSlotFunction(slotName, c, this);
        }
        else {
          throw new OntologyException("Schema "+schema.getTypeName()+" for class "+c.getClass()+" does not contain a slot called "+slotName);
        }
      }
      else {
        throw new OntologyException("Ontology "+name+" does not support usage of concept slots as functions");
      }
    }
    else {
      for (int i = 0; i < base.length; ++i) {
        try {
          return base[i].createConceptSlotFunction(slotName, c);
        }
        catch (UnknownSchemaException use) {
          // Try the next one
        }
      }
    }
    throw new UnknownSchemaException();
  }
 
  /**
   * Instruct this ontology to support usage of concept slots as functions.
   * This method must be invoked after all schemas have been completely defined and added to this ontology.
   * @see ConceptSlotFunction
   * @see createConceptSlotFunction(String, Concept)
   * @since JADE 3.7
   */
  protected void useConceptSlotsAsFunctions() {
    conceptSlots = new Hashtable();
    Enumeration en = schemas.elements();
    while (en.hasMoreElements()) {
      ObjectSchema schema = (ObjectSchema) en.nextElement();
      String[] slotNames = schema.getNames();
      for (int i = 0; i < slotNames.length; ++i) {
        System.out.println("Concept-slot-function: "+slotNames[i]);
        conceptSlots.put(slotNames[i], slotNames[i]);
      }
    }
  }
  //#MIDP_EXCLUDE_END
 
  public static AbsObject externalizeSlotValue(Object obj, Introspector introspector, Ontology referenceOnto) throws OntologyException {
    try {
      return introspector.externalizeAggregate(null, obj, null, referenceOnto);
    } catch(NotAnAggregate nan) {
     
      return referenceOnto.fromObject(obj);
    }
  }
 
  public static Object internalizeSlotValue(AbsObject abs, Introspector introspector, Ontology referenceOnto) throws OntologyException {
    if (abs.getAbsType() == AbsObject.ABS_AGGREGATE) {
      return introspector.internalizeAggregate(null, (AbsAggregate)abs, null, referenceOnto);
    }
   
    return referenceOnto.toObject(abs);
  }
 
  //#J2ME_EXCLUDE_BEGIN 
  /**
   * Dump ontology to default output stream
   */
  public void dump() {
    dump(System.out);
  }
 
  /**
   * Dump ontology to specified PrintStream
   */
  public void dump(PrintStream ps) {
    try {
      StringBuilder sb = new StringBuilder();
      sb.append("Ontology "+name+"\n");
     
      dump(getConceptNames(), "concept", sb);
      dump(getPredicateNames(), "predicate", sb);
      dump(getActionNames(), "action", sb);

      ps.println(sb.toString());

    } catch(Exception e) {
      e.printStackTrace();
    }
  }

  private void dump(List schemaNames, String label, StringBuilder sb) throws Exception {
 
    Iterator iter = schemaNames.iterator();
    String conceptName;
    ObjectSchema os;
    while (iter.hasNext()) {
      conceptName = (String)iter.next();
      os = getSchema(conceptName);
     
      StringBuilder sbsc = new StringBuilder();
      boolean first = true;
      ObjectSchema[] superSchemas = os.getSuperSchemas();
      for (int i = 0; i < superSchemas.length; i++) {
        if (!first) {
          sbsc.append(" ");
        }
        sbsc.append(superSchemas[i].getTypeName());
        first = false;
      }
     
      sb.append("  "+label+" "+conceptName+" ("+sbsc.toString()+") {\n");
      String[] names = os.getOwnNames();
      for (int i = 0; i < names.length; i++) {
        sb.append("    "+names[i]+": ");
        boolean mandatory = os.isMandatory(names[i]);
        ObjectSchema schema = os.getSchema(names[i]);
        if (schema == null) {
          sb.append("ERROR: no schema!\n");
        } else {
          Object defaultValue = null;
          Object regex = null;
          String pValues = null;
          Integer cardMin = null;
          Integer cardMax = null;
          Facet[] facets = os.getFacets(names[i]);
          if (facets != null) {
            for (int j = 0; j < facets.length; j++) {
              Facet facet = facets[j];
              if (facet instanceof DefaultValueFacet) {
                DefaultValueFacet dvf = (DefaultValueFacet)facet;
                defaultValue = dvf.getDefaultValue();
              } else if (facet instanceof RegexFacet) {
                RegexFacet rf = (RegexFacet)facet;
                regex = rf.getRegex();
              } else if (facet instanceof PermittedValuesFacet) {
                PermittedValuesFacet pvf = (PermittedValuesFacet)facet;
                pValues = pvf.getPermittedValuesAsString();
              } else if (facet instanceof CardinalityFacet) {
                CardinalityFacet cf = (CardinalityFacet)facet;
                cardMin = cf.getCardMin();
                cardMax = cf.getCardMax();
              }
            }
          }
         
          sb.append(schema.getTypeName()+ (!mandatory ? " (OPTIONAL)":""));
          if (defaultValue != null) {
            sb.append(" (DEFAULT="+defaultValue+")");
          }
          if (regex != null) {
            sb.append(" (REGEX="+regex+")");
          }
          if (pValues != null && pValues.length() > 0) {
            sb.append(" (VALUES="+pValues+")");
          }
          if (cardMin != null && cardMax != null) {
            sb.append(" (["+cardMin+","+(cardMax!=-1?cardMax:"unbounded")+"])");
          }
          sb.append("\n");
        }
      }
      sb.append("  } -> "+getClassForElement(os.getTypeName()).getName()+"\n\n");
    }
  }
  //#J2ME_EXCLUDE_END
}
TOP

Related Classes of jade.content.onto.Ontology

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.