package org.compass.core.impl; import java.util.ArrayList; import java.util.List; import javax.naming.NamingException; import javax.naming.Reference; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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.ResourceFactory; import org.compass.core.config.CompassConfiguration; import org.compass.core.config.CompassEnvironment; import org.compass.core.config.CompassSettings; import org.compass.core.converter.ConverterLookup; import org.compass.core.engine.SearchEngineFactory; import org.compass.core.engine.SearchEngineIndexManager; import org.compass.core.engine.SearchEngineOptimizer; 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.transaction.LocalTransactionFactory; import org.compass.core.transaction.TransactionFactory; /** * A wrapper around an actual implemenation of {@link Compass} that allows to rebuild it * after changes that are perfomed on the {@link #getConfig()} configuration. * * @author kimchy */ public class RefreshableCompass implements InternalCompass { private static final Log logger = LogFactory.getLog(RefreshableCompass.class); private final CompassConfiguration config; private volatile InternalCompass compass; private List<RebuildEventListener> rebuildEventListeners = new ArrayList<RebuildEventListener>(); public RefreshableCompass(CompassConfiguration config, InternalCompass compass) { this.config = config; this.compass = compass; } public CompassConfiguration getConfig() { return config; } public synchronized void rebuild() throws CompassException { compass.stop(); config.getSettings().addSettings(compass.getSettings()); InternalCompass rebuiltCompass; try { rebuiltCompass = (InternalCompass) config.buildCompass(); } catch (RuntimeException e) { compass.start(); throw e; } // do the switch Compass oldCompass = compass; compass = rebuiltCompass; oldCompass.getSearchEngineIndexManager().clearCache(); long sleepBeforeClose = getConfig().getSettings().getSettingAsTimeInMillis(CompassEnvironment.Rebuild.SLEEP_BEFORE_CLOSE, CompassEnvironment.Rebuild.DEFAULT_SLEEP_BEFORE_CLOSE); // schedule Compass to be closed if (sleepBeforeClose <= 0) { oldCompass.close(); } else { Thread t = new Thread(new CloseCompassRunnable(oldCompass, sleepBeforeClose), "Close Compass"); t.start(); } for (RebuildEventListener eventListener : rebuildEventListeners) { eventListener.onCompassRebuild(compass); } } public Compass clone(CompassSettings addedSettings) { InternalCompass clonedCompass = (InternalCompass) compass.clone(addedSettings); return new RefreshableCompass(config, clonedCompass); } public synchronized void addRebuildEventListener(RebuildEventListener eventListener) { rebuildEventListeners.add(eventListener); } public synchronized void removeRebuildEventListener(RebuildEventListener eventListener) { rebuildEventListeners.remove(eventListener); } // Delegate Methods public void start() { compass.start(); } public void stop() { compass.stop(); } public CompassSession openSession(boolean allowCreate, boolean checkClosed) { return compass.openSession(allowCreate, checkClosed); } public CompassSession openSession() throws CompassException { return compass.openSession(); } public CompassSearchSession openSearchSession() throws CompassException { return compass.openSearchSession(); } public CompassIndexSession openIndexSession() throws CompassException { return compass.openIndexSession(); } public String getName() { return compass.getName(); } public CompassSettings getSettings() { return compass.getSettings(); } public CompassMapping getMapping() { return compass.getMapping(); } public ExecutorManager getExecutorManager() { return compass.getExecutorManager(); } public CompassMetaData getMetaData() { return compass.getMetaData(); } public SearchEngineFactory getSearchEngineFactory() { return compass.getSearchEngineFactory(); } public TransactionFactory getTransactionFactory() { return compass.getTransactionFactory(); } public LocalTransactionFactory getLocalTransactionFactory() { return compass.getLocalTransactionFactory(); } public ConverterLookup getConverterLookup() { return compass.getConverterLookup(); } public PropertyNamingStrategy getPropertyNamingStrategy() { return compass.getPropertyNamingStrategy(); } public CompassEventManager getEventManager() { return compass.getEventManager(); } public void close() throws CompassException { compass.close(); } public CompassQueryBuilder queryBuilder() throws CompassException { return compass.queryBuilder(); } public CompassQueryFilterBuilder queryFilterBuilder() throws CompassException { return compass.queryFilterBuilder(); } public ResourceFactory getResourceFactory() { return compass.getResourceFactory(); } public SearchEngineOptimizer getSearchEngineOptimizer() { return compass.getSearchEngineOptimizer(); } public SearchEngineIndexManager getSearchEngineIndexManager() { return compass.getSearchEngineIndexManager(); } public SearchEngineSpellCheckManager getSpellCheckManager() { return compass.getSpellCheckManager(); } public boolean isClosed() { return compass.isClosed(); } public Reference getReference() throws NamingException { return compass.getReference(); } private class CloseCompassRunnable implements Runnable { private final Compass compass; private final long timeout; private CloseCompassRunnable(Compass compass, long timeout) { this.compass = compass; this.timeout = timeout; } public void run() { try { Thread.sleep(timeout); } catch (InterruptedException e) { // do nothing } try { compass.close(); } catch (Exception e) { logger.error("Failed to close original Compass after rebuild", e); } } } }