/*
* RDFEntityRemover.java
*
* Created on August 13, 2007, 1:06 PM
*
* Description: This class removes domain entities from the RDF store.
*
* Copyright (C) August 13, 2007 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.persistence;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.jcip.annotations.NotThreadSafe;
import org.apache.log4j.Logger;
import org.openrdf.model.BNode;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import org.texai.util.TexaiException;
/** This helper class removes domain entities from the RDF store.
*
* @author reed
*/
@NotThreadSafe
public final class RDFEntityRemover extends AbstractRDFEntityAccessor {
/** the logger */
private final Logger logger = Logger.getLogger(RDFEntityRemover.class); // NOPMD
/** the entity manager */
private final RDFEntityManager rdfEntityManager;
/**
* Creates a new instance of RDFEntityRemover.
*
* @param rdfEntityManager the RDF entity manager
*/
public RDFEntityRemover(final RDFEntityManager rdfEntityManager) {
super();
//Preconditions
assert rdfEntityManager != null : "rdfEntityManager must not be null";
this.rdfEntityManager = rdfEntityManager;
}
/** Remove the statements in the RDF store that mention the URI that represents the given RDF entity.
*
* @param repositoryConnection the repository connection
* @param rdfEntity the RDF entity to be removed
*/
public void remove(
final RepositoryConnection repositoryConnection,
final RDFPersistent rdfEntity) {
//Preconditions
assert repositoryConnection != null : "repositoryConnection must not be null";
assert rdfEntity != null : "rdfEntity must not be null";
assert isRDFEntity(rdfEntity) : rdfEntity + "(" + rdfEntity.getClass().getName() + ")\n must be have a @RDFEntity class level annotation in\n" + Arrays.toString(rdfEntity.getClass().getAnnotations());
initializeAbstractSessionState();
if (getLogger().isDebugEnabled()) {
logger.debug(stackLevel() + "removing " + rdfEntity);
}
setRDFEntity(rdfEntity);
setRDFEntityClass(rdfEntity.getClass());
gatherAnnotationsForRDFEntityClass();
configureRDFEntitySettings();
findInstanceURI();
try {
final boolean isAutoCommit = repositoryConnection.isAutoCommit();
if (isAutoCommit) {
// perform removal operations within a transaction to avoid the otherwise unsatisfactory performance resulting from auto-commiting each
// removal operation
repositoryConnection.setAutoCommit(false);
}
// remove the blank nodes that persist list fields and map fields
for (final Field field : getFieldAnnotationDictionary().keySet()) {
final Annotation annotation = getFieldAnnotationDictionary().get(field);
if (!("@javax.persistence.Id()".equals(annotation.toString()))) {
if (annotation instanceof RDFProperty) {
final Class<?> fieldType = field.getType();
if (List.class.isAssignableFrom(fieldType) || field.getType().isArray()) {
// the field is a List or an Array whose values are persisted in an RDF collection, which is a chain of blank nodes
final BNode listNode = (BNode) RDFUtility.getObjectGivenSubjectAndPredicate(
getInstanceURI(), // subject
getEffectivePropertyURI(field, (RDFProperty) annotation), // predicate
getEffectiveContextURI(), // context
repositoryConnection);
if (listNode != null) {
logger.info("removing statements in the RDF list for field " + field);
removeRDFList(
repositoryConnection,
rdfEntityManager,
listNode);
}
} else if (Map.class.isAssignableFrom(fieldType)) {
// the field is a Map whose entry values are persisted as blank nodes,
// each related to the map entry key and map entry value
final Set<Value> bNodes = RDFUtility.getObjectsGivenSubjectAndPredicate(
getInstanceURI(), // subject
getEffectivePropertyURI(field, (RDFProperty) annotation), // predicate
getEffectiveContextURI(), // context
repositoryConnection);
for (final Value bNode : bNodes) {
logger.info("removing statements having map entry subject " + bNode);
RepositoryResult<Statement> repositoryResult =
repositoryConnection.getStatements((BNode) bNode, null, null, false);
while (repositoryResult.hasNext()) {
rdfEntityManager.removeStatement(repositoryConnection, repositoryResult.next());
}
}
}
}
}
}
logger.info("removing statements having subject " + getInstanceURI());
RepositoryResult<Statement> repositoryResult =
repositoryConnection.getStatements(getInstanceURI(), null, null, false);
while (repositoryResult.hasNext()) {
rdfEntityManager.removeStatement(repositoryConnection, repositoryResult.next());
}
logger.info("removing statements having object " + getInstanceURI());
repositoryResult =
repositoryConnection.getStatements(null, null, getInstanceURI(), false);
while (repositoryResult.hasNext()) {
rdfEntityManager.removeStatement(repositoryConnection, repositoryResult.next());
}
if (isAutoCommit) {
repositoryConnection.commit();
repositoryConnection.setAutoCommit(true);
}
} catch (final RepositoryException ex) {
throw new TexaiException(ex);
}
}
/** Finds the domain instance URI. */
private void findInstanceURI() {
//Preconditions
assert getClassURI() != null : "classURI must not be null";
assert getRDFEntity() != null : "rdfEntity() must not be null";
final Field idField = getIdField();
if (idField == null) {
throw new TexaiException("Id field not found for RDF entity " + getRDFEntity());
}
Object value;
if (!idField.isAccessible()) {
idField.setAccessible(true);
}
try {
value = idField.get(getRDFEntity());
} catch (final IllegalArgumentException | IllegalAccessException ex) {
throw new TexaiException(ex);
}
if (value == null) {
throw new TexaiException("Id field has no value " + idField);
} else {
if (URI.class.isAssignableFrom(value.getClass())) {
setInstanceURI((URI) value);
} else {
setInstanceURI(makeURI(value.toString()));
}
if (getLogger().isDebugEnabled()) {
logger.debug(stackLevel() + " Id specifies existing instance " + getInstanceURI());
}
}
//Postconditions
assert getInstanceURI() != null : "instanceURI must not be null";
}
/** Gets the logger.
*
* @return the logger
*/
@Override
protected Logger getLogger() {
return logger;
}
}