package org.hibernate.boot.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.AssertionFailure;
import org.hibernate.annotations.common.reflection.ClassLoaderDelegate;
import org.hibernate.annotations.common.reflection.ClassLoadingException;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.java.JavaReflectionManager;
import org.hibernate.annotations.common.util.StandardClassLoaderDelegateImpl;
import org.hibernate.boot.AttributeConverterInfo;
import org.hibernate.boot.CacheRegionDefinition;
import org.hibernate.boot.archive.scan.internal.StandardScanOptions;
import org.hibernate.boot.archive.scan.spi.ScanEnvironment;
import org.hibernate.boot.archive.scan.spi.ScanOptions;
import org.hibernate.boot.archive.scan.spi.Scanner;
import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.ClassLoaderAccess;
import org.hibernate.boot.spi.MetadataBuildingOptions;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.jpa.internal.MutableJpaComplianceImpl;
import org.hibernate.jpa.spi.MutableJpaCompliance;
import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.jandex.IndexView;
import org.jboss.logging.Logger;
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
public class BootstrapContextImpl implements BootstrapContext {
private static final Logger log = Logger.getLogger( BootstrapContextImpl.class );
private final StandardServiceRegistry serviceRegistry;
private final MutableJpaCompliance jpaCompliance;
private final TypeConfiguration typeConfiguration;
private final ClassLoaderAccessImpl classLoaderAccess;
private final JavaReflectionManager hcannReflectionManager;
private final ClassmateContext classmateContext;
private final MetadataBuildingOptions metadataBuildingOptions;
private boolean isJpaBootstrap;
private ScanOptions scanOptions;
private ScanEnvironment scanEnvironment;
private Object scannerSetting;
private ArchiveDescriptorFactory archiveDescriptorFactory;
private IndexView jandexView;
private HashMap<String,SQLFunction> sqlFunctionMap;
private ArrayList<AuxiliaryDatabaseObject> auxiliaryDatabaseObjectList;
private HashMap<Class,AttributeConverterInfo> attributeConverterInfoMap;
private ArrayList<CacheRegionDefinition> cacheRegionDefinitions;
public BootstrapContextImpl(
StandardServiceRegistry serviceRegistry,
MetadataBuildingOptions metadataBuildingOptions) {
this.serviceRegistry = serviceRegistry;
this.classmateContext = new ClassmateContext();
this.metadataBuildingOptions = metadataBuildingOptions;
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
this.classLoaderAccess = new ClassLoaderAccessImpl( classLoaderService );
this.hcannReflectionManager = generateHcannReflectionManager();
final StrategySelector strategySelector = serviceRegistry.getService( StrategySelector.class );
final ConfigurationService configService = serviceRegistry.getService( ConfigurationService.class );
this.jpaCompliance = new MutableJpaComplianceImpl( configService.getSettings(), false );
this.scanOptions = new StandardScanOptions(
(String) configService.getSettings().get( AvailableSettings.SCANNER_DISCOVERY ),
false
);
this.scannerSetting = configService.getSettings().get( AvailableSettings.SCANNER );
if ( this.scannerSetting == null ) {
this.scannerSetting = configService.getSettings().get( AvailableSettings.SCANNER_DEPRECATED );
if ( this.scannerSetting != null ) {
DEPRECATION_LOGGER.logDeprecatedScannerSetting();
}
}
this.archiveDescriptorFactory = strategySelector.resolveStrategy(
ArchiveDescriptorFactory.class,
configService.getSettings().get( AvailableSettings.SCANNER_ARCHIVE_INTERPRETER )
);
this.typeConfiguration = new TypeConfiguration();
}
@Override
public StandardServiceRegistry getServiceRegistry() {
return serviceRegistry;
}
@Override
public MutableJpaCompliance getJpaCompliance() {
return jpaCompliance;
}
@Override
public TypeConfiguration getTypeConfiguration() {
return typeConfiguration;
}
@Override
public MetadataBuildingOptions getMetadataBuildingOptions() {
return metadataBuildingOptions;
}
@Override
public boolean isJpaBootstrap() {
return isJpaBootstrap;
}
@Override
public void markAsJpaBootstrap() {
isJpaBootstrap = true;
}
@Override
public ClassLoader getJpaTempClassLoader() {
return classLoaderAccess.getJpaTempClassLoader();
}
@Override
public ClassLoaderAccess getClassLoaderAccess() {
return classLoaderAccess;
}
@Override
public ClassmateContext getClassmateContext() {
return classmateContext;
}
@Override
public ArchiveDescriptorFactory getArchiveDescriptorFactory() {
return archiveDescriptorFactory;
}
@Override
public ScanOptions getScanOptions() {
return scanOptions;
}
@Override
public ScanEnvironment getScanEnvironment() {
return scanEnvironment;
}
@Override
public Object getScanner() {
return scannerSetting;
}
@Override
public ReflectionManager getReflectionManager() {
return hcannReflectionManager;
}
@Override
public IndexView getJandexView() {
return jandexView;
}
@Override
public Map<String, SQLFunction> getSqlFunctions() {
return sqlFunctionMap == null ? Collections.emptyMap() : sqlFunctionMap;
}
@Override
public Collection<AuxiliaryDatabaseObject> getAuxiliaryDatabaseObjectList() {
return auxiliaryDatabaseObjectList == null ? Collections.emptyList() : auxiliaryDatabaseObjectList;
}
@Override
public Collection<AttributeConverterInfo> getAttributeConverters() {
return attributeConverterInfoMap != null
? new ArrayList<>( attributeConverterInfoMap.values() )
: Collections.emptyList();
}
@Override
public Collection<CacheRegionDefinition> getCacheRegionDefinitions() {
return cacheRegionDefinitions == null ? Collections.emptyList() : cacheRegionDefinitions;
}
@Override
public void release() {
classmateContext.release();
classLoaderAccess.release();
scanOptions = null;
scanEnvironment = null;
scannerSetting = null;
archiveDescriptorFactory = null;
jandexView = null;
if ( sqlFunctionMap != null ) {
sqlFunctionMap.clear();
}
if ( auxiliaryDatabaseObjectList != null ) {
auxiliaryDatabaseObjectList.clear();
}
if ( attributeConverterInfoMap != null ) {
attributeConverterInfoMap.clear();
}
if ( cacheRegionDefinitions != null ) {
cacheRegionDefinitions.clear();
}
}
public void addAttributeConverterInfo(AttributeConverterInfo info) {
if ( this.attributeConverterInfoMap == null ) {
this.attributeConverterInfoMap = new HashMap<>();
}
final Object old = this.attributeConverterInfoMap.put( info.getConverterClass(), info );
if ( old != null ) {
throw new AssertionFailure(
String.format(
"AttributeConverter class [%s] registered multiple times",
info.getConverterClass()
)
);
}
}
void injectJpaTempClassLoader(ClassLoader jpaTempClassLoader) {
log.debugf( "Injecting JPA temp ClassLoader [%s] into BootstrapContext; was [%s]", jpaTempClassLoader, this.getJpaTempClassLoader() );
this.classLoaderAccess.injectTempClassLoader( jpaTempClassLoader );
}
void injectScanOptions(ScanOptions scanOptions) {
log.debugf( "Injecting ScanOptions [%s] into BootstrapContext; was [%s]", scanOptions, this.scanOptions );
this.scanOptions = scanOptions;
}
void injectScanEnvironment(ScanEnvironment scanEnvironment) {
log.debugf( "Injecting ScanEnvironment [%s] into BootstrapContext; was [%s]", scanEnvironment, this.scanEnvironment );
this.scanEnvironment = scanEnvironment;
}
void injectScanner(Scanner scanner) {
log.debugf( "Injecting Scanner [%s] into BootstrapContext; was [%s]", scanner, this.scannerSetting );
this.scannerSetting = scanner;
}
void injectArchiveDescriptorFactory(ArchiveDescriptorFactory factory) {
log.debugf( "Injecting ArchiveDescriptorFactory [%s] into BootstrapContext; was [%s]", factory, this.archiveDescriptorFactory );
this.archiveDescriptorFactory = factory;
}
void injectJandexView(IndexView jandexView) {
log.debugf( "Injecting Jandex IndexView [%s] into BootstrapContext; was [%s]", jandexView, this.jandexView );
this.jandexView = jandexView;
}
public void addSqlFunction(String functionName, SQLFunction function) {
if ( this.sqlFunctionMap == null ) {
this.sqlFunctionMap = new HashMap<>();
}
this.sqlFunctionMap.put( functionName, function );
}
public void addAuxiliaryDatabaseObject(AuxiliaryDatabaseObject auxiliaryDatabaseObject) {
if ( this.auxiliaryDatabaseObjectList == null ) {
this.auxiliaryDatabaseObjectList = new ArrayList<>();
}
this.auxiliaryDatabaseObjectList.add( auxiliaryDatabaseObject );
}
public void addCacheRegionDefinition(CacheRegionDefinition cacheRegionDefinition) {
if ( cacheRegionDefinitions == null ) {
cacheRegionDefinitions = new ArrayList<>();
}
cacheRegionDefinitions.add( cacheRegionDefinition );
}
private JavaReflectionManager generateHcannReflectionManager() {
final JavaReflectionManager reflectionManager = new JavaReflectionManager();
reflectionManager.setMetadataProvider( new JPAMetadataProvider( this ) );
reflectionManager.injectClassLoaderDelegate( generateHcannClassLoaderDelegate() );
return reflectionManager;
}
private ClassLoaderDelegate generateHcannClassLoaderDelegate() {
final ClassLoaderService classLoaderService = getServiceRegistry().getService( ClassLoaderService.class );
return new ClassLoaderDelegate() {
@Override
public <T> Class<T> classForName(String className) throws ClassLoadingException {
try {
return classLoaderService.classForName( className );
}
catch (org.hibernate.boot.registry.classloading.spi.ClassLoadingException e) {
return StandardClassLoaderDelegateImpl.INSTANCE.classForName( className );
}
}
};
}
}