/*
* RDFEntityManager.java
*
* Created on August 13, 2007, 12:01 PM
*
* Description: Provides a facade for the RDF entity manager components.
*
* 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.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import net.jcip.annotations.NotThreadSafe;
import org.apache.log4j.Logger;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.impl.BooleanLiteralImpl;
import org.openrdf.model.impl.ContextStatementImpl;
import org.openrdf.model.impl.LiteralImpl;
import org.openrdf.model.impl.NumericLiteralImpl;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import org.texai.kb.Constants;
import org.texai.kb.journal.JournalRequest;
import org.texai.kb.journal.JournalWriter;
import org.texai.subsumptionReasoner.SubClassOfQueries;
import org.texai.subsumptionReasoner.SubPropertyOfQueries;
import org.texai.subsumptionReasoner.TypeQueries;
import org.texai.util.TexaiException;
/** This class provides a facade for public methods in RDFEntityLoader, RDFEntityPersister, RDFEntityRemover, RDFUtility
* and it provides a facade for commonly used methods (e.g. transactions) in the Sesame RepositoryConnection.
*
* @author reed
*/
@NotThreadSafe
public final class RDFEntityManager {
/** the logger */
private static final Logger LOGGER = Logger.getLogger(RDFEntityManager.class);
/** the singleton distributed repository manager, required here because of how the distributed repository manager is initialized */
private static DistributedRepositoryManager distributedRepositoryManager = null;
/** the RDF utility */
private final RDFUtility rdfUtility;
/** the RDF entity persister */
private final RDFEntityPersister rdfEntityPersister;
/** the RDF entity loader */
private final RDFEntityLoader rdfEntityLoader;
/** the RDF entity remover */
private final RDFEntityRemover rdfEntityRemover;
/** the journal writer */
private final JournalWriter journalWriter;
/** the cached indicator whether to automatically commit every repository operation */
private final boolean isAutoCommit = true; // NOPMD
/** the type queries object */
private TypeQueries typeQueries;
/** the subclass queries object */
private SubClassOfQueries subClassOfQueries;
/** the subproperty queries object */
private SubPropertyOfQueries subPropertyOfQueries;
/** the repository connection dictionary, repository name --> repository connection */
private final Map<String, RepositoryConnection> repositoryConnectionDictionary = new HashMap<>();
/** the indicator that this RDF entity manager is closed */
private boolean isClosed = false;
/** Creates a new instance of RDFEntityManager. */
public RDFEntityManager() {
rdfUtility = new RDFUtility(this);
rdfEntityPersister = new RDFEntityPersister(this);
rdfEntityLoader = new RDFEntityLoader();
rdfEntityRemover = new RDFEntityRemover(this);
journalWriter = new JournalWriter();
}
/** Closes this object and releases its resources. */
public void close() {
try {
for (final RepositoryConnection repositoryConnection : repositoryConnectionDictionary.values()) {
if (repositoryConnection.isOpen()) {
if (!repositoryConnection.isAutoCommit()) {
LOGGER.info("commiting any pending transaction for " + repositoryConnection
+ " to " + repositoryConnection.getRepository().getDataDir().getName());
repositoryConnection.commit();
}
repositoryConnection.close();
}
}
} catch (final RepositoryException ex) {
throw new TexaiException(ex);
}
isClosed = true;
}
/** Gets the indicator that this RDF entity manager is closed.
*
* @return the indicator that this RDF entity manager is closed
*/
public boolean isClosed() {
return isClosed;
}
/** Get the singleton distributed repository manager.
*
* @return the singleton distributed repository manager
*/
public static DistributedRepositoryManager getDistributedRepositoryManager() {
return distributedRepositoryManager;
}
/** the singleton distributed repository manager.
*
* @param aDistributedRepositoryManager the singleton distributed repository manager
*/
public static void setDistributedRepositoryManager(final DistributedRepositoryManager aDistributedRepositoryManager) {
distributedRepositoryManager = aDistributedRepositoryManager;
}
/** Returns a possible new root RDF entity given the existing root and a contained candidate root RDF entity.
*
* @param rootRDFEntity the existing root RDF entity
* @param candidateRootRDFEntity a contained candidate root RDF entity
* @return a possible new root RDF entity
*/
public RDFPersistent possibleNewRoot(
final RDFPersistent rootRDFEntity,
final RDFPersistent candidateRootRDFEntity) {
//Preconditions
assert rootRDFEntity != null : "rootRDFEntity must not be null";
assert DistributedRepositoryManager.getInstance().getRepositoryNameForClass(rootRDFEntity.getClass()) != null :
"invalid root RDF entity does not have a matching repository content description, class: " + rootRDFEntity.getClass().getName()
+ ", item id: " + rootRDFEntity.getId();
assert candidateRootRDFEntity != null : "candidateRootRDFEntity must not be null";
final String repositoryName = DistributedRepositoryManager.getInstance().getRepositoryNameForClass(candidateRootRDFEntity.getClass());
if (repositoryName == null) {
// the candidate root RDF entity has a repository content description item that supercedes the repository content description
// of the existing root RDF entity
return rootRDFEntity;
} else {
return candidateRootRDFEntity;
}
}
/** Gets a repository connection to the repository that contains the given class.
* The RDF entity manager is responsible for closing the connection.
*
* @param clazz the given class
* @return a repository connection to the repository that contains the given class
*/
public RepositoryConnection getConnectionToRepositoryContainingClass(final Class<?> clazz) {
//Preconditions
assert clazz != null : "clazz must not be null";
final String repositoryName = DistributedRepositoryManager.getInstance().getRepositoryNameForClass(clazz);
if (repositoryName == null) {
return null;
} else {
return getConnectionToNamedRepository(repositoryName);
}
}
/** Gets a cached repository connection to the named repository.
*
* @param repositoryName the named repository
* @return a repository connection to the named repository
*/
public RepositoryConnection getConnectionToNamedRepository(final String repositoryName) {
//Preconditions
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
if (distributedRepositoryManager == null) {
// initialize the distributed repository manager
DistributedRepositoryManager.getInstance();
}
assert distributedRepositoryManager != null : "distributedRepositoryManager must not be null";
RepositoryConnection repositoryConnection = repositoryConnectionDictionary.get(repositoryName);
if (repositoryConnection == null) {
repositoryConnection = distributedRepositoryManager.getRepositoryConnectionForRepositoryName(repositoryName);
repositoryConnectionDictionary.put(repositoryName, repositoryConnection);
}
//Postconditions
assert repositoryConnection != null : "repositoryConnection must not be null";
try {
assert repositoryConnection.isOpen() : "repositoryConnection " + repositoryConnection + " must be open for " + repositoryName;
} catch (final RepositoryException ex) {
throw new TexaiException(ex);
}
return repositoryConnection;
}
/** Removes all statements from specific contexts in the repository.
*
* @param repositoryName the repository name
* @param contexts the context(s) to remove the data from. Note that this parameter is a vararg and as such is optional.
* If no contexts are supplied the method operates on the entire repository.
*/
public void clear(
final String repositoryName,
final Resource... contexts) {
//Preconditions
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
assert contexts != null : "contexts must not be null";
final RepositoryConnection repositoryConnection = getConnectionToNamedRepository(repositoryName);
final List<JournalRequest> journalRequests = new ArrayList<>();
try {
if (contexts.length == 0) {
// enumerate the statements in all contexts in order to journal their remove operations
final RepositoryResult<Statement> repositoryResult = repositoryConnection.getStatements(null, null, null, false);
while (repositoryResult.hasNext()) {
final Statement statement = repositoryResult.next();
journalRequests.add(new JournalRequest(
repositoryConnection.getRepository().getDataDir().getName(),
Constants.REMOVE_OPERATION,
statement));
}
repositoryConnection.clear();
} else {
for (final Resource context : contexts) {
// enumerate the statements in this context in order to journal their remove operations
final RepositoryResult<Statement> repositoryResult = repositoryConnection.getStatements(null, null, null, false, context);
while (repositoryResult.hasNext()) {
final Statement statement = repositoryResult.next();
journalRequests.add(new JournalRequest(
repositoryConnection.getRepository().getDataDir().getName(),
Constants.REMOVE_OPERATION,
new ContextStatementImpl(statement.getSubject(), statement.getPredicate(), statement.getObject(), context)));
}
repositoryConnection.clear(context);
}
}
} catch (final RepositoryException ex) {
throw new TexaiException(ex);
}
journalWriter.write(journalRequests);
if (isAutoCommit) {
journalWriter.commit();
}
}
/** Adds the supplied statement to the named repository, optionally to one or more named contexts.
*
* @param repositoryName the repository name
* @param statement the statement to add
* @param contexts the optional contexts
*/
public void add(
final String repositoryName,
final Statement statement,
final Resource... contexts) {
//Preconditions
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
assert statement != null : "statement must not be null";
assert contexts != null : "contexts must not be null";
final RepositoryConnection repositoryConnection = getConnectionToNamedRepository(repositoryName);
addStatement(repositoryConnection, statement, contexts);
}
/** Removes the given statement from the named repository, optionally from one or more named contexts.
*
* @param repositoryName the repository name
* @param statement the statement to remove
* @param contexts the optional contexts
*/
public void remove(
final String repositoryName,
final Statement statement,
final Resource... contexts) {
//Preconditions
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
assert statement != null : "statement must not be null";
assert contexts != null : "contexts must not be null";
final RepositoryConnection repositoryConnection = getConnectionToNamedRepository(repositoryName);
removeStatement(repositoryConnection, statement, contexts);
}
/** Gets the default context of the given persistent class.
*
* @param rdfEntityClass the persistent class
* @return the default context
*/
public URI getDefaultContext(final Class<?> rdfEntityClass) {
return rdfEntityLoader.getDefaultContext(rdfEntityClass);
}
/** Gets the effective context of the given persistent class, given a potentially non-null override context.
*
* @param rdfEntityClass the persistent class
* @param overrideContext the override context
* @return the effective context
*/
public URI getEffectiveContext(final Class<?> rdfEntityClass, final URI overrideContext) {
//Preconditions
assert rdfEntityClass != null : "rdfEntityClass must not be null";
if (overrideContext == null) {
return rdfEntityLoader.getDefaultContext(rdfEntityClass);
} else {
return overrideContext;
}
}
/** Persists the given RDF entity as propositions in the RDF store.
*
* @param rdfEntity the RDF entity
* @param repositoryName the repository name
* @return the instance URI that represents the RDF entity
*/
public URI persist(final RDFPersistent rdfEntity, final String repositoryName) {
//Preconditions
assert rdfEntity != null : "rdfEntity must not be null";
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
final RepositoryConnection repositoryConnection = getConnectionToNamedRepository(repositoryName);
return rdfEntityPersister.persist(repositoryConnection, rdfEntity);
}
/** Persists the given RDF entity as propositions in the RDF store.
*
* @param rdfEntity the RDF entity
* @return the instance URI that represents the RDF entity
*/
public URI persist(final RDFPersistent rdfEntity) {
return persist(
rdfEntity, // root RDF entity, same as the RDF entity in this case
rdfEntity); // the RDF entity
}
/** Exports the given RDF entity as RDF statements into the given output stream. Use KBInitializer to import.
*
* @param rdfEntity the RDF entity
* @param writer the export output writer
*/
public void export(
final RDFPersistent rdfEntity,
final BufferedWriter writer) {
//Preconditions
assert rdfEntity != null : "rdfEntity must not be null";
assert writer != null : "outputStream must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(rdfEntity, rdfEntity);
rdfEntityPersister.export(repositoryConnection, rdfEntity, writer);
}
/** Persists the given RDF entity as propositions in the RDF store, with the given override context.
*
* @param rdfEntity the RDF entity
* @param overrideContext the override context
* @return the instance URI that represents the RDF entity
*/
public URI persist(final RDFPersistent rdfEntity, final URI overrideContext) {
return persist(
rdfEntity, // root RDF entity, same as the RDF entity in this case
rdfEntity, // the RDF entity
overrideContext);
}
/** Persists the given RDF entity. The default preference is to persist the RDF entity in the same
* repository in which the root RDF entity is persisted.
*
* @param rootRDFEntity the root RDF entity that contains the RDF entity
* @param rdfEntity the RDF entity to persist
* @return the instance URI that represents the RDF entity
*/
public URI persist(
final RDFPersistent rootRDFEntity,
final RDFPersistent rdfEntity) {
//Preconditions
assert rootRDFEntity != null : "rootRDFEntity must not be null";
assert rdfEntity != null : "rdfEntity must not be null";
//assert isSerializable(rdfEntity) : "rdfEntity must be indeed serializable";
final RepositoryConnection repositoryConnection = getRepositoryConnection(rootRDFEntity, rdfEntity);
return rdfEntityPersister.persist(repositoryConnection, rdfEntity);
}
/** Persists the given RDF entity. The default preference is to persist the RDF entity in the same
* repository in which the root RDF entity is persisted.
*
* @param rootRDFEntity the root RDF entity that contains the RDF entity
* @param rdfEntity the RDF entity to persist
* @param overrideContext the override context
* @return the instance URI that represents the RDF entity
*/
public URI persist(
final RDFPersistent rootRDFEntity,
final RDFPersistent rdfEntity, // the RDF entity
final URI overrideContext) {
//Preconditions
assert rootRDFEntity != null : "rootRDFEntity must not be null";
assert rdfEntity != null : "rdfEntity must not be null";
//assert isSerializable(rdfEntity) : "rdfEntity must be indeed serializable";
final RepositoryConnection repositoryConnection = getRepositoryConnection(rootRDFEntity, rdfEntity);
return rdfEntityPersister.persist(
repositoryConnection,
rdfEntity,
overrideContext,
null); // outputStream
}
/** Returns whether the given object is indeed serializable.
*
* @param obj the given object
* @return whether the given object is indeed serializable
*/
public static boolean isSerializable(final Serializable obj) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos;
try {
oos = new ObjectOutputStream(out);
oos.writeObject(obj);
oos.close();
} catch (IOException ex) {
throw new TexaiException(ex);
}
return out.toByteArray().length > 0;
}
/** Remove the statements in the RDF store that mention the URI that represents the given RDF entity.
*
* @param rdfEntity the given RDF entity
* @param repositoryName the given repository name
*/
public void remove(final RDFPersistent rdfEntity, final String repositoryName) {
//Preconditions
assert rdfEntity != null : "rdfEntity must not be null";
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
final RepositoryConnection repositoryConnection = getConnectionToNamedRepository(repositoryName);
rdfEntityRemover.remove(repositoryConnection, rdfEntity);
}
/** Remove the statements in the RDF store that mention the URI that represents the given RDF entity.
*
* @param rdfEntity the given RDF entity
*/
public void remove(final RDFPersistent rdfEntity) {
//Preconditions
assert rdfEntity != null : "rdfEntity must not be null";
remove(rdfEntity, rdfEntity);
}
/** Removes the given RDF entity. The default preference is to remove the RDF entity from the same
* repository in which the root RDF entity is persisted.
*
* @param rootRDFEntity the root RDF entity that contains the RDF entity
* @param rdfEntity the RDF entity to remove
*/
public void remove(
final RDFPersistent rootRDFEntity,
final RDFPersistent rdfEntity) {
//Preconditions
assert rootRDFEntity != null : "rootRDFEntity must not be null";
assert rdfEntity != null : "rdfEntity must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(rootRDFEntity, rdfEntity);
rdfEntityRemover.remove(repositoryConnection, rdfEntity);
}
/** Sets the identification URI of the given RDF entity.
*
* @param rdfEntity the RDF entity
*/
public void setIdFor(final RDFPersistent rdfEntity) {
//Preconditions
assert rdfEntity != null : "rdfEntity must not be null";
rdfEntityPersister.setIdFor(rdfEntity);
}
/** Sets the identification URI of the given RDF entity to the given id.
*
* @param rdfEntity the RDF entity
* @param id the given id
*/
public void setIdFor(final RDFPersistent rdfEntity, final URI id) {
//Preconditions
assert rdfEntity != null : "rdfEntity must not be null";
assert id != null : "id must not be null";
rdfEntityPersister.setIdFor(rdfEntity, id);
}
/** Creates a default id for the given RDF entity, ignoring the annotated subject.
*
* @param rdfEntity the given RDF entity
* @return a default id for the given RDF entity
*/
public static URI createId(final Object rdfEntity) {
//Preconditions
assert rdfEntity != null : "rdfEntity must not be null";
return new URIImpl(Constants.TEXAI_NAMESPACE + rdfEntity.getClass().getName() + "_" + UUID.randomUUID().toString());
}
/** Gets the indicator to validate persisted statements.
*
* @return the indicator whether to validate persisted statements
*/
public boolean areStatementsValidated() {
return rdfEntityPersister.areStatementsValidated();
}
/** Sets the indicator to validate persisted statements.
*
* @param areStatementsValidated the indicator whether to validate persisted statements
*/
public void setAreStatementsValidated(final boolean areStatementsValidated) {
rdfEntityPersister.setAreStatementsValidated(areStatementsValidated);
}
/** Finds and loads the RDF entity from propositions in the knowledge base given its URI.
*
* @param instanceURI the URI that represents the RDF entity
* @return the RDF entity
*/
public Object find(final URI instanceURI) {
//Preconditions
assert instanceURI != null : "instanceURI must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(instanceURI);
return rdfEntityLoader.find(repositoryConnection, instanceURI);
}
/** Finds and loads the RDF entity from propositions in the knowledge base given its URI and class. If the class is null,
* then the class name is looked up from the RDF store before instantiating the entity.
*
* @param <T> the RDF entity class
* @param clazz the RDF entity class
* @param instanceURI the URI that represents the RDF entity
* @param repositoryName the repository name
* @return the RDF entity
*/
public <T> T find(
final Class<T> clazz,
final URI instanceURI,
final String repositoryName) {
//Preconditions
assert clazz != null : "clazz must not be null";
assert instanceURI != null : "instanceURI must not be null";
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
final RepositoryConnection repositoryConnection = getConnectionToNamedRepository(repositoryName);
return rdfEntityLoader.find(repositoryConnection, clazz, instanceURI);
}
/** Finds and loads the RDF entity from propositions in the knowledge base given its URI and class. If the class is null,
* then the class name is looked up from the RDF store before instantiating the entity.
*
* @param <T> the RDF entity class
* @param clazz the RDF entity class
* @param instanceURI the URI that represents the RDF entity
* @return the RDF entity
*/
public <T> T find(
final Class<T> clazz,
final URI instanceURI) {
//Preconditions
assert clazz != null : "clazz must not be null";
assert instanceURI != null : "instanceURI must not be null";
try {
final RepositoryConnection repositoryConnection = getRepositoryConnection(instanceURI);
return rdfEntityLoader.find(repositoryConnection, clazz, instanceURI);
} catch (Throwable ex) {
LOGGER.error("class: " + clazz.getName());
LOGGER.error("instanceURI: " + instanceURI);
if (distributedRepositoryManager == null) {
// initialize the distributed repository manager
distributedRepositoryManager = DistributedRepositoryManager.getInstance();
}
assert distributedRepositoryManager != null : "distributedRepositoryManager must not be null";
LOGGER.error("repository: " + distributedRepositoryManager.getRepositoryNameForInstance(instanceURI));
throw new TexaiException(ex);
}
}
/** Finds and loads the RDF entity from propositions in the knowledge base given its URI and class. If the class is null,
* then the class name is looked up from the RDF store before instantiating the entity.
*
* @param <T> the rdf entity class
* @param rootEntityClass the root RDF entity class that governs which repository contains the RDF entity to be found
* @param clazz the RDF entity class
* @param instanceURI the URI that represents the RDF entity
* @return the RDF entity
*/
public <T> T find(
final Class<?> rootEntityClass,
final Class<T> clazz,
final URI instanceURI) {
//Preconditions
assert rootEntityClass != null : "rootEntityClass must not be null";
assert clazz != null : "clazz must not be null";
assert instanceURI != null : "instanceURI must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(rootEntityClass);
return rdfEntityLoader.find(repositoryConnection, clazz, instanceURI);
}
/** Finds and loads the RDF entity from propositions in the knowledge base given its id string, without clearing
* the dictionary of connected RDF entities.
*
* @param <T> the RDF entity class
* @param clazz the RDF entity class
* @param idString the id string that represents the RDF entity
* @return the RDF entity or null if not found
*/
public <T> T find(
final Class<T> clazz,
final String idString) {
//Preconditions
assert clazz != null : "clazz must not be null";
assert idString != null : "idString must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.find(repositoryConnection, clazz, idString);
}
/** Finds and loads RDF entities having the given RDF predicate and RDF value.
*
* @param <T> the RDF entity class
* @param predicate the given RDF predicate
* @param rdfValue the RDF value of the predicate
* @param clazz the class of the desired RDF entities
* @return the RDF entities having the given RDF predicate and RDF value
*/
public <T> List<T> find(
final URI predicate,
final Value rdfValue,
final Class<T> clazz) {
//Preconditions
assert predicate != null : "predicate must not be null";
assert rdfValue != null : "rdfValue must not be null";
assert clazz != null : "clazz must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.find(repositoryConnection, predicate, rdfValue, clazz);
}
/** Finds and loads RDF entities having the given RDF predicate and RDF value.
*
* @param <T> the RDF entity class
* @param predicate the given RDF predicate
* @param rdfValue the RDF value of the predicate
* @param clazz the class of the desired RDF entities
* @param repositoryName the repository name
* @return the RDF entities having the given RDF predicate and RDF value
*/
public <T> List<T> find(
final URI predicate,
final Value rdfValue,
final Class<T> clazz,
final String repositoryName) {
//Preconditions
assert predicate != null : "predicate must not be null";
assert rdfValue != null : "rdfValue must not be null";
assert clazz != null : "clazz must not be null";
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
final RepositoryConnection repositoryConnection = this.getConnectionToNamedRepository(repositoryName);
return rdfEntityLoader.find(repositoryConnection, predicate, rdfValue, clazz);
}
/** Finds and loads RDF entities having the given RDF predicate and RDF value.
*
* @param <T> the RDF entity class
* @param predicate the given RDF predicate
* @param rdfValue the RDF value of the predicate
* @param overrideContext the override context
* @param clazz the class of the desired RDF entities
* @return the RDF entities having the given RDF predicate and RDF value
*/
public <T> List<T> find(
final URI predicate,
final Value rdfValue,
final URI overrideContext,
final Class<T> clazz) {
//Preconditions
assert predicate != null : "predicate must not be null";
assert rdfValue != null : "rdfValue must not be null";
assert clazz != null : "clazz must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.find(repositoryConnection, predicate, rdfValue, overrideContext, clazz);
}
/** Finds and loads RDF entities having the given RDF predicate and boolean value.
*
* @param <T> the RDF entity class
* @param predicate the given RDF predicate
* @param value the boolean value
* @param clazz the class of the desired RDF entities
* @return the RDF entities having the given RDF predicate and RDF value
*/
public <T> List<T> find(
final URI predicate,
final boolean value,
final Class<T> clazz) {
//Preconditions
assert predicate != null : "predicate must not be null";
assert clazz != null : "clazz must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.find(
repositoryConnection,
predicate,
new BooleanLiteralImpl(value),
clazz);
}
/** Finds and loads RDF entities having the given RDF predicate and byte value.
*
* @param <T> the RDF entity class
* @param predicate the given RDF predicate
* @param value the byte value
* @param clazz the class of the desired RDF entities
* @return the RDF entities having the given RDF predicate and RDF value
*/
public <T> List<T> find(
final URI predicate,
final byte value,
final Class<T> clazz) {
//Preconditions
assert predicate != null : "predicate must not be null";
assert clazz != null : "clazz must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.find(
repositoryConnection,
predicate,
new NumericLiteralImpl(value),
clazz);
}
/** Finds and loads RDF entities having the given RDF predicate and double value.
*
* @param <T> the RDF entity class
* @param predicate the given RDF predicate
* @param value the double value
* @param clazz the class of the desired RDF entities
* @return the RDF entities having the given RDF predicate and RDF value
*/
public <T> List<T> find(
final URI predicate,
final double value,
final Class<T> clazz) {
//Preconditions
assert predicate != null : "predicate must not be null";
assert clazz != null : "clazz must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.find(
repositoryConnection,
predicate,
new NumericLiteralImpl(value),
clazz);
}
/** Finds and loads RDF entities having the given RDF predicate and float value.
*
* @param <T> the RDF entity class
* @param predicate the given RDF predicate
* @param value the float value
* @param clazz the class of the desired RDF entities
* @return the RDF entities having the given RDF predicate and RDF value
*/
public <T> List<T> find(
final URI predicate,
final float value,
final Class<T> clazz) {
//Preconditions
assert predicate != null : "predicate must not be null";
assert clazz != null : "clazz must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.find(
repositoryConnection,
predicate,
new NumericLiteralImpl(value),
clazz);
}
/** Finds and loads RDF entities having the given RDF predicate and int value.
*
* @param <T> the RDF entity class
* @param predicate the given RDF predicate
* @param value the int value
* @param clazz the class of the desired RDF entities
* @return the RDF entities having the given RDF predicate and RDF value
*/
public <T> List<T> find(
final URI predicate,
final int value,
final Class<T> clazz) {
//Preconditions
assert predicate != null : "predicate must not be null";
assert clazz != null : "clazz must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.find(
repositoryConnection,
predicate,
new NumericLiteralImpl(value),
clazz);
}
/** Finds and loads RDF entities having the given RDF predicate and long value.
*
* @param <T> the RDF entity class
* @param predicate the given RDF predicate
* @param value the long value
* @param clazz the class of the desired RDF entities
* @return the RDF entities having the given RDF predicate and RDF value
*/
public <T> List<T> find(
final URI predicate,
final long value,
final Class<T> clazz) {
//Preconditions
assert predicate != null : "predicate must not be null";
assert clazz != null : "clazz must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.find(
repositoryConnection,
predicate,
new NumericLiteralImpl(value),
clazz);
}
/** Finds and loads RDF entities having the given RDF predicate and short value.
*
* @param <T> the RDF entity class
* @param predicate the given RDF predicate
* @param value the short value
* @param clazz the class of the desired RDF entities
* @return the RDF entities having the given RDF predicate and RDF value
*/
public <T> List<T> find(
final URI predicate,
final short value,
final Class<T> clazz) {
//Preconditions
assert predicate != null : "predicate must not be null";
assert clazz != null : "clazz must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.find(
repositoryConnection,
predicate,
new NumericLiteralImpl(value),
clazz);
}
/** Finds and loads RDF entities having the given RDF predicate and String value.
*
* @param <T> the RDF entity class
* @param predicate the given RDF predicate
* @param value the String value
* @param clazz the class of the desired RDF entities
* @return the RDF entities having the given RDF predicate and RDF value
*/
public <T> List<T> find(
final URI predicate,
final String value,
final Class<T> clazz) {
//Preconditions
assert predicate != null : "predicate must not be null";
assert clazz != null : "clazz must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.find(
repositoryConnection,
predicate,
new LiteralImpl(value),
clazz);
}
/** Returns an iterator over the set of RDF entity terms that represent instances of the given RDF entity class.
*
* @param <T> the RDF entity class
* @param clazz the given RDF entity class
* @param overrideContext the override context
* @return an iterator over the set of RDF entity terms that represent instances of the given RDF entity class
*/
public <T> Iterator<T> rdfEntityIterator(
final Class<T> clazz,
final URI overrideContext) {
//Preconditions
assert clazz != null : "clazz must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.rdfEntityIterator(
repositoryConnection,
clazz,
overrideContext);
}
/** Returns an iterator over the set of RDF entity terms that represent instances of the given RDF entity class.
*
* @param <T> the RDF entity class
* @param clazz the given RDF entity class
* @return an iterator over the set of RDF entity terms that represent instances of the given RDF entity class
*/
public <T> Iterator<T> rdfEntityIterator(
final Class<T> clazz) {
//Preconditions
assert clazz != null : "clazz must not be null";
final RepositoryConnection repositoryConnection = getRepositoryConnection(clazz);
return rdfEntityLoader.rdfEntityIterator(
repositoryConnection,
clazz,
null);
}
/** Gets the type queries object.
*
* @return the type queries object
*/
public TypeQueries getTypeQueries() {
if (typeQueries == null) {
typeQueries = new TypeQueries(this);
}
return typeQueries;
}
/** Returns whether the given term is an individual.
*
* @param repositoryName the repository name
* @param term the given term
* @return whether the given term is an individual
*/
public boolean isIndividualTerm(
final String repositoryName,
final URI term) {
//Preconditions
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
assert term != null : "term must not be null";
return getTypeQueries().isIndividualTerm(repositoryName, term);
}
/** Returns whether the given term is a class.
*
* @param repositoryName the repository name
* @param term the given term
* @return whether the given term is a class
*/
public boolean isClassTerm(
final String repositoryName,
final URI term) {
//Preconditions
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
assert term != null : "term must not be null";
return getTypeQueries().isClassTerm(repositoryName, term);
}
/** Returns whether the given term is a context.
*
* @param repositoryName the repository name
* @param term the given term
* @return whether the given term is a context
*/
public boolean isContextTerm(
final String repositoryName,
final URI term) {
//Preconditions
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
assert term != null : "term must not be null";
return getTypeQueries().isContextTerm(repositoryName, term);
}
/** Returns whether the given term is a property.
*
* @param repositoryName the repository name
* @param term the given term
* @return whether the given term is a property
*/
public boolean isPropertyTerm(
final String repositoryName,
final URI term) {
//Preconditions
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
assert term != null : "term must not be null";
return getTypeQueries().isPropertyTerm(repositoryName, term);
}
/** Returns whether the given term is a situation.
*
* @param repositoryName the repository name
* @param term the given term
* @return whether the given term is a situation
*/
public boolean isSituationTerm(
final String repositoryName,
final URI term) {
//Preconditions
assert repositoryName != null : "repositoryName must not be null";
assert !repositoryName.isEmpty() : "repositoryName must not be empty";
assert term != null : "term must not be null";
return getSubClassOfQueries().isSituationClass(repositoryName, term);
}
/** Gets the subclass-of queries object.
*
* @return the subclass-of queries object
*/
public SubClassOfQueries getSubClassOfQueries() {
if (subClassOfQueries == null) {
subClassOfQueries = new SubClassOfQueries(this);
}
return subClassOfQueries;
}
/** Gets the subproperty-of queries object.
*
* @return the subproperty-of queries object
*/
public SubPropertyOfQueries getSubPropertyOfQueries() {
if (subPropertyOfQueries == null) {
subPropertyOfQueries = new SubPropertyOfQueries(this);
}
return subPropertyOfQueries;
}
/** Asserts the defining statements for a new RDF class. This method is useful in the case where a new RDF class is required
* but no direct instances of the RDF class will ever be instantiated as Java objects.
*
* @param repositoryName the repository name
* @param classURI the RDF class
* @param comment the RDF class comment
* @param typeURIs the RDF class typeURIs
* @param subClassOfURIs the RDF classes for which this RDF class is a subclass
* @param writer the export output writer, or null when objects are ordinarily persisted to the given RDF quad store
*/
public void defineRDFClass(
final String repositoryName,
final URI classURI,
final String comment,
final List<URI> typeURIs,
final List<URI> subClassOfURIs,
final BufferedWriter writer) {
rdfUtility.defineRDFClass(
repositoryName,
classURI,
comment,
typeURIs,
subClassOfURIs,
writer);
}
/** Asserts the defining statements for a new RDF individual. This method is useful in the case where a new RDF individual is required
* but no corresponding Java class has been created.
*
* @param repositoryName the repository name
* @param individualURI the individual URI
* @param comment the RDF individual comment
* @param typeURIs the RDF class typeURIs
* @param writer the export output writer, or null when objects are ordinarily persisted to the given RDF quad store
*/
public void defineRDFIndividual(
final String repositoryName,
final URI individualURI,
final String comment,
final List<URI> typeURIs,
final BufferedWriter writer) {
rdfUtility.defineRDFIndividual(
repositoryName,
individualURI,
comment,
typeURIs,
writer);
}
/** Asserts the defining statements for a new RDF context.
*
* @param repositoryName the repository name
* @param contextURI the RDF context URI
* @param comment the RDF class comment
* @param typeURIs the RDF context typeURIs
* @param genlMtURIs the RDF contexts for which this RDF context is a specialization
* @param writer the export output writer, or null when objects are ordinarily persisted to the given RDF quad store
*/
public void defineRDFContext(
final String repositoryName,
final URI contextURI,
final String comment,
final List<URI> typeURIs,
final List<URI> genlMtURIs,
final BufferedWriter writer) {
rdfUtility.defineRDFContext(
repositoryName,
contextURI,
comment,
typeURIs,
genlMtURIs,
writer);
}
/** Asserts that the two given classes are disjoint.
*
* @param repositoryName the repository name
* @param classURI1 the first given class
* @param classURI2 the second given class
* @param writer the export output writer, or null when objects are ordinarily persisted to the given RDF quad store
*/
public void assertDisjoint(
final String repositoryName,
final URI classURI1,
final URI classURI2,
final BufferedWriter writer) {
rdfUtility.assertDisjoint(
repositoryName,
classURI1,
classURI2,
writer);
}
/**
* Asserts the defining statements for a new RDF predicate.
*
* @param repositoryName the repository name
* @param predicateURI the RDF predicate
* @param comment the RDF predicate comment
* @param typeURIs the RDF predicate typeURIs
* @param subPropertyOfs the RDF predicates for which this RDF predicate is a subproperty
* @param domainURI the type of the RDF subject that can be used with this predicate
* @param rangeURI the type of the RDF object that can be used with this predicate
* @param writer the export output writer, or null when objects are ordinarily persisted to the given RDF quad store
*/
public void defineRDFPredicate(
final String repositoryName,
final URI predicateURI,
final String comment,
final List<URI> typeURIs,
final List<URI> subPropertyOfs,
final URI domainURI,
final URI rangeURI,
final BufferedWriter writer) {
rdfUtility.defineRDFPredicate(
repositoryName,
predicateURI,
comment,
typeURIs,
subPropertyOfs,
domainURI,
rangeURI,
writer);
}
/** Formats an RDF statement.
*
* @param statement the statement
* @return the formatted statement in which namespaces are represented by prefixes
*/
public String formatStatement(final Statement statement) {
return RDFUtility.formatStatement(statement);
}
/** Persists the given RDF entity.
*
* @param repositoryConnection the repository connection
* @param rdfEntity the RDF entity to persist
* @return the instance URI that represents the RDF entity
*/
protected URI persist(
final RepositoryConnection repositoryConnection,
final RDFPersistent rdfEntity) {
//Preconditions
assert repositoryConnection != null : "repositoryConnection must not be null";
assert rdfEntity != null : "rdfEntity must not be null";
return rdfEntityPersister.persist(repositoryConnection, rdfEntity);
}
/** Adds the supplied statement to the connected repository, optionally to one or more named contexts.
*
* @param repositoryConnection the repository connection
* @param statement the statement to add
* @param contexts the optional contexts
*/
protected void addStatement(
final RepositoryConnection repositoryConnection,
final Statement statement,
final Resource... contexts) {
//Preconditions
assert repositoryConnection != null : "repositoryConnection must not be null";
assert statement != null : "statement must not be null";
assert contexts != null : "contexts must not be null";
final List<JournalRequest> journalRequests = new ArrayList<>();
try {
if (contexts.length == 0) {
repositoryConnection.add(statement);
journalRequests.add(new JournalRequest(
repositoryConnection.getRepository().getDataDir().getName(),
Constants.ADD_OPERATION,
statement));
} else {
for (final Resource context : contexts) {
repositoryConnection.add(statement, context);
journalRequests.add(new JournalRequest(
repositoryConnection.getRepository().getDataDir().getName(),
Constants.ADD_OPERATION,
new ContextStatementImpl(statement.getSubject(), statement.getPredicate(), statement.getObject(), context)));
}
}
} catch (final AssertionError | RepositoryException ex) {
LOGGER.error("repository: " + repositoryConnection.getRepository().getDataDir());
throw new TexaiException(ex);
}
journalWriter.write(journalRequests);
if (isAutoCommit) {
journalWriter.commit();
}
}
/** Removes the given statement from specific contexts in the repository.
*
* @param repositoryConnection the repository connection
* @param statement the given statement
* @param contexts the context(s) to remove the data from. Note that this parameter is a vararg and as such is optional.
* If no contexts are supplied the method operates on the entire repository.
*/
protected void removeStatement(
final RepositoryConnection repositoryConnection,
final Statement statement,
final Resource... contexts) {
//Preconditions
assert repositoryConnection != null : "repositoryConnection must not be null";
assert statement != null : "statement must not be null";
assert contexts != null : "contexts must not be null";
final List<JournalRequest> journalRequests = new ArrayList<>();
try {
if (contexts.length == 0) {
journalRequests.add(new JournalRequest(
repositoryConnection.getRepository().getDataDir().getName(),
Constants.REMOVE_OPERATION,
statement));
repositoryConnection.remove(statement);
} else {
for (final Resource context : contexts) {
journalRequests.add(new JournalRequest(
repositoryConnection.getRepository().getDataDir().getName(),
Constants.REMOVE_OPERATION,
new ContextStatementImpl(statement.getSubject(), statement.getPredicate(), statement.getObject(), context)));
repositoryConnection.remove(statement, context);
}
}
} catch (final RepositoryException ex) {
throw new TexaiException(ex);
}
journalWriter.write(journalRequests);
if (isAutoCommit) {
journalWriter.commit();
}
}
/** Rolls back all updates that have been performed as part of this connection so far.
*
* @param repositoryConnection the repository connection
*/
protected void rollback(final RepositoryConnection repositoryConnection) {
//Preconditions
assert repositoryConnection != null : "repositoryConnection must not be null";
try {
repositoryConnection.rollback();
journalWriter.rollback();
} catch (final RepositoryException ex) {
throw new TexaiException(ex);
}
}
/** Loads the given RDF entity field.
*
* @param repositoryConnection the repository connection
* @param rdfEntity the RDF entity
* @param field the field to be loaded
* @param rdfProperty the RDF property the associates field value(s) in the knowledge base
* @param predicateValuesDictionary the predicate values dictionary, predicate --> RDF values
* @return the value of the loaded field
*/
protected Object loadRDFEntityField(
final RepositoryConnection repositoryConnection,
final RDFPersistent rdfEntity,
final Field field,
final RDFProperty rdfProperty,
final Map<URI, List<Value>> predicateValuesDictionary) {
return rdfEntityLoader.loadLazyRDFEntityField(
repositoryConnection,
rdfEntity,
field,
rdfProperty,
predicateValuesDictionary);
}
/** Gets a repository connection for the given RDF entity URI.
*
* @param uri the given RDF entity URI
* @return a repository connection
*/
protected RepositoryConnection getRepositoryConnection(final URI uri) {
//Preconditions
assert uri != null : "uri must not be null";
if (distributedRepositoryManager == null) {
// initialize the distributed repository manager
distributedRepositoryManager = DistributedRepositoryManager.getInstance();
}
assert distributedRepositoryManager != null : "distributedRepositoryManager must not be null";
final String repositoryName = distributedRepositoryManager.getRepositoryNameForInstance(uri);
if (repositoryName == null) {
throw new TexaiException("repository name not found for " + uri);
}
final RepositoryConnection repositoryConnection = getConnectionToNamedRepository(repositoryName);
//Postconditions
assert repositoryConnection != null : "repositoryConnection must not be null";
return repositoryConnection;
}
/** Gets a repository connection for the given RDF entity class.
*
* @param clazz the given RDF entity class
* @return a repository connection
*/
private RepositoryConnection getRepositoryConnection(final Class<?> clazz) {
//Preconditions
assert clazz != null : "clazz must not be null";
if (distributedRepositoryManager == null) {
// initialize the distributed repository manager
DistributedRepositoryManager.getInstance();
}
assert distributedRepositoryManager != null : "distributedRepositoryManager must not be null";
final String repositoryName = distributedRepositoryManager.getRepositoryNameForClassName(clazz.getName());
if (repositoryName == null) {
DistributedRepositoryManager.logClassNameRepositoryDictionary();
throw new TexaiException("repository name not found for " + clazz);
}
final RepositoryConnection repositoryConnection = getConnectionToNamedRepository(repositoryName);
//Postconditions
assert repositoryConnection != null : "repositoryConnection must not be null";
return repositoryConnection;
}
/** Returns a repository connection for the given RDF entity, returning a repository connection for the root RDF entity
* if the repository connection cannot be determined from the given RDF entity alone.
*
* @param rootRDFEntity the root RDF entity that contains the RDF entity
* @param rdfEntity the RDF entity to persist
* @return a repository connection
*/
private RepositoryConnection getRepositoryConnection(
final RDFPersistent rootRDFEntity,
final RDFPersistent rdfEntity) {
//Preconditions
assert rootRDFEntity != null : "rootRDFEntity must not be null";
assert rdfEntity != null : "rdfEntity must not be null";
if (distributedRepositoryManager == null) {
// initialize the distributed repository manager
DistributedRepositoryManager.getInstance();
}
assert distributedRepositoryManager != null : "distributedRepositoryManager must not be null";
if (rootRDFEntity.getId() == null) {
setIdFor(rootRDFEntity);
}
final String rootRepositoryName = distributedRepositoryManager.getRepositoryNameForInstance(rootRDFEntity);
if (rootRepositoryName == null) {
DistributedRepositoryManager.logClassNameRepositoryDictionary();
throw new TexaiException("repository name not found for " + rootRDFEntity.getId()
+ "\nclass: " + DistributedRepositoryManager.parseClassNameFromURI(rootRDFEntity.getId()));
}
final RepositoryConnection rootRepositoryConnection = getConnectionToNamedRepository(rootRepositoryName);
assert rootRepositoryConnection != null;
RepositoryConnection repositoryConnection;
if (rdfEntity.getId() == null) {
setIdFor(rdfEntity);
}
final String repositoryName = distributedRepositoryManager.getRepositoryNameForInstance(rdfEntity);
if (repositoryName == null) {
repositoryConnection = rootRepositoryConnection;
} else {
repositoryConnection = getConnectionToNamedRepository(repositoryName);
}
//Postconditions
assert repositoryConnection != null : "repositoryConnection must not be null";
return repositoryConnection;
}
}