1 package org.hibernate.event.def; 3 4 import java.io.Serializable ; 5 6 import org.apache.commons.logging.Log; 7 import org.apache.commons.logging.LogFactory; 8 import org.hibernate.AssertionFailure; 9 import org.hibernate.HibernateException; 10 import org.hibernate.StaleObjectStateException; 11 import org.hibernate.EntityMode; 12 import org.hibernate.action.EntityUpdateAction; 13 import org.hibernate.classic.Validatable; 14 import org.hibernate.engine.EntityEntry; 15 import org.hibernate.engine.EntityKey; 16 import org.hibernate.engine.Nullability; 17 import org.hibernate.engine.PersistenceContext; 18 import org.hibernate.engine.Status; 19 import org.hibernate.engine.Versioning; 20 import org.hibernate.event.EventSource; 21 import org.hibernate.event.FlushEntityEvent; 22 import org.hibernate.event.FlushEntityEventListener; 23 import org.hibernate.engine.SessionImplementor; 24 import org.hibernate.intercept.FieldInterceptor; 25 import org.hibernate.persister.entity.EntityPersister; 26 import org.hibernate.pretty.MessageHelper; 27 import org.hibernate.type.Type; 28 import org.hibernate.type.TypeFactory; 29 import org.hibernate.util.ArrayHelper; 30 31 36 public class DefaultFlushEntityEventListener 37 extends AbstractEventListener 38 implements FlushEntityEventListener { 39 40 private static final Log log = LogFactory.getLog(DefaultFlushEntityEventListener.class); 41 42 45 public void checkId(Object object, EntityPersister persister, Serializable id, EntityMode entityMode) 46 throws HibernateException { 47 48 if ( persister.hasIdentifierPropertyOrEmbeddedCompositeIdentifier() ) { 49 50 Serializable oid = persister.getIdentifier( object, entityMode ); 51 if (id==null) { 52 throw new AssertionFailure("null id in entry (don't flush the Session after an exception occurs)"); 53 } 54 if ( !persister.getIdentifierType().isEqual(id, oid, entityMode) ) { 55 throw new HibernateException( 56 "identifier of an instance of " + 57 persister.getEntityName() + 58 " was altered from " + id + 59 " to " + oid 60 ); 61 } 62 } 63 64 } 65 66 private void checkNaturalId(EntityPersister persister, Object [] current, Object [] loaded, EntityMode entityMode) { 67 if ( persister.hasNaturalIdentifier() ) { 68 Type[] types = persister.getPropertyTypes(); 69 int[] props = persister.getNaturalIdentifierProperties(); 70 boolean[] updateable = persister.getPropertyUpdateability(); 71 for ( int i=0; i<props.length; i++ ) { 72 int prop = props[i]; 73 if ( !updateable[prop] ) { 74 if ( !types[prop].isEqual( current[prop], loaded[prop], entityMode ) ) { 75 throw new HibernateException( 76 "immutable natural identifier of an instance of " + 77 persister.getEntityName() + 78 " was altered" 79 ); 80 } 81 } 82 } 83 } 84 } 85 86 90 public void onFlushEntity(FlushEntityEvent event) throws HibernateException { 91 final Object entity = event.getEntity(); 92 final EntityEntry entry = event.getEntityEntry(); 93 final EventSource session = event.getSession(); 94 final EntityPersister persister = entry.getPersister(); 95 final Status status = entry.getStatus(); 96 final EntityMode entityMode = session.getEntityMode(); 97 final Object [] loadedState = entry.getLoadedState(); 98 final Type[] types = persister.getPropertyTypes(); 99 100 final boolean mightBeDirty = entry.requiresDirtyCheck(entity); 101 102 final Object [] values; 103 if ( status == Status.DELETED ) { 104 values = entry.getDeletedState(); 106 } 107 else if ( !mightBeDirty && loadedState!=null ) { 108 values = loadedState; 109 } 110 else { 111 checkId( entity, persister, entry.getId(), entityMode ); 112 113 values = persister.getPropertyValues( entity, entityMode ); 115 116 checkNaturalId( persister, values, loadedState, entityMode ); 117 } 118 119 event.setPropertyValues(values); 120 121 boolean substitute = false; 122 123 if ( persister.hasCollections() ) { 125 126 129 134 WrapVisitor visitor = new WrapVisitor(session); 135 visitor.processEntityPropertyValues(values, types); 137 substitute = visitor.isSubstitutionRequired(); 138 } 139 140 if ( mightBeDirty || status==Status.DELETED ) { 141 dirtyCheck(event); 143 if ( isUpdateNecessary(event) ) { 144 substitute = scheduleUpdate( event, entity, entry, values, persister, session ) 145 || substitute; 146 } 147 else { 148 FieldInterceptor.clearDirty(entity); 149 } 150 } 151 152 if ( status != Status.DELETED ) { 153 if (substitute) persister.setPropertyValues( entity, values, entityMode ); 155 156 if ( persister.hasCollections() ) { 159 new FlushVisitor(session, entity).processEntityPropertyValues(values, types); 160 } 161 } 162 163 } 164 165 private boolean scheduleUpdate( 166 final FlushEntityEvent event, 167 final Object entity, 168 final EntityEntry entry, 169 final Object [] values, 170 final EntityPersister persister, 171 final EventSource session 172 ) { 173 174 final Status status = entry.getStatus(); 175 final EntityMode entityMode = session.getEntityMode(); 176 final Type[] types = persister.getPropertyTypes(); 177 178 if ( log.isTraceEnabled() ) { 179 if ( status == Status.DELETED ) { 180 log.trace( 181 "Updating deleted entity: " + 182 MessageHelper.infoString( persister, entry.getId(), session.getFactory() ) 183 ); 184 } 185 else { 186 log.trace( 187 "Updating entity: " + 188 MessageHelper.infoString( persister, entry.getId(), session.getFactory() ) 189 ); 190 } 191 } 192 193 boolean substitute; 194 195 if ( !entry.isBeingReplicated() ) { 196 substitute = handleInterception(event); 199 } 200 else { 201 substitute = false; 202 } 203 204 validate( entity, persister, status, entityMode ); 205 206 final Object nextVersion = getNextVersion(event); 208 209 Object [] updatedState = null; 211 if ( status==Status.MANAGED ) { 212 updatedState = new Object [values.length]; 213 TypeFactory.deepCopy( 214 values, 215 types, 216 persister.getPropertyCheckability(), 217 updatedState, 218 session 219 ); 220 } 221 222 int[] dirtyProperties = event.getDirtyProperties(); 224 if ( event.isDirtyCheckPossible() && dirtyProperties==null ) { 225 if ( !event.hasDirtyCollection() ) { 226 throw new AssertionFailure("dirty, but no dirty properties"); 227 } 228 dirtyProperties = ArrayHelper.EMPTY_INT_ARRAY; 229 } 230 231 new Nullability(session).checkNullability( values, persister, true ); 234 235 session.getActionQueue().addAction( 238 new EntityUpdateAction( 239 entry.getId(), 240 values, 241 dirtyProperties, 242 event.hasDirtyCollection(), 243 entry.getLoadedState(), 244 entry.getVersion(), 245 nextVersion, 246 entity, 247 updatedState, 248 entry.getRowId(), 249 persister, 250 session 251 ) 252 ); 253 254 return substitute; 255 } 256 257 protected void validate(Object entity, EntityPersister persister, Status status, EntityMode entityMode) { 258 if ( status == Status.MANAGED && persister.implementsValidatable( entityMode ) ) { 260 ( (Validatable) entity ).validate(); 261 } 262 } 263 264 protected boolean handleInterception(FlushEntityEvent event) { 265 SessionImplementor session = event.getSession(); 266 EntityEntry entry = event.getEntityEntry(); 267 EntityPersister persister = entry.getPersister(); 268 Object entity = event.getEntity(); 269 270 final Object [] values = event.getPropertyValues(); 272 final boolean intercepted = invokeInterceptor( session, entity, entry, values, persister ); 273 274 if ( intercepted && event.isDirtyCheckPossible() && !event.isDirtyCheckHandledByInterceptor() ) { 276 int[] dirtyProperties; 277 if ( event.hasDatabaseSnapshot() ) { 278 dirtyProperties = persister.findModified( event.getDatabaseSnapshot(), values, entity, session ); 279 } 280 else { 281 dirtyProperties = persister.findDirty( values, entry.getLoadedState(), entity, session ); 282 } 283 event.setDirtyProperties(dirtyProperties); 284 } 285 286 return intercepted; 287 } 288 289 protected boolean invokeInterceptor( 290 SessionImplementor session, Object entity, EntityEntry entry, final Object [] values, 291 EntityPersister persister 292 ) { 293 final boolean intercepted = session.getInterceptor().onFlushDirty( 294 entity, 295 entry.getId(), 296 values, 297 entry.getLoadedState(), 298 persister.getPropertyNames(), 299 persister.getPropertyTypes() 300 ); 301 return intercepted; 302 } 303 304 307 private Object getNextVersion(FlushEntityEvent event) throws HibernateException { 308 309 EntityEntry entry = event.getEntityEntry(); 310 EntityPersister persister = entry.getPersister(); 311 if ( persister.isVersioned() ) { 312 313 Object [] values = event.getPropertyValues(); 314 315 if ( entry.isBeingReplicated() ) { 316 return Versioning.getVersion(values, persister); 317 } 318 else { 319 int[] dirtyProperties = event.getDirtyProperties(); 320 321 final boolean isVersionIncrementRequired = entry.getStatus()!=Status.DELETED && ( 322 dirtyProperties==null || 323 Versioning.isVersionIncrementRequired( 324 dirtyProperties, 325 event.hasDirtyCollection(), 326 persister.getPropertyVersionability() 327 ) 328 ); 329 330 final Object nextVersion = isVersionIncrementRequired ? 331 Versioning.increment( entry.getVersion(), persister.getVersionType() ) : 332 entry.getVersion(); 334 Versioning.setVersion(values, nextVersion, persister); 335 336 return nextVersion; 337 } 338 } 339 else { 340 return null; 341 } 342 343 } 344 345 350 protected final boolean isUpdateNecessary(FlushEntityEvent event) throws HibernateException { 351 352 EntityPersister persister = event.getEntityEntry().getPersister(); 353 Status status = event.getEntityEntry().getStatus(); 354 355 if ( !event.isDirtyCheckPossible() ) { 356 return true; 357 } 358 else { 359 360 int[] dirtyProperties = event.getDirtyProperties(); 361 if ( dirtyProperties!=null && dirtyProperties.length!=0 ) { 362 return true; } 364 else { 365 boolean checkCollections = status==Status.MANAGED && 366 persister.isVersioned() && 367 persister.hasCollections(); 368 369 if ( checkCollections ) { 370 DirtyCollectionSearchVisitor visitor = new DirtyCollectionSearchVisitor( 371 event.getSession(), 372 persister.getPropertyVersionability() 373 ); 374 visitor.processEntityPropertyValues( event.getPropertyValues(), persister.getPropertyTypes() ); 375 boolean hasDirtyCollections = visitor.wasDirtyCollectionFound(); 376 event.setHasDirtyCollection(hasDirtyCollections); 377 return hasDirtyCollections; 378 } 379 else { 380 return false; 381 } 382 } 383 384 } 385 } 386 387 390 protected void dirtyCheck(FlushEntityEvent event) throws HibernateException { 391 392 final Object entity = event.getEntity(); 393 final Object [] values = event.getPropertyValues(); 394 final SessionImplementor session = event.getSession(); 395 final EntityEntry entry = event.getEntityEntry(); 396 final EntityPersister persister = entry.getPersister(); 397 final Serializable id = entry.getId(); 398 final Object [] loadedState = entry.getLoadedState(); 399 400 int[] dirtyProperties = session.getInterceptor().findDirty( 401 entity, 402 id, 403 values, 404 loadedState, 405 persister.getPropertyNames(), 406 persister.getPropertyTypes() 407 ); 408 409 event.setDatabaseSnapshot(null); 410 411 final boolean interceptorHandledDirtyCheck; 412 boolean cannotDirtyCheck; 413 414 if ( dirtyProperties==null ) { 415 interceptorHandledDirtyCheck = false; 417 418 cannotDirtyCheck = loadedState==null; if ( !cannotDirtyCheck ) { 420 dirtyProperties = persister.findDirty( values, loadedState, entity, session ); 422 423 } 424 else { 425 final PersistenceContext persistenceContext = session.getPersistenceContext(); 427 Object [] databaseSnapshot; 428 if ( persister.isSelectBeforeUpdateRequired() ) { 429 databaseSnapshot = persistenceContext.getDatabaseSnapshot(id, persister); 430 } 431 else { 432 EntityKey entityKey = new EntityKey( id, persister, session.getEntityMode() ); 434 databaseSnapshot = persistenceContext.getCachedDatabaseSnapshot( entityKey ); 435 } 436 437 if ( databaseSnapshot != null ) { 438 dirtyProperties = persister.findModified(databaseSnapshot, values, entity, session); 439 cannotDirtyCheck = false; 440 event.setDatabaseSnapshot(databaseSnapshot); 441 } 442 else if ( persister.isSelectBeforeUpdateRequired() ) { 444 throw new StaleObjectStateException( persister.getEntityName(), id ); 445 } 446 447 } 448 } 449 else { 450 cannotDirtyCheck = false; 452 interceptorHandledDirtyCheck = true; 453 } 454 455 event.setDirtyProperties(dirtyProperties); 456 event.setDirtyCheckHandledByInterceptor(interceptorHandledDirtyCheck); 457 event.setDirtyCheckPossible(!cannotDirtyCheck); 458 459 } 460 461 } 462 | Popular Tags |