/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* 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.ogm.backendtck.optimisticlocking;
import static org.fest.assertions.Assertions.assertThat;
import java.io.Serializable;
import java.util.Map;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.ogm.cfg.OgmProperties;
import org.hibernate.ogm.datastore.spi.DatastoreProvider;
import org.hibernate.ogm.dialect.impl.ForwardingGridDialect;
import org.hibernate.ogm.dialect.spi.TupleContext;
import org.hibernate.ogm.model.key.spi.EntityKey;
import org.hibernate.ogm.model.spi.Tuple;
import org.hibernate.ogm.utils.GridDialectType;
import org.hibernate.ogm.utils.OgmTestCase;
import org.hibernate.ogm.utils.SkipByGridDialect;
import org.hibernate.ogm.utils.TestHelper;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
/**
* Test for detecting concurrent updates by dialects which support atomic find/update semantics or have their own
* optimistic locking scheme.
*
* @author Gunnar Morling
*/
@SkipByGridDialect(
value = { GridDialectType.INFINISPAN_REMOTE },
comment = "list - bag semantics unsupported (no primary key)"
)
public class OptimisticLockingExtraTest extends OgmTestCase {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void updateToEmbeddedCollectionCausesVersionToBeIncreased() throws Throwable {
Galaxy galaxy = persistGalaxy();
Session session = openSession();
Transaction transaction = session.beginTransaction();
Galaxy entity = session.get( Galaxy.class, galaxy.getId() );
entity.getStars().add( new Star( "Algol" ) );
transaction.commit();
session.clear();
session = openSession();
transaction = session.beginTransaction();
entity = session.get( Galaxy.class, galaxy.getId() );
assertThat( entity.getVersion() ).isEqualTo( 1 );
assertThat( entity.getStars() ).hasSize( 3 );
transaction.commit();
session.close();
}
private Galaxy persistGalaxy() {
Session session = openSession();
session.beginTransaction();
Galaxy milkyWay = new Galaxy( "galaxy-1", "Milky Way", new Star( "Sun" ), new Star( "Alpha Centauri" ) );
session.persist( milkyWay );
session.getTransaction().commit();
session.close();
return milkyWay;
}
@Override
protected void configure(Map<String, Object> settings) {
settings.put( OgmProperties.GRID_DIALECT, TestDialect.class );
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { Galaxy.class };
}
@SuppressWarnings("serial")
public static class TestDialect extends ForwardingGridDialect<Serializable> {
public TestDialect(DatastoreProvider provider) {
super( TestHelper.getCurrentGridDialect( provider ) );
}
@Override
public boolean updateTupleWithOptimisticLock(EntityKey entityKey, Tuple oldVersion, Tuple tuple, TupleContext tupleContext) {
if ( Thread.currentThread().getName().equals( "ogm-test-thread-0" ) ) {
waitALittleBit();
}
return super.updateTupleWithOptimisticLock( entityKey, oldVersion, tuple, tupleContext );
}
@Override
public boolean removeTupleWithOptimisticLock(EntityKey entityKey, Tuple oldVersion, TupleContext tupleContext) {
if ( Thread.currentThread().getName().equals( "ogm-test-thread-0" ) ) {
waitALittleBit();
}
return super.removeTupleWithOptimisticLock( entityKey, oldVersion, tupleContext );
}
private void waitALittleBit() {
try {
Thread.sleep( 1000 );
}
catch (InterruptedException e) {
throw new RuntimeException( e );
}
}
}
}