1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.persistence.jpa;
20
21 import com.zaxxer.hikari.HikariConfig;
22 import com.zaxxer.hikari.HikariDataSource;
23 import java.io.ByteArrayInputStream;
24 import java.nio.charset.StandardCharsets;
25 import java.util.Map;
26 import java.util.Objects;
27 import javax.persistence.EntityManagerFactory;
28 import javax.sql.DataSource;
29 import org.apache.syncope.common.keymaster.client.api.model.Domain;
30 import org.apache.syncope.core.persistence.api.DomainRegistry;
31 import org.apache.syncope.core.persistence.jpa.openjpa.ConnectorManagerRemoteCommitListener;
32 import org.apache.syncope.core.persistence.jpa.spring.DomainEntityManagerFactoryBean;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35 import org.springframework.beans.factory.annotation.Qualifier;
36 import org.springframework.beans.factory.config.BeanDefinition;
37 import org.springframework.beans.factory.support.AbstractBeanDefinition;
38 import org.springframework.beans.factory.support.AutowireCandidateQualifier;
39 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
40 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
41 import org.springframework.context.ConfigurableApplicationContext;
42 import org.springframework.core.io.ClassPathResource;
43 import org.springframework.jdbc.datasource.init.DataSourceInitializer;
44 import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
45 import org.springframework.jndi.JndiObjectFactoryBean;
46 import org.springframework.orm.jpa.JpaTransactionManager;
47 import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
48 import org.springframework.transaction.support.TransactionTemplate;
49
50 public class DomainConfFactory implements DomainRegistry {
51
52 protected static final Logger LOG = LoggerFactory.getLogger(DomainConfFactory.class);
53
54 protected final ConfigurableApplicationContext ctx;
55
56 public DomainConfFactory(final ConfigurableApplicationContext ctx) {
57 this.ctx = ctx;
58 }
59
60 protected DefaultListableBeanFactory beanFactory() {
61 return (DefaultListableBeanFactory) ctx.getBeanFactory();
62 }
63
64 protected void unregisterSingleton(final String name) {
65 if (beanFactory().containsSingleton(name)) {
66 beanFactory().destroySingleton(name);
67 }
68 }
69
70 protected void registerSingleton(final String name, final Object bean) {
71 unregisterSingleton(name);
72 beanFactory().registerSingleton(name, bean);
73 }
74
75 protected void unregisterBeanDefinition(final String name) {
76 if (beanFactory().containsBeanDefinition(name)) {
77 beanFactory().removeBeanDefinition(name);
78 }
79 }
80
81 protected void registerBeanDefinition(final String name, final BeanDefinition beanDefinition) {
82 unregisterBeanDefinition(name);
83 beanFactory().registerBeanDefinition(name, beanDefinition);
84 }
85
86 @Override
87 public void register(final Domain domain) {
88 HikariConfig hikariConfig = new HikariConfig();
89 hikariConfig.setDriverClassName(domain.getJdbcDriver());
90 hikariConfig.setJdbcUrl(domain.getJdbcURL());
91 hikariConfig.setUsername(domain.getDbUsername());
92 hikariConfig.setPassword(domain.getDbPassword());
93 hikariConfig.setSchema(domain.getDbSchema());
94 hikariConfig.setTransactionIsolation(domain.getTransactionIsolation().name());
95 hikariConfig.setMaximumPoolSize(domain.getPoolMaxActive());
96 hikariConfig.setMinimumIdle(domain.getPoolMinIdle());
97
98
99 registerBeanDefinition(
100 domain.getKey() + "DataSource",
101 BeanDefinitionBuilder.rootBeanDefinition(JndiObjectFactoryBean.class).
102 addPropertyValue("jndiName", "java:comp/env/jdbc/syncope" + domain.getKey() + "DataSource").
103 addPropertyValue("defaultObject", new HikariDataSource(hikariConfig)).
104 getBeanDefinition());
105 DataSource initedDataSource = beanFactory().getBean(domain.getKey() + "DataSource", DataSource.class);
106
107
108 ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
109 databasePopulator.setContinueOnError(true);
110 databasePopulator.setIgnoreFailedDrops(true);
111 databasePopulator.setSqlScriptEncoding(StandardCharsets.UTF_8.name());
112 databasePopulator.addScript(new ClassPathResource("/audit/" + domain.getAuditSql()));
113 registerSingleton(domain.getKey().toLowerCase() + "ResourceDatabasePopulator", databasePopulator);
114
115
116 DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
117 dataSourceInitializer.setDataSource(initedDataSource);
118 dataSourceInitializer.setEnabled(true);
119 dataSourceInitializer.setDatabasePopulator(databasePopulator);
120 registerSingleton(domain.getKey().toLowerCase() + "DataSourceInitializer", dataSourceInitializer);
121
122
123 OpenJpaVendorAdapter vendorAdapter = new OpenJpaVendorAdapter();
124 vendorAdapter.setShowSql(false);
125 vendorAdapter.setGenerateDdl(true);
126 vendorAdapter.setDatabasePlatform(domain.getDatabasePlatform());
127
128 ConnectorManagerRemoteCommitListener connectorManagerRemoteCommitListener =
129 new ConnectorManagerRemoteCommitListener(domain.getKey());
130
131 BeanDefinitionBuilder emf = BeanDefinitionBuilder.rootBeanDefinition(DomainEntityManagerFactoryBean.class).
132 addPropertyValue("mappingResources", domain.getOrm()).
133 addPropertyValue("persistenceUnitName", domain.getKey()).
134 addPropertyReference("dataSource", domain.getKey() + "DataSource").
135 addPropertyValue("jpaVendorAdapter", vendorAdapter).
136 addPropertyReference("commonEntityManagerFactoryConf", "commonEMFConf").
137 addPropertyValue("connectorManagerRemoteCommitListener", connectorManagerRemoteCommitListener);
138 if (ctx.getEnvironment().containsProperty("openjpaMetaDataFactory")) {
139 emf.addPropertyValue("jpaPropertyMap", Map.of(
140 "openjpa.MetaDataFactory",
141 Objects.requireNonNull(ctx.getEnvironment().getProperty("openjpaMetaDataFactory")).
142 replace("##orm##", domain.getOrm())));
143 }
144 registerBeanDefinition(domain.getKey() + "EntityManagerFactory", emf.getBeanDefinition());
145 beanFactory().getBean(domain.getKey() + "EntityManagerFactory");
146
147
148 AbstractBeanDefinition domainTransactionManager =
149 BeanDefinitionBuilder.rootBeanDefinition(JpaTransactionManager.class).
150 addPropertyReference("entityManagerFactory", domain.getKey() + "EntityManagerFactory").
151 getBeanDefinition();
152 domainTransactionManager.addQualifier(new AutowireCandidateQualifier(Qualifier.class, domain.getKey()));
153 registerBeanDefinition(domain.getKey() + "TransactionManager", domainTransactionManager);
154
155
156 AbstractBeanDefinition domainTransactionTemplate =
157 BeanDefinitionBuilder.rootBeanDefinition(TransactionTemplate.class).
158 addPropertyReference("transactionManager", domain.getKey() + "TransactionManager").
159 getBeanDefinition();
160 registerBeanDefinition(domain.getKey() + "TransactionTemplate", domainTransactionTemplate);
161
162
163 registerBeanDefinition(domain.getKey() + "ContentXML",
164 BeanDefinitionBuilder.rootBeanDefinition(ByteArrayInputStream.class).
165 addConstructorArgValue(domain.getContent().getBytes()).
166 getBeanDefinition());
167
168
169 registerBeanDefinition(domain.getKey() + "KeymasterConfParamsJSON",
170 BeanDefinitionBuilder.rootBeanDefinition(ByteArrayInputStream.class).
171 addConstructorArgValue(domain.getKeymasterConfParams().getBytes()).
172 getBeanDefinition());
173 }
174
175 @Override
176 public void unregister(final String domain) {
177
178 unregisterSingleton(domain + "KeymasterConfParamsJSON");
179 unregisterBeanDefinition(domain + "KeymasterConfParamsJSON");
180
181
182 unregisterSingleton(domain + "ContentXML");
183 unregisterBeanDefinition(domain + "ContentXML");
184
185
186 try {
187 EntityManagerFactory emf = beanFactory().
188 getBean(domain + "EntityManagerFactory", EntityManagerFactory.class);
189 emf.close();
190 } catch (Exception e) {
191 LOG.error("Could not close EntityManagerFactory for Domain {}", domain, e);
192 }
193 unregisterSingleton(domain + "EntityManagerFactory");
194 unregisterBeanDefinition(domain + "EntityManagerFactory");
195
196
197 unregisterSingleton(domain + "TransactionManager");
198 unregisterBeanDefinition(domain + "TransactionManager");
199
200
201 unregisterSingleton(domain.toLowerCase() + "DataSourceInitializer");
202
203
204 unregisterSingleton(domain.toLowerCase() + "ResourceDatabasePopulator");
205
206
207 unregisterSingleton(domain + "DataSource");
208 unregisterBeanDefinition(domain + "DataSource");
209 }
210 }