Package org.ontoware.rdfreactor.runtime

Source Code of org.ontoware.rdfreactor.runtime.ReactorBaseImpl

package org.ontoware.rdfreactor.runtime;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.ontoware.aifbcommons.collection.ClosableIterator;
import org.ontoware.rdf2go.exception.ModelRuntimeException;
import org.ontoware.rdf2go.model.Model;
import org.ontoware.rdf2go.model.QueryRow;
import org.ontoware.rdf2go.model.Statement;
import org.ontoware.rdf2go.model.node.Node;
import org.ontoware.rdf2go.model.node.Resource;
import org.ontoware.rdf2go.model.node.URI;
import org.ontoware.rdf2go.model.node.Variable;
import org.ontoware.rdf2go.vocabulary.RDF;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* <b>ReactorBaseImpl</b> is the base class for instances of classes from the
* RDFS/OWL schema generated by the code generator. <br>
*
* If a class inheriting from ReactorBaseImpl is instantiated, it represents an
* instance of a class from an RDFS/OWL schema. The properties of this class
* instance are stored in an RDF model using RDF2Go (via the static Bridge
* object) as triples of the form: (this.instanceIdentifier, key, value). <br>
*
* Besides methods for putting, getting and removing properties, the Map<URI,
* Object> Interface is also supported for handling of all properties of this
* instance in one Map, backed by the actual RDF2Go model.
*
* <br>
* RDF Reactor uses the following naming:
*
* <b>resource</b> - instance of an RDF schema class, identified by the
* resource ID (an URI or BlankNode), almost all statements about the resource
* use the resource ID as the object
*
* <b>property</b> - a property belongs to a resource, represented by the
* predicate of a statement about a resource
*
* <b>value</b> - value of a property of a resource, represented by the object
* of the statement with the property as predicate and the resource ID as the
* subject
*
* @author $Author: xamde $
* @version $Id: ReactorBaseImpl.java,v 1.24 2006/12/05 19:47:28 xamde Exp $
*
*
*/
public class ReactorBaseImpl implements ReactorBase {

  private static Logger log = LoggerFactory.getLogger(ReactorBaseImpl.class);

  /**
   * the underlying RDF2Go model in which the triples representing the
   * properties of this object are saved
   */
  protected Model model;

  /**
   * the URI of the RDFS class from which this object is an instance
   */
  protected URI classURI;

  /**
   * the identifier of this instance is a URI or a BlankNode. It is used as
   * the Subject of all triples representing this instance in the RDF model.
   */
  private Resource instanceIdentifier;

  /**
   * Constructor: create a ReactorBaseImpl for the RDFS/OWL schema class
   * identified by classURI, with instanceIdentifier as the identifing URL or
   * BlankNode.
   *
   * @param model,
   *            the underlying RDF2Go model
   * @param classURI,
   *            URI of the RDFS/OWL class from which this object is an
   *            instance
   * @param instanceIdentifier,
   *            has to be an URI or URL or BlankNode
   * @param write
   *            if true, the triple (this, rdf:type, classURI) is written to
   *            the model (in addition to any other triples denoting
   *            properties of the instance)
   */
  public ReactorBaseImpl(Model model, URI classURI,
      Resource instanceIdentifier, boolean write) {
    this.model = model;
    this.classURI = classURI;
    this.instanceIdentifier = instanceIdentifier;

    // this can lead to concurrenty exceptions when used in
    // iterators on the model
    if (write) {
      try {
        // add type information only if not present
        if (!model
            .contains(this.instanceIdentifier, RDF.type, classURI)) {
          log.debug("adding type information: "
              + this.instanceIdentifier + " a " + classURI);
          add(RDF.type, classURI);

        }
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
  }

  /**
   * Constructor: create a ReactorBaseImpl for the RDFS/OWL schema class
   * identified by classURI, with instanceIdentifier as the identifing URL or
   * BlankNode. Dont write (this, rdf:type, classURI) for this instance to the
   * model.
   *
   * @param model,
   *            the underlying RDF2Go model
   * @param classURI,
   *            URI of the RDFS/OWL class from which this object is an
   *            instance
   * @param instanceIdentifier,
   *            has to be an URI or URL or BlankNode
   */
  public ReactorBaseImpl(Model model, URI classURI,
      Resource instanceIdentifier) {
    // FIXME: default true or false?
    this(model, classURI, instanceIdentifier, false);
  }

  /**
   * implements
   *
   * @see ReactorEntity
   */
  public Resource getResource() {
    return this.instanceIdentifier;
  }

  /**
   * @return the URI of the RDFS schema class of which this object is an
   *         instance
   */
  public URI getRDFSClassURI() {
    return this.classURI;
  }

  /**
   * Find the URI of the RDFS schema class through inspection, this is usefull
   * if the model contains no (this, rdf:type, classURI) triple
   *
   * @param javaClass
   *            for which the RDFS schema class should be found
   * @return the RDFs_CLASS URI of an instance by using reflection
   */
  private static URI getClassURI(Class<?> javaClass) {
    // TODO experimental
    try {
      URI classURI;
      classURI = (URI) javaClass.getDeclaredField("RDFS_CLASS").get(null);
      return classURI;
    } catch (Exception e) {
      throw new IllegalArgumentException(
          javaClass
              + " seems not to have an RDFS_CLASS. Is it really a subclass of ReactorBaseImpl ?",
          e);
    }
  }

  // //////////////////////////////////////
  // override some java.lang.Object methods

  /**
   * implement
   *
   * @see Object methods
   */
  @Override
  public boolean equals(Object other) {

    if (other instanceof ReactorBase) {
      return ((ReactorBase) other).getResource().equals(
          this.getResource());
    } else if (other instanceof URI) {
      return this.getResource().equals(other);
    } else
      return false;
  }

  /**
   * implement
   *
   * @see Object methods
   */
  @Override
  public int hashCode() {
    return this.instanceIdentifier.hashCode();
  }

  /**
   * implement
   *
   * @see Object methods
   * @return a string representation of the instance identifier (URI or blank
   *         node). Representations are dependant on the used RDF2Go adaptor.
   */
  @Override
  public String toString() {
    return this.instanceIdentifier.toString();
  }

  // ////////////////////////
  // queries

  public static boolean hasInstance(Model model, URI uri, URI classURI) {
    try {
      return (model.contains(uri, RDF.type, classURI));
    } catch (ModelRuntimeException e) {
      throw new RuntimeException(e);
    }
  }

  public static Object getInstance(Model model, URI uri,
      Class<?> javaClass) throws Exception {
    if (model.contains(uri, RDF.type, getClassURI(javaClass))) {
      return RDFReactorRuntime.resource2reactorbase(model, uri, javaClass);
    } else
      return null;
  }

  /**
   * Return all instances of the given class.
   *
   * @param model -
   *            underlying RDF2Go model
   * @param javaClass -
   *            the java class representing the class the instances which
   *            should be returned
   * @param classURI -
   *            URI of the (RDFS/OWL) class. currently not used
   * @return array of all instances of the given java class in the model
   */
  private static Object[] getAllInstances(Model model, Class<?> javaClass,
      URI classURI) {

    // FIXME
    if (!model.isOpen())
      model.open();

    // FIXME: classURI is not used ?
    List<Object> result = new ArrayList<Object>();
    try {

      ClosableIterator<? extends Statement> it = model.findStatements(
          Variable.ANY, RDF.type, getClassURI(javaClass));
      while (it.hasNext()) {
        Resource o = it.next().getSubject();
        // log.debug("found instance " + o + " of class "
        // + javaClass.getName());
        result.add(RDFReactorRuntime.node2javatype(model, o, javaClass));
      }
      it.close();

      Object[] typedResult = (Object[]) Array.newInstance(javaClass,
          result.size());
      for (int i = 0; i < typedResult.length; i++)
        typedResult[i] = javaClass.cast(result.get(i));

      log.debug("returning " + typedResult.length + " typed " + javaClass
          + " instances");
      return typedResult;

    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Return all instances of the given class as a SubjectResultIterator
   * object.
   *
   * @param model -
   *            underlying RDF2Go model
   * @param javaClass -
   *            the java class representing the class the instances which
   *            should be returned
   * @param classURI -
   *            URI of the (RDFS/OWL) class. currently not used
   * @return SubjectResultIterator over the resulting instances
   */
  @SuppressWarnings("unchecked")
  public static Iterator<?> getAllInstancesAsIterator(Model model,
      Class javaClass, URI classURI) {
    ClosableIterator<QueryRow> it;
    try {
      // it = model.findStatements(Variable.ANY, RDF.type,
      // getClassURI(javaClass)).iterator();
      it = model.sparqlSelect(
          "SELECT ?x WHERE { ?x <" + RDF.type + "> <" + classURI
              + ">}").iterator();
      return new ObjectResultIterator(model, new ExtractingIterator(
          model, it, "x"), javaClass);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Return all instances of the given class.
   *
   * @param model -
   *            underlying RDF2Go model
   * @param javaClass -
   *            the java class representing the class the instances which
   *            should be returned
   * @return array of all instances of the given java class in the model
   */
  public static Object[] getAllInstances(Model model, Class<?> javaClass) {
    URI classURI = getClassURI(javaClass);
    return getAllInstances(model, javaClass, classURI);
  }

  /**
   * Check if .this object is an instance of the given RDFS/OWL class URI.
   *
   * @param classURI -
   *            URI of the RDFS/OWL class
   * @return true if .this is an instance of the given classURI
   */
  public boolean isInstanceof(URI classURI) throws ModelRuntimeException {
    return this.model.contains(this.getResource(), RDF.type, classURI);
  }

  /**
   * Check if .this object is an instance of the given Java class.
   *
   * @param javaClass -
   *            given Java class
   * @return true if .this is an instance of the given Java Class in the model
   * @deprecated
   */
  @Deprecated
  public boolean isInstanceof(Class<?> javaClass) throws ModelRuntimeException {
    return (isInstanceof(getClassURI(javaClass)));
  }

  /**
   * Cast .this object to the given target Java type.
   *
   * @param targetType -
   *            Java type to which to cast this object
   * @return converted object
   */
  public Object castTo(Class<?> targetType) {
    return RDFReactorRuntime.node2javatype(this.model, this.getResource(), targetType);
  }

  // FIXME new

  /**
   * Returns the first x in (this, prop, x) if such a statement is in the
   * model. Null otherwise. If there are several x the first is returned
   * (depending on the underlying RDF store). This method is useful for
   * functional properties.
   *
   * @param prop -
   *            URI of the property
   * @param returnType -
   *            desired Java return type
   * @return null or object typed as returnType
   * @throws RDFDataException
   */
  public Object get(URI prop, Class<?> returnType) throws RDFDataException {
    return BridgeBase.getValue(this.model, this.instanceIdentifier, prop,
        returnType);
  }

  /**
   * Returns an array of x with (this, prop, x) if such statements are in the
   * model. Null otherwise.
   *
   * @param prop -
   *            URI of the property
   * @param returnType -
   *            desired Java return type
   * @return all values, array can be empty, never null
   */
  public Object[] getAll(URI prop, Class<?> returnType) {

    try {
      return BridgeBase.getAllValues(this.model, this.instanceIdentifier,
          prop, returnType);
    } catch (Exception e) {
      throw new RuntimeException("return type " + returnType.getName()
          + ". " + e, e);
    }
  }

  /**
   * Get all resources having the given property and value. Return x matching
   * (x, property, o).
   *
   * @param property -
   *            URI of the property
   * @param o -
   *            value of the property
   * @param returnType -
   *            desired Java return type
   * @return array of desired returnType representing the found resources
   */
  public Object[] getAll_Inverse(URI property, Node o, Class<?> returnType) {
    try {
      return BridgeBase.getAllValues_Inverse(this.model, property, o,
          returnType);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Get all values for the given property of this resource instance as a Set.
   *
   * @param prop -
   *            URI of the property
   * @param returnType -
   *            desired Java return type
   * @return Set of all values for the given property
   */
  public Set<Object> getAll_AsSet(URI prop, Class<?> returnType) {

    try {
      return BridgeBase.getAllValues_asSet(this.model,
          this.instanceIdentifier, prop, returnType);
    } catch (Exception e) {
      throw new RuntimeException("type " + returnType.getName(), e);
    }
  }

  /**
   * Removes all statements (this, prop, x) and set one anew: (this, prop, o).
   *
   * @param prop -
   *            URI of the property
   * @param o -
   *            new value for the property
   */
  public void set(URI prop, Object o) {
    try {
      Bridge.setValue(this.model, this.instanceIdentifier, prop, o);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Removes all statements (this, prop, x) and sets anew: (this, prop, o[0]),
   * (this, prop, o[1]), ...
   *
   * @param prop -
   *            URI of the property
   * @param o -
   *            array of new values for the property
   */
  public void setAll(URI prop, Object[] o) throws ModelRuntimeException {
    Bridge.setAllValue(this.model, this.instanceIdentifier, prop, o);
  }

  /**
   * Removes all statements (this, prop, x) and sets anew: (this, prop, o[0]),
   * (this, prop, o[1]), ... But only if the number of objects in o[] is less
   * than or equal to maxCard.
   *
   * @param prop -
   *            URI of the property
   * @param o -
   *            array of new values of the property
   * @param maxCard -
   *            the maximum number of triples allowed to match (this, prop, x)
   * @throws CardinalityException
   * @throws CardinalityException
   *             if the size of o[] is larger then maxCard
   */
  public void setAll(URI prop, Object[] o, int maxCard)
      throws ModelRuntimeException, CardinalityException {
    if (o.length <= maxCard)
      setAll(prop, o);
    else
      throw new CardinalityException("Only " + maxCard
          + " values allowed for property " + prop + " in class "
          + this.classURI + ". You tried to add " + o.length);
  }

  /**
   * Looks for a statement (this, prop, oldValue) and replaces it by a new
   * statement (this, prop, newValue). If the first cannot be found, false is
   * returned, true otherwise.
   *
   * @param prop -
   *            URI of the property
   * @param oldValue -
   *            old value of the property
   * @param newValue -
   *            new value of the property
   * @return true if old value was found
   */
  public boolean update(URI prop, Object oldValue, Object newValue) {
    try {
      return Bridge.updateValue(this.model, this.instanceIdentifier,
          prop, oldValue, newValue);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }

  }

  /**
   *
   * @param prop
   * @param value
   * @return true if the model contains the statement (this, prop, value)
   */
  public boolean hasValue(URI prop, Object value) {
    try {
      return BridgeBase.containsGivenValue(this.model, this.instanceIdentifier, prop,
          value);
    } catch (ModelRuntimeException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * @param prop
   * @return true if the model contains any statement (this, prop, *)
   */
  public boolean hasValue(URI prop) {
    try {
      return ResourceUtils.containsAnyValue(this.model, this.instanceIdentifier,
          prop);
    } catch (ModelRuntimeException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Adds a statement (this, prop, o). Returns false if this statement has
   * already been in model. True otherwise.
   *
   * @param property -
   *            URI of the property
   * @param object -
   *            value of the property
   * @return true if value was already in the model
   */
  public boolean add(URI property, Object object) {
    try {
      return Bridge.addValue(this.model, this.instanceIdentifier,
          property, object);
    } catch (Exception e) {
      log.error("", e);
      throw new RuntimeException(e);
    }
  }

  /**
   * Adds a statement (this, prop, o) if the number of statements matching
   * (this, prop, x) is less then maxCard
   *
   * @param property -
   *            URI of the property
   * @param object -
   *            value of the property
   * @param maxCard -
   *            number of occurences of (this, prop, x) allowed in the model
   * @return true if value was already preset
   * @throws CardinalityException
   *             if the resource already has more then maxCard values for the
   *             property
   */
  public boolean add(URI property, Object object, int maxCard)
      throws CardinalityException {
    if (getAll(property, Resource.class).length < maxCard)
      return add(property, object);
    else
      throw new CardinalityException("Only " + maxCard
          + " values allowed for property " + property + " in class "
          + this.classURI);
  }

  /**
   * Tries to remove a statement (this, prop, o).
   *
   * @param prop -
   *            URI of the property
   * @param o -
   *            value of the property
   * @return true, if value was present
   */
  public boolean remove(URI prop, Object o) {
    try {
      return BridgeBase.removeValue(this.model, this.instanceIdentifier,
          prop, o);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Tries to remove a statement (this, prop, o) if the number of statements
   * matching (this, prop, x) in the model is less then minCard
   *
   * @param prop -
   *            URI of the property
   * @param o -
   *            value of the property
   * @param minCard -
   *            number of occurences of (this, prop, x) needed in the model
   * @return true if value was found
   * @throws CardinalityException
   *             if resource has less then minCard values for the property
   */
  public boolean remove(URI prop, Object o, int minCard)
      throws CardinalityException {
    if (getAll(prop, Object.class).length > minCard)
      return remove(prop, o);
    else
      throw new CardinalityException("Must have at least " + minCard
          + " values for property " + prop + " in class " + this.classURI);
  }

  /**
   * remove all (this, rdf:type, prop) statements
   *
   * @param prop,
   *            Object of a Triple
   */
  public boolean removeAll(URI prop) {
    try {
      return BridgeBase.removeAllValues(this.model, this.instanceIdentifier,
          prop);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public Model getModel() {
    return this.model;
  }

  /**
   * Delete all statements of the form (this, *,*)
   */
  public void delete() {
    try {
      this.model.removeStatements(this.model.createTriplePattern(
          this.instanceIdentifier, Variable.ANY, Variable.ANY));
    } catch (ModelRuntimeException e) {
      throw new RuntimeException(e);
    }

  }

  // TODO implement boolean in(Model)
  public boolean in(
  Model model) {
    throw new UnsupportedOperationException("not yet implemented");

  }

  // TODO re-enable after cleanup is complete
  // 
  // public Map<URI, Object> map() {
  // return new ReactorMap(model, instanceIdentifier);
  // }

}
TOP

Related Classes of org.ontoware.rdfreactor.runtime.ReactorBaseImpl

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.