All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.foreach.across.modules.hibernate.config.ModuleSettingsRegistrar Maven / Gradle / Ivy

There is a newer version: 4.5.1
Show newest version
/*
 * Copyright 2014 the original author or authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.foreach.across.modules.hibernate.config;

import com.foreach.across.core.AcrossModule;
import com.foreach.across.core.annotations.Module;
import com.foreach.across.core.context.AcrossListableBeanFactory;
import com.foreach.across.core.context.info.AcrossContextInfo;
import com.foreach.across.core.context.info.AcrossModuleInfo;
import com.foreach.across.modules.hibernate.AbstractHibernatePackageModule;
import com.foreach.across.modules.hibernate.AcrossHibernateModuleSettings;
import com.foreach.across.modules.hibernate.extensions.HibernatePersistenceContextInViewConfiguration;
import com.foreach.across.modules.hibernate.jpa.AcrossHibernateJpaModule;
import com.foreach.across.modules.hibernate.jpa.AcrossHibernateJpaModuleSettings;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.transaction.PlatformTransactionManager;

/**
 * Creates the {@link com.foreach.across.modules.hibernate.AcrossHibernateModuleSettings} as early as possible,
 * and registers it as a singleton named moduleSettings in the {@link  BeanFactory}.
 *
 * @author Arne Vandamme
 * @since 3.0.0
 */
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ModuleSettingsRegistrar implements ImportSelector, BeanFactoryAware, EnvironmentAware
{
	public static final String BEAN_NAME = "moduleSettings";

	private Environment environment;
	private BeanFactory beanFactory;

	@Override
	public void setEnvironment( Environment environment ) {
		this.environment = environment;
	}

	@Override
	public void setBeanFactory( BeanFactory beanFactory ) throws BeansException {
		this.beanFactory = beanFactory;
	}

	@Override
	public final String[] selectImports( AnnotationMetadata importingClassMetadata ) {
		AcrossListableBeanFactory lbf = (AcrossListableBeanFactory) beanFactory;

		String beanName = AcrossModule.CURRENT_MODULE + "Settings";
		AcrossHibernateModuleSettings moduleSettings = new ModuleSettingsFactory(
				lbf.getParentBeanFactory().getBean( AcrossContextInfo.class ),
				(AbstractHibernatePackageModule) lbf.getBean( AcrossModule.CURRENT_MODULE ),
				environment
		).createInstance();

		if ( !lbf.containsBeanDefinition( beanName ) ) {
			GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
			beanDefinition.setBeanClass( moduleSettings.getClass() );
			beanDefinition.setPrimary( true );
			beanDefinition.addQualifier(
					new AutowireCandidateQualifier( Module.class.getName(), AcrossModule.CURRENT_MODULE )
			);
			lbf.registerBeanDefinition( beanName, beanDefinition );
		}

		lbf.registerSingleton( beanName, moduleSettings );
		lbf.registerAlias( beanName, BEAN_NAME );

		return settingsDependantImports();
	}

	protected String[] settingsDependantImports() {
		return new String[] { HibernatePersistenceContextInViewConfiguration.class.getName() };
	}

	@RequiredArgsConstructor
	static class ModuleSettingsFactory
	{
		private final AcrossContextInfo contextInfo;
		private final AbstractHibernatePackageModule currentModule;
		private final Environment environment;

		@SneakyThrows
		AcrossHibernateModuleSettings createInstance() {
			AcrossHibernateModuleSettings moduleSettings = currentModule.createSettings();
			applyDefaultValues( moduleSettings );

			if ( isDefaultHibernateModule() ) {
				bindProperties( "spring.jpa", moduleSettings );
				bindProperties( "spring.jpa.hibernate", moduleSettings.getHibernate() );
				bindProperties( "spring.transaction", moduleSettings.getTransactionProperties() );
				moduleSettings.getApplicationModule().setRepositoryScan(
						environment.getProperty( "spring.data.jpa.repositories.enabled", boolean.class,
						                         moduleSettings.getApplicationModule().isRepositoryScan() )
				);
			}

			String modulePrefix = currentModule.getPropertiesPrefix();
			bindProperties( modulePrefix, moduleSettings );
			bindProperties( modulePrefix + ".transaction", moduleSettings.getTransactionProperties() );
			bindProperties( modulePrefix + ".hibernate", moduleSettings.getHibernate() );
			bindProperties( modulePrefix + ".application", moduleSettings.getApplicationModule() );

			return moduleSettings;
		}

		private void bindProperties( String prefix, Object target ) {
			Binder binder = Binder.get( environment );
			binder.bind( prefix, Bindable.ofInstance( target ) );
		}

		/**
		 * Configure the default values based on the context we're running in.
		 * If a dynamic application module is present, and we are the original JPA module as well
		 * as the only one, scan the application module for entities automatically.
		 */
		private void applyDefaultValues( AcrossHibernateModuleSettings moduleSettings ) {
			boolean scanDefaults = isDefaultHibernateModule() && isSingleHibernateModule();

			moduleSettings.setDataSource( currentModule.getDataSourceName() );
			moduleSettings.getApplicationModule().setEntityScan( scanDefaults );
			moduleSettings.getApplicationModule().setRepositoryScan( scanDefaults );
			moduleSettings.setGenerateDdl( false );
			moduleSettings.getHibernate().setDdlAuto( "none" );

			if ( moduleSettings instanceof AcrossHibernateJpaModuleSettings ) {
				final AcrossHibernateJpaModuleSettings jpaModuleSettings = (AcrossHibernateJpaModuleSettings) moduleSettings;
				jpaModuleSettings.setPersistenceUnitName( currentModule.getName() );

				if ( isSingleHibernateModule()
						&& BeanFactoryUtils.beansOfTypeIncludingAncestors( contextInfo.getApplicationContext(),
						                                                   PlatformTransactionManager.class ).isEmpty() ) {
					LOG.trace(
							"Switching to default primary as this is the only AcrossHibernateJpaModule and there are no other transaction managers" );
					jpaModuleSettings.setPrimary( true );
				}
			}
		}

		private boolean isDefaultHibernateModule() {
			return AcrossHibernateJpaModule.NAME.equals( currentModule.getName() );
		}

		private boolean isSingleHibernateModule() {
			return contextInfo.getModules()
			                  .stream()
			                  .map( AcrossModuleInfo::getModule )
			                  .filter( AbstractHibernatePackageModule.class::isInstance )
			                  .count() == 1;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy