package org.infinispan.hibernate.search.impl; import java.io.IOException; import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import org.hibernate.search.engine.service.spi.ServiceManager; import org.hibernate.search.engine.service.spi.Startable; import org.hibernate.search.engine.service.spi.Stoppable; import org.hibernate.search.exception.SearchException; import org.hibernate.search.spi.BuildContext; import org.hibernate.search.util.configuration.impl.ConfigurationParseHelper; import org.infinispan.configuration.global.GlobalConfigurationBuilder; import org.infinispan.configuration.global.SerializationConfigurationBuilder; import org.infinispan.configuration.parsing.ConfigurationBuilderHolder; import org.infinispan.hibernate.search.logging.Log; import org.infinispan.hibernate.search.spi.CacheManagerService; import org.infinispan.hibernate.search.util.impl.JNDIHelper; import org.infinispan.lucene.LifecycleCallbacks; import org.infinispan.manager.DefaultCacheManager; import org.infinispan.manager.EmbeddedCacheManager; import org.kohsuke.MetaInfServices; /** * Provides access to Infinispan's CacheManager; one CacheManager is needed for all caches, it can be taken via JNDI or * started by this ServiceProvider; in this case it will also be stopped when no longer needed. * * @author Sanne Grinovero */ @MetaInfServices(CacheManagerService.class) public class DefaultCacheManagerService implements CacheManagerService, Startable, Stoppable { private static final Log log = LoggerFactory.make(); /** * If no configuration is defined an no JNDI lookup name is provided, than a new Infinispan CacheManager will be * started using this configuration. Such a configuration file is provided in Hibernate Search's jar. */ public static final String DEFAULT_INFINISPAN_CONFIGURATION_RESOURCENAME = "default-hibernatesearch-infinispan.xml"; /** * Reuses the same JNDI name from the second level cache implementation based on Infinispan * * @see org.hibernate.cache.infinispan.JndiInfinispanRegionFactory.CACHE_MANAGER_RESOURCE_PROP */ public static final String CACHE_MANAGER_RESOURCE_PROP = "hibernate.search.infinispan.cachemanager_jndiname"; /** * The configuration property to use as key to define a custom configuration for Infinispan. Ignored if * hibernate.search.infinispan.cachemanager_jndiname is defined. */ public static final String INFINISPAN_CONFIGURATION_RESOURCENAME = "hibernate.search.infinispan.configuration_resourcename"; /** * Configuration property to replace the Transport configuration property in Infinispan with a different value, after * the configuration file was parsed. */ public static final String INFINISPAN_TRANSPORT_OVERRIDE_RESOURCENAME = "hibernate.search.infinispan.configuration.transport_override_resourcename"; private EmbeddedCacheManager cacheManager; /** * JNDI retrieved cachemanagers are not started by us, so avoid attempting to close them. */ private volatile boolean manageCacheManager = false; @Override public void start(Properties properties, BuildContext context) { ServiceManager serviceManager = context.getServiceManager(); String name = ConfigurationParseHelper.getString(properties, CACHE_MANAGER_RESOURCE_PROP, null); if (name == null) { // No JNDI lookup configured: start the CacheManager String cfgName = properties.getProperty( INFINISPAN_CONFIGURATION_RESOURCENAME, DEFAULT_INFINISPAN_CONFIGURATION_RESOURCENAME ); final String transportOverrideResource = properties.getProperty(INFINISPAN_TRANSPORT_OVERRIDE_RESOURCENAME); try { InfinispanConfigurationParser ispnConfiguration = new InfinispanConfigurationParser(); ConfigurationBuilderHolder configurationBuilderHolder = ispnConfiguration.parseFile(cfgName, transportOverrideResource, serviceManager); forceExternalizerRegistration(configurationBuilderHolder); cacheManager = new DefaultCacheManager(configurationBuilderHolder, true); manageCacheManager = true; } catch (IOException e) { throw new SearchException( "Could not start Infinispan CacheManager using as configuration file: " + cfgName, e ); } } else { // use the CacheManager via JNDI cacheManager = locateCacheManager(name, JNDIHelper.getJndiProperties(properties, JNDIHelper.HIBERNATE_JNDI_PREFIX)); manageCacheManager = false; } } /** * Do not rely on automatic discovery but enforce the registration of the required Externalizers. */ private void forceExternalizerRegistration(ConfigurationBuilderHolder configurationBuilderHolder) { SerializationConfigurationBuilder serialization = configurationBuilderHolder .getGlobalConfigurationBuilder() .serialization(); LifecycleCallbacks.moduleExternalizers().forEach( (i, e) -> serialization.addAdvancedExternalizer( i, e ) ); } private EmbeddedCacheManager locateCacheManager(String jndiNamespace, Properties jndiProperties) { Context ctx = null; try { ctx = new InitialContext(jndiProperties); return (EmbeddedCacheManager) ctx.lookup(jndiNamespace); } catch (NamingException ne) { String msg = "Unable to retrieve CacheManager from JNDI [" + jndiNamespace + "]"; log.unableToRetrieveCacheManagerFromJndi(jndiNamespace, ne); throw new SearchException(msg); } finally { if (ctx != null) { try { ctx.close(); } catch (NamingException ne) { log.unableToReleaseInitialContext(ne); } } } } @Override public EmbeddedCacheManager getEmbeddedCacheManager() { return cacheManager; } @Override public void stop() { if (cacheManager != null && manageCacheManager) { cacheManager.stop(); } } }