1 /*
2  * Copyright 2014-2020 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.springframework.data.jpa.repository.support;
17
18 import static org.springframework.data.jpa.util.BeanDefinitionUtils.*;
19
20 import javax.persistence.EntityManager;
21 import javax.persistence.EntityManagerFactory;
22
23 import org.springframework.beans.BeansException;
24 import org.springframework.beans.factory.BeanFactory;
25 import org.springframework.beans.factory.annotation.Qualifier;
26 import org.springframework.beans.factory.config.BeanDefinition;
27 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
28 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
29 import org.springframework.beans.factory.support.AbstractBeanDefinition;
30 import org.springframework.beans.factory.support.AutowireCandidateQualifier;
31 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
32 import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
33 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
34 import org.springframework.core.Ordered;
35 import org.springframework.data.jpa.util.BeanDefinitionUtils.EntityManagerFactoryBeanDefinition;
36 import org.springframework.orm.jpa.SharedEntityManagerCreator;
37
38 /**
39  * {@link BeanFactoryPostProcessor} to register a {@link SharedEntityManagerCreator} for every
40  * {@link EntityManagerFactory} bean definition found in the application context to enable autowiring
41  * {@link EntityManager} instances into constructor arguments. Adds the {@link EntityManagerFactory} bean name as
42  * qualifier to the {@link EntityManager} {@link BeanDefinition} to enable explicit references in case of multiple
43  * {@link EntityManagerFactory} instances.
44  *
45  * @author Oliver Gierke
46  */

47 public class EntityManagerBeanDefinitionRegistrarPostProcessor implements BeanFactoryPostProcessor, Ordered {
48
49     /* 
50      * (non-Javadoc)
51      * @see org.springframework.core.Ordered#getOrder()
52      */

53     @Override
54     public int getOrder() {
55         return Ordered.HIGHEST_PRECEDENCE + 10;
56     }
57
58     /* 
59      * (non-Javadoc)
60      * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
61      */

62     @Override
63     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
64
65         if (!ConfigurableListableBeanFactory.class.isInstance(beanFactory)) {
66             return;
67         }
68
69         ConfigurableListableBeanFactory factory = (ConfigurableListableBeanFactory) beanFactory;
70
71         for (EntityManagerFactoryBeanDefinition definition : getEntityManagerFactoryBeanDefinitions(factory)) {
72
73             BeanFactory definitionFactory = definition.getBeanFactory();
74
75             if (!(definitionFactory instanceof BeanDefinitionRegistry)) {
76                 continue;
77             }
78
79             BeanDefinitionRegistry definitionRegistry = (BeanDefinitionRegistry) definitionFactory;
80
81             BeanDefinitionBuilder builder = BeanDefinitionBuilder
82                     .rootBeanDefinition("org.springframework.orm.jpa.SharedEntityManagerCreator");
83             builder.setFactoryMethod("createSharedEntityManager");
84             builder.addConstructorArgReference(definition.getBeanName());
85
86             AbstractBeanDefinition emBeanDefinition = builder.getRawBeanDefinition();
87
88             emBeanDefinition.addQualifier(new AutowireCandidateQualifier(Qualifier.class, definition.getBeanName()));
89             emBeanDefinition.setScope(definition.getBeanDefinition().getScope());
90             emBeanDefinition.setSource(definition.getBeanDefinition().getSource());
91             emBeanDefinition.setLazyInit(true);
92
93             BeanDefinitionReaderUtils.registerWithGeneratedName(emBeanDefinition, definitionRegistry);
94         }
95     }
96 }
97