Code Search for Developers
 
 
  

DomainEntityPersisterBean.java from Texai at Krugle


Show DomainEntityPersisterBean.java syntax highlighted

/*
 * DomainEntityPersisterBean.java
 *
 * Created on October 31, 2006, 11:23 AM
 *
 * Description: This stateless session bean persists domain entities into the knowledge base,
 * mapping entity associations onto KB propositions.
 *
 * Copyright (C) 2006 Stephen L. Reed.
 *
 * This program is free software; you can redistribute it and/or modify it under the terms
 * of the GNU General Public License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program;
 * if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package org.texai.kb.ejb.session;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
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 java.util.Stack;
import java.util.UUID;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import net.sf.cglib.proxy.Factory;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.apache.log4j.Logger;
import org.texai.kb.Constants;
import org.texai.kb.ejb.session.shared.AssociationEditorLocal;
import org.texai.kb.ejb.session.shared.AssociationFinderLocal;
import org.texai.kb.ejb.session.shared.TermDefinitionAccessorLocal;
import org.texai.kb.ejb.session.shared.TermDeleterFacadeLocal;
import org.texai.kb.ejb.session.shared.TermFinderFacadeLocal;
import org.texai.kb.entity.AtomicTerm;
import org.texai.kb.entity.BinaryGAF;
import org.texai.kb.entity.NonAtomicTerm;
import org.texai.kb.entity.PString;
import org.texai.kb.entity.AbstractReifiedTerm;
import org.texai.kb.entity.AbstractTerm;
import org.texai.kb.persistence.DomainEntity;
import org.texai.kb.persistence.DomainProperty;
import org.texai.kb.persistence.lazy.LazyList;
import org.texai.kb.persistence.lazy.LazySet;
import org.texai.util.ByteUtils;
import org.texai.util.TexaiException;

/**
 *
 * @author reed
 */
@Stateless
public class DomainEntityPersisterBean                     // NOPMD
        extends AbstractDomainEntityAccessor
        implements DomainEntityPersisterLocal {
  
  /** the term id dictionary, term name --> term id */
  private static final transient Map<String, UUID> termIdDictionary = new HashMap<String, UUID>();
  
  /** the term finder, which is injected by the container */
  @EJB
  private TermFinderFacadeLocal termFinderFacade;          // NOPMD
  
  /** the term deleter, which is injected by the container */
  @EJB
  private TermDeleterFacadeLocal termDeleterFacade;        // NOPMD
  
  /** the association finder, which is injected by the container */
  @EJB
  private AssociationFinderLocal associationFinder;        // NOPMD
  
  /** the association editor, which is injected by the container */
  @EJB
  private AssociationEditorLocal associationEditor;        // NOPMD
  
  /** the term definition accessor, which is injected by the container */
  @EJB
  private TermDefinitionAccessorLocal termDefinitionAccessor;        // NOPMD
  
  /** the logger */
  private transient Logger logger;                         // NOPMD
  
  /** the context into which the class-scoped associations are persisted */
  private transient AbstractReifiedTerm classPersistenceContext;        // NOPMD
  
  /** the indicator that the domain instance is new */
  private transient boolean isNewDomainInstance;
  
  /** the stack of domain entity information that allows the session bean to perform recursive method calls */
  private final transient Stack<DomainEntityInfo> domainEntityInfoStack = new Stack<DomainEntityInfo>();
  
  /** the context into which definitional gafs are persisted */
  private transient AtomicTerm universalVocabularyMt;
  
  /** the indicator to validate persisted gafs as a well-formed formulas */
  private transient boolean validateWellFormedFormula = false;
  
  /** the creator of the persisted domain entity */
  private AbstractReifiedTerm creator;
  
  /** the creation purpose of the persisted domain entity */
  private AbstractReifiedTerm creationPurpose;
  
  /** Creates a new instance of DomainEntityPersisterBean */
  public DomainEntityPersisterBean() {
    super();
  }
  
  /** Injects the shared session bean dependencies. */
  public void injectSharedBeanDependencies() {
    if (termFinderFacade != null) {
      termFinderFacade.setTermDefinitionAccessor(termDefinitionAccessor);
    }
    if (associationFinder != null) {
      associationFinder.setTermFinderFacade(termFinderFacade);
    }
    if (associationEditor != null) {
      associationEditor.setTermFinderFacade(termFinderFacade);
    }
    if (termDefinitionAccessor != null) {
      termDefinitionAccessor.setTermFinderFacade(termFinderFacade);
      termDefinitionAccessor.setAssociationFinder(associationFinder);
    }
    if (termDeleterFacade != null) {
      termDeleterFacade.setTermFinderFacade(termFinderFacade);
      termDeleterFacade.setAssociationFinder(associationFinder);
    }
  }
  
  /** Persists the given domain entity as propositions in the knowledge base.
   *
   * @param domainEntity the domain entity
   * @param creator the creator
   * @param creationPurpose the creation purpose
   * @return the instance term that represents the domain entity
   */
  public AtomicTerm persistDomainEntity(
          final Object domainEntity,
          final AbstractReifiedTerm creator,
          final AbstractReifiedTerm creationPurpose) {
    //Preconditions
    assert domainEntity != null : "domainEntity must not be null";
    assert isDomainEntity(domainEntity) : domainEntity + "(" +  domainEntity.getClass().getName()
    + ") must be have a @DomainEntity class level annotation in " + Arrays.toString(domainEntity.getClass().getAnnotations());
    assert creator != null : "creator must not be null";
    assert creationPurpose != null : "creationPurpose must not be null";
    
    final boolean wasStackEmpty = domainEntityInfoStack.empty();
    this.creator = creator;
    this.creationPurpose = creationPurpose;
    initializeAbstractSessionState();
    initializeSessionState();
    getLogger().debug(stackLevel() + "persisting " + domainEntity);
    setDomainEntity(domainEntity);
    setDomainEntityClass(domainEntity.getClass());
    gatherAnnotationsForDomainEntityClass();
    configureDomainContextSettings();
    configureDomainEntitySettings();
    cacheFrequentlyUsedTerms();
    findOrCreatePersistenceContext();
    final boolean isFirstTime = findOrCreateClassTerm();
    if (isFirstTime) {
      persistTypeofs();
      persistSubClassOfs();
    }
    findOrCreateDomainInstanceTerm();
    persistFields();
    
    //Postconditions
    assert getInstanceTerm() != null : "instanceTerm must not be null";
    assert wasStackEmpty == domainEntityInfoStack.empty() : "beginning stack empty status " + wasStackEmpty
            + " must equal ending stack status " + domainEntityInfoStack.empty();
    
    return getInstanceTerm();
  }
  
  /** Persists the given domain entity class as propositions in the knowledge base.
   *
   * @param domainEntityClass the domain entity class
   * @param creator the creator
   * @param creationPurpose the creation purpose
   * @return the term that represents the domain entity class
   */
  @SuppressWarnings("unchecked")
  public AtomicTerm persistDomainEntityClass(
          final Class domainEntityClass,
          final AbstractReifiedTerm creator,
          final AbstractReifiedTerm creationPurpose) {
    //Preconditions
    assert domainEntityClass != null : "domainEntityClass must not be null";
    assert domainEntityClass.isAnnotationPresent(DomainEntity.class) : "domainEntityClass " + domainEntityClass
            + " must have a @DomainEntity annotation";
    assert creator != null : "creator must not be null";
    assert creationPurpose != null : "creationPurpose must not be null";
    
    this.creator = creator;
    this.creationPurpose = creationPurpose;
    initializeAbstractSessionState();
    initializeSessionState();
    getLogger().debug(stackLevel() + "persisting class" + domainEntityClass);
    setDomainEntityClass(domainEntityClass);
    gatherAnnotationsForDomainEntityClass();
    configureDomainContextSettings();
    configureDomainEntitySettings();
    cacheFrequentlyUsedTerms();
    findOrCreatePersistenceContext();
    final AtomicTerm classKBPartition = findOrCreateClassKBPartition(getKBPartitionName());
    setClassKBPartition(classKBPartition);
    final AtomicTerm classTerm = findOrCreateClassTermForClassName(domainEntityClass.getName());
    termIdDictionary.put(getClassTermName(), classTerm.getTermIdAsUUID());
    setClassTerm(classTerm);
    persistTypeofs();
    persistSubClassOfs();
    
    //Postconditions
    assert getClassTerm() != null : "classTerm must not be null";
    
    return getClassTerm();
  }
  
  /** Sets the term finder during out-of-the-container unit testing.
   *
   * @param termFinderFacade the term finder
   */
  public void setTermFinderFacade(final TermFinderFacadeLocal termFinderFacade) {
    //Preconditions
    assert termFinderFacade != null : "termFinderFacade must not be null";
    
    this.termFinderFacade = termFinderFacade;
  }
  
  /** Sets the term deleter during out-of-the-container unit testing.
   *
   * @param termDeleterFacade the term deleter
   */
  public void setTermDeleterFacade(final TermDeleterFacadeLocal termDeleterFacade) {
    //Preconditions
    assert termDeleterFacade != null : "termDeleterFacade must not be null";
    
    this.termDeleterFacade = termDeleterFacade;
  }
  
  /** Sets the association finder during out-of-the-container unit testing.
   *
   * @param associationFinder the association finder
   */
  public void setAssociationFinder(final AssociationFinderLocal associationFinder) {
    //Preconditions
    assert associationFinder != null : "associationFinder must not be null";
    
    this.associationFinder = associationFinder;
  }
  
  /** Sets the association editor during out-of-the-container unit testing.
   *
   * @param associationEditor the association editor
   */
  public void setAssociationEditor(final AssociationEditorLocal associationEditor) {
    //Preconditions
    assert associationEditor != null : "associationEditor must not be null";
    
    this.associationEditor = associationEditor;
  }
  
  /** Sets the term definition accessor during out-of-the-container unit testing.
   *
   * @param termDefinitionAccessor the term definition accessor
   */
  public void setTermDefinitionAccessor(final TermDefinitionAccessorLocal termDefinitionAccessor) {
    //Preconditions
    assert termDefinitionAccessor != null : "termDefinitionAccessor must not be null";
    
    this.termDefinitionAccessor = termDefinitionAccessor;
  }
  
  /** Sets the indicator to validate persisted gafs as a well-formed formulas.
   *
   * @param validateWellFormedFormula the indicator to validate persisted gafs as a well-formed formulas
   */
  public void setValidateWellFormedFormula(boolean validateWellFormedFormula) {
    this.validateWellFormedFormula = validateWellFormedFormula;
  }
  
  /** Gets the logger.
   *
   * @return the logger
   */
  protected Logger getLogger() {
    if (logger == null) {
      logger = Logger.getLogger(DomainEntityPersisterBean.class.getName());
    }
    return logger;
  }
  
  /** Finds or creates the persist-to context term. */
  private void findOrCreatePersistenceContext() {
    assert getClassPersistenceContextName() != null : "classPersistemceContextName must not be null";
    
    classPersistenceContext = termFinderFacade.findAtomicTermByTermName(getClassPersistenceContextName());
    if (classPersistenceContext == null) {
      final List<AbstractReifiedTerm> isaTerms = new ArrayList<AbstractReifiedTerm>();
      final List<AbstractReifiedTerm> genlMtTerms = new ArrayList<AbstractReifiedTerm>();
      for (final String subContextOfName : getSubContextOfNames()) {
        final AbstractReifiedTerm subContextOfTerm = termFinderFacade.findAtomicTermByTermName(subContextOfName);
        if (subContextOfTerm == null) {
          throw new TexaiException("term not found for " + subContextOfName);
        }
        genlMtTerms.add(subContextOfTerm);
      }
      final AtomicTerm kbPartition = termFinderFacade.findAtomicTermByTermName(getKBPartitionName());
      if (kbPartition == null) {
        throw new TexaiException("kbPartition not found for " + getKBPartitionName());
      }
      classPersistenceContext = termFinderFacade.findAtomicTermByTermName(getClassPersistenceContextName());
      if (classPersistenceContext == null) {
        classPersistenceContext = termFinderFacade.createContextTerm(
                getClassPersistenceContextName(),
                "the domain entity context " + getClassPersistenceContextName(),
                getClassPersistenceContextName() + " is a domain entity context.",
                isaTerms,
                genlMtTerms,
                creator,
                creationPurpose,
                kbPartition);
      }
    }
  }
  
  /** Finds or creates the domain entity class term.
   *
   * @return true when this is the first time that the class is processed
   */
  private boolean findOrCreateClassTerm() {
    //Preconditions
    assert getDomainEntity() != null : "domainEntity must not be null";
    assert getClassTermName() != null : "classTermName must not be null";
    
    boolean isFirstTime = false;
    AtomicTerm classTerm = null;
    final UUID termId = termIdDictionary.get(getClassTermName());
    if (termId == null) {
      isFirstTime = true;
      classTerm = findOrCreateClassTermForClassName(getClassTermName());
      termIdDictionary.put(getClassTermName(), classTerm.getTermIdAsUUID());
    } else {
      // more efficient to lookup via primary key rather than by name string
      classTerm = termFinderFacade.findAtomicTermByTermId(termId);
    }
    assert classTerm != null : "classTerm must not be null";
    setClassTerm(classTerm);
    getLogger().debug(stackLevel() + "classTerm: " + getClassTerm());
    
    //Postconditions
    assert getClassTerm() != null : Constants.CLASS_TERM_ERR;
    
    return isFirstTime;
  }
  
  /** Finds or creates the class term for the given class name.
   *
   * @param className the given class name
   * @return the class term for the given class name
   */
  private AtomicTerm findOrCreateClassTermForClassName(final String className) {
    //Preconditions
    assert className != null : "className must not be null";
    assert className.length() > 0 : "className must not be an empty string";
    
    final String classTermPrettyName = "the domain entity class " + className;
    AtomicTerm classTerm = termFinderFacade.findAtomicTermByTermName(className);
    if (classTerm == null) {
      classTerm = termFinderFacade.createAtomicTermByTermName(
              className,
              classTermPrettyName,
              creator,
              creationPurpose,
              getClassKBPartition());
    }
    return classTerm;
  }
  
  /** Finds or creates the KB partition term for the given name.
   *
   * @param classKBPartitionName the given name
   * @return the KB partition term for the given name
   */
  private AtomicTerm findOrCreateClassKBPartition(final String classKBPartitionName) {
    //Preconditions
    assert classKBPartitionName != null : "classKBPartitionName must not be null";
    assert classKBPartitionName.length() > 0 : "classKBPartitionName must not be an empty string";
    
    AtomicTerm kbPartition = termFinderFacade.findAtomicTermByTermName(classKBPartitionName);
    if (kbPartition == null) {
      final AtomicTerm partitionInfoPartition = termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_PARTITION_INFO_PARTITION);
      kbPartition = termFinderFacade.createAtomicTermByTermName(
              classKBPartitionName,
              null,
              creator,
              creationPurpose,
              partitionInfoPartition);
    }
    return kbPartition;
  }
  
  /** Caches frequently used terms. */
  private void cacheFrequentlyUsedTerms() {
    universalVocabularyMt = null;
    final UUID universalVocabularyMtTermId = termIdDictionary.get(Constants.TERM_NAME_UNIVERSAL_VOCABULARY_MT);
    if (universalVocabularyMtTermId == null) {
      universalVocabularyMt = termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_UNIVERSAL_VOCABULARY_MT);
      termIdDictionary.put(Constants.TERM_NAME_UNIVERSAL_VOCABULARY_MT, universalVocabularyMt.getTermIdAsUUID());
    } else {
      universalVocabularyMt = termFinderFacade.findAtomicTermByTermId(universalVocabularyMtTermId);
    }
    
    //Postconditions
    assert universalVocabularyMt != null : "cannot find term for " + Constants.TERM_NAME_UNIVERSAL_VOCABULARY_MT;
  }
  
  
  /** Gathers the existing type class names for which the domain class is a direct instance.
   *
   * @return the existing type class names for which the domain class is a direct instance
   */
  private Set<String> gatherExistingTypeOfs() {
    //Preconditions
    assert getClassTerm() != null : Constants.CLASS_TERM_ERR;
    
    final Set<String> existingTypeOfNames = new HashSet<String>();
    for (final AbstractTerm type : associationFinder.gatherArg2TermsFromBinaryGAFs(
            termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_ISA),
            getClassTerm(),
            universalVocabularyMt)) {
      existingTypeOfNames.add(type.toString());
    }
    getLogger().debug(stackLevel() + "existingTypeOfNames: " + existingTypeOfNames);
    return existingTypeOfNames;
  }
  
  /** Gathers the existing class names for which the domain class is a direct subclass.
   *
   * @return the existing class names for which the domain class is a direct subclass
   */
  private Set<String> gatherExistingSubClassOfs() {
    //Preconditions
    assert getClassTerm() != null : Constants.CLASS_TERM_ERR;
    
    final Set<String> existingSubClassOfNames = new HashSet<String>();
    for (final AbstractTerm type : associationFinder.gatherArg2TermsFromBinaryGAFs(
            termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_GENLS),
            getClassTerm(),
            universalVocabularyMt)) {
      existingSubClassOfNames.add(type.toString());
    }
    getLogger().debug(stackLevel() + "existingSubClassOfNames: " + existingSubClassOfNames);
    return existingSubClassOfNames;
  }
  
  /** Persists the domain entity class isa propositions. */
  private void persistTypeofs() {
    //Preconditions
    assert getClassTerm() != null : Constants.CLASS_TERM_ERR;
    final AtomicTerm isa = termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_ISA);
    final Set<String> existingTypeOfs = gatherExistingTypeOfs();
    if (existingTypeOfs.isEmpty() && getTypeOfs().length == 0) {
      // default to FirstOrderCollection for a new domain class
      final String[] typeOfs = {"FirstOrderCollection"};
      setTypeOfs(typeOfs);
    }
    for (final String typeOf : getTypeOfs()) {
      if (!existingTypeOfs.contains(typeOf)) {
        getLogger().debug(stackLevel() + "adding type: " + typeOf);
        final AbstractTerm typeOfTerm = (AbstractTerm) termFinderFacade.findAtomicTermByTermName(typeOf);
        if (typeOfTerm == null) {
          throw new TexaiException("did not find term for " + typeOf);
        }
        final List<AbstractTerm> args = Arrays.asList(getClassTerm(), typeOfTerm);
        BinaryGAF binaryGAF = null;
        if (!existingTypeOfs.isEmpty()) {
          binaryGAF = termFinderFacade.findBinaryGAFByConstituents(
                  isa,
                  args,
                  universalVocabularyMt);
        }
        if (binaryGAF == null) {
          binaryGAF = termFinderFacade.createBinaryGAFByConstituents(
                  isa,
                  args,
                  universalVocabularyMt,
                  Constants.STRENGTH_MONOTONIC,
                  null,
                  validateWellFormedFormula,
                  creator,
                  creationPurpose,
                  getClassKBPartition());
          getLogger().info("persisted: " + binaryGAF);    // NOPMD
        }
      }
    }
    if (getTypeOfs().length > 0) {
      // if the DomainEntity annotation specified typeOf, then delete any existing isa relationships not contained in the specification
      final List<String> typeOfsList = Arrays.asList(getTypeOfs());
      for (final String existingTypeOf : existingTypeOfs) {
        if (!typeOfsList.contains(existingTypeOf)) {
          getLogger().debug(stackLevel() + "deleting type: " + existingTypeOf);
          final List<AbstractTerm> args = Arrays.asList(
                  getClassTerm(),
                  (AbstractTerm) termFinderFacade.findAtomicTermByTermName(existingTypeOf));
          termDeleterFacade.deleteBinaryGAFsFromRelevantContexts(
                  isa,
                  args,
                  universalVocabularyMt);
        }
      }
    }
  }
  
  /** Persists the domain entity class genls propositions. */
  private void persistSubClassOfs() {
    //Preconditions
    assert getClassTerm() != null : Constants.CLASS_TERM_ERR;
    assert getClassPersistenceContextName() != null : "classPersistenceContextName must not be null";
    
    final AtomicTerm genls = termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_GENLS);
    final Set<String> existingSubClassOfs = gatherExistingSubClassOfs();
    if (existingSubClassOfs.isEmpty() && getSubClassOfs().length == 0) {
      // default to Collection for a new domain class
      final String[] subClassOfs = {"Collection"};
      setSubClassOfs(subClassOfs);
    }
    for (final String subClassOf : getSubClassOfs()) {
      if (!existingSubClassOfs.contains(subClassOf)) {
        getLogger().debug(stackLevel() + "adding subclass: " + subClassOf);
        final AbstractTerm subClassOfTerm = (AbstractTerm) termFinderFacade.findAtomicTermByTermName(subClassOf);
        if (subClassOfTerm == null) {
          throw new TexaiException("did not find term for " + subClassOf);
        }
        final List<AbstractTerm> args = Arrays.asList(getClassTerm(), subClassOfTerm);
        BinaryGAF binaryGAF = null;
        if (!existingSubClassOfs.isEmpty()) {
          binaryGAF = termFinderFacade.findBinaryGAFByConstituents(
                  genls,
                  args,
                  universalVocabularyMt);
        }
        if (binaryGAF == null) {
          binaryGAF = termFinderFacade.createBinaryGAFByConstituents(
                  genls,
                  args,
                  universalVocabularyMt,
                  Constants.STRENGTH_MONOTONIC,
                  null,
                  validateWellFormedFormula,
                  creator,
                  creationPurpose,
                  getClassKBPartition());
          getLogger().info("persisted: " + binaryGAF);
        }
      }
    }
    if (getSubClassOfs().length > 0) {
      // if the DomainEntity annotation specified subClassOf, then delete any existing genls relationships not contained
      // in the specification
      final List<String> subClassOfsList = Arrays.asList(getSubClassOfs());
      for (final String existingSubClassOf : existingSubClassOfs) {
        if (!subClassOfsList.contains(existingSubClassOf)) {
          getLogger().debug(stackLevel() + "deleting subclass: " + existingSubClassOf);
          final List<AbstractTerm> args = Arrays.asList(
                  getClassTerm(),
                  (AbstractTerm) termFinderFacade.findAtomicTermByTermName(existingSubClassOf));
          termDeleterFacade.deleteBinaryGAFsFromRelevantContexts(
                  genls,
                  args,
                  universalVocabularyMt);
        }
      }
    }
  }
  
  /** Finds or creates the domain instance term. */
  private void findOrCreateDomainInstanceTerm() {
    //Preconditions
    assert getFieldAnnotationDictionary() != null : "fieldAnnotationDictionary must not be null";
    assert !getFieldAnnotationDictionary().isEmpty() : "fieldAnnotationDictionary must not be empty";
    assert getClassTermName() != null : "classTermName must not be null";
    assert getClassTermName().length() > 0 : "classTermName must not be an empty string";
    assert getDomainEntity() != null : "domainEntity() must not be null";
    
    getLogger().debug(stackLevel() + "  finding ID field for domainEntity " + getDomainEntity());
    Field idField = null;
    boolean isIdFound = false;
    Object value = null;
    for (final Field field : getFieldAnnotationDictionary().keySet()) {
      if (!field.isAccessible()) {
        field.setAccessible(true);
      }
      try {
        value = field.get(getDomainEntity());
      } catch (final IllegalArgumentException ex) {
        throw new TexaiException(ex);
      } catch (final IllegalAccessException ex) {
        throw new TexaiException(ex);
      }
      final Annotation annotation = getFieldAnnotationDictionary().get(field);
      getLogger().debug(stackLevel() + "    field: " + field + ", annotation: " + annotation);
      if ("@javax.persistence.Id()".equals(annotation.toString())) {
        getLogger().debug(stackLevel() + "  found ID field");
        isIdFound = true;
        idField = field;
        break;
      }
    }
    if (!isIdFound) {
      throw new TexaiException("Id field not found for domain entity " + getDomainEntity());
    }
    if (value == null) {
      final String tempName = UUID.randomUUID().toString();
      setInstanceTerm(termFinderFacade.createAtomicTermByTermName(
              tempName,
              null,
              creator,
              creationPurpose,
              getClassKBPartition()));
      try {
        idField.set( getDomainEntity(), getInstanceTerm().getTermId());
      } catch (final IllegalArgumentException ex) {
        throw new TexaiException(ex);
      } catch (final IllegalAccessException ex) {
        throw new TexaiException(ex);
      }
      final String instanceTermIdString = String.valueOf(getInstanceTerm().getTermId());
      getInstanceTerm().setTermName(getClassTermName() + "_" + instanceTermIdString.replace('-', '_'));
      getInstanceTerm().setPrettyName(getClassTermName() + " instance " + instanceTermIdString);
      getLogger().debug(stackLevel() + "  created new instance " + getInstanceTerm());
      final List<AbstractTerm> args = Arrays.asList((AbstractTerm) getInstanceTerm(), getClassTerm());
      AtomicTerm isa = null;
      final UUID isaTermId = termIdDictionary.get(Constants.TERM_NAME_ISA);
      if (isaTermId == null) {
        isa = termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_ISA);
        termIdDictionary.put(Constants.TERM_NAME_ISA, isa.getTermIdAsUUID());
      } else {
        // more efficient SQL to lookup via primary key rather than by name string
        isa = termFinderFacade.findAtomicTermByTermId(isaTermId);
      }
      assert isa != null : "isa term must not be null";
      final BinaryGAF isaGAF = termFinderFacade.createBinaryGAFByConstituents(
              isa,
              args,
              universalVocabularyMt,
              Constants.STRENGTH_MONOTONIC,
              null,
              validateWellFormedFormula,
              creator,
              creationPurpose,
              getClassKBPartition());
      getLogger().info("persisted: " + isaGAF);
      assert getDomainEntityClass() != null : "domainEntityClass must not be null";
      AtomicTerm domainEntityClassName = null;
      final UUID domainEntityClassNameTermId = termIdDictionary.get(Constants.TERM_NAME_DOMAIN_ENTITY_CLASS_NAME);
      if (domainEntityClassNameTermId == null) {
        domainEntityClassName = termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_DOMAIN_ENTITY_CLASS_NAME);
        termIdDictionary.put(Constants.TERM_NAME_DOMAIN_ENTITY_CLASS_NAME, domainEntityClassName.getTermIdAsUUID());
      } else {
        // more efficient to lookup via primary key rather than by name string
        domainEntityClassName = termFinderFacade.findAtomicTermByTermId(domainEntityClassNameTermId);
      }
      assert domainEntityClassName != null : "domainEntityClassName term must not be null";
      PString classNameTerm = null;
      final String classNameTermKey = "PString for " + getDomainEntityClass().getName();
      final UUID classNameTermId = termIdDictionary.get(classNameTermKey);
      if (classNameTermId == null) {
        classNameTerm = termFinderFacade.createPStringByStringValue(getDomainEntityClass().getName());
        termIdDictionary.put(classNameTermKey, classNameTerm.getTermIdAsUUID());
      } else {
        // more efficient to lookup via primary key rather than by string value
        classNameTerm = termFinderFacade.findPStringByTermId(classNameTermId);
      }
      assert classNameTerm != null : "classNameTerm term must not be null";
      final BinaryGAF domainEntityClassNameGAF = termFinderFacade.createBinaryGAFByConstituents(
              domainEntityClassName,
              Arrays.asList((AbstractTerm) getInstanceTerm(), classNameTerm),
              universalVocabularyMt,
              Constants.STRENGTH_MONOTONIC,
              null,
              validateWellFormedFormula,
              creator,
              creationPurpose,
              getClassKBPartition());
      getLogger().info("persisted: " + domainEntityClassNameGAF);
    } else {
      if (!(value instanceof UUID)) {
        throw new TexaiException("Id field must be type UUID " + getDomainEntity() + ", is type " + value.getClass());
      }
      setInstanceTerm(termFinderFacade.findAtomicTermByTermId((UUID) value));
      isNewDomainInstance = false;
      getLogger().debug(stackLevel() + "  found existing instance " + getInstanceTerm());
    }
    final Cache cache = CacheManager.getInstance().getCache(Constants.CACHE_CONNECTED_DOMAIN_ENTITIES);
    assert cache != null : "cache not found for: " + Constants.CACHE_CONNECTED_DOMAIN_ENTITIES;
    final Element element = new Element(getDomainEntity(), getInstanceTerm());
    cache.put(element);
    
    //Postconditions
    assert getInstanceTerm() != null : "instanceTerm must not be null";
    assert getInstanceTerm().getPrettyName().indexOf(" instance ") > -1 : "malformed domain instance pretty name: " + getInstanceTerm();
  }
 
  /** Iterates over the fields in the domain entity instance and persists them
   * to the knowledge base as propositions.
   */
  private void persistFields() {
    //Preconditions
    assert getClassPersistenceContextName() != null : "classPersistenceContextName must not be null";
    
    setClassPersistenceContext(termFinderFacade.findAtomicTermByTermName(getClassPersistenceContextName()));
    if (getClassPersistenceContext() == null) {
      throw new TexaiException("did not find term for " + getClassPersistenceContextName());
    }
    for (final Field field : getFieldAnnotationDictionary().keySet()) {
      final Annotation annotation = getFieldAnnotationDictionary().get(field);
      getLogger().debug(stackLevel() + "field: " + field + ", annotation: " + annotation);
      if ("@javax.persistence.Id()".equals(annotation.toString())) {
        getLogger().debug(stackLevel() + "  skipping Id field");
        continue;
      } else {
        if (annotation instanceof DomainProperty) {
          persistField(field, (DomainProperty) annotation);
        }
      }
    }
  }
  
  /** Persists the given field according to the given domain property.
   *
   * @param field the given domain entity instance field
   * @param domainProperty the property annotation associated with the field
   */
  @SuppressWarnings({"unchecked"})
  private void persistField(final Field field, final DomainProperty domainProperty) {     // NOPMD
    //Preconditions
    assert field != null : "field must not be null";
    assert domainProperty != null : "domainProperty must not be null";
    
    getLogger().debug(stackLevel() + "  processing domain property: " + domainProperty);
    // obtain the value object
    if (!field.isAccessible()) {
      field.setAccessible(true);
    }
    Object value = null;
    try {
      value = field.get(getDomainEntity());
    } catch (final IllegalArgumentException ex) {
      throw new TexaiException(ex);
    } catch (final IllegalAccessException ex) {
      throw new TexaiException(ex);
    }
    final Class fieldType = field.getType();
    getLogger().debug(stackLevel() + "  field type: " + fieldType.getName());
    if (value != null) {
      if (value instanceof LazySet || value instanceof LazyList) {
        getLogger().debug(stackLevel() + "    skipping lazyily loaded field which has not yet been loaded");
        return;
      }
      if (Factory.class.isAssignableFrom(value.getClass())) {
        getLogger().debug(stackLevel() + "    skipping lazyily loaded proxy field which has not yet been loaded");
        return;
      }
    }
    final boolean isBooleanField = "boolean".equals(fieldType.getName());
    // obtain the optional strength
    final Field strengthField = getStrengthFieldDictionary().get(field);
    Object strengthValue = null;
    if (strengthField != null) {
      if (!strengthField.isAccessible()) {
        strengthField.setAccessible(true);
      }
      try {
        strengthValue = strengthField.get(getDomainEntity());
      } catch (final IllegalArgumentException ex) {
        throw new TexaiException(ex);
      } catch (final IllegalAccessException ex) {
        throw new TexaiException(ex);
      }
      getLogger().debug(stackLevel() + "  strengthField: " + strengthField);
      getLogger().debug(stackLevel() + "  strengthValue: " + strengthValue);
    }
    // determine the predicate
    final AtomicTerm predicate = findPredicate(field, domainProperty, isBooleanField);
    // obtain the existing value and strength terms
    List<List<Object>> existingValueAndStrengthTerms = null;
    if (isNewDomainInstance) {
      existingValueAndStrengthTerms = Collections.EMPTY_LIST;
    } else if (domainProperty.inverse()) {
      existingValueAndStrengthTerms = associationFinder.gatherArg1TermsAndStrengthsFromBinaryGAFs(
              predicate,
              getInstanceTerm(),
              getClassPersistenceContext());
    } else {
      existingValueAndStrengthTerms = associationFinder.gatherArg2TermsAndStrengthsFromBinaryGAFs(
              predicate,
              getInstanceTerm(),
              getClassPersistenceContext());
    }
    // existing value --> strength dictionary
    final Map<AbstractTerm, Double> existingValueStrengthDictionary = new HashMap<AbstractTerm, Double>();
    for (final List<Object> pair : existingValueAndStrengthTerms) {
      existingValueStrengthDictionary.put((AbstractTerm) pair.get(0), (Double) pair.get(1));
    }
    Double strength = Constants.STRENGTH_MONOTONIC;
    Set<AbstractTerm> assertedValueTerms = null;
    getLogger().debug(stackLevel() + "  existing terms and strengths for predicate " + predicate + ": " + existingValueAndStrengthTerms);
    final List<Double> strengthValues = validateAndGetStrengthValues(
            field,
            value,
            strengthField,
            strengthValue);
    if (isBooleanField) {
      final String trueClassName = domainProperty.trueClass();
      if (trueClassName.isEmpty()) {
        throw new TexaiException("trueClass must be specified for boolean field " + field.getName());
      }
      final String falseClassName = domainProperty.falseClass();
      if (falseClassName.isEmpty()) {
        throw new TexaiException("falseClass must be specified for boolean field " + field.getName());
      }
      persistBooleanFieldAndStrength(
              (Boolean) value,
              strengthField,
              strengthValues,
              existingValueStrengthDictionary,
              predicate,
              trueClassName,
              falseClassName,
              field);
      return;
    }
    // persist the current value and strength
    if (value == null) {
      getLogger().debug(stackLevel() + "  field value is null: " + field);
    } else if (value instanceof Collection) {
      getLogger().debug(stackLevel() + "  field value is Collection: " + field + " value: " + value);
      assertedValueTerms = persistFieldValuesAndStrengths(
              (Collection) value,
              strengthField,
              strengthValues,
              existingValueStrengthDictionary,
              domainProperty.inverse(),
              predicate);
    } else if (field.getType().isArray()) {
      getLogger().debug(stackLevel() + "  field value is Array: " + field);
      final int arrayLength = Array.getLength(value);
      final List<Object> valueObjects = new ArrayList<Object>(arrayLength);
      for (int i = 0; i < arrayLength; i++) {
        valueObjects.add(Array.get(value, i));
      }
      assertedValueTerms = persistFieldValuesAndStrengths(
              valueObjects,
              strengthField,
              strengthValues,
              existingValueStrengthDictionary,
              domainProperty.inverse(),
              predicate);
    } else {
      getLogger().debug(stackLevel() + "  field value is Object: " + field);
      final List<Object> valueList = new ArrayList<Object>(1);
      valueList.add(value);
      List<Double> strengthValueList = null;
      if (strengthField != null) {
        strengthValueList = new ArrayList<Double>(1);
        if (strengthValue instanceof Double) {
          strengthValueList.add((Double) strengthValue);
        } else if (!strengthField.getType().equals(Double.class)) {
          throw new TexaiException("strengthField must be of type Double, found " + strengthField);
        }
      }
      assertedValueTerms = persistFieldValuesAndStrengths(
              valueList,
              strengthField,
              strengthValues,
              existingValueStrengthDictionary,
              domainProperty.inverse(),
              predicate);
    }
    // delete previous associations if no longer applicable
    for (final AbstractTerm existingValueTerm : existingValueStrengthDictionary.keySet()) {
      if (!assertedValueTerms.contains(existingValueTerm)) {
        getLogger().debug(stackLevel() + "deleting existing value term: " + existingValueTerm + " for predicate: " + predicate);
        final List<AbstractTerm> args = Arrays.asList((AbstractTerm) getInstanceTerm(), existingValueTerm);
        termDeleterFacade.deleteBinaryGAFsFromRelevantContexts(
                predicate,
                args,
                classPersistenceContext);
      }
    }
  }
  
  /** Finds the predicate that will be used to persist the current field.
   *
   * @param field the given domain entity instance field
   * @param domainProperty the property annotation associated with the field
   * @param isBooleanField the indicator that the current field is a boolean type
   * @return the predicate that will be used to persist the current field
   */
  private AtomicTerm findPredicate(final Field field, final DomainProperty domainProperty, final boolean isBooleanField) {
    //Preconditions
    assert field != null : "field must not be null";
    assert domainProperty != null : "domainProperty must not be null";
    
    String predicateName = null;
    if (isBooleanField) {
      predicateName = Constants.TERM_NAME_ISA;
    } else {
      predicateName = domainProperty.name();
    }
    if (predicateName.length() == 0) {
      predicateName = field.getName();
    }
    AtomicTerm predicate = null;
    final UUID predicateTermId = termIdDictionary.get(predicateName);
    if (predicateTermId == null) {
      predicate = termFinderFacade.findAtomicTermByTermName(predicateName);
      if (predicate == null) {
        predicate = createNewPredicate(domainProperty, predicateName, field);
      }
      termIdDictionary.put(predicateName, predicateTermId);
    } else {
      // faster lookup by term id
      predicate = termFinderFacade.findAtomicTermByTermId(predicateTermId);
    }
    
    //Postconditions
    assert predicate != null : "predicate must not be null";
    
    return predicate;
  }
  
  /** Validates the field against its associated strength field, returning the strength(s) as a list.
   *
   * @param field the field
   * @param value the field value object
   * @param strengthField the strength field
   * @param strengthValue the strength value object
   * @return the strength(s) as a list
   */
  @SuppressWarnings("unchecked")
  private List<Double> validateAndGetStrengthValues(
          final Field field,
          final Object value,
          final Field strengthField,
          final Object strengthValue) {
    //Preconditions
    assert field != null : "field must not be null";
    
    final List<Double> strengthValues = new ArrayList<Double>();
    if (strengthField == null || strengthValue == null || value == null) {
      return strengthValues;
    }
    if (value instanceof List) {
      if (strengthValue instanceof List) {
        strengthValues.addAll((List<Double>) strengthValue);
      } else {
        throw new TexaiException("when field is a List, strengthField " + strengthField + " must also be a List");
      }
      if (strengthValues.size() != ((List) value).size()) {
        throw new TexaiException("strengthField " + strengthValue + " must have the same size as the field " + value);
      }
    } else if (value instanceof Collection) {
      throw new TexaiException("when strengthField is specified, the only collection type supported is List");
    }  else if (field.getType().isArray()) {
      if (strengthField.getType().isArray()) {
        final int arrayLength = Array.getLength(strengthValue);
        for (int i = 0; i < arrayLength; i++) {
          strengthValues.add((Double) Array.get(strengthValue, i));
        }
      } else {
        throw new TexaiException("when field is an Array, strengthField " + strengthField + " must also be an Array");
      }
      if (strengthValues.size() != Array.getLength(value)) {
        throw new TexaiException("strengthField " + strengthValue + " must have the same size as the field " + value);
      }
    } else {
      if (strengthValue instanceof Double) {
        strengthValues.add((Double) strengthValue);
      } else {
        throw new TexaiException("when field is a object, strengthField " + strengthField + " must be a Double");
      }
    }
    return strengthValues;
  }
  
  /** Persists the given boolean field value and strength.  When the boolean property is true, a binary GAF of the form
   * isa(<instance-term>, <true-class>) is asserted in the KB, otherwise the boolean property is false and this GAF
   * is removed from the KB if previously asserted.
   *
   * @param valueList the list of existing values
   * @param strengthField the strength field
   * @param strengthValues the list of values of the strength field
   * @param existingValueStrengthDictionary the dictionary of value --> strength
   * @param predicate the predicate that represents the association
   * @param trueClassName the name of the class of domain instances for which the boolean association holds true
   * @param falseClassName the name of the class of domain instances for which the boolean association holds false
   * @param field the given domain entity instance field
   */
  @SuppressWarnings("unchecked")
  private void persistBooleanFieldAndStrength(
          final Boolean value,
          final Field strengthField,
          final List<Double> strengthValues,
          final Map<AbstractTerm, Double> existingValueStrengthDictionary,
          final AtomicTerm predicate,
          final String trueClassName,
          final String falseClassName,
          final Field field) {
    //Preconditions
    assert value != null : "value must not be null";
    assert existingValueStrengthDictionary != null : "existingValueStrengthDictionary must not be null";
    assert predicate != null : "predicate must not be null";
    assert trueClassName != null : "trueClassName must not be null";
    assert !trueClassName.isEmpty() : "trueClassName must not be an empty string";
    assert falseClassName != null : "falseClassName must not be null";
    assert !falseClassName.isEmpty() : "falseClassName must not be an empty string";
    
    boolean haveCreatedTrueOrFalseClassTerm = false;
    AtomicTerm trueClass = termFinderFacade.findAtomicTermByTermName(trueClassName);
    if (trueClass == null) {
      final List<AbstractReifiedTerm> isaTerms = new ArrayList<AbstractReifiedTerm>();
      isaTerms.add(termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_FIRST_ORDER_COLLECTION));
      final List<AbstractReifiedTerm> genlsTerms = new ArrayList<AbstractReifiedTerm>();
      genlsTerms.add(getClassTerm());
      trueClass = termFinderFacade.createCollectionTerm(
              trueClassName,
              trueClassName,
              "This is the collection of " + getClassTermName() + " instances for which boolean property " + field.getName() + " holds true.",
              isaTerms,
              genlsTerms,
              creator,
              creationPurpose,
              getClassKBPartition());
      haveCreatedTrueOrFalseClassTerm = true;
    }
    AtomicTerm falseClass = termFinderFacade.findAtomicTermByTermName(falseClassName);
    if (falseClass == null) {
      final List<AbstractReifiedTerm> isaTerms = new ArrayList<AbstractReifiedTerm>();
      isaTerms.add(termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_FIRST_ORDER_COLLECTION));
      final List<AbstractReifiedTerm> genlsTerms = new ArrayList<AbstractReifiedTerm>();
      genlsTerms.add(getClassTerm());
      falseClass = termFinderFacade.createCollectionTerm(
              falseClassName,
              falseClassName,
              "This is the collection of " + getClassTermName() + " instances for which boolean property " + field.getName() + " holds false.",
              isaTerms,
              genlsTerms,
              creator,
              creationPurpose,
              getClassKBPartition());
      haveCreatedTrueOrFalseClassTerm = true;
    }
    if (haveCreatedTrueOrFalseClassTerm) {
      persistDisjointWithGAF(trueClass, falseClass);
    }
    Double strength = Constants.STRENGTH_MONOTONIC;
    if (strengthValues != null && !strengthValues.isEmpty()) {
      strength = strengthValues.get(0);
    }
    if (value.booleanValue()) {
      if (!existingValueStrengthDictionary.keySet().contains(trueClass)) {
        assertGAF(predicate,
                trueClass,
                strength,
                false);
      }
      if (existingValueStrengthDictionary.keySet().contains(falseClass)) {
        getLogger().debug(stackLevel() + "deleting existing value term: " + falseClass + " for predicate: " + predicate);
        final List<AbstractTerm> args = Arrays.asList((AbstractTerm) getInstanceTerm(), falseClass);
        termDeleterFacade.deleteBinaryGAFsFromRelevantContexts(
                predicate,
                args,
                classPersistenceContext);
      }
    } else {
      if (!existingValueStrengthDictionary.keySet().contains(falseClass)) {
        assertGAF(predicate,
                falseClass,
                strength,
                false);
      }
      if (existingValueStrengthDictionary.keySet().contains(trueClass)) {
        getLogger().debug(stackLevel() + "deleting existing value term: " + trueClass + " for predicate: " + predicate);
        final List<AbstractTerm> args = Arrays.asList((AbstractTerm) getInstanceTerm(), trueClass);
        termDeleterFacade.deleteBinaryGAFsFromRelevantContexts(
                predicate,
                args,
                classPersistenceContext);
      }
    }
  }
  
  /** Persists a disjointWith GAF for the given trueClass and falseClass.
   *
   * @param trueClass the trueClass obtained from the domain property of a boolean field
   * @param falseClass the trueClass obtained from the domain property of a boolean field
   */
  private void persistDisjointWithGAF(final AtomicTerm trueClass, final AtomicTerm falseClass) {
    //Preconditions
    assert trueClass != null : "trueClass must not be null";
    assert falseClass != null : "falseClass must not be null";
    
    final Double strength = Constants.STRENGTH_MONOTONIC;
    List<AbstractTerm> args = Arrays.asList((AbstractTerm) trueClass, falseClass);
    final BinaryGAF binaryGAF = termFinderFacade.createBinaryGAFByConstituents(
            termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_DISJOINT_WITH),
            args,
            classPersistenceContext,
            strength,
            null,
            validateWellFormedFormula,
            creator,
            creationPurpose,
            getClassKBPartition());
    getLogger().info("persisted: " + binaryGAF + " " + strength);
  }
  
  /** Persists the field value(s) and strength(s).
   *
   * @param valueList the list of existing values
   * @param strengthField the strength field
   * @param strengthValues the list of values of the strength field
   * @param existingValueStrengthDictionary the dictionary of value --> strength
   * @param isInverseProperty the indicator that the property is to be inverted with respect to treatment of arg1 and arg2
   * @param predicate the predicate that represents the association
   * @return the set of asserted value terms
   */
  @SuppressWarnings("unchecked")
  private Set<AbstractTerm> persistFieldValuesAndStrengths(
          final Collection valueList,
          final Field strengthField,
          final List<Double> strengthValues,
          final Map<AbstractTerm, Double> existingValueStrengthDictionary,
          final boolean isInverseProperty,
          final AtomicTerm predicate) {
    //Preconditions
    assert valueList != null : "valueList must not be null";
    assert existingValueStrengthDictionary != null : "existingValueStrengthDictionary must not be null";
    
    final Set<AbstractTerm> assertedValueTerms = new HashSet<AbstractTerm>();
    Double strength = Constants.STRENGTH_MONOTONIC;
    final List<AbstractTerm> valueTerms = findOrCreateValueTerms(valueList);
    final Iterator<AbstractTerm> valueTermsIter = valueTerms.iterator();
    Iterator<Double> strengthValuesIter = strengthValues.iterator();
    while (valueTermsIter.hasNext()) {
      final AbstractTerm valueTerm = valueTermsIter.next();
      if (strengthField != null) {
        if (strengthValuesIter.hasNext()) {
          strength = strengthValuesIter.next();
        }
      }
      if (!existingValueStrengthDictionary.keySet().contains(valueTerm)) {
        assertGAF(predicate, valueTerm, strength, isInverseProperty);
      } else if (strengthField != null && !existingValueStrengthDictionary.get(valueTerm).equals(strength)) {
        editGAF(predicate, valueTerm, strength, isInverseProperty);
      }
      assertedValueTerms.add(valueTerm);
    }
    return assertedValueTerms;
  }
  
  /** Asserts a binary GAF that relates a value to the domain entity.
   *
   * @param predicate the knowledge base predicate that relates the value to the domain entity
   * @param valueTerm the field value term
   * @param strength the assertion strength
   * @param isInverseProperty the indicator that the property is to be inverted with respect to treatment of arg1 and arg2
   */
  private void assertGAF(
          final AtomicTerm predicate,
          final AbstractTerm valueTerm,
          final Double strength,
          final boolean isInverseProperty) {
    //Preconditions
    assert predicate != null : "predicate must not be null";
    assert valueTerm != null : "valueTerm must not be null";
    assert strength != null : "strength must not be null";
    assert getInstanceTerm() != null : "instanceTerm must not be null";
    assert classPersistenceContext != null : "classPersistenceContext must not be null";
    assert ByteUtils.isNonZero(predicate.getTermId()) : "predicate must be persisted";
    assert ByteUtils.isNonZero(getInstanceTerm().getTermId()) : "getInstanceTerm() must be persisted";
    assert ByteUtils.isNonZero(valueTerm.getTermId()) : "valueTerm must be persisted";
    assert ByteUtils.isNonZero(classPersistenceContext.getTermId()) : "classPersistenceContext must be persisted";
    
    List<AbstractTerm> args = null;
    if (isInverseProperty) {
      args = Arrays.asList(valueTerm, getInstanceTerm());
    } else {
      args = Arrays.asList((AbstractTerm) getInstanceTerm(), valueTerm);
    }
    final BinaryGAF binaryGAF = termFinderFacade.createBinaryGAFByConstituents(
            predicate,
            args,
            classPersistenceContext,
            strength,
            null,
            validateWellFormedFormula,
            creator,
            creationPurpose,
            getClassKBPartition());
    getLogger().info("persisted: " + binaryGAF + " " + strength);
  }
  
  /** Edits the strength of a binary GAF that relates a value to the domain entity.
   *
   * @param predicate the knowledge base predicate that relates the value to the domain entity
   * @param valueTerm the field value term
   * @param strength the assertion strength
   * @param isInverseProperty the indicator that the property is to be inverted with respect to treatment of arg1 and arg2
   */
  private void editGAF(
          final AtomicTerm predicate,
          final AbstractTerm valueTerm,
          final Double strength,
          final boolean isInverseProperty) {
    //Preconditions
    assert predicate != null : "predicate must not be null";
    assert valueTerm != null : "valueTerm must not be null";
    assert strength != null : "strength must not be null";
    assert getInstanceTerm() != null : "instanceTerm must not be null";
    assert classPersistenceContext != null : "classPersistenceContext must not be null";
    assert ByteUtils.isNonZero(predicate.getTermId()) : "predicate must be persisted";
    assert ByteUtils.isNonZero(getInstanceTerm().getTermId()) : "getInstanceTerm() must be persisted";
    assert ByteUtils.isNonZero(valueTerm.getTermId()) : "valueTerm must be persisted";
    assert ByteUtils.isNonZero(classPersistenceContext.getTermId()) : "classPersistenceContext must be persisted";
    
    List<AbstractTerm> args = null;
    if (isInverseProperty) {
      args = Arrays.asList(valueTerm, getInstanceTerm());
    } else {
      args = Arrays.asList((AbstractTerm) getInstanceTerm(), valueTerm);
    }
    final BinaryGAF binaryGAF = termFinderFacade.findBinaryGAFByConstituents(
            predicate,
            args,
            classPersistenceContext);
    binaryGAF.setStrength(strength);
    associationEditor.editBinaryGAF(binaryGAF);
  }
  
  /** Returns true if the given identifier value term is used elsewhere.
   *
   * @param predicate the knowledge base predicate that relates the value to the domain entity
   * @param valueTerm the field value term
   */
  private boolean isIdentifierValueUsedElsewhere(final AtomicTerm predicate, final AbstractTerm valueTerm) {
    //Preconditions
    assert predicate != null : "predicate must not be null";
    assert valueTerm != null : "valueTerm must not be null";
    assert classPersistenceContext != null : "classPersistenceContext must not be null";
    assert ByteUtils.isNonZero(predicate.getTermId()) : "predicate must be persisted";
    assert ByteUtils.isNonZero(valueTerm.getTermId()) : "valueTerm must be persisted";
    assert ByteUtils.isNonZero(classPersistenceContext.getTermId()) : "classPersistenceContext must be persisted";
    
    Set<AbstractTerm> arg1s = associationFinder.gatherArg1TermsFromBinaryGAFs(predicate, valueTerm, classPersistenceContext);
    if (arg1s.isEmpty()) {
      return false;
    } else {
      getLogger().error("identifier " + predicate + " already used with arg1s: " + arg1s + " in context: " + classPersistenceContext);
      return true;
    }
  }
  
  /** Creates a new predicate for the given domain property.
   *
   * @param domainProperty the given domain property
   * @param predicateName the name for the predicate
   * @param field the given field
   * @return a new predicate for the given domain property
   */
  private AtomicTerm createNewPredicate(
          final DomainProperty domainProperty,
          final String predicateName,
          final Field field) {
    //Preconditions
    assert domainProperty != null : "domainProperty must not be null";
    assert predicateName != null : "predicateName must not be null";
    assert predicateName.length() > 0 : "predicateName must not be an empty string";
    assert field != null : "field must not be null";
    
    AtomicTerm domainTerm = null;
    final String domainName = domainProperty.domain();
    if (domainName.length() == 0) {
      domainTerm = getClassTerm();
    } else {
      domainTerm = termFinderFacade.findAtomicTermByTermName(domainName);
      if (domainTerm == null) {
        // handle forward reference to a new domain entity class
        Class domainClass;
        try {
          domainClass = Class.forName(domainName);
        } catch (final ClassNotFoundException ex) {
          throw new TexaiException("domain " + domainName + " not found for domain property " + domainProperty);
        }
        if (domainClass != null) {
          getLogger().debug(stackLevel() + "  saving session state for domainEntity: " + getDomainEntity());
          saveAbstractSessionState();
          saveSessionState();
          domainTerm = persistDomainEntityClass(domainClass, creator, creationPurpose);
          restoreAbstractSessionState();
          restoreSessionState();
        }
      }
    }
    if (domainTerm == null) {
      throw new TexaiException("domain " + domainName + " not found for domain property " + domainProperty);
    }
    AtomicTerm rangeTerm = null;
    final String rangeName = domainProperty.range();
    if (rangeName.length() == 0) {
      rangeTerm = getTermTypeForFieldType(field);
    } else {
      rangeTerm = termFinderFacade.findAtomicTermByTermName(rangeName);
      if (rangeTerm == null) {
        // handle forward reference to a new domain entity class
        Class rangeClass;
        try {
          rangeClass = Class.forName(rangeName);
        } catch (final ClassNotFoundException ex) {
          throw new TexaiException("range " + rangeName + " not found for domain property " + domainProperty);
        }
        if (rangeClass != null) {
          getLogger().debug(stackLevel() + "  saving session state for domainEntity: " + getDomainEntity());
          saveAbstractSessionState();
          saveSessionState();
          rangeTerm = persistDomainEntityClass(rangeClass, creator, creationPurpose);
          restoreAbstractSessionState();
          restoreSessionState();
        }
      }
    }
    if (rangeTerm == null) {
      throw new TexaiException("range " + rangeName + " not found for domain property " + domainProperty);
    }
    final String commentString = predicateName + "(" + domainTerm + ", " + rangeTerm + ")";
    final String prettyName = "the domain property " + predicateName;
    AtomicTerm predicateType;
    if (domainProperty.functional()) {
      predicateType = termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_FUNCTIONAL_SLOT);
    } else {
      predicateType = termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_BINARY_PREDICATE);
    }
    final List<AbstractReifiedTerm> isaTerms = new ArrayList<AbstractReifiedTerm>(1);
    isaTerms.add(predicateType);
    final List<AbstractReifiedTerm> genlPredTerms = new ArrayList<AbstractReifiedTerm>(0);
    final List<AbstractReifiedTerm> argConstraintTerms = new ArrayList<AbstractReifiedTerm>(2);
    if (domainProperty.inverse()) {
      argConstraintTerms.add(rangeTerm);
      argConstraintTerms.add(domainTerm);
    } else {
      argConstraintTerms.add(domainTerm);
      argConstraintTerms.add(rangeTerm);
    }
    return termFinderFacade.createBinaryPredicateTerm(
            predicateName,
            prettyName,
            commentString,
            isaTerms,
            genlPredTerms,
            argConstraintTerms,
            creator,
            creationPurpose,
            getClassKBPartition());
  }
  
  /** Returns the KB term type that corresponds to the type of the given field.
   *
   * @param field the given field
   * @return the KB term type that corresponds to the type of the given field
   */
  private AtomicTerm getTermTypeForFieldType(final Field field) {
    //Preconditions
    assert field != null : "field must not be null";
    
    AtomicTerm fieldTypeTerm = null;
    final Class<?> fieldType = field.getType();
    
    if (fieldType.equals(String.class)) {
      fieldTypeTerm = termFinderFacade.findAtomicTermByTermName("CharacterString");
    } else if (fieldType.equals(Integer.class)
    || fieldType.equals(Long.class)) {
      fieldTypeTerm = termFinderFacade.findAtomicTermByTermName("Integer");
    } else if (fieldType.equals(Float.class)
    || fieldType.equals(Double.class)) {
      fieldTypeTerm = termFinderFacade.findAtomicTermByTermName("RealNumber");
    } else {
      fieldTypeTerm = termFinderFacade.findAtomicTermByTermName(Constants.TERM_NAME_THING);
    }
    
    //Postconditions
    assert fieldTypeTerm != null : "fieldTypeTerm must not be null";
    
    return fieldTypeTerm;
  }
  
  /** Finds or creates the value terms for the given value list.
   *
   * @param valueList the given value list
   * @return the value terms for the given value list
   */
  private List<AbstractTerm> findOrCreateValueTerms(final Collection valueList) {
    //Preconditions
    assert valueList != null : "valueList must not be null";
    
    getLogger().debug(stackLevel() + "  valueList: " + valueList);
    final List<AbstractTerm> valueTerms = new ArrayList<AbstractTerm> (valueList.size());
    for (final Object value : valueList) {
      valueTerms.add(findOrCreateValueTerm(value));
    }
    return valueTerms;
  }
  
  /** Finds or creates the value term for the given value.  If the value is already a term
   * from the kb, then value is returned.
   *
   * @param value the given value
   * @return the value term for the given value
   */
  private AbstractTerm findOrCreateValueTerm(final Object value) {    // NOPMD
    //Preconditions
    assert value != null : "value must not be null";
    
    AbstractTerm valueTerm = null;
    
    if (value instanceof String) {
      valueTerm = termFinderFacade.findPStringByStringValue((String) value);
      if (valueTerm == null) {
        valueTerm = termFinderFacade.createPStringByStringValue((String) value);
      }
    } else if (value instanceof Integer) {
      valueTerm = termFinderFacade.findPLongByLongValue(Long.valueOf(((Integer) value).longValue()));
      if (valueTerm == null) {
        valueTerm = termFinderFacade.createPLongByLongValue(Long.valueOf(((Integer) value).longValue()));
      }
    } else if (value instanceof Long) {
      valueTerm = termFinderFacade.findPLongByLongValue((Long) value);
      if (valueTerm == null) {
        valueTerm = termFinderFacade.createPLongByLongValue((Long) value);
      }
    } else if (value instanceof Float) {
      valueTerm = termFinderFacade.findPDoubleByDoubleValue(Double.valueOf(((Float) value).doubleValue()));
      if (valueTerm == null) {
        valueTerm = termFinderFacade.createPDoubleByDoubleValue(Double.valueOf(((Float) value).doubleValue()));
      }
    } else if (value instanceof Double) {
      valueTerm = termFinderFacade.findPDoubleByDoubleValue((Double) value);
      if (valueTerm == null) {
        valueTerm = termFinderFacade.createPDoubleByDoubleValue((Double) value);
      }
    } else if (value instanceof Date) {
      valueTerm = termFinderFacade.findPDateByDateValue((Date) value);
      if (valueTerm == null) {
        valueTerm = termFinderFacade.createPDateByDateValue((Date) value);
      }
    } else if (value instanceof AtomicTerm) {
      valueTerm = (AtomicTerm) value;
    } else if (value instanceof NonAtomicTerm) {
      // ensure that the non-atomic kb term is currently managed by the entity manager
      valueTerm = (NonAtomicTerm) value;
    } else if (value instanceof AbstractTerm) {
      assert false : "unhandled  term value " + value;
      // ensure that the kb term is currently managed by the entity manager
      valueTerm = (AbstractTerm) value;
    } else if (isDomainEntity(value)) {
      final Cache cache = CacheManager.getInstance().getCache(Constants.CACHE_CONNECTED_DOMAIN_ENTITIES);
      final Element element = cache.get(value);
      if (element != null) {
        valueTerm = (AbstractTerm) element.getObjectValue();
      }
      if (valueTerm == null) {
        // save this session state before the recursive method call because session beans cannot
        // create a new session bean instance
        getLogger().debug(stackLevel() + "  saving session state for domainEntity: " + getDomainEntity());
        saveAbstractSessionState();
        saveSessionState();
        valueTerm = persistDomainEntity(
                value,
                creator,
                creationPurpose);
        restoreAbstractSessionState();
        restoreSessionState();
        getLogger().debug(stackLevel() + "  restored session state for domainEntity: " + getDomainEntity());
      } else {
        getLogger().debug(stackLevel() + "  previously persisted valueTerm: " + valueTerm);
      }
    } else {
      throw new TexaiException("unhandled value type (" + value.getClass().getName() + ") " + value);
    }
    
    //Postconditions
    assert valueTerm != null : "valueTerm must not be null";
    assert ByteUtils.isNonZero(valueTerm.getTermId()) : "valueTerm must have non-zero termId";
    
    return valueTerm;
  }
  
  /** Pushes the current session bean state onto a stack and then intitializes the session state. */
  public void saveSessionState() {
    //Preconditions
    assert domainEntityInfoStack != null : "domainEntityInfoStack must not be null";
    
    getLogger().debug(stackLevel() + "saving session state");
    domainEntityInfoStack.push(new DomainEntityInfo(classPersistenceContext, isNewDomainInstance));
  }
  
  /** Initializes the session bean state during a recursive method call. */
  private void initializeSessionState() {
    classPersistenceContext = null;                                    // NOPMD
    isNewDomainInstance = true;                                      // NOPMD
  }
  
  /** Restores the session state following a recursive method call. */
  public void restoreSessionState() {
    //Preconditions
    assert domainEntityInfoStack != null : "domainEntityInfoStack must not be null";
    
    final DomainEntityInfo domainEntityInfo = domainEntityInfoStack.pop();
    classPersistenceContext = domainEntityInfo.classPersistenceContext;
    isNewDomainInstance = domainEntityInfo.isNewDomainInstance;
    getLogger().debug(stackLevel() + "restored session state");
  }
  
  /** Contains the session bean state for recursive method calls. */
  private class DomainEntityInfo {
    
    /** the context into which the class-scoped associations are persisted */
    private transient final AbstractReifiedTerm classPersistenceContext;         // NOPMD
    
    /** the indicator that the domain instance is new */
    private transient boolean isNewDomainInstance;
    
    /** Creates a new DomainEntityInfo instance.
     *
     * @param classPersistenceContext the context into which the class-scoped associations are persisted
     * @param isNewDomainInstance  the indicator that the domain instance is new
     */
    protected DomainEntityInfo(
            final AbstractReifiedTerm classPersistenceContext,
            final boolean isNewDomainInstance) {
      this.classPersistenceContext = classPersistenceContext;
      this.isNewDomainInstance = isNewDomainInstance;
    }
  }
  
  
}




See more files for this project here

Texai

Texai is an chatbot that intelligently seeks to acquire knowledge and friendly behaviors.

Project homepage: http://sourceforge.net/projects/texai
Programming language(s): Java,Shell Script,XML
License: other

  shared/
    AssociationEditorBean.java
    AssociationEditorLocal.java
    AssociationFinderBean.java
    AssociationFinderLocal.java
    KBPartitionFacadeBean.java
    KBPartitionFacadeLocal.java
    KBShardFacadeBean.java
    TermDeleterFacadeBean.java
    TermDeleterFacadeLocal.java
    TermFinderFacadeBean.java
    TermFinderFacadeLocal.java
    TermManagerBean.java
    TermManagerLocal.java
  AbstractDomainEntityAccessor.java
  DomainEntityDeleterBean.java
  DomainEntityDeleterLocal.java
  DomainEntityLoaderBean.java
  DomainEntityLoaderLocal.java
  DomainEntityManagerBean.java
  DomainEntityManagerLocal.java
  DomainEntityPersisterBean.java
  DomainEntityPersisterLocal.java
  package.html