package pt.ist.fenixframework.hibernatesearch;
import java.lang.annotation.ElementType;
import java.util.*;
import org.hibernate.search.backend.TransactionContext;
import org.hibernate.search.backend.spi.Work;
import org.hibernate.search.backend.spi.WorkType;
import org.hibernate.search.cfg.*;
import org.hibernate.search.engine.spi.SearchFactoryImplementor;
import org.hibernate.search.spi.SearchFactoryBuilder;
import pt.ist.fenixframework.DomainObject;
import pt.ist.fenixframework.FenixFramework;
import pt.ist.fenixframework.core.AbstractDomainObject;
import pt.ist.fenixframework.dml.DomainClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Entry point for interactions with Hibernate-Search.
*
* This class provides a SearchFactory instance that can be used to perform searches using hibernate-search.
*/
public class HibernateSearchSupport {
private static final Logger logger = LoggerFactory.getLogger(HibernateSearchSupport.class);
private static final Set<Class<?>> INDEXED_CLASSES = new HashSet<Class<?>>(getIndexedDomainClasses());
private static SearchFactoryImplementor searchFactory;
/**
* Returns the SearchFactory instance. Null when HibernateSearchSupport is disabled.
*/
public static SearchFactoryImplementor getSearchFactory() {
return searchFactory;
}
static void initializeSearchFactory(Properties hibernateSearchConfiguration) {
if (searchFactory != null) {
throw new RuntimeException("Tried to initialize already initialized HibernateSearchSupport");
}
if (INDEXED_CLASSES.isEmpty()) {
logger.warn("Hibernate Search enabled but no domain classes are marked with @Indexed");
}
SearchConfiguration configuration =
new SearchConfiguration(hibernateSearchConfiguration, getBuiltinMapping(), INDEXED_CLASSES);
searchFactory = new SearchFactoryBuilder().configuration(configuration).buildSearchFactory();
}
protected static void updateIndex(TransactionContext context, Collection<DomainObject> objects, WorkType workType) {
try {
for (DomainObject obj : objects) {
if (!INDEXED_CLASSES.contains(obj.getClass())) continue;
searchFactory.getWorker().performWork(new Work<DomainObject>(obj, workType), context);
}
} catch (RuntimeException e) {
logger.warn("Problem inside updateIndex", e);
throw e;
}
}
/** Built-in default programatic mapping for hibernate-search **/
private static SearchMapping getBuiltinMapping() {
SearchMapping mapping = new SearchMapping();
// Map the getExternalId() method as a documentId for all domain classes
// Note that hibernate-search currently requires this method to really exist in the
// AbstractDomainObject class
mapping
.entity(AbstractDomainObject.class)
.property("externalId", ElementType.METHOD)
.documentId()
.name("id");
return mapping;
}
/** Scans for domain classes annotated with @Indexed **/
private static Set<Class<?>> getIndexedDomainClasses() {
Set<Class<?>> classList = new HashSet<Class<?>>();
for (DomainClass dc : FenixFramework.getDomainModel().getDomainClasses()) {
try {
Class<?> domainClass = Class.forName(dc.getFullName());
if (domainClass.getAnnotation(org.hibernate.search.annotations.Indexed.class) != null) {
logger.trace("Indexing " + dc.getFullName());
classList.add(domainClass);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
return classList;
}
}