1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.orm.hibernate4;
18
19 import java.io.IOException;
20 import java.lang.annotation.Annotation;
21 import java.lang.reflect.Method;
22 import java.util.Properties;
23 import java.util.Set;
24 import java.util.TreeSet;
25 import javax.persistence.AttributeConverter;
26 import javax.persistence.Embeddable;
27 import javax.persistence.Entity;
28 import javax.persistence.MappedSuperclass;
29 import javax.sql.DataSource;
30 import javax.transaction.TransactionManager;
31
32 import org.hibernate.HibernateException;
33 import org.hibernate.MappingException;
34 import org.hibernate.SessionFactory;
35 import org.hibernate.cache.spi.RegionFactory;
36 import org.hibernate.cfg.AvailableSettings;
37 import org.hibernate.cfg.Configuration;
38 import org.hibernate.cfg.Environment;
39 import org.hibernate.cfg.Settings;
40 import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory;
41 import org.hibernate.service.ServiceRegistry;
42
43 import org.springframework.core.io.Resource;
44 import org.springframework.core.io.ResourceLoader;
45 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
46 import org.springframework.core.io.support.ResourcePatternResolver;
47 import org.springframework.core.io.support.ResourcePatternUtils;
48 import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
49 import org.springframework.core.type.classreading.MetadataReader;
50 import org.springframework.core.type.classreading.MetadataReaderFactory;
51 import org.springframework.core.type.filter.AnnotationTypeFilter;
52 import org.springframework.core.type.filter.TypeFilter;
53 import org.springframework.transaction.jta.JtaTransactionManager;
54 import org.springframework.util.Assert;
55 import org.springframework.util.ClassUtils;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 @SuppressWarnings("serial")
80 public class LocalSessionFactoryBuilder extends Configuration {
81
82 private static final String RESOURCE_PATTERN = "/**/*.class";
83
84 private static final String PACKAGE_INFO_SUFFIX = ".package-info";
85
86 private static final TypeFilter[] DEFAULT_ENTITY_TYPE_FILTERS = new TypeFilter[] {
87 new AnnotationTypeFilter(Entity.class, false),
88 new AnnotationTypeFilter(Embeddable.class, false),
89 new AnnotationTypeFilter(MappedSuperclass.class, false)};
90
91
92 private static TypeFilter converterTypeFilter;
93
94 static {
95 try {
96 @SuppressWarnings("unchecked")
97 Class<? extends Annotation> converterAnnotation = (Class<? extends Annotation>)
98 ClassUtils.forName("javax.persistence.Converter", LocalSessionFactoryBuilder.class.getClassLoader());
99 converterTypeFilter = new AnnotationTypeFilter(converterAnnotation, false);
100 }
101 catch (ClassNotFoundException ex) {
102
103 }
104 }
105
106
107 private final ResourcePatternResolver resourcePatternResolver;
108
109 private RegionFactory cacheRegionFactory;
110
111 private TypeFilter[] entityTypeFilters = DEFAULT_ENTITY_TYPE_FILTERS;
112
113
114
115
116
117
118
119 public LocalSessionFactoryBuilder(DataSource dataSource) {
120 this(dataSource, new PathMatchingResourcePatternResolver());
121 }
122
123
124
125
126
127
128
129 public LocalSessionFactoryBuilder(DataSource dataSource, ClassLoader classLoader) {
130 this(dataSource, new PathMatchingResourcePatternResolver(classLoader));
131 }
132
133
134
135
136
137
138
139 @SuppressWarnings("deprecation")
140 public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader) {
141 getProperties().put(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName());
142 if (dataSource != null) {
143 getProperties().put(Environment.DATASOURCE, dataSource);
144 }
145
146 getProperties().put(AvailableSettings.APP_CLASSLOADER, resourceLoader.getClassLoader());
147 this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
148 }
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164 public LocalSessionFactoryBuilder setJtaTransactionManager(Object jtaTransactionManager) {
165 Assert.notNull(jtaTransactionManager, "Transaction manager reference must not be null");
166 if (jtaTransactionManager instanceof JtaTransactionManager) {
167 boolean webspherePresent = ClassUtils.isPresent("com.ibm.wsspi.uow.UOWManager", getClass().getClassLoader());
168 if (webspherePresent) {
169 getProperties().put(AvailableSettings.JTA_PLATFORM,
170 ConfigurableJtaPlatform.getJtaPlatformBasePackage() + "internal.WebSphereExtendedJtaPlatform");
171 }
172 else {
173 JtaTransactionManager jtaTm = (JtaTransactionManager) jtaTransactionManager;
174 if (jtaTm.getTransactionManager() == null) {
175 throw new IllegalArgumentException(
176 "Can only apply JtaTransactionManager which has a TransactionManager reference set");
177 }
178 getProperties().put(AvailableSettings.JTA_PLATFORM,
179 new ConfigurableJtaPlatform(jtaTm.getTransactionManager(), jtaTm.getUserTransaction(),
180 jtaTm.getTransactionSynchronizationRegistry()).getJtaPlatformProxy());
181 }
182 }
183 else if (jtaTransactionManager instanceof TransactionManager) {
184 getProperties().put(AvailableSettings.JTA_PLATFORM,
185 new ConfigurableJtaPlatform((TransactionManager) jtaTransactionManager, null, null).getJtaPlatformProxy());
186 }
187 else {
188 throw new IllegalArgumentException(
189 "Unknown transaction manager type: " + jtaTransactionManager.getClass().getName());
190 }
191 getProperties().put(AvailableSettings.TRANSACTION_STRATEGY, new CMTTransactionFactory());
192 return this;
193 }
194
195
196
197
198
199
200
201
202
203 public LocalSessionFactoryBuilder setMultiTenantConnectionProvider(Object multiTenantConnectionProvider) {
204 getProperties().put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
205 return this;
206 }
207
208
209
210
211
212
213
214 public LocalSessionFactoryBuilder setCurrentTenantIdentifierResolver(Object currentTenantIdentifierResolver) {
215 getProperties().put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver);
216 return this;
217 }
218
219
220
221
222
223
224
225
226
227 public LocalSessionFactoryBuilder setCacheRegionFactory(RegionFactory cacheRegionFactory) {
228 this.cacheRegionFactory = cacheRegionFactory;
229 return this;
230 }
231
232
233
234
235
236
237
238
239
240 public LocalSessionFactoryBuilder setEntityTypeFilters(TypeFilter... entityTypeFilters) {
241 this.entityTypeFilters = entityTypeFilters;
242 return this;
243 }
244
245
246
247
248
249
250 public LocalSessionFactoryBuilder addAnnotatedClasses(Class<?>... annotatedClasses) {
251 for (Class<?> annotatedClass : annotatedClasses) {
252 addAnnotatedClass(annotatedClass);
253 }
254 return this;
255 }
256
257
258
259
260
261
262 public LocalSessionFactoryBuilder addPackages(String... annotatedPackages) {
263 for (String annotatedPackage : annotatedPackages) {
264 addPackage(annotatedPackage);
265 }
266 return this;
267 }
268
269
270
271
272
273
274
275 public LocalSessionFactoryBuilder scanPackages(String... packagesToScan) throws HibernateException {
276 Set<String> entityClassNames = new TreeSet<String>();
277 Set<String> converterClassNames = new TreeSet<String>();
278 Set<String> packageNames = new TreeSet<String>();
279 try {
280 for (String pkg : packagesToScan) {
281 String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
282 ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN;
283 Resource[] resources = this.resourcePatternResolver.getResources(pattern);
284 MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
285 for (Resource resource : resources) {
286 if (resource.isReadable()) {
287 MetadataReader reader = readerFactory.getMetadataReader(resource);
288 String className = reader.getClassMetadata().getClassName();
289 if (matchesEntityTypeFilter(reader, readerFactory)) {
290 entityClassNames.add(className);
291 }
292 else if (converterTypeFilter != null && converterTypeFilter.match(reader, readerFactory)) {
293 converterClassNames.add(className);
294 }
295 else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
296 packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
297 }
298 }
299 }
300 }
301 }
302 catch (IOException ex) {
303 throw new MappingException("Failed to scan classpath for unlisted classes", ex);
304 }
305 try {
306 ClassLoader cl = this.resourcePatternResolver.getClassLoader();
307 for (String className : entityClassNames) {
308 addAnnotatedClass(cl.loadClass(className));
309 }
310 for (String className : converterClassNames) {
311 ConverterRegistrationDelegate.registerConverter(this, cl.loadClass(className));
312 }
313 for (String packageName : packageNames) {
314 addPackage(packageName);
315 }
316 }
317 catch (ClassNotFoundException ex) {
318 throw new MappingException("Failed to load annotated classes from classpath", ex);
319 }
320 return this;
321 }
322
323
324
325
326
327 private boolean matchesEntityTypeFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException {
328 if (this.entityTypeFilters != null) {
329 for (TypeFilter filter : this.entityTypeFilters) {
330 if (filter.match(reader, readerFactory)) {
331 return true;
332 }
333 }
334 }
335 return false;
336 }
337
338
339
340
341 @Override
342 public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) throws HibernateException {
343 Settings settings = super.buildSettings(props, serviceRegistry);
344 if (this.cacheRegionFactory != null) {
345 try {
346 Method setRegionFactory = Settings.class.getDeclaredMethod("setRegionFactory", RegionFactory.class);
347 setRegionFactory.setAccessible(true);
348 setRegionFactory.invoke(settings, this.cacheRegionFactory);
349 }
350 catch (Exception ex) {
351 throw new IllegalStateException("Failed to invoke Hibernate's setRegionFactory method", ex);
352 }
353 }
354 return settings;
355 }
356
357
358
359
360 @Override
361 @SuppressWarnings("deprecation")
362 public SessionFactory buildSessionFactory() throws HibernateException {
363 ClassLoader appClassLoader = (ClassLoader) getProperties().get(AvailableSettings.APP_CLASSLOADER);
364 Thread currentThread = Thread.currentThread();
365 ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
366 boolean overrideClassLoader =
367 (appClassLoader != null && !appClassLoader.equals(threadContextClassLoader));
368 if (overrideClassLoader) {
369 currentThread.setContextClassLoader(appClassLoader);
370 }
371 try {
372 return super.buildSessionFactory();
373 }
374 finally {
375 if (overrideClassLoader) {
376 currentThread.setContextClassLoader(threadContextClassLoader);
377 }
378 }
379 }
380
381
382
383
384
385 private static class ConverterRegistrationDelegate {
386
387 @SuppressWarnings("unchecked")
388 public static void registerConverter(Configuration config, Class<?> converterClass) {
389 config.addAttributeConverter((Class<? extends AttributeConverter<?, ?>>) converterClass);
390 }
391 }
392
393 }