/* * JBoss, Home of Professional Open Source * Copyright 2009 Red Hat Inc. and/or its affiliates and other * contributors as indicated by the @author tags. All rights reserved. * See the copyright.txt in the distribution for a full listing of * individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.infinispan.query.impl; import java.util.Map; import java.util.Properties; import java.util.TreeMap; import org.hibernate.search.cfg.spi.SearchConfiguration; import org.hibernate.search.spi.SearchFactoryBuilder; import org.hibernate.search.spi.SearchFactoryIntegrator; import org.infinispan.Cache; import org.infinispan.config.Configuration; import org.infinispan.config.FluentConfiguration.CustomInterceptorPosition; import org.infinispan.factories.ComponentRegistry; import org.infinispan.interceptors.InterceptorChain; import org.infinispan.interceptors.base.CommandInterceptor; import org.infinispan.interceptors.locking.NonTransactionalLockingInterceptor; import org.infinispan.interceptors.locking.OptimisticLockingInterceptor; import org.infinispan.interceptors.locking.PessimisticLockingInterceptor; import org.infinispan.lifecycle.AbstractModuleLifecycle; import org.infinispan.query.CommandInitializer; import org.infinispan.query.backend.LocalQueryInterceptor; import org.infinispan.query.backend.QueryInterceptor; import org.infinispan.query.backend.SearchableCacheConfiguration; import org.infinispan.query.clustered.QueryBox; import org.infinispan.query.logging.Log; import org.infinispan.transaction.LockingMode; import org.infinispan.util.logging.LogFactory; /** * Lifecycle of the Query module: initializes the Hibernate Search engine and shuts it down * at cache stop. * * @author Sanne Grinovero <sanne@hibernate.org> (C) 2011 Red Hat Inc. */ public class LifecycleManager extends AbstractModuleLifecycle { private static final Log log = LogFactory.getLog(LifecycleManager.class, Log.class); private final Map<String,SearchFactoryIntegrator> searchFactoriesToShutdown = new TreeMap<String,SearchFactoryIntegrator>(); /** * Registers the Search interceptor in the cache before it gets started */ @Override public void cacheStarting(ComponentRegistry cr, Configuration configuration, String cacheName) { Configuration cfg = cr.getComponent(Configuration.class); if (cfg.isIndexingEnabled()) { log.registeringQueryInterceptor(); SearchFactoryIntegrator searchFactory = getSearchFactory(cfg.getIndexingProperties(), cr); createQueryInterceptorIfNeeded(cr, cfg, searchFactory); } } private void createQueryInterceptorIfNeeded(ComponentRegistry cr, Configuration cfg, SearchFactoryIntegrator searchFactory) { QueryInterceptor queryInterceptor = cr.getComponent(QueryInterceptor.class); if (queryInterceptor == null) { queryInterceptor = buildQueryInterceptor(cfg, searchFactory); cr.registerComponent(queryInterceptor, QueryInterceptor.class); CustomInterceptorPosition customInterceptorPosition = cfg.fluent() .customInterceptors() .add(queryInterceptor); if (!cfg.isTransactionalCache()) { customInterceptorPosition.after(NonTransactionalLockingInterceptor.class); } else if (cfg.getTransactionLockingMode() == LockingMode.OPTIMISTIC) { customInterceptorPosition.after(OptimisticLockingInterceptor.class); } else { customInterceptorPosition.after(PessimisticLockingInterceptor.class); } } } private QueryInterceptor buildQueryInterceptor(Configuration cfg, SearchFactoryIntegrator searchFactory) { if ( cfg.isIndexLocalOnly() ) { return new LocalQueryInterceptor(searchFactory); } else { return new QueryInterceptor(searchFactory); } } @Override public void cacheStarted(ComponentRegistry cr, String cacheName) { Configuration configuration = cr.getComponent(Configuration.class); boolean indexingEnabled = configuration.isIndexingEnabled(); if ( ! indexingEnabled ) { if ( verifyChainContainsQueryInterceptor(cr) ) { throw new IllegalStateException( "It was NOT expected to find the Query interceptor registered in the InterceptorChain as indexing was disabled, but it was found" ); } return; } if ( ! verifyChainContainsQueryInterceptor(cr) ) { throw new IllegalStateException( "It was expected to find the Query interceptor registered in the InterceptorChain but it wasn't found" ); } // initializing the query module command initializer. we can t inject Cache with @inject in there Cache<?, ?> cache = cr.getComponent(Cache.class); CommandInitializer initializer = cr.getComponent(CommandInitializer.class); initializer.setCache(cache); QueryBox queryBox = new QueryBox(); queryBox.setCache(cache.getAdvancedCache()); cr.registerComponent(queryBox, QueryBox.class); } private boolean verifyChainContainsQueryInterceptor(ComponentRegistry cr) { InterceptorChain interceptorChain = cr.getComponent(InterceptorChain.class); CommandInterceptor chainElement = interceptorChain.getFirstInChain(); if (chainElement instanceof QueryInterceptor) { return true; } while (chainElement.hasNext()) { chainElement = chainElement.getNext(); if (chainElement instanceof QueryInterceptor) { return true; } } return false; } private SearchFactoryIntegrator getSearchFactory(Properties indexingProperties, ComponentRegistry cr) { SearchFactoryIntegrator searchFactory = cr.getComponent(SearchFactoryIntegrator.class); //defend against multiple initialization: if (searchFactory==null) { // Set up the search factory for Hibernate Search first. SearchConfiguration config = new SearchableCacheConfiguration(new Class[0], indexingProperties); searchFactory = new SearchFactoryBuilder().configuration(config).buildSearchFactory(); cr.registerComponent(searchFactory, SearchFactoryIntegrator.class); } return searchFactory; } @Override public void cacheStopping(ComponentRegistry cr, String cacheName) { //TODO move this to cacheStopped event (won't work right now as the ComponentRegistry is half empty at that point: ISPN-1006) SearchFactoryIntegrator searchFactoryImplementor = cr.getComponent(SearchFactoryIntegrator.class); if (searchFactoryImplementor != null) { searchFactoriesToShutdown.put(cacheName, searchFactoryImplementor); } } @Override public void cacheStopped(ComponentRegistry cr, String cacheName) { SearchFactoryIntegrator searchFactoryIntegrator = searchFactoriesToShutdown.remove(cacheName); if (searchFactoryIntegrator != null) { searchFactoryIntegrator.close(); } } }