1 package org.hibernate.event.def; 3 4 import java.io.Serializable ; 5 import java.util.Map ; 6 7 import org.apache.commons.logging.Log; 8 import org.apache.commons.logging.LogFactory; 9 import org.hibernate.AssertionFailure; 10 import org.hibernate.HibernateException; 11 import org.hibernate.ObjectDeletedException; 12 import org.hibernate.StaleObjectStateException; 13 import org.hibernate.WrongClassException; 14 import org.hibernate.engine.Cascade; 15 import org.hibernate.engine.CascadingAction; 16 import org.hibernate.event.EventSource; 17 import org.hibernate.event.MergeEvent; 18 import org.hibernate.event.MergeEventListener; 19 import org.hibernate.engine.SessionImplementor; 20 import org.hibernate.persister.entity.EntityPersister; 21 import org.hibernate.proxy.HibernateProxy; 22 import org.hibernate.proxy.LazyInitializer; 23 import org.hibernate.type.ForeignKeyDirection; 24 import org.hibernate.type.TypeFactory; 25 import org.hibernate.util.IdentityMap; 26 27 33 public class DefaultMergeEventListener extends AbstractSaveEventListener 34 implements MergeEventListener { 35 36 private static final Log log = LogFactory.getLog(DefaultMergeEventListener.class); 37 38 private final boolean isSaveOrUpdateCopyListener; 39 40 public DefaultMergeEventListener() { 41 this(false); 42 } 43 44 protected Map getMergeMap(Object anything) { 45 return IdentityMap.invert( (Map ) anything ); 46 } 47 48 public DefaultMergeEventListener(boolean isSaveOrUpdateCopyListener) { 49 this.isSaveOrUpdateCopyListener = isSaveOrUpdateCopyListener; 50 } 51 52 59 public Object onMerge(MergeEvent event) throws HibernateException { 60 return onMerge( event, IdentityMap.instantiate(10) ); 61 } 62 63 70 public Object onMerge(MergeEvent event, Map copyCache) throws HibernateException { 71 72 final EventSource source = event.getSession(); 73 final Object original = event.getOriginal(); 74 75 final Object entity; 76 if ( original == null ) { 77 return null; 79 } 80 else if ( original instanceof HibernateProxy ) { 81 LazyInitializer li = ( (HibernateProxy) original ).getHibernateLazyInitializer(); 82 if ( li.isUninitialized() ) { 83 log.trace("ignoring uninitialized proxy"); 85 return source.load( li.getEntityName(), li.getIdentifier() ); 86 } 87 else { 88 entity = li.getImplementation(); 89 } 90 } 91 else { 92 entity = original; 93 } 94 95 if ( copyCache.containsKey(entity) ) { 96 log.trace("already merged"); 97 return entity; } 99 100 event.setEntity(entity); 101 102 int entityState = getEntityState( 103 entity, 104 event.getEntityName(), 105 source.getPersistenceContext().getEntry(entity), 106 source 107 ); 108 109 switch (entityState) { 110 case DETACHED: 111 return entityIsDetached(event, copyCache); 112 case TRANSIENT: 113 return entityIsTransient(event, copyCache); 114 case PERSISTENT: 115 return entityIsPersistent(event, copyCache); 116 default: throw new ObjectDeletedException( "deleted instance passed to merge", null, event.getEntityName() ); 118 } 119 120 } 121 122 protected Object entityIsPersistent(MergeEvent event, Map copyCache) { 123 log.trace("ignoring persistent instance"); 124 125 127 final Object entity = event.getEntity(); 128 final EventSource source = event.getSession(); 129 final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity ); 130 131 copyCache.put(entity, entity); 133 cascadeOnMerge(source, persister, entity, copyCache); 134 copyValues(persister, entity, entity, source, copyCache); 135 136 return entity; 137 } 138 139 protected Object entityIsTransient(MergeEvent event, Map copyCache) { 140 141 log.trace("merging transient instance"); 142 143 final Object entity = event.getEntity(); 144 final EventSource source = event.getSession(); 145 146 final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity ); 147 final String entityName = persister.getEntityName(); 148 149 final Serializable id = persister.hasIdentifierProperty() ? 150 persister.getIdentifier( entity, source.getEntityMode() ) : 151 null; 152 153 final Object copy = persister.instantiate( id, source.getEntityMode() ); copyCache.put(entity, copy); 156 super.cascadeBeforeSave(source, persister, entity, copyCache); 160 copyValues(persister, entity, copy, source, copyCache, ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT); 161 162 final Serializable requestedId = event.getRequestedId(); 166 if (requestedId==null) { 167 saveWithGeneratedId(copy, entityName, copyCache, source); 168 } 169 else { 170 saveWithRequestedId(copy, requestedId, entityName, copyCache, source); 171 } 172 173 super.cascadeAfterSave(source, persister, entity, copyCache); 176 copyValues(persister, entity, copy, source, copyCache, ForeignKeyDirection.FOREIGN_KEY_TO_PARENT); 177 178 return copy; 179 180 } 181 182 protected Object entityIsDetached(MergeEvent event, Map copyCache) { 183 184 log.trace("merging detached instance"); 185 186 final Object entity = event.getEntity(); 187 final EventSource source = event.getSession(); 188 189 final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity ); 190 final String entityName = persister.getEntityName(); 191 192 Serializable id = event.getRequestedId(); 193 if ( id == null ) { 194 id = persister.getIdentifier( entity, source.getEntityMode() ); 195 } 196 else { 197 } 199 200 final Object result = source.get(entityName, id); 201 if ( result == null ) { 202 206 return entityIsTransient(event, copyCache); 210 } 211 else { 212 copyCache.put(entity, result); 214 final Object target = source.getPersistenceContext().unproxy(result); 215 if ( target == entity ) { 216 throw new AssertionFailure("entity was not detached"); 217 } 218 else if ( !source.getEntityName(target).equals(entityName) ) { 219 throw new WrongClassException( 220 "class of the given object did not match class of persistent copy", 221 event.getRequestedId(), 222 entityName 223 ); 224 } 225 else if ( 226 persister.isVersioned() && 227 !persister.getVersionType().isSame( 228 persister.getVersion( target, source.getEntityMode() ), 229 persister.getVersion( entity, source.getEntityMode() ), 230 source.getEntityMode() 231 ) 232 ) { 233 throw new StaleObjectStateException( entityName, event.getRequestedId() ); 234 } 235 236 cascadeOnMerge(source, persister, entity, copyCache); 239 copyValues(persister, entity, target, source, copyCache); 240 241 return result; 242 } 243 244 } 245 246 protected void copyValues( 247 final EntityPersister persister, 248 final Object entity, 249 final Object target, 250 final SessionImplementor source, 251 final Map copyCache 252 ) { 253 254 final Object [] copiedValues = TypeFactory.replace( 255 persister.getPropertyValues( entity, source.getEntityMode() ), 256 persister.getPropertyValues( target, source.getEntityMode() ), 257 persister.getPropertyTypes(), 258 source, 259 target, 260 copyCache 261 ); 262 263 persister.setPropertyValues( target, copiedValues, source.getEntityMode() ); 264 } 265 266 protected void copyValues( 267 final EntityPersister persister, 268 final Object entity, 269 final Object target, 270 final SessionImplementor source, 271 final Map copyCache, 272 final ForeignKeyDirection foreignKeyDirection 273 ) { 274 275 final Object [] copiedValues = TypeFactory.replace( 276 persister.getPropertyValues( entity, source.getEntityMode() ), 277 persister.getPropertyValues( target, source.getEntityMode() ), 278 persister.getPropertyTypes(), 279 source, 280 target, 281 copyCache, 282 foreignKeyDirection 283 ); 284 285 persister.setPropertyValues( target, copiedValues, source.getEntityMode() ); 286 } 287 288 297 protected void cascadeOnMerge( 298 final EventSource source, 299 final EntityPersister persister, 300 final Object entity, 301 final Map copyCache 302 ) { 303 source.getPersistenceContext().incrementCascadeLevel(); 304 try { 305 new Cascade( getCascadeAction(), Cascade.BEFORE_MERGE, source ) 306 .cascade(persister, entity, copyCache); 307 } 308 finally { 309 source.getPersistenceContext().decrementCascadeLevel(); 310 } 311 } 312 313 314 protected CascadingAction getCascadeAction() { 315 return isSaveOrUpdateCopyListener ? 316 CascadingAction.SAVE_UPDATE_COPY : 317 CascadingAction.MERGE; 318 } 319 320 protected Boolean getAssumedUnsaved() { 321 return Boolean.FALSE; 322 } 323 324 327 protected void cascadeAfterSave(EventSource source, EntityPersister persister, Object entity, Object anything) 328 throws HibernateException { 329 } 330 331 334 protected void cascadeBeforeSave(EventSource source, EntityPersister persister, Object entity, Object anything) 335 throws HibernateException { 336 } 337 338 } 339 | Popular Tags |