/*
* 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.cache;
import org.hibernate.Session;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.Proxy;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.ManagedEntity;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* @author John O'Hara
*/
public class ByteCodeEnhancedImmutableReferenceCacheTest extends BaseCoreFunctionalTestCase {
@Override
protected void configure(Configuration configuration) {
super.configure( configuration );
configuration.setProperty( AvailableSettings.USE_DIRECT_REFERENCE_CACHE_ENTRIES, "true" );
configuration.setProperty( AvailableSettings.USE_QUERY_CACHE, "true" );
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[]{MyEnhancedReferenceData.class};
}
@Test
public void testUseOfDirectReferencesInCache() throws Exception {
EntityPersister persister = (EntityPersister) sessionFactory().getClassMetadata( MyEnhancedReferenceData.class );
assertFalse( persister.isMutable() );
assertTrue( persister.buildCacheEntry( null, null, null, null ).isReferenceEntry() );
assertFalse( persister.hasProxy() );
final MyEnhancedReferenceData myReferenceData = new MyEnhancedReferenceData( 1, "first item", "abc" );
// save a reference in one session
Session s = openSession();
s.beginTransaction();
s.save( myReferenceData );
s.getTransaction().commit();
s.close();
assertNotNull( myReferenceData.$$_hibernate_getEntityEntry() );
// now load it in another
s = openSession();
s.beginTransaction();
// MyEnhancedReferenceData loaded = (MyEnhancedReferenceData) s.get( MyEnhancedReferenceData.class, 1 );
MyEnhancedReferenceData loaded = (MyEnhancedReferenceData) s.load( MyEnhancedReferenceData.class, 1 );
s.getTransaction().commit();
s.close();
// the 2 instances should be the same (==)
assertTrue( "The two instances were different references", myReferenceData == loaded );
// now try query caching
s = openSession();
s.beginTransaction();
MyEnhancedReferenceData queried = (MyEnhancedReferenceData) s.createQuery( "from MyEnhancedReferenceData" ).setCacheable( true ).list().get( 0 );
s.getTransaction().commit();
s.close();
// the 2 instances should be the same (==)
assertTrue( "The two instances were different references", myReferenceData == queried );
// cleanup
s = openSession();
s.beginTransaction();
s.delete( myReferenceData );
s.getTransaction().commit();
s.close();
}
@Test
@TestForIssue( jiraKey = "HHH-10795")
public void testAssociatedWithMultiplePersistenceContexts() {
MyEnhancedReferenceData myReferenceData = new MyEnhancedReferenceData( 1, "first item", "abc" );
MyEnhancedReferenceData myOtherReferenceData = new MyEnhancedReferenceData( 2, "second item", "def" );
// save a reference in one session
Session s1 = openSession();
s1.beginTransaction();
s1.save( myReferenceData );
s1.save( myOtherReferenceData );
s1.getTransaction().commit();
s1.close();
assertNotNull( myReferenceData.$$_hibernate_getEntityEntry() );
assertNotNull( myOtherReferenceData.$$_hibernate_getEntityEntry() );
// now associate myReferenceData with 2 sessions
s1 = openSession();
s1.beginTransaction();
myReferenceData = s1.get( MyEnhancedReferenceData.class, myReferenceData.getId() );
myOtherReferenceData = s1.get( MyEnhancedReferenceData.class, myOtherReferenceData.getId() );
assertTrue( s1.contains( myReferenceData ) );
assertTrue( s1.contains( myOtherReferenceData ) );
// prev/next references should be null; entityEntry should be non-null;
assertNull( myReferenceData.$$_hibernate_getPreviousManagedEntity() );
assertNull( myReferenceData.$$_hibernate_getNextManagedEntity() );
assertNull( myOtherReferenceData.$$_hibernate_getPreviousManagedEntity() );
assertNull( myOtherReferenceData.$$_hibernate_getNextManagedEntity() );
assertSame(
myReferenceData.$$_hibernate_getEntityEntry(),
( (SharedSessionContractImplementor) s1 ).getPersistenceContext().getEntry( myReferenceData )
);
assertSame(
myOtherReferenceData.$$_hibernate_getEntityEntry(),
( (SharedSessionContractImplementor) s1 ).getPersistenceContext().getEntry( myOtherReferenceData )
);
Session s2 = openSession();
s2.beginTransaction();
// s2 should contains no entities
assertFalse( s2.contains( myReferenceData ) );
assertFalse( s2.contains( myOtherReferenceData ) );
assertNull( ( (SharedSessionContractImplementor) s2 ).getPersistenceContext().getEntry( myReferenceData ) );
assertNull( ( (SharedSessionContractImplementor) s2 ).getPersistenceContext().getEntry( myOtherReferenceData ) );
// evict should do nothing, since p is not associated with s2
s2.evict( myReferenceData );
s2.evict( myOtherReferenceData );
assertSame( myReferenceData, s2.get( MyEnhancedReferenceData.class, myReferenceData.getId() ) );
assertSame( myOtherReferenceData, s2.get( MyEnhancedReferenceData.class, myOtherReferenceData.getId() ) );
assertTrue( s2.contains( myReferenceData ) );
assertTrue( s2.contains( myOtherReferenceData ) );
// still associated with s1
assertTrue( s1.contains( myReferenceData ) );
assertTrue( s1.contains( myOtherReferenceData ) );
s2.evict( myReferenceData );
s2.evict( myOtherReferenceData );
assertFalse( s2.contains( myReferenceData ) );
assertFalse( s2.contains( myOtherReferenceData ) );
s2.getTransaction().commit();
s2.close();
// still associated with s1
assertTrue( s1.contains( myReferenceData ) );
assertTrue( s1.contains( myOtherReferenceData ) );
s1.clear();
assertFalse( s1.contains( myReferenceData ) );
assertFalse( s1.contains( myOtherReferenceData ) );
s1.close();
// EntityEntry should still be set
assertNotNull( myReferenceData.$$_hibernate_getEntityEntry() );
assertNotNull( myOtherReferenceData.$$_hibernate_getEntityEntry() );
// load them into 2 sessions
s1 = openSession();
s1.getTransaction().begin();
assertSame( myReferenceData, s1.get( MyEnhancedReferenceData.class, myReferenceData.getId() ) );
assertSame( myOtherReferenceData, s1.get( MyEnhancedReferenceData.class, myOtherReferenceData.getId() ) );
s2 = openSession();
s2.getTransaction().begin();
assertSame( myReferenceData, s2.get( MyEnhancedReferenceData.class, myReferenceData.getId() ) );
assertSame( myOtherReferenceData, s2.get( MyEnhancedReferenceData.class, myOtherReferenceData.getId() ) );
assertEquals( Status.READ_ONLY, myReferenceData.$$_hibernate_getEntityEntry().getStatus() );
assertEquals( Status.READ_ONLY, myOtherReferenceData.$$_hibernate_getEntityEntry().getStatus() );
// delete myReferenceData from s1
s1.delete( myReferenceData );
assertEquals( Status.DELETED, myReferenceData.$$_hibernate_getEntityEntry().getStatus() );
assertEquals( Status.READ_ONLY, myOtherReferenceData.$$_hibernate_getEntityEntry().getStatus() );
// delete myOtherReferenceData from s2
s2.delete( myOtherReferenceData );
assertEquals( Status.DELETED, myReferenceData.$$_hibernate_getEntityEntry().getStatus() );
assertEquals( Status.DELETED, myOtherReferenceData.$$_hibernate_getEntityEntry().getStatus() );
s1.getTransaction().commit();
s1.close();
assertEquals( Status.GONE, myReferenceData.$$_hibernate_getEntityEntry().getStatus() );
assertEquals( Status.DELETED, myOtherReferenceData.$$_hibernate_getEntityEntry().getStatus() );
s2.getTransaction().commit();
s2.close();
assertEquals( Status.GONE, myReferenceData.$$_hibernate_getEntityEntry().getStatus() );
assertEquals( Status.GONE, myOtherReferenceData.$$_hibernate_getEntityEntry().getStatus() );
}
@Entity(name = "MyEnhancedReferenceData")
@Immutable
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
@Proxy(lazy = false)
@SuppressWarnings("UnusedDeclaration")
public static class MyEnhancedReferenceData implements ManagedEntity {
@Id
private Integer id;
private String name;
private String theValue;
@Transient
private transient EntityEntry entityEntry;
@Transient
private transient ManagedEntity previous;
@Transient
private transient ManagedEntity next;
public MyEnhancedReferenceData(Integer id, String name, String theValue) {
this.id = id;
this.name = name;
this.theValue = theValue;
}
protected MyEnhancedReferenceData() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTheValue() {
return theValue;
}
public void setTheValue(String theValue) {
this.theValue = theValue;
}
@Override
public Object $$_hibernate_getEntityInstance() {
return this;
}
@Override
public EntityEntry $$_hibernate_getEntityEntry() {
return entityEntry;
}
@Override
public void $$_hibernate_setEntityEntry(EntityEntry entityEntry) {
this.entityEntry = entityEntry;
}
@Override
public ManagedEntity $$_hibernate_getNextManagedEntity() {
return next;
}
@Override
public void $$_hibernate_setNextManagedEntity(ManagedEntity next) {
this.next = next;
}
@Override
public ManagedEntity $$_hibernate_getPreviousManagedEntity() {
return previous;
}
@Override
public void $$_hibernate_setPreviousManagedEntity(ManagedEntity previous) {
this.previous = previous;
}
}
}