/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.readonly;
import java.math.BigDecimal;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
*
* @author Gavin King
* @author Gail Badner
*/
public class ReadOnlyTest extends AbstractReadOnlyTest {
@Override
public String[] getMappings() {
return new String[] { "readonly/DataPoint.hbm.xml", "readonly/TextHolder.hbm.xml" };
}
@Test
public void testReadOnlyOnProxies() {
clearCounts();
Session s = openSession();
s.beginTransaction();
DataPoint dp = new DataPoint();
dp.setX( new BigDecimal( 0.1d ).setScale(19, BigDecimal.ROUND_DOWN) );
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
dp.setDescription( "original" );
s.save( dp );
long dpId = dp.getId();
s.getTransaction().commit();
s.close();
assertInsertCount( 1 );
assertUpdateCount( 0 );
clearCounts();
s = openSession();
s.beginTransaction();
dp = ( DataPoint ) s.load( DataPoint.class, new Long( dpId ) );
assertFalse( "was initialized", Hibernate.isInitialized( dp ) );
s.setReadOnly( dp, true );
assertFalse( "was initialized during setReadOnly", Hibernate.isInitialized( dp ) );
dp.setDescription( "changed" );
assertTrue( "was not initialized during mod", Hibernate.isInitialized( dp ) );
assertEquals( "desc not changed in memory", "changed", dp.getDescription() );
s.flush();
s.getTransaction().commit();
s.close();
assertUpdateCount( 0 );
s = openSession();
s.beginTransaction();
List list = s.createQuery( "from DataPoint where description = 'changed'" ).list();
assertEquals( "change written to database", 0, list.size() );
assertEquals( 1, s.createQuery("delete from DataPoint").executeUpdate() );
s.getTransaction().commit();
s.close();
assertUpdateCount( 0 );
//deletes from Query.executeUpdate() are not tracked
//assertDeleteCount( 1 );
}
@Test
public void testReadOnlyMode() {
clearCounts();
Session s = openSession();
Transaction t = s.beginTransaction();
for ( int i=0; i<100; i++ ) {
DataPoint dp = new DataPoint();
dp.setX( new BigDecimal(i * 0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
s.save(dp);
}
t.commit();
s.close();
assertInsertCount( 100 );
assertUpdateCount( 0 );
clearCounts();
s = openSession();
t = s.beginTransaction();
int i = 0;
ScrollableResults sr = s.createQuery("from DataPoint dp order by dp.x asc")
.setReadOnly(true)
.scroll(ScrollMode.FORWARD_ONLY);
while ( sr.next() ) {
DataPoint dp = (DataPoint) sr.get(0);
if (++i==50) {
s.setReadOnly(dp, false);
}
dp.setDescription("done!");
}
t.commit();
assertUpdateCount( 1 );
clearCounts();
s.clear();
t = s.beginTransaction();
List single = s.createQuery("from DataPoint where description='done!'").list();
assertEquals( single.size(), 1 );
assertEquals( 100, s.createQuery("delete from DataPoint").executeUpdate() );
t.commit();
s.close();
assertUpdateCount( 0 );
//deletes from Query.executeUpdate() are not tracked
//assertDeleteCount( 100 );
}
@Test
public void testReadOnlyModeAutoFlushOnQuery() {
clearCounts();
Session s = openSession();
Transaction t = s.beginTransaction();
DataPoint dpFirst = null;
for ( int i=0; i<100; i++ ) {
DataPoint dp = new DataPoint();
dp.setX( new BigDecimal(i * 0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
s.save(dp);
}
assertInsertCount( 0 );
assertUpdateCount( 0 );
ScrollableResults sr = s.createQuery("from DataPoint dp order by dp.x asc")
.setReadOnly(true)
.scroll(ScrollMode.FORWARD_ONLY);
assertInsertCount( 100 );
assertUpdateCount( 0 );
clearCounts();
while ( sr.next() ) {
DataPoint dp = (DataPoint) sr.get(0);
assertFalse( s.isReadOnly( dp ) );
s.delete( dp );
}
t.commit();
s.close();
assertUpdateCount( 0 );
assertDeleteCount( 100 );
}
@Test
public void testSaveReadOnlyModifyInSaveTransaction() {
clearCounts();
Session s = openSession();
Transaction t = s.beginTransaction();
DataPoint dp = new DataPoint();
dp.setDescription( "original" );
dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
s.save(dp);
s.setReadOnly( dp, true );
dp.setDescription( "different" );
t.commit();
s.close();
assertInsertCount( 1 );
assertUpdateCount( 0 );
clearCounts();
s = openSession();
t = s.beginTransaction();
dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() );
s.setReadOnly( dp, true );
assertEquals( "original", dp.getDescription() );
dp.setDescription( "changed" );
assertEquals( "changed", dp.getDescription() );
s.refresh( dp );
assertEquals( "original", dp.getDescription() );
dp.setDescription( "changed" );
assertEquals( "changed", dp.getDescription() );
t.commit();
assertInsertCount( 0 );
assertUpdateCount( 0 );
s.clear();
t = s.beginTransaction();
dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() );
assertEquals( "original", dp.getDescription() );
s.delete( dp );
t.commit();
s.close();
assertUpdateCount( 0 );
assertDeleteCount( 1 );
clearCounts();
}
@Test
public void testReadOnlyRefresh() {
clearCounts();
Session s = openSession();
Transaction t = s.beginTransaction();
DataPoint dp = new DataPoint();
dp.setDescription( "original" );
dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
s.save(dp);
t.commit();
s.close();
assertInsertCount( 1 );
assertUpdateCount( 0 );
clearCounts();
s = openSession();
t = s.beginTransaction();
dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() );
s.setReadOnly( dp, true );
assertEquals( "original", dp.getDescription() );
dp.setDescription( "changed" );
assertEquals( "changed", dp.getDescription() );
s.refresh( dp );
assertEquals( "original", dp.getDescription() );
dp.setDescription( "changed" );
assertEquals( "changed", dp.getDescription() );
t.commit();
assertInsertCount( 0 );
assertUpdateCount( 0 );
s.clear();
t = s.beginTransaction();
dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() );
assertEquals( "original", dp.getDescription() );
s.delete( dp );
t.commit();
s.close();
assertUpdateCount( 0 );
assertDeleteCount( 1 );
clearCounts();
}
@Test
public void testReadOnlyRefreshDetached() {
clearCounts();
Session s = openSession();
Transaction t = s.beginTransaction();
DataPoint dp = new DataPoint();
dp.setDescription( "original" );
dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
s.save(dp);
t.commit();
s.close();
assertInsertCount( 1 );
assertUpdateCount( 0 );
clearCounts();
s = openSession();
t = s.beginTransaction();
dp.setDescription( "changed" );
assertEquals( "changed", dp.getDescription() );
s.refresh( dp );
assertEquals( "original", dp.getDescription() );
assertFalse( s.isReadOnly( dp ) );
s.setReadOnly( dp, true );
dp.setDescription( "changed" );
assertEquals( "changed", dp.getDescription() );
s.evict( dp );
s.refresh( dp );
assertEquals( "original", dp.getDescription() );
assertFalse( s.isReadOnly( dp ) );
t.commit();
assertInsertCount( 0 );
assertUpdateCount( 0 );
s.clear();
t = s.beginTransaction();
dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() );
assertEquals( "original", dp.getDescription() );
s.delete( dp );
t.commit();
s.close();
assertUpdateCount( 0 );
assertDeleteCount( 1 );
}
@Test
public void testReadOnlyDelete() {
clearCounts();
Session s = openSession();
Transaction t = s.beginTransaction();
DataPoint dp = new DataPoint();
dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
s.save(dp);
t.commit();
s.close();
assertInsertCount( 1 );
assertUpdateCount( 0 );
clearCounts();
s = openSession();
t = s.beginTransaction();
dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() );
s.setReadOnly( dp, true );
s.delete( dp );
t.commit();
s.close();
assertUpdateCount( 0 );
assertDeleteCount( 1 );
s = openSession();
t = s.beginTransaction();
List list = s.createQuery("from DataPoint where description='done!'").list();
assertTrue( list.isEmpty() );
t.commit();
s.close();
}
@Test
public void testReadOnlyGetModifyAndDelete() {
clearCounts();
Session s = openSession();
Transaction t = s.beginTransaction();
DataPoint dp = new DataPoint();
dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
s.save(dp);
t.commit();
s.close();
assertInsertCount( 1 );
assertUpdateCount( 0 );
clearCounts();
s = openSession();
t = s.beginTransaction();
dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() );
s.setReadOnly( dp, true );
dp.setDescription( "a DataPoint" );
s.delete( dp );
t.commit();
s.close();
assertUpdateCount( 0 );
assertDeleteCount( 1 );
clearCounts();
s = openSession();
t = s.beginTransaction();
List list = s.createQuery("from DataPoint where description='done!'").list();
assertTrue( list.isEmpty() );
t.commit();
s.close();
}
@Test
public void testReadOnlyModeWithExistingModifiableEntity() {
clearCounts();
Session s = openSession();
Transaction t = s.beginTransaction();
DataPoint dp = null;
for ( int i=0; i<100; i++ ) {
dp = new DataPoint();
dp.setX( new BigDecimal(i * 0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
s.save(dp);
}
t.commit();
s.close();
assertInsertCount( 100 );
assertUpdateCount( 0 );
clearCounts();
s = openSession();
t = s.beginTransaction();
DataPoint dpLast = ( DataPoint ) s.get( DataPoint.class, dp.getId() );
assertFalse( s.isReadOnly( dpLast ) );
int i = 0;
ScrollableResults sr = s.createQuery("from DataPoint dp order by dp.x asc")
.setReadOnly(true)
.scroll(ScrollMode.FORWARD_ONLY);
int nExpectedChanges = 0;
while ( sr.next() ) {
dp = (DataPoint) sr.get(0);
if ( dp.getId() == dpLast.getId() ) {
//dpLast existed in the session before executing the read-only query
assertFalse( s.isReadOnly( dp ) );
}
else {
assertTrue( s.isReadOnly( dp ) );
}
if (++i==50) {
s.setReadOnly(dp, false);
nExpectedChanges = ( dp == dpLast ? 1 : 2 );
}
dp.setDescription("done!");
}
t.commit();
s.clear();
assertInsertCount( 0 );
assertUpdateCount( nExpectedChanges );
clearCounts();
t = s.beginTransaction();
List list = s.createQuery("from DataPoint where description='done!'").list();
assertEquals( list.size(), nExpectedChanges );
assertEquals( 100, s.createQuery("delete from DataPoint").executeUpdate() );
t.commit();
s.close();
assertUpdateCount( 0 );
}
@Test
public void testModifiableModeWithExistingReadOnlyEntity() {
clearCounts();
Session s = openSession();
Transaction t = s.beginTransaction();
DataPoint dp = null;
for ( int i=0; i<100; i++ ) {
dp = new DataPoint();
dp.setX( new BigDecimal(i * 0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
s.save(dp);
}
t.commit();
s.close();
assertInsertCount( 100 );
assertUpdateCount( 0 );
clearCounts();
s = openSession();
t = s.beginTransaction();
DataPoint dpLast = ( DataPoint ) s.get( DataPoint.class, dp.getId() );
assertFalse( s.isReadOnly( dpLast ) );
s.setReadOnly( dpLast, true );
assertTrue( s.isReadOnly( dpLast ) );
dpLast.setDescription( "oy" );
int i = 0;
assertUpdateCount( 0 );
ScrollableResults sr = s.createQuery("from DataPoint dp order by dp.x asc")
.setReadOnly(false)
.scroll(ScrollMode.FORWARD_ONLY);
int nExpectedChanges = 0;
while ( sr.next() ) {
dp = (DataPoint) sr.get(0);
if ( dp.getId() == dpLast.getId() ) {
//dpLast existed in the session before executing the read-only query
assertTrue( s.isReadOnly( dp ) );
}
else {
assertFalse( s.isReadOnly( dp ) );
}
if (++i==50) {
s.setReadOnly(dp, true);
nExpectedChanges = ( dp == dpLast ? 99 : 98 );
}
dp.setDescription("done!");
}
t.commit();
s.clear();
assertUpdateCount( nExpectedChanges );
clearCounts();
t = s.beginTransaction();
List list = s.createQuery("from DataPoint where description='done!'").list();
assertEquals( list.size(), nExpectedChanges );
assertEquals( 100, s.createQuery("delete from DataPoint").executeUpdate() );
t.commit();
s.close();
assertUpdateCount( 0 );
}
@Test
public void testReadOnlyOnTextType() {
final String origText = "some huge text string";
final String newText = "some even bigger text string";
clearCounts();
Session s = openSession();
s.beginTransaction();
TextHolder holder = new TextHolder( origText );
s.save( holder );
Long id = holder.getId();
s.getTransaction().commit();
s.close();
assertInsertCount( 1 );
assertUpdateCount( 0 );
clearCounts();
s = openSession();
s.beginTransaction();
holder = ( TextHolder ) s.get( TextHolder.class, id );
s.setReadOnly( holder, true );
holder.setTheText( newText );
s.flush();
s.getTransaction().commit();
s.close();
assertUpdateCount( 0 );
s = openSession();
s.beginTransaction();
holder = ( TextHolder ) s.get( TextHolder.class, id );
assertEquals( "change written to database", origText, holder.getTheText() );
s.delete( holder );
s.getTransaction().commit();
s.close();
assertUpdateCount( 0 );
assertDeleteCount( 1 );
}
@Test
public void testMergeWithReadOnlyEntity() {
clearCounts();
Session s = openSession();
Transaction t = s.beginTransaction();
DataPoint dp = new DataPoint();
dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
s.save(dp);
t.commit();
s.close();
assertInsertCount( 1 );
assertUpdateCount( 0 );
clearCounts();
dp.setDescription( "description" );
s = openSession();
t = s.beginTransaction();
DataPoint dpManaged = ( DataPoint ) s.get( DataPoint.class, new Long( dp.getId() ) );
s.setReadOnly( dpManaged, true );
DataPoint dpMerged = ( DataPoint ) s.merge( dp );
assertSame( dpManaged, dpMerged );
t.commit();
s.close();
assertUpdateCount( 0 );
s = openSession();
t = s.beginTransaction();
dpManaged = ( DataPoint ) s.get( DataPoint.class, new Long( dp.getId() ) );
assertNull( dpManaged.getDescription() );
s.delete( dpManaged );
t.commit();
s.close();
assertUpdateCount( 0 );
assertDeleteCount( 1 );
}
}