/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.event.collection.detached;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.event.spi.AbstractCollectionEvent;
import org.hibernate.event.spi.PostCollectionRecreateEvent;
import org.hibernate.event.spi.PreCollectionRemoveEvent;
import org.hibernate.event.spi.PreCollectionUpdateEvent;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
/**
* Test HHH-6361: Collection events may contain wrong stored snapshot after
* merging a detached entity into the persistencecontext.
*
* @author Erik-Berndt Scheper
*/
@TestForIssue( jiraKey = "HHH-6361" )
public class DetachedMultipleCollectionChangeTest extends BaseCoreFunctionalTestCase {
@Override
public String[] getMappings() {
return new String[] { "event/collection/detached/MultipleCollectionBagMapping.hbm.xml" };
}
@Override
protected void cleanupTest() {
Session s = null;
s = openSession();
s.beginTransaction();
s.createQuery("delete MultipleCollectionRefEntity1").executeUpdate();
s.createQuery("delete MultipleCollectionRefEntity2").executeUpdate();
s.createQuery("delete MultipleCollectionEntity").executeUpdate();
s.getTransaction().commit();
s.close();
}
@Test
public void testMergeMultipleCollectionChangeEvents() {
MultipleCollectionListeners listeners = new MultipleCollectionListeners(
sessionFactory());
listeners.clear();
int eventCount = 0;
List<MultipleCollectionRefEntity1> oldRefentities1
= new ArrayList<MultipleCollectionRefEntity1>();
List<MultipleCollectionRefEntity2> oldRefentities2
= new ArrayList<MultipleCollectionRefEntity2>();
Session s = openSession();
s.beginTransaction();
MultipleCollectionEntity mce = new MultipleCollectionEntity();
mce.setText("MultipleCollectionEntity-1");
s.save(mce);
s.getTransaction().commit();
checkListener(listeners, listeners.getPreCollectionRecreateListener(),
mce, oldRefentities1, eventCount++);
checkListener(listeners, listeners.getPostCollectionRecreateListener(),
mce, oldRefentities1, eventCount++);
checkListener(listeners, listeners.getPreCollectionRecreateListener(),
mce, oldRefentities2, eventCount++);
checkListener(listeners, listeners.getPostCollectionRecreateListener(),
mce, oldRefentities2, eventCount++);
checkEventCount(listeners, eventCount);
s.close();
Long mceId1 = mce.getId();
assertNotNull(mceId1);
// add new entities to both collections
MultipleCollectionEntity prevMce = mce.deepCopy();
oldRefentities1 = prevMce.getRefEntities1();
oldRefentities2 = prevMce.getRefEntities2();
listeners.clear();
eventCount = 0;
s = openSession();
s.beginTransaction();
MultipleCollectionRefEntity1 re1_1 = new MultipleCollectionRefEntity1();
re1_1.setText("MultipleCollectionRefEntity1-1");
re1_1.setMultipleCollectionEntity(mce);
MultipleCollectionRefEntity1 re1_2 = new MultipleCollectionRefEntity1();
re1_2.setText("MultipleCollectionRefEntity1-2");
re1_2.setMultipleCollectionEntity(mce);
mce.addRefEntity1(re1_1);
mce.addRefEntity1(re1_2);
mce = (MultipleCollectionEntity) s.merge(mce);
s.getTransaction().commit();
s.close();
checkListener(listeners, listeners.getInitializeCollectionListener(),
mce, null, eventCount++);
checkListener(listeners, listeners.getPreCollectionUpdateListener(),
mce, oldRefentities1, eventCount++);
checkListener(listeners, listeners.getPostCollectionUpdateListener(),
mce, mce.getRefEntities1(), eventCount++);
s = openSession();
s.beginTransaction();
MultipleCollectionRefEntity2 re2_1 = new MultipleCollectionRefEntity2();
re2_1.setText("MultipleCollectionRefEntity2-1");
re2_1.setMultipleCollectionEntity(mce);
MultipleCollectionRefEntity2 re2_2 = new MultipleCollectionRefEntity2();
re2_2.setText("MultipleCollectionRefEntity2-2");
re2_2.setMultipleCollectionEntity(mce);
mce.addRefEntity2(re2_1);
mce.addRefEntity2(re2_2);
mce = (MultipleCollectionEntity) s.merge(mce);
s.getTransaction().commit();
checkListener(listeners, listeners.getInitializeCollectionListener(),
mce, null, eventCount++);
checkListener(listeners, listeners.getPreCollectionUpdateListener(),
mce, oldRefentities2, eventCount++);
checkListener(listeners, listeners.getPostCollectionUpdateListener(),
mce, mce.getRefEntities2(), eventCount++);
checkEventCount(listeners, eventCount);
s.close();
for (MultipleCollectionRefEntity1 refEnt1 : mce.getRefEntities1()) {
assertNotNull(refEnt1.getId());
}
for (MultipleCollectionRefEntity2 refEnt2 : mce.getRefEntities2()) {
assertNotNull(refEnt2.getId());
}
// remove and add entities in both collections
prevMce = mce.deepCopy();
oldRefentities1 = prevMce.getRefEntities1();
oldRefentities2 = prevMce.getRefEntities2();
listeners.clear();
eventCount = 0;
s = openSession();
s.beginTransaction();
assertEquals(2, mce.getRefEntities1().size());
assertEquals(2, mce.getRefEntities2().size());
mce.removeRefEntity1(re1_2);
MultipleCollectionRefEntity1 re1_3 = new MultipleCollectionRefEntity1();
re1_3.setText("MultipleCollectionRefEntity1-3");
re1_3.setMultipleCollectionEntity(mce);
mce.addRefEntity1(re1_3);
mce = (MultipleCollectionEntity) s.merge(mce);
s.getTransaction().commit();
s.close();
checkListener(listeners, listeners.getInitializeCollectionListener(),
mce, null, eventCount++);
checkListener(listeners, listeners.getPreCollectionUpdateListener(),
mce, oldRefentities1, eventCount++);
checkListener(listeners, listeners.getPostCollectionUpdateListener(),
mce, mce.getRefEntities1(), eventCount++);
s = openSession();
s.beginTransaction();
mce.removeRefEntity2(re2_2);
MultipleCollectionRefEntity2 re2_3 = new MultipleCollectionRefEntity2();
re2_3.setText("MultipleCollectionRefEntity2-3");
re2_3.setMultipleCollectionEntity(mce);
mce.addRefEntity2(re2_3);
mce = (MultipleCollectionEntity) s.merge(mce);
s.getTransaction().commit();
checkListener(listeners, listeners.getInitializeCollectionListener(),
mce, null, eventCount++);
checkListener(listeners, listeners.getPreCollectionUpdateListener(),
mce, oldRefentities2, eventCount++);
checkListener(listeners, listeners.getPostCollectionUpdateListener(),
mce, mce.getRefEntities2(), eventCount++);
checkEventCount(listeners, eventCount);
s.close();
}
protected void checkListener(
MultipleCollectionListeners listeners,
MultipleCollectionListeners.Listener listenerExpected,
org.hibernate.test.event.collection.Entity ownerExpected,
List<? extends org.hibernate.test.event.collection.Entity> expectedCollectionEntrySnapshot,
int index) {
AbstractCollectionEvent event = listeners
.getEvents().get(index);
assertSame(listenerExpected, listeners.getListenersCalled().get(index));
assertEquals(ownerExpected, event.getAffectedOwnerOrNull());
assertEquals(ownerExpected.getId(), event.getAffectedOwnerIdOrNull());
assertEquals(ownerExpected.getClass().getName(),
event.getAffectedOwnerEntityName());
if (event instanceof PreCollectionUpdateEvent) {
Serializable snapshot = listeners.getSnapshots().get(index);
assertEquals(expectedCollectionEntrySnapshot, snapshot);
}
if (event instanceof PreCollectionRemoveEvent) {
Serializable snapshot = listeners.getSnapshots().get(index);
assertEquals(expectedCollectionEntrySnapshot, snapshot);
}
if (event instanceof PostCollectionRecreateEvent) {
Serializable snapshot = listeners.getSnapshots().get(index);
assertEquals(expectedCollectionEntrySnapshot, snapshot);
}
}
private void checkEventCount(MultipleCollectionListeners listeners,
int nEventsExpected) {
assertEquals(nEventsExpected, listeners.getListenersCalled().size());
assertEquals(nEventsExpected, listeners.getEvents().size());
}
}