KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > event > def > DefaultSaveOrUpdateEventListener


1 // $Id: DefaultSaveOrUpdateEventListener.java,v 1.12 2005/07/20 07:16:33 oneovthafew Exp $
2
package org.hibernate.event.def;
3
4 import java.io.Serializable JavaDoc;
5
6 import org.apache.commons.logging.Log;
7 import org.apache.commons.logging.LogFactory;
8 import org.hibernate.AssertionFailure;
9 import org.hibernate.EntityMode;
10 import org.hibernate.HibernateException;
11 import org.hibernate.LockMode;
12 import org.hibernate.PersistentObjectException;
13 import org.hibernate.TransientObjectException;
14 import org.hibernate.classic.Lifecycle;
15 import org.hibernate.engine.Cascade;
16 import org.hibernate.engine.CascadingAction;
17 import org.hibernate.engine.EntityEntry;
18 import org.hibernate.engine.EntityKey;
19 import org.hibernate.engine.SessionFactoryImplementor;
20 import org.hibernate.engine.SessionImplementor;
21 import org.hibernate.engine.Status;
22 import org.hibernate.event.EventSource;
23 import org.hibernate.event.SaveOrUpdateEvent;
24 import org.hibernate.event.SaveOrUpdateEventListener;
25 import org.hibernate.persister.entity.EntityPersister;
26 import org.hibernate.pretty.MessageHelper;
27 import org.hibernate.proxy.HibernateProxy;
28
29 /**
30  * Defines the default update event listener used by hibernate for updating
31  * transient entities in response to generated update events.
32  *
33  * @author Steve Ebersole, Gavin King
34  */

35 public class DefaultSaveOrUpdateEventListener extends AbstractSaveEventListener implements SaveOrUpdateEventListener {
36
37     private static final Log log = LogFactory.getLog(DefaultSaveOrUpdateEventListener.class);
38
39     /**
40      * Handle the given update event.
41      *
42      * @param event The update event to be handled.
43      * @throws HibernateException
44      */

45     public Serializable JavaDoc onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException {
46         
47         final SessionImplementor source = event.getSession();
48         final Object JavaDoc object = event.getObject();
49
50         final Serializable JavaDoc requestedId = event.getRequestedId();
51         if ( requestedId!=null ) {
52             //assign the requested id to the proxy, *before*
53
//reassociating the proxy
54
if ( object instanceof HibernateProxy ) {
55                 ( (HibernateProxy) object ).getHibernateLazyInitializer().setIdentifier(requestedId);
56             }
57         }
58         
59         if ( reassociateIfUninitializedProxy(object, source) ) {
60             log.trace("reassociated uninitialized proxy");
61             // an uninitialized proxy, noop, don't even need to
62
// return an id, since it is never a save()
63
return null;
64         }
65         
66         //initialize properties of the event:
67
final Object JavaDoc entity = source.getPersistenceContext().unproxyAndReassociate(object);
68         event.setEntity(entity);
69         event.setEntry( source.getPersistenceContext().getEntry(entity) );
70         
71         return performSaveOrUpdate(event);
72         
73     }
74     
75     protected boolean reassociateIfUninitializedProxy(Object JavaDoc object, SessionImplementor source) {
76         return source.getPersistenceContext().reassociateIfUninitializedProxy(object);
77     }
78     
79     protected Serializable JavaDoc performSaveOrUpdate(SaveOrUpdateEvent event) {
80         
81         // use various roles to determine if the instance is
82
// transient, persistent or detached:
83

84         int entityState = getEntityState(
85                 event.getEntity(),
86                 event.getEntityName(),
87                 event.getEntry(),
88                 event.getSession()
89             );
90         
91         switch (entityState) {
92             case DETACHED:
93                 entityIsDetached(event);
94                 return null;
95             case PERSISTENT:
96                 return entityIsPersistent(event);
97             default: //TRANSIENT or DELETED
98
return entityIsTransient(event);
99         }
100         
101     }
102     
103     protected Serializable JavaDoc entityIsPersistent(SaveOrUpdateEvent event) throws HibernateException {
104         
105         log.trace("ignoring persistent instance");
106         
107         EntityEntry entityEntry = event.getEntry();
108         if ( entityEntry==null ) {
109             throw new AssertionFailure("entity was transient or detached");
110         }
111         else {
112             
113             if ( entityEntry.getStatus() == Status.DELETED ) {
114                 throw new AssertionFailure("entity was deleted");
115             }
116             
117             final SessionFactoryImplementor factory = event.getSession().getFactory();
118
119             Serializable JavaDoc requestedId = event.getRequestedId();
120             
121             Serializable JavaDoc savedId;
122             if ( requestedId == null ) {
123                 savedId = entityEntry.getId();
124             }
125             else {
126                 
127                 final boolean isEqual = !entityEntry.getPersister().getIdentifierType()
128                         .isEqual( requestedId, entityEntry.getId(), event.getSession().getEntityMode(), factory );
129                 
130                 if ( isEqual ) {
131                     throw new PersistentObjectException(
132                             "object passed to save() was already persistent: " +
133                             MessageHelper.infoString( entityEntry.getPersister(), requestedId, factory )
134                         );
135                 }
136                 
137                 savedId = requestedId;
138                 
139             }
140             
141             if ( log.isTraceEnabled() ) {
142                 log.trace(
143                         "object already associated with session: " +
144                         MessageHelper.infoString( entityEntry.getPersister(), savedId, factory )
145                     );
146             }
147             
148             return savedId;
149             
150         }
151     }
152         
153     /**
154      * Handle the given save event.
155      *
156      * @param event The save event to be handled.
157      * @throws HibernateException
158      */

159     protected Serializable JavaDoc entityIsTransient(SaveOrUpdateEvent event) throws HibernateException {
160         
161         log.trace("saving transient instance");
162
163         final EventSource source = event.getSession();
164
165         EntityEntry entityEntry = event.getEntry();
166         if ( entityEntry != null ) {
167             if ( entityEntry.getStatus() == Status.DELETED ) {
168                 source.forceFlush(entityEntry);
169             }
170             else {
171                 throw new AssertionFailure("entity was persistent");
172             }
173         }
174         
175         Serializable JavaDoc id = saveWithGeneratedOrRequestedId(event);
176
177         source.getPersistenceContext().reassociateProxy( event.getObject(), id );
178         
179         return id;
180     }
181     
182     /**
183      * Save the transient instance, assigning the right identifier
184      */

185     protected Serializable JavaDoc saveWithGeneratedOrRequestedId(SaveOrUpdateEvent event) {
186         return saveWithGeneratedId(
187                 event.getEntity(),
188                 event.getEntityName(),
189                 null,
190                 event.getSession()
191         );
192     }
193     
194     /**
195      * Handle the given update event.
196      *
197      * @param event The update event to be handled.
198      * @throws HibernateException
199      */

200     protected void entityIsDetached(SaveOrUpdateEvent event) throws HibernateException {
201         
202         log.trace("updating detached instance");
203                 
204         
205         if ( event.getSession().getPersistenceContext().isEntryFor( event.getEntity() ) ) {
206             //TODO: assertion only, could be optimized away
207
throw new AssertionFailure("entity was persistent");
208         }
209         
210         Object JavaDoc entity = event.getEntity();
211
212         EntityPersister persister = event.getSession().getEntityPersister( event.getEntityName(), entity );
213
214         event.setRequestedId( getUpdateId( entity, persister, event.getRequestedId(), event.getSession().getEntityMode() ) );
215         
216         performUpdate(event, entity, persister);
217
218     }
219     
220     protected Serializable JavaDoc getUpdateId(Object JavaDoc entity, EntityPersister persister, Serializable JavaDoc requestedId, EntityMode entityMode)
221     throws HibernateException {
222         // use the id assigned to the instance
223
Serializable JavaDoc id = persister.getIdentifier(entity, entityMode);
224         if ( id==null ) {
225             // assume this is a newly instantiated transient object
226
// which should be saved rather than updated
227
throw new TransientObjectException(
228                     "The given object has a null identifier: " +
229                     persister.getEntityName()
230                 );
231         }
232         else {
233             return id;
234         }
235             
236     }
237
238     protected void performUpdate(SaveOrUpdateEvent event, Object JavaDoc entity, EntityPersister persister)
239     throws HibernateException {
240     
241         if ( !persister.isMutable() ) {
242             log.trace( "immutable instance passed to doUpdate(), locking" );
243             reassociate( event, entity, event.getRequestedId(), persister );
244         }
245         else {
246
247             if ( log.isTraceEnabled() ) {
248                 log.trace(
249                         "updating " +
250                         MessageHelper.infoString( persister, event.getRequestedId(), event.getSession().getFactory() )
251                     );
252             }
253     
254             final EventSource source = event.getSession();
255             
256             EntityKey key = new EntityKey( event.getRequestedId(), persister, source.getEntityMode() );
257             
258             source.getPersistenceContext().checkUniqueness( key, entity );
259     
260             if ( invokeUpdateLifecycle( entity, persister, source ) ) {
261                 reassociate( event, event.getObject(), event.getRequestedId(), persister );
262                 return;
263             }
264     
265             // this is a transient object with existing persistent state not loaded by the session
266

267             new OnUpdateVisitor( source, event.getRequestedId() ).process( entity, persister );
268             
269             //TODO: put this stuff back in to read snapshot from
270
// the second-level cache (needs some extra work)
271
/*Object[] cachedState = null;
272
273             if ( persister.hasCache() ) {
274                 CacheEntry entry = (CacheEntry) persister.getCache()
275                         .get( event.getRequestedId(), source.getTimestamp() );
276                 cachedState = entry==null ?
277                         null :
278                         entry.getState(); //TODO: half-assemble this stuff
279             }*/

280
281             source.getPersistenceContext().addEntity(
282                     entity,
283                     Status.MANAGED,
284                     null, //cachedState,
285
key,
286                     persister.getVersion( entity, source.getEntityMode() ),
287                     LockMode.NONE,
288                     true,
289                     persister,
290                     false,
291                     true //assume true, since we don't really know, and it doesn't matter
292
);
293             
294             persister.afterReassociate(entity, source);
295     
296             if ( log.isTraceEnabled() ) {
297                 log.trace(
298                         "updating " +
299                         MessageHelper.infoString( persister, event.getRequestedId(), source.getFactory() )
300                     );
301             }
302     
303             cascadeOnUpdate(event, persister, entity);
304             
305         }
306     }
307
308     protected boolean invokeUpdateLifecycle(Object JavaDoc entity, EntityPersister persister, EventSource source) {
309         if ( persister.implementsLifecycle( source.getEntityMode() ) ) {
310             log.debug( "calling onUpdate()" );
311             if ( ( ( Lifecycle ) entity ).onUpdate(source) ) {
312                 log.debug( "update vetoed by onUpdate()" );
313                 return true;
314             }
315         }
316         return false;
317     }
318
319     /**
320      * Handles the calls needed to perform cascades as part of an update request
321      * for the given entity.
322      *
323      * @param event The event currently being processed.
324      * @param persister The defined persister for the entity being updated.
325      * @param entity The entity being updated.
326      */

327     private void cascadeOnUpdate(SaveOrUpdateEvent event, EntityPersister persister, Object JavaDoc entity) {
328         EventSource source = event.getSession();
329         source.getPersistenceContext().incrementCascadeLevel();
330         try {
331             new Cascade(CascadingAction.SAVE_UPDATE, Cascade.AFTER_UPDATE, source)
332                     .cascade(persister, entity);
333         }
334         finally {
335             source.getPersistenceContext().decrementCascadeLevel();
336         }
337     }
338
339     protected CascadingAction getCascadeAction() {
340         return CascadingAction.SAVE_UPDATE;
341     }
342 }
343
Popular Tags