1 //$Id: EventListenerConfigurator.java 11251 2007-03-02 08:26:10Z epbernard $
2 package org.hibernate.ejb;
3
4 import java.beans.BeanInfo;
5 import java.beans.Introspector;
6 import java.beans.PropertyDescriptor;
7 import java.lang.reflect.Array;
8 import java.util.ArrayList;
9 import java.util.Enumeration;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.Properties;
13 import java.util.StringTokenizer;
14
15 import org.hibernate.HibernateException;
16 import org.hibernate.MappingException;
17 import org.hibernate.ejb.event.CallbackHandlerConsumer;
18 import org.hibernate.ejb.event.EJB3AutoFlushEventListener;
19 import org.hibernate.ejb.event.EJB3DeleteEventListener;
20 import org.hibernate.ejb.event.EJB3FlushEntityEventListener;
21 import org.hibernate.ejb.event.EJB3FlushEventListener;
22 import org.hibernate.ejb.event.EJB3MergeEventListener;
23 import org.hibernate.ejb.event.EJB3PersistEventListener;
24 import org.hibernate.ejb.event.EJB3PersistOnFlushEventListener;
25 import org.hibernate.ejb.event.EJB3PostDeleteEventListener;
26 import org.hibernate.ejb.event.EJB3PostInsertEventListener;
27 import org.hibernate.ejb.event.EJB3PostLoadEventListener;
28 import org.hibernate.ejb.event.EJB3PostUpdateEventListener;
29 import org.hibernate.ejb.event.EJB3SaveEventListener;
30 import org.hibernate.ejb.event.EJB3SaveOrUpdateEventListener;
31 import org.hibernate.ejb.event.EntityCallbackHandler;
32 import org.hibernate.event.AutoFlushEventListener;
33 import org.hibernate.event.DeleteEventListener;
34 import org.hibernate.event.EventListeners;
35 import org.hibernate.event.FlushEntityEventListener;
36 import org.hibernate.event.FlushEventListener;
37 import org.hibernate.event.MergeEventListener;
38 import org.hibernate.event.PersistEventListener;
39 import org.hibernate.event.PostDeleteEventListener;
40 import org.hibernate.event.PostInsertEventListener;
41 import org.hibernate.event.PostLoadEventListener;
42 import org.hibernate.event.PostUpdateEventListener;
43 import org.hibernate.event.PreDeleteEventListener;
44 import org.hibernate.event.PreInsertEventListener;
45 import org.hibernate.event.PreLoadEventListener;
46 import org.hibernate.event.PreUpdateEventListener;
47 import org.hibernate.event.SaveOrUpdateEventListener;
48 import org.hibernate.mapping.PersistentClass;
49 import org.hibernate.annotations.common.reflection.ReflectionManager;
50 import org.hibernate.secure.JACCPreDeleteEventListener;
51 import org.hibernate.secure.JACCPreInsertEventListener;
52 import org.hibernate.secure.JACCPreLoadEventListener;
53 import org.hibernate.secure.JACCPreUpdateEventListener;
54 import org.hibernate.secure.JACCSecurityListener;
55 import org.hibernate.validator.event.ValidateEventListener;
56
57 /**
58 * @author Emmanuel Bernard
59 */
60 public class EventListenerConfigurator {
61 private static final Object[] READER_METHOD_ARGS = new Object[0];
62
63 private Ejb3Configuration configuration;
64 private boolean isSecurity;
65
66 public EventListenerConfigurator(Ejb3Configuration configuration) {
67 this.configuration = configuration;
68 EventListeners listenerConfig = configuration.getEventListeners();
69
70 //Action event
71 //EJB3-specific ops listeners
72 listenerConfig.setFlushEventListeners( new FlushEventListener[]{EJB3FlushEventListener.INSTANCE} );
73 //EJB3-specific ops listeners
74 listenerConfig.setAutoFlushEventListeners( new AutoFlushEventListener[]{EJB3AutoFlushEventListener.INSTANCE} );
75 listenerConfig.setDeleteEventListeners( new DeleteEventListener[]{new EJB3DeleteEventListener()} );
76 listenerConfig.setFlushEntityEventListeners(
77 new FlushEntityEventListener[]{new EJB3FlushEntityEventListener()}
78 );
79 listenerConfig.setMergeEventListeners( new MergeEventListener[]{new EJB3MergeEventListener()} );
80 listenerConfig.setPersistEventListeners( new PersistEventListener[]{new EJB3PersistEventListener()} );
81 listenerConfig.setPersistOnFlushEventListeners(
82 new PersistEventListener[]{new EJB3PersistOnFlushEventListener()}
83 );
84 listenerConfig.setSaveEventListeners( new SaveOrUpdateEventListener[]{new EJB3SaveEventListener()} );
85 listenerConfig.setSaveOrUpdateEventListeners(
86 new SaveOrUpdateEventListener[]{new EJB3SaveOrUpdateEventListener()}
87 );
88
89 //Pre events
90 listenerConfig.setPreInsertEventListeners(
91 new PreInsertEventListener[]{
92 new JACCPreInsertEventListener(),
93 }
94 );
95 listenerConfig.setPreUpdateEventListeners(
96 new PreUpdateEventListener[]{
97 new JACCPreUpdateEventListener(),
98 }
99 );
100 listenerConfig.setPreDeleteEventListeners(
101 new PreDeleteEventListener[]{
102 new JACCPreDeleteEventListener()
103 }
104 );
105 listenerConfig.setPreLoadEventListeners(
106 new PreLoadEventListener[]{
107 new JACCPreLoadEventListener()
108 }
109 );
110
111 //post events
112 listenerConfig.setPostDeleteEventListeners(
113 new PostDeleteEventListener[]{new EJB3PostDeleteEventListener()}
114 );
115 listenerConfig.setPostInsertEventListeners(
116 new PostInsertEventListener[]{new EJB3PostInsertEventListener()}
117 );
118 listenerConfig.setPostLoadEventListeners(
119 new PostLoadEventListener[]{new EJB3PostLoadEventListener()}
120 );
121 listenerConfig.setPostUpdateEventListeners(
122 new PostUpdateEventListener[]{new EJB3PostUpdateEventListener()}
123 );
124 }
125
126 public void setProperties(Properties properties) {
127 if ( properties.containsKey( HibernatePersistence.JACC_ENABLED ) ) {
128 isSecurity = true;
129 }
130 //override events if needed
131 Enumeration<?> enumeration = properties.propertyNames();
132 while ( enumeration.hasMoreElements() ) {
133 String name = (String) enumeration.nextElement();
134 if ( name.startsWith( HibernatePersistence.EVENT_LISTENER_PREFIX ) ) {
135 String type = name.substring( HibernatePersistence.EVENT_LISTENER_PREFIX.length() + 1 );
136 StringTokenizer st = new StringTokenizer( properties.getProperty( name ), " ,", false );
137 List<String> listeners = new ArrayList<String>();
138 while ( st.hasMoreElements() ) {
139 listeners.add( (String) st.nextElement() );
140 }
141 configuration.setListeners( type, listeners.toArray( new String[ listeners.size() ] ) );
142 }
143 }
144 }
145
146 public void configure() {
147 //TODO exclude pure hbm file classes?
148 //TODO move it to each event listener initialize()?
149 EntityCallbackHandler callbackHandler = new EntityCallbackHandler();
150 configuration.buildMappings(); //needed to get all the classes
151 Iterator classes = configuration.getClassMappings();
152 ReflectionManager reflectionManager = configuration.getHibernateConfiguration().getReflectionManager();
153 while ( classes.hasNext() ) {
154 PersistentClass clazz = (PersistentClass) classes.next();
155 if ( clazz.getClassName() != null ) {
156 //we can have non java class persisted by hibernate
157 try {
158 callbackHandler.add( reflectionManager.classForName( clazz.getClassName(), this.getClass() ), reflectionManager );
159 }
160 catch (ClassNotFoundException e) {
161 throw new MappingException("entity class not found: " + clazz.getNodeName(), e);
162 }
163 }
164 }
165
166 EventListeners listenerConfig = configuration.getEventListeners();
167
168 BeanInfo beanInfo = null;
169 try {
170 beanInfo = Introspector.getBeanInfo( listenerConfig.getClass(), Object.class );
171 PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
172 try {
173 for ( int i = 0, max = pds.length; i < max ; i++ ) {
174 final Object listeners = pds[i].getReadMethod().invoke( listenerConfig, READER_METHOD_ARGS );
175 if ( listeners == null ) {
176 throw new HibernateException( "Listener [" + pds[i].getName() + "] was null" );
177 }
178 if ( listeners instanceof Object[] ) {
179 int securityListenersNbr = 0;
180 Object[] listenersArray = (Object[]) listeners;
181 for ( Object listener : listenersArray ) {
182 if ( listener != null && listener instanceof CallbackHandlerConsumer ) {
183 ( (CallbackHandlerConsumer) listener ).setCallbackHandler( callbackHandler );
184 }
185 if ( listener != null && listener instanceof JACCSecurityListener ) {
186 if ( !isSecurity ) {
187 securityListenersNbr++;
188 }
189 }
190 }
191 if ( !isSecurity ) {
192 Class clazz = pds[i].getReadMethod().getReturnType().getComponentType();
193 Object newArray = Array.newInstance( clazz, listenersArray.length - securityListenersNbr );
194 int index = 0;
195 for ( Object listener : listenersArray ) {
196 if ( ! ( listener != null && listener instanceof JACCSecurityListener ) ) {
197 Array.set( newArray, index++, listener );
198 }
199 }
200 pds[i].getWriteMethod().invoke( listenerConfig, newArray );
201 }
202 }
203 }
204 }
205 catch (HibernateException e) {
206 throw e;
207 }
208 catch (Throwable t) {
209 throw new HibernateException( "Unable to validate listener config", t );
210 }
211 }
212 catch (Exception t) {
213 throw new HibernateException( "Unable to copy listeners", t );
214 }
215 finally {
216 if ( beanInfo != null ) {
217 // release the jdk internal caches everytime to ensure this
218 // plays nicely with destroyable class-loaders
219 Introspector.flushFromCaches( getClass() );
220 }
221 }
222 }
223 }