/*
* 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.ops;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.event.spi.EntityCopyObserver;
import org.hibernate.event.spi.EventSource;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
import static junit.framework.TestCase.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* Tests merging multiple detached representations of the same entity using a custom EntityCopyObserver.
*
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-9106")
public class MergeMultipleEntityCopiesCustomTest extends BaseCoreFunctionalTestCase {
public String[] getMappings() {
return new String[] {
"ops/Hoarder.hbm.xml"
};
}
public void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty(
"hibernate.event.merge.entity_copy_observer",
CustomEntityCopyObserver.class.getName()
);
}
@Test
public void testMergeMultipleEntityCopiesAllowed() {
Item item1 = new Item();
item1.setName( "item1" );
Hoarder hoarder = new Hoarder();
hoarder.setName( "joe" );
Session s = openSession();
s.getTransaction().begin();
s.persist( item1 );
s.persist( hoarder );
s.getTransaction().commit();
s.close();
// Get another representation of the same Item.
s = openSession();
Item item1_1 = (Item) s.get( Item.class, item1.getId() );
s.close();
// item1_1 and item1_2 are unmodified representations of the same persistent entity.
assertFalse( item1 == item1_1 );
assertTrue( item1.equals( item1_1 ) );
// Update hoarder (detached) to references both representations.
hoarder.getItems().add( item1 );
hoarder.setFavoriteItem( item1_1 );
s = openSession();
s.getTransaction().begin();
// the merge should succeed because it does not have Category copies.
// (CustomEntityCopyObserver does not allow Category copies; it does allow Item copies)
hoarder = (Hoarder) s.merge( hoarder );
assertEquals( 1, hoarder.getItems().size() );
assertSame( hoarder.getFavoriteItem(), hoarder.getItems().iterator().next() );
assertEquals( item1.getId(), hoarder.getFavoriteItem().getId() );
assertEquals( item1.getCategory(), hoarder.getFavoriteItem().getCategory() );
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
hoarder = (Hoarder) s.get( Hoarder.class, hoarder.getId() );
assertEquals( 1, hoarder.getItems().size() );
assertSame( hoarder.getFavoriteItem(), hoarder.getItems().iterator().next() );
assertEquals( item1.getId(), hoarder.getFavoriteItem().getId() );
assertEquals( item1.getCategory(), hoarder.getFavoriteItem().getCategory() );
s.getTransaction().commit();
s.close();
cleanup();
}
@Test
public void testMergeMultipleEntityCopiesAllowedAndDisallowed() {
Item item1 = new Item();
item1.setName( "item1 name" );
Category category = new Category();
category.setName( "category" );
item1.setCategory( category );
category.setExampleItem( item1 );
Session s = openSession();
s.getTransaction().begin();
s.persist( item1 );
s.getTransaction().commit();
s.close();
// get another representation of item1
s = openSession();
s.getTransaction().begin();
Item item1_1 = (Item) s.get( Item.class, item1.getId() );
// make sure item1_1.category is initialized
Hibernate.initialize( item1_1.getCategory() );
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
Item item1Merged = (Item) s.merge( item1 );
item1Merged.setCategory( category );
category.setExampleItem( item1_1 );
// now item1Merged is managed and it has a nested detached item
// and there is multiple managed/detached Category objects
try {
// the following should fail because multiple copies of Category objects is not allowed by
// CustomEntityCopyObserver
s.merge( item1Merged );
fail( "should have failed because CustomEntityCopyObserver does not allow multiple copies of a Category. ");
}
catch (IllegalStateException ex ) {
// expected
}
finally {
s.getTransaction().rollback();
}
s.close();
s = openSession();
s.getTransaction().begin();
item1 = (Item) s.get( Item.class, item1.getId() );
assertEquals( category.getName(), item1.getCategory().getName() );
assertSame( item1, item1.getCategory().getExampleItem() );
s.getTransaction().commit();
s.close();
cleanup();
}
@SuppressWarnings( {"unchecked"})
private void cleanup() {
Session s = openSession();
s.getTransaction().begin();
for ( Hoarder hoarder : (List<Hoarder>) s.createQuery( "from Hoarder" ).list() ) {
hoarder.getItems().clear();
s.delete( hoarder );
}
for ( Category category : (List<Category>) s.createQuery( "from Category" ).list() ) {
if ( category.getExampleItem() != null ) {
category.setExampleItem( null );
s.delete( category );
}
}
for ( Item item : (List<Item>) s.createQuery( "from Item" ).list() ) {
item.setCategory( null );
s.delete( item );
}
s.createQuery( "delete from Item" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
@Override
public Class[] getAnnotatedClasses() {
return new Class[] {
Category.class,
Hoarder.class,
Item.class
};
}
public static class CustomEntityCopyObserver implements EntityCopyObserver {
@Override
public void entityCopyDetected(Object managedEntity, Object mergeEntity1, Object mergeEntity2, EventSource session) {
if ( Category.class.isInstance( managedEntity ) ) {
throw new IllegalStateException(
String.format( "Entity copies of type [%s] not allowed", Category.class.getName() )
);
}
}
@Override
public void topLevelMergeComplete(EventSource session) {
}
@Override
public void clear() {
}
}
}