package org.infinispan.hibernate.search.impl;
import java.io.IOException;
import java.io.InputStream;
import org.hibernate.search.engine.service.classloading.spi.ClassLoaderService;
import org.hibernate.search.engine.service.spi.ServiceManager;
import org.infinispan.commons.util.Util;
import org.infinispan.configuration.parsing.ConfigurationBuilderHolder;
import org.infinispan.configuration.parsing.ParserRegistry;
/**
* The Infinispan configuration is ClassLoader sensitive, this wrapper around the standard Parser is used to allow it to
* find resources in a modular classloading environment.
*
* @author Sanne Grinovero
* @since 4.3
*/
public class InfinispanConfigurationParser {
private final ParserRegistry configurationParser;
private final ClassLoader ispnClassLoadr;
public InfinispanConfigurationParser() {
//This class instance will have visibility on the components we need
ispnClassLoadr = InfinispanConfigurationParser.class.getClassLoader();
configurationParser = new ParserRegistry(ispnClassLoadr);
}
/**
* Resolves an Infinispan configuration file but using the Hibernate Search classloader. The returned Infinispan
* configuration template also overrides Infinispan's runtime classloader to the one of Hibernate Search.
*
* @param filename Infinispan configuration resource name
* @param transportOverrideResource An alternative JGroups configuration file to be injected
* @param serviceManager the ServiceManager to load resources
* @return
* @throws IOException
*/
public ConfigurationBuilderHolder parseFile(String filename, String transportOverrideResource, ServiceManager serviceManager) throws IOException {
ClassLoaderService classLoaderService = serviceManager.requestService(ClassLoaderService.class);
try {
return parseFile(classLoaderService, filename, transportOverrideResource);
} finally {
serviceManager.releaseService(ClassLoaderService.class);
}
}
private ConfigurationBuilderHolder parseFile(ClassLoaderService classLoaderService, String filename, String transportOverrideResource) {
InputStream is = classLoaderService.locateResourceStream(filename);
try {
//Infinispan requires the context ClassLoader to have full visibility on all
//its components and eventual extension points even *during* configuration parsing.
final Thread currentThread = Thread.currentThread();
final ClassLoader originalContextClassLoader = currentThread.getContextClassLoader();
try {
currentThread.setContextClassLoader(ispnClassLoadr);
ConfigurationBuilderHolder builderHolder = configurationParser.parse(is);
//Workaround Infinispan's ClassLoader strategies to bend to our will:
fixClassLoaders(builderHolder);
patchTransportConfiguration(builderHolder, transportOverrideResource);
return builderHolder;
} finally {
currentThread.setContextClassLoader(originalContextClassLoader);
}
} finally {
Util.close(is);
}
}
private void fixClassLoaders(ConfigurationBuilderHolder builderHolder) {
//Global section:
builderHolder.getGlobalConfigurationBuilder().classLoader(ispnClassLoadr);
}
/**
* After having parsed the Infinispan configuration file, we might want to override the specified JGroups
* configuration file.
*
* @param builderHolder
* @param transportOverrideResource The alternative JGroups configuration file to be used, or null
*/
private void patchTransportConfiguration(ConfigurationBuilderHolder builderHolder, String transportOverrideResource) {
if (transportOverrideResource != null) {
builderHolder.getGlobalConfigurationBuilder().transport().addProperty("configurationFile", transportOverrideResource);
}
}
}