/*
* RDFEntityLazyLoader.java
*
* Created on March 2, 2007, 1:30 PM
*
* Description: Provides a lazy loader for RDF entities.
*
* Copyright (C) 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.lazy;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import net.jcip.annotations.ThreadSafe;
import net.sf.cglib.proxy.LazyLoader;
import org.apache.log4j.Logger;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.texai.kb.persistence.RDFEntityLoader;
import org.texai.kb.persistence.RDFProperty;
import org.texai.kb.persistence.DistributedRepositoryManager;
import org.texai.kb.persistence.RDFPersistent;
import org.texai.util.TexaiException;
/** Provides a facility that lazily loads an RDF entity field. The RDF entity value is loaded automatically from the RDF store when any of its
* defined methods are invoked. The method call is delegated to the loaded RDF entity. Subsequent references to the RDF entity field obtain the
* loaded RDF entity directly. Note that because not-yet-loaded lazy RDF entities are not persisted to the RDF store, before they are copied into
* another persistent field they should first be initialized (loaded) by invoking any of their defined methods.
*
* Instances of this class are associated with the RDF entity field by means of a cglib proxy Enhancer.
*
* @author reed
*/
@ThreadSafe
public final class RDFEntityLazyLoader implements LazyLoader, Serializable {
/** the logger */
private static final Logger LOGGER = Logger.getLogger(RDFEntityLazyLoader.class);
/** the serial version UID */
private static final long serialVersionUID = 1L;
/** the repository name */
private final String repositoryName;
/** the RDF instance */
private final RDFPersistent rdfEntity;
/** the RDF instance field */
private transient Field field;
/** the RDF instance field name */
private final String fieldName;
/** the RDF property */
private final RDFProperty rdfProperty;
/** the predicate values dictionary, predicate --> RDF values */
private final Map<URI, List<Value>> predicateValuesDictionary;
/** the loaded object */
private Object loadedObject;
/** the indicator that the lazy object is currently being loaded */
private boolean isLoading = false;
/** Creates a new instance of RDFEntityLazyLoader.
*
* @param repositoryConnection the repository connection
* @param rdfInstance RDF instance
* @param field the RDF instance field
* @param rdfProperty RDF property
* @param predicateValuesDictionary the predicate values dictionary, predicate --> RDF values
*/
public RDFEntityLazyLoader(
final RepositoryConnection repositoryConnection,
final RDFPersistent rdfInstance,
final Field field,
final RDFProperty rdfProperty,
final Map<URI, List<Value>> predicateValuesDictionary) {
super();
//Preconditions
assert repositoryConnection != null : "repositoryConnection must not be null";
assert rdfInstance != null : "rdfInstance must not be null";
assert field != null : "field must not be null";
assert rdfProperty != null : "rdfProperty must not be null";
assert predicateValuesDictionary != null : "predicateValuesDictionary must not be null";
this.predicateValuesDictionary = predicateValuesDictionary;
repositoryName = repositoryConnection.getRepository().getDataDir().getName();
this.rdfEntity = rdfInstance;
this.field = field;
this.fieldName = field.getName();
this.rdfProperty = rdfProperty;
}
/** Returns the object to which the original method invocation should be dispatched.
* Also replaces the lazy object with the loaded object on the RDF entity so that subsequent
* invocations will directly access the object.
*
* @return the object to which the original method invocation should be dispatched
* @throws RepositoryException when a repository error occurs
*/
@Override
public synchronized Object loadObject() throws RepositoryException {
if (!isLoading && loadedObject == null) {
isLoading = true;
final RDFEntityLoader rdfEntityLoader = new RDFEntityLoader();
// obtain a new repository connection from the named repository
final RepositoryConnection repositoryConnection =
DistributedRepositoryManager.getInstance().getRepositoryConnectionForRepositoryName(repositoryName);
if (field == null) {
try {
field = rdfEntity.getClass().getField(fieldName);
} catch (NoSuchFieldException | SecurityException ex) {
throw new TexaiException(ex);
}
}
loadedObject = rdfEntityLoader.loadLazyRDFEntityField(
repositoryConnection,
rdfEntity,
field,
rdfProperty,
predicateValuesDictionary);
repositoryConnection.close();
isLoading = false;
LOGGER.debug("dynamically loaded " + loadedObject + " for field " + field);
}
return loadedObject;
}
}