1 package ch.elca.el4j.services.persistence.hibernate.entityfinder;
2
3 import java.beans.BeanInfo;
4 import java.beans.Introspector;
5 import java.beans.PropertyDescriptor;
6 import java.lang.reflect.Array;
7 import java.lang.reflect.Field;
8 import java.util.ArrayList;
9 import java.util.Arrays;
10 import java.util.Collection;
11 import java.util.HashSet;
12 import java.util.Iterator;
13 import java.util.Map;
14
15 import javax.persistence.Entity;
16
17 import org.apache.commons.lang.ArrayUtils;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20 import org.hibernate.HibernateException;
21 import org.hibernate.SessionFactory;
22 import org.hibernate.cfg.Configuration;
23 import org.hibernate.ejb.Ejb3Configuration;
24 import org.hibernate.ejb.HibernateEntityManagerFactory;
25 import org.hibernate.ejb.event.CallbackHandlerConsumer;
26 import org.hibernate.event.EventListeners;
27 import org.hibernate.secure.JACCSecurityListener;
28 import org.springframework.beans.factory.InitializingBean;
29 import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
30 import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
31 import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;
32 import org.springframework.util.Assert;
33 import org.springframework.util.StringUtils;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public class EntityDetectorAnnotationSessionFactoryBean extends AnnotationSessionFactoryBean
50 implements InitializingBean {
51
52 private static final Logger s_logger =
53 LoggerFactory.getLogger(EntityDetectorAnnotationSessionFactoryBean.class);
54
55
56
57
58 private String autoDetectEntityPackage[];
59
60
61
62
63
64 private Class<?>[] localAnnotatedClasses;
65
66
67
68
69 private boolean jpaFullSupportEnabled;
70
71
72
73
74
75
76
77
78
79 public void setAutoDetectEntityPackage(String... pack) {
80 autoDetectEntityPackage = pack;
81 }
82
83
84
85
86 protected String[] getAutoDetectEntityPackage() {
87 return autoDetectEntityPackage;
88 }
89
90
91
92
93
94
95
96 public void setAutoDetectAnnotatedPackages(String[] annotatedPackages) {
97 final Package[] packages = Package.getPackages();
98
99 HashSet<String> detectedAnnotatedPackages = new HashSet<String>();
100 for (String prefix : annotatedPackages) {
101 for (Package p : packages) {
102 if (p.getName().startsWith(prefix)) {
103 detectedAnnotatedPackages.add(p.getName());
104 }
105 }
106 }
107 setAnnotatedPackages(detectedAnnotatedPackages.toArray(new String[0]));
108 }
109
110
111
112
113 @Override
114 @SuppressWarnings("unchecked")
115 public void setAnnotatedClasses(Class[] annotatedClasses) {
116 ArrayList<Class> classes;
117 if (!ArrayUtils.isEmpty(annotatedClasses)) {
118 classes = new ArrayList<Class>(Arrays.asList(annotatedClasses));
119 } else {
120 classes = new ArrayList<Class>();
121 }
122 localAnnotatedClasses = (Class[]) classes.toArray(new Class[classes.size()]);
123 super.setAnnotatedClasses(localAnnotatedClasses);
124 }
125
126
127
128
129
130 public Class<?>[] getAnnotatedClasses() {
131 return localAnnotatedClasses;
132 }
133
134
135
136
137
138 public void setJpaFullSupportEnabled(boolean enabled) {
139 jpaFullSupportEnabled = enabled;
140 }
141
142
143
144
145 public boolean isJpaFullSupportEnabled() {
146 return jpaFullSupportEnabled;
147 }
148
149
150
151
152 public void afterPropertiesSet() throws Exception {
153 if (getAutoDetectEntityPackage() != null) {
154 ArrayList<Class<?>> classes = new ArrayList<Class<?>>();;
155 try {
156 ClassLocator cl = new ClassLocator(getAutoDetectEntityPackage());
157 for (ClassLocation loc : cl.getAllClassLocations()) {
158 Class<?> clazz = Class.forName(loc.getClassName());
159 Entity isEntity = (Entity) clazz.getAnnotation(Entity.class);
160 if (isEntity != null) {
161 classes.add(clazz);
162 if (s_logger.isDebugEnabled()) {
163 s_logger.debug("Adding entity " + clazz);
164 }
165 }
166 }
167
168 s_logger.debug("all detected hibernate entities"+
169 StringUtils.arrayToCommaDelimitedString(classes.toArray()));
170
171
172 if (localAnnotatedClasses != null) {
173 classes.addAll(Arrays.asList(localAnnotatedClasses));
174 }
175
176 localAnnotatedClasses = (Class[]) classes.toArray(new Class[classes.size()]);
177 s_logger.debug("number of classes detected:"+localAnnotatedClasses.length);
178 super.setAnnotatedClasses(localAnnotatedClasses);
179
180 } catch (Exception e) {
181 s_logger.error(e.toString());
182 throw new RuntimeException(e);
183 }
184
185
186 }
187 super.afterPropertiesSet();
188 }
189
190
191 protected SessionFactory newSessionFactory(Configuration config) throws HibernateException {
192 if (jpaFullSupportEnabled) {
193 Ejb3Configuration cfg = new Ejb3Configuration();
194
195
196 try {
197 Field listeners = LocalSessionFactoryBean.class.getDeclaredField("eventListeners");
198 listeners.setAccessible(true);
199 Map<?, ?> listenerMap = (Map<?, ?>) listeners.get(this);
200 Configuration newConfig = mergeEventListeners(config, cfg.getHibernateConfiguration(), listenerMap);
201
202 Field f = cfg.getClass().getDeclaredField("cfg");
203 f.setAccessible(true);
204 f.set(cfg, newConfig);
205 DefaultPersistenceUnitManager pum = new DefaultPersistenceUnitManager();
206 pum.setPersistenceXmlLocation("classpath*:META-INF/defaultPersistence.xml");
207 pum.preparePersistenceUnitInfos();
208 Ejb3Configuration configured = cfg.configure(
209 pum.obtainPersistenceUnitInfo("DefaultPersistenceUnit"),
210 null
211 );
212 return configured.getHibernateConfiguration().buildSessionFactory();
213 } catch (Throwable e) {
214 s_logger.debug("Could not load SessionFactory with Ejb3Configuration. "
215 + "Not all JPA Annotations are available!");
216 return super.newSessionFactory(config);
217 }
218 } else {
219 return super.newSessionFactory(config);
220 }
221 }
222
223
224
225
226
227
228
229
230
231 private Configuration mergeEventListeners(Configuration targetConfig, Configuration sourceConfig, Map listenerMap) {
232
233 final Object[] readerMethodArgs = new Object[0];
234
235 EventListeners listenerConfig = targetConfig.getEventListeners();
236 EventListeners secondListenerConfig = sourceConfig.getEventListeners();
237
238 BeanInfo beanInfo = null;
239 try {
240 if (!listenerConfig.getClass().equals(secondListenerConfig.getClass())) {
241 throw new HibernateException("Listeners are not of the same type!");
242 }
243
244 beanInfo = Introspector.getBeanInfo(listenerConfig.getClass(), Object.class);
245 PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
246 try {
247 int i = 0;
248 for (int max = pds.length; i < max; i++) {
249
250 final Object listeners = pds[i].getReadMethod().invoke(secondListenerConfig, readerMethodArgs);
251 if (listeners == null) {
252 throw new HibernateException("Listener [" + pds[i].getName() + "] was null");
253 }
254 if (listeners instanceof Object[]) {
255
256
257 pds[i].getWriteMethod().invoke(listenerConfig, listeners);
258 }
259 }
260 } catch (HibernateException e) {
261 throw e;
262 } catch (Throwable t) {
263 throw new HibernateException("Unable to validate listener config", t);
264 }
265 } catch (Exception t) {
266 throw new HibernateException("Unable to copy listeners", t);
267 } finally {
268 if (beanInfo != null) {
269
270
271 Introspector.flushFromCaches(getClass());
272 }
273 }
274 if (listenerMap != null) {
275
276 for (Iterator<?> it = listenerMap.entrySet().iterator(); it.hasNext();) {
277 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it.next();
278 Assert.isTrue(entry.getKey() instanceof String, "Event listener key needs to be of type String");
279 String listenerType = (String) entry.getKey();
280 Object listenerObject = entry.getValue();
281 if (listenerObject instanceof Collection) {
282 Collection<?> listeners = (Collection<?>) listenerObject;
283 EventListeners listenerRegistry = targetConfig.getEventListeners();
284 Object[] listenerArray = (Object[]) Array.newInstance(
285 listenerRegistry.getListenerClassFor(listenerType),
286 listeners.size());
287 listenerArray = listeners.toArray(listenerArray);
288 targetConfig.setListeners(listenerType, listenerArray);
289 } else {
290 targetConfig.setListener(listenerType, listenerObject);
291 }
292 }
293 }
294 return targetConfig;
295 }
296
297 }