/*
* 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.tool.schema;
import java.sql.SQLSyntaxErrorException;
import java.util.Collections;
import java.util.EnumSet;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl;
import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.tool.schema.SourceType;
import org.hibernate.tool.schema.TargetType;
import org.hibernate.tool.schema.spi.CommandAcceptanceException;
import org.hibernate.tool.schema.spi.SchemaCreator;
import org.hibernate.tool.schema.spi.SchemaDropper;
import org.hibernate.tool.schema.spi.SchemaManagementTool;
import org.hibernate.tool.schema.spi.ScriptSourceInput;
import org.hibernate.tool.schema.spi.ScriptTargetOutput;
import org.hibernate.tool.schema.spi.SourceDescriptor;
import org.hibernate.tool.schema.spi.TargetDescriptor;
import org.hibernate.testing.jta.TestingJtaBootstrap;
import org.hibernate.testing.jta.TestingJtaPlatformImpl;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author Steve Ebersole
*/
public class SchemaToolTransactionHandlingTest extends BaseUnitTestCase {
// for each case we want to run these tool delegates in a matrix of:
// 1) JTA versus JDBC transaction handling
// 2) existing transaction versus not
//
// cases:
// 1) create-drop
// 2) update
// 3) validate
//
// so:
// 1) create-drop
// 1.1) JTA transaction handling
// 1.1.1) inside an existing transaction
// 1.1.2) outside any transaction
// 1.1) JDBC transaction handling
// - there really cannot be an "existing transaction" case...
@Test
public void testDropCreateDropInExistingJtaTransaction() {
// test for 1.1.1 - create-drop + JTA handling + existing
// start a JTA transaction...
try {
TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin();
}
catch (Exception e) {
throw new RuntimeException( "Unable to being JTA transaction prior to starting test", e );
}
// hold reference to Transaction object
final Transaction jtaTransaction;
try {
jtaTransaction = TestingJtaPlatformImpl.INSTANCE.getTransactionManager().getTransaction();
}
catch (SystemException e) {
throw new RuntimeException( "Unable to access JTA Transaction prior to starting test", e );
}
final StandardServiceRegistry registry = buildJtaStandardServiceRegistry();
// perform the test...
try {
final SchemaManagementTool smt = registry.getService( SchemaManagementTool.class );
final SchemaDropper schemaDropper = smt.getSchemaDropper( Collections.emptyMap() );
final SchemaCreator schemaCreator = smt.getSchemaCreator( Collections.emptyMap() );
final Metadata mappings = buildMappings( registry );
try {
try {
schemaDropper.doDrop(
mappings,
ExecutionOptionsTestImpl.INSTANCE,
SourceDescriptorImpl.INSTANCE,
TargetDescriptorImpl.INSTANCE
);
}catch (CommandAcceptanceException e){
//ignore may happen if sql drop does not support if exist
}
schemaCreator.doCreation(
mappings,
ExecutionOptionsTestImpl.INSTANCE,
SourceDescriptorImpl.INSTANCE,
TargetDescriptorImpl.INSTANCE
);
}
finally {
try {
schemaDropper.doDrop(
mappings,
ExecutionOptionsTestImpl.INSTANCE,
SourceDescriptorImpl.INSTANCE,
TargetDescriptorImpl.INSTANCE
);
}
catch (Exception ignore) {
// ignore
}
}
}
finally {
try {
jtaTransaction.commit();
((StandardServiceRegistryImpl) registry).destroy();
}
catch (Exception e) {
// not much we can do...
}
}
}
@Test
public void testValidateInExistingJtaTransaction() {
// test for 1.1.1 - create-drop + JTA handling + existing
// start a JTA transaction...
try {
TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin();
}
catch (Exception e) {
throw new RuntimeException( "Unable to being JTA transaction prior to starting test", e );
}
// hold reference to Transaction object
final Transaction jtaTransaction;
try {
jtaTransaction = TestingJtaPlatformImpl.INSTANCE.getTransactionManager().getTransaction();
}
catch (SystemException e) {
throw new RuntimeException( "Unable to access JTA Transaction prior to starting test", e );
}
final StandardServiceRegistry registry = buildJtaStandardServiceRegistry();
// perform the test...
try {
final SchemaManagementTool smt = registry.getService( SchemaManagementTool.class );
final Metadata mappings = buildMappings( registry );
// first make the schema exist...
try {
smt.getSchemaCreator( Collections.emptyMap() ).doCreation(
mappings,
ExecutionOptionsTestImpl.INSTANCE,
SourceDescriptorImpl.INSTANCE,
TargetDescriptorImpl.INSTANCE
);
}
catch (Exception e) {
throw new RuntimeException( "Unable to create schema to validation tests", e );
}
try {
smt.getSchemaValidator( Collections.emptyMap() ).doValidation(
mappings,
ExecutionOptionsTestImpl.INSTANCE
);
}
finally {
try {
smt.getSchemaDropper( Collections.emptyMap() ).doDrop(
mappings,
ExecutionOptionsTestImpl.INSTANCE,
SourceDescriptorImpl.INSTANCE,
TargetDescriptorImpl.INSTANCE
);
}
catch (Exception ignore) {
// ignore
}
}
}
finally {
try {
jtaTransaction.commit();
((StandardServiceRegistryImpl) registry).destroy();
}
catch (Exception e) {
// not much we can do...
}
}
}
private Metadata buildMappings(StandardServiceRegistry registry) {
return new MetadataSources( registry )
.addAnnotatedClass( MyEntity.class )
.buildMetadata();
}
protected StandardServiceRegistry buildJtaStandardServiceRegistry() {
StandardServiceRegistry registry = TestingJtaBootstrap.prepare().build();
assertThat( registry.getService( TransactionCoordinatorBuilder.class ), instanceOf( JtaTransactionCoordinatorBuilderImpl.class ) );
return registry;
}
@Entity( name = "MyEntity" )
@Table( name = "MyEntity" )
public static class MyEntity {
@Id
public Integer id;
public String name;
}
private static class SourceDescriptorImpl implements SourceDescriptor {
/**
* Singleton access
*/
public static final SourceDescriptorImpl INSTANCE = new SourceDescriptorImpl();
@Override
public SourceType getSourceType() {
return SourceType.METADATA;
}
@Override
public ScriptSourceInput getScriptSourceInput() {
return null;
}
}
private static class TargetDescriptorImpl implements TargetDescriptor {
/**
* Singleton access
*/
public static final TargetDescriptorImpl INSTANCE = new TargetDescriptorImpl();
@Override
public EnumSet<TargetType> getTargetTypes() {
return EnumSet.of( TargetType.DATABASE );
}
@Override
public ScriptTargetOutput getScriptTargetOutput() {
return null;
}
}
}