package org.compass.core.impl;
import java.lang.ref.WeakReference;
import org.compass.core.Compass;
import org.compass.core.CompassException;
import org.compass.core.CompassIndexSession;
import org.compass.core.CompassQueryBuilder;
import org.compass.core.CompassQueryFilterBuilder;
import org.compass.core.CompassSearchSession;
import org.compass.core.CompassSession;
import org.compass.core.CompassSessionFactory;
import org.compass.core.LocalCompassSessionFactory;
import org.compass.core.ResourceFactory;
import org.compass.core.SessionFactoryFactory;
import org.compass.core.cache.first.FirstLevelCache;
import org.compass.core.cache.first.FirstLevelCacheFactory;
import org.compass.core.config.CompassConfiguration;
import org.compass.core.config.CompassEnvironment;
import org.compass.core.config.CompassSettings;
import org.compass.core.config.RuntimeCompassSettings;
import org.compass.core.converter.ConverterLookup;
import org.compass.core.engine.SearchEngineFactory;
import org.compass.core.engine.SearchEngineIndexManager;
import org.compass.core.engine.naming.PropertyNamingStrategy;
import org.compass.core.engine.spellcheck.SearchEngineSpellCheckManager;
import org.compass.core.events.CompassEventManager;
import org.compass.core.events.RebuildEventListener;
import org.compass.core.executor.ExecutorManager;
import org.compass.core.mapping.CompassMapping;
import org.compass.core.metadata.CompassMetaData;
import org.compass.core.spi.InternalCompass;
import org.compass.core.spi.InternalCompassSession;
import at.molindo.elastic.compass.ElasticSearchEngineFactory;
public class DefaultCompass implements InternalCompass {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory
.getLogger(DefaultCompass.class);
private final CompassSettings settings;
private CompassMapping mapping;
private ConverterLookup converterLookup;
private CompassMetaData compassMetaData;
private PropertyNamingStrategy propertyNamingStrategy;
private ExecutorManager executorManager;
private String name;
private boolean duplicate;
private FirstLevelCacheFactory firstLevelCacheFactory;
private SearchEngineFactory searchEngineFactory;
private ShutdownThread shutdownThread;
private boolean debug;
private boolean closed;
private CompassEventManager eventManager;
private CompassSessionFactory sessionFactory;
private LocalCompassSessionFactory localSessionFactory;
public DefaultCompass(CompassMapping mapping, ConverterLookup converterLookup, CompassMetaData compassMetaData, PropertyNamingStrategy propertyNamingStrategy, ExecutorManager executorManager, CompassSettings settings) throws CompassException {
this(mapping, converterLookup, compassMetaData, propertyNamingStrategy, executorManager, settings, false);
}
public DefaultCompass(CompassMapping mapping, ConverterLookup converterLookup, CompassMetaData compassMetaData, PropertyNamingStrategy propertyNamingStrategy, ExecutorManager executorManager, CompassSettings settings, boolean duplicate) {
this(mapping, converterLookup, compassMetaData, propertyNamingStrategy, executorManager, settings, duplicate, new ElasticSearchEngineFactory(propertyNamingStrategy, settings, mapping, executorManager));
}
public DefaultCompass(CompassMapping mapping, ConverterLookup converterLookup, CompassMetaData compassMetaData, PropertyNamingStrategy propertyNamingStrategy, ExecutorManager executorManager, CompassSettings settings, boolean duplicate, SearchEngineFactory searchEngineFactory) throws CompassException {
this.mapping = mapping;
this.converterLookup = converterLookup;
this.compassMetaData = compassMetaData;
this.propertyNamingStrategy = propertyNamingStrategy;
this.executorManager = executorManager;
this.name = settings.getSetting(CompassEnvironment.NAME, "default");
this.settings = settings;
this.duplicate = duplicate;
this.eventManager = new CompassEventManager(this, mapping);
eventManager.configure(settings);
// build the session factory
sessionFactory = SessionFactoryFactory.createSessionFactory(this, settings);
localSessionFactory = SessionFactoryFactory.createLocalSessionFactory(this, settings);
firstLevelCacheFactory = new FirstLevelCacheFactory();
firstLevelCacheFactory.configure(settings);
this.searchEngineFactory = searchEngineFactory;
this.searchEngineFactory.getIndexManager().verifyIndex();
if (!duplicate) {
start();
}
if (settings.getSettingAsBoolean(CompassEnvironment.REGISTER_SHUTDOWN_HOOK, true)) {
shutdownThread = new ShutdownThread(this);
if (log.isDebugEnabled()) {
log.debug("Registering shutdown hook [" + System.identityHashCode(shutdownThread)
+ "]");
}
Runtime.getRuntime().addShutdownHook(shutdownThread);
}
this.debug = settings.getSettingAsBoolean(CompassEnvironment.DEBUG, false);
}
public SearchEngineSpellCheckManager getSpellCheckManager() {
return searchEngineFactory.getSpellCheckManager();
}
@Override
public CompassSettings getSettings() {
return settings;
}
@Override
public CompassMapping getMapping() {
return mapping;
}
@Override
public SearchEngineFactory getSearchEngineFactory() {
return searchEngineFactory;
}
@Override
public PropertyNamingStrategy getPropertyNamingStrategy() {
return propertyNamingStrategy;
}
@Override
public SearchEngineIndexManager getSearchEngineIndexManager() {
return searchEngineFactory.getIndexManager();
}
private void checkClosed() throws IllegalStateException {
if (closed) {
throw new IllegalStateException("Compass already closed");
}
}
public CompassSearchSession openSearchSession() {
CompassSession session = openSession();
session.setReadOnly();
return session;
}
public CompassIndexSession openIndexSession() {
CompassSession session = openSession();
return session;
}
public CompassSession openSession() {
return openSession(true);
}
public CompassSession openSession(boolean allowCreate) {
return openSession(allowCreate, true);
}
public CompassSession openSession(boolean allowCreate, boolean checkClosed) {
if (checkClosed) {
checkClosed();
}
CompassSession session = sessionFactory.getTransactionBoundSession();
if (session != null) {
return new ExistingCompassSession((InternalCompassSession) session);
}
if (!allowCreate) {
return null;
}
FirstLevelCache firstLevelCache = firstLevelCacheFactory.createFirstLevelCache();
RuntimeCompassSettings runtimeSettings = new RuntimeCompassSettings(getSettings());
return new DefaultCompassSession(runtimeSettings, this, searchEngineFactory.openSearchEngine(runtimeSettings), firstLevelCache);
}
public CompassQueryBuilder queryBuilder() throws CompassException {
return new DefaultCompassQueryBuilder(searchEngineFactory.queryBuilder(), this);
}
public CompassQueryFilterBuilder queryFilterBuilder() throws CompassException {
return new DefaultCompassQueryFilterBuilder(searchEngineFactory.queryFilterBuilder(), this);
}
@Override
public CompassSessionFactory getCompassSessionFactory() {
return sessionFactory;
}
@Override
public LocalCompassSessionFactory getLocalCompassSessionFactory() {
return localSessionFactory;
}
@Override
public ResourceFactory getResourceFactory() {
return getSearchEngineFactory().getResourceFactory();
}
public CompassMetaData getMetaData() {
return compassMetaData;
}
public ConverterLookup getConverterLookup() {
return converterLookup;
}
public void clearShutdownHook() {
shutdownThread = null;
}
public void start() {
searchEngineFactory.start();
}
public void stop() {
searchEngineFactory.stop();
}
public void close() {
if (closed) {
return;
}
closed = true;
log.info("Closing Compass [" + name + "]");
if (shutdownThread != null) {
if (log.isDebugEnabled()) {
log.debug("Removing shutdown hook");
}
try {
Runtime.getRuntime().removeShutdownHook(shutdownThread);
} catch (IllegalStateException e) {
// ignore, we are shuttng down
}
}
searchEngineFactory.close();
if (!duplicate) {
executorManager.close();
}
log.info("Closed Compass [" + name + "]");
}
public boolean isClosed() {
return this.closed;
}
@Override
public void addRebuildEventListener(RebuildEventListener rebuildEventListener) {
throw new UnsupportedOperationException();
}
public Compass clone(CompassSettings addedSettings) {
CompassSettings copySettings = settings.copy();
copySettings.addSettings(addedSettings);
return new DefaultCompass(mapping, converterLookup, compassMetaData, propertyNamingStrategy, executorManager, copySettings, true);
}
@Override
public CompassEventManager getEventManager() {
return eventManager;
}
public CompassConfiguration getConfig() {
throw new UnsupportedOperationException();
}
public void rebuild() {
throw new UnsupportedOperationException();
}
/**
* A shutdown hook that closes Compass.
*/
private static class ShutdownThread extends Thread {
private final WeakReference<Compass> compass;
public ShutdownThread(Compass compass) {
this.compass = new WeakReference<Compass>(compass);
}
@Override
public void run() {
Compass compass = this.compass.get();
if (compass != null) {
((DefaultCompass) compass).clearShutdownHook();
if (!compass.isClosed()) {
compass.close();
}
}
}
}
}