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