branch feature/3685 created (now 61f31da)
This is an automated email from the git hooks/post-receive script. New change to branch feature/3685 in repository topia. See http://git.nuiton.org/topia.git at 61f31da Introduce TopiaConfiguration#isValidateSchema and implement it This branch includes the following new commits: new 61f31da Introduce TopiaConfiguration#isValidateSchema and implement it The 1 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit 61f31da24421a4de7a42921265dfb14f0b7be673 Author: Brendan Le Ny <bleny@codelutin.com> Date: Wed May 6 13:03:06 2015 +0200 Introduce TopiaConfiguration#isValidateSchema and implement it -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/3685 in repository topia. See http://git.nuiton.org/topia.git commit 61f31da24421a4de7a42921265dfb14f0b7be673 Author: Brendan Le Ny <bleny@codelutin.com> Date: Wed May 6 13:03:06 2015 +0200 Introduce TopiaConfiguration#isValidateSchema and implement it --- .../topia/persistence/BeanTopiaConfiguration.java | 11 ++++ .../SchemaValidationTopiaException.java | 49 ++++++++++++++++++ .../topia/persistence/TopiaConfiguration.java | 9 ++++ .../persistence/TopiaConfigurationBuilder.java | 60 +++++++++++++++++----- .../persistence/internal/HibernateProvider.java | 6 ++- .../nuiton/topia/persistence/util/TopiaUtil.java | 11 +++- .../persistence/TopiaConfigurationBuilderTest.java | 1 + .../topia/migration/TopiaMigrationEngineTest.java | 7 ++- 8 files changed, 133 insertions(+), 21 deletions(-) diff --git a/topia-persistence/src/main/java/org/nuiton/topia/persistence/BeanTopiaConfiguration.java b/topia-persistence/src/main/java/org/nuiton/topia/persistence/BeanTopiaConfiguration.java index a1c306b..ec9c3eb 100644 --- a/topia-persistence/src/main/java/org/nuiton/topia/persistence/BeanTopiaConfiguration.java +++ b/topia-persistence/src/main/java/org/nuiton/topia/persistence/BeanTopiaConfiguration.java @@ -38,6 +38,8 @@ public class BeanTopiaConfiguration extends BeanJdbcConfiguration implements Top protected boolean initSchema = true; + protected boolean validateSchema = true; + protected Map<String, Class<? extends TopiaService>> declaredServices = new LinkedHashMap<String, Class<? extends TopiaService>>(); @@ -116,6 +118,15 @@ public class BeanTopiaConfiguration extends BeanJdbcConfiguration implements Top } @Override + public boolean isValidateSchema() { + return validateSchema; + } + + public void setValidateSchema(boolean validateSchema) { + this.validateSchema = validateSchema; + } + + @Override public Map<String, Class<? extends TopiaService>> getDeclaredServices() { return declaredServices; } diff --git a/topia-persistence/src/main/java/org/nuiton/topia/persistence/SchemaValidationTopiaException.java b/topia-persistence/src/main/java/org/nuiton/topia/persistence/SchemaValidationTopiaException.java new file mode 100644 index 0000000..832df52 --- /dev/null +++ b/topia-persistence/src/main/java/org/nuiton/topia/persistence/SchemaValidationTopiaException.java @@ -0,0 +1,49 @@ +package org.nuiton.topia.persistence; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import org.hibernate.HibernateException; +import org.hibernate.tool.hbm2ddl.SchemaValidator; + +import java.util.Arrays; + +/** + * This exception is throwed when the database schema is not suitable for the + * current entities model. It means that a table or a column is missing + * + * @since 3.0 + */ +public class SchemaValidationTopiaException extends TopiaException { + + /** + * We can know that an {@link HibernateException} is about schema validation + * if one of the stack trace element validate this predicate. + */ + protected static final Predicate<StackTraceElement> IS_STACK_TRACE_ELEMENT_ABOUT_SCHEMA_VALIDATION = + new Predicate<StackTraceElement>() { + + @Override + public boolean apply(StackTraceElement input) { + return input.getClassName().equals(SchemaValidator.class.getName()) + && input.getMethodName().equals("validate"); + } + }; + + public SchemaValidationTopiaException(String message, HibernateException e) { + super(message, e); + } + + /** + * If given {@link HibernateException} is about schema validation, throw a SchemaValidationTopiaException. + */ + public static void throwIfHibernateExceptionIsAboutSchemaValidation(HibernateException hibernateException) { + // XXX brendan 06/05/15 dirty hack to know if e is about schema validation since Hibernate exception management sucks + boolean stackTraceIsAboutSchemaValidation = Iterables.any( + Arrays.asList(hibernateException.getStackTrace()), + IS_STACK_TRACE_ELEMENT_ABOUT_SCHEMA_VALIDATION); + if (stackTraceIsAboutSchemaValidation) { + throw new SchemaValidationTopiaException(hibernateException.getMessage(), hibernateException); + } + } + +} diff --git a/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaConfiguration.java b/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaConfiguration.java index 4b109b0..b2eb019 100644 --- a/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaConfiguration.java +++ b/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaConfiguration.java @@ -48,6 +48,15 @@ public interface TopiaConfiguration extends JdbcConfiguration { boolean isInitSchema(); /** + * If true, ToPIA will validate schema against model upon starting. ToPIA will raise a + * {@link SchemaValidationTopiaException} if the schema is not suitable for ToPIA to run + * fine. + * + * @since 3.0 + */ + boolean isValidateSchema(); + + /** * Configuration directive to change topia Ids generation strategy. * * @since 3.0 diff --git a/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaConfigurationBuilder.java b/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaConfigurationBuilder.java index 1b92a59..99ba014 100644 --- a/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaConfigurationBuilder.java +++ b/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaConfigurationBuilder.java @@ -22,7 +22,6 @@ package org.nuiton.topia.persistence; * #L% */ -import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; @@ -30,8 +29,6 @@ import com.google.common.collect.ImmutableSet; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.hibernate.cfg.AvailableSettings; -import org.nuiton.topia.persistence.internal.DefaultTopiaIdFactory; -import org.nuiton.topia.persistence.internal.FullyQualifiedNamePlusUuidTopiaIdFactory; import org.nuiton.topia.persistence.jdbc.JdbcConfiguration; import org.nuiton.topia.persistence.jdbc.JdbcConfigurationBuilder; import org.nuiton.util.beans.Binder; @@ -73,6 +70,9 @@ public class TopiaConfigurationBuilder { protected static final String CONFIG_PERSISTENCE_INIT_SCHEMA = "topia.persistence.initSchema"; + protected static final String CONFIG_PERSISTENCE_VALIDATE_SCHEMA = + "topia.persistence.validateSchema"; + /** * Configuration that must not be in {@link TopiaConfiguration#getHibernateExtraConfiguration()}. */ @@ -154,6 +154,11 @@ public class TopiaConfigurationBuilder { boolean initSchema = StringUtils.isBlank(initSchemaConfigValue) || Boolean.parseBoolean(initSchemaConfigValue); result.setInitSchema(initSchema); + // Schema validation + String validateSchemaConfigValue = configuration.get(CONFIG_PERSISTENCE_VALIDATE_SCHEMA); + boolean validateSchema = StringUtils.isBlank(validateSchemaConfigValue) || Boolean.parseBoolean(validateSchemaConfigValue); + result.setValidateSchema(validateSchema); + // others String topiaIdFactoryClassName = configuration.get(CONFIG_PERSISTENCE_TOPIA_ID_FACTORY_CLASS_NAME); if (!Strings.isNullOrEmpty(topiaIdFactoryClassName)) { @@ -225,6 +230,11 @@ public class TopiaConfigurationBuilder { if ( ! topiaConfiguration.isInitSchema()) { map.put(CONFIG_PERSISTENCE_INIT_SCHEMA, String.valueOf(topiaConfiguration.isInitSchema())); } + + // Schema validation + if ( ! topiaConfiguration.isInitSchema()) { + map.put(CONFIG_PERSISTENCE_VALIDATE_SCHEMA, String.valueOf(topiaConfiguration.isValidateSchema())); + } // others map.put(CONFIG_PERSISTENCE_TOPIA_ID_FACTORY_CLASS_NAME, topiaConfiguration.getTopiaIdFactory().getClass().getName()); @@ -266,7 +276,7 @@ public class TopiaConfigurationBuilder { public BeanTopiaConfiguration forTest(Class<?> testClass, String methodName) { JdbcConfiguration jdbcConfiguration = jdbcConfigurationBuilder.forTestDatabase(testClass, methodName); - BeanTopiaConfiguration configuration = forDatabase(jdbcConfiguration).onlyCreateSchemaIfDatabaseIsEmpty().build(); + BeanTopiaConfiguration configuration = forDatabase(jdbcConfiguration).onlyCreateSchemaIfDatabaseIsEmpty().validateSchemaOnStartup().build(); return configuration; } @@ -285,31 +295,55 @@ public class TopiaConfigurationBuilder { this.beanTopiaConfiguration = beanTopiaConfiguration; } - public BuildStep onlyCreateSchemaIfDatabaseIsEmpty() { + public ConfigureValidateSchemaStep onlyCreateSchemaIfDatabaseIsEmpty() { beanTopiaConfiguration.setInitSchema(true); - return new BuildStep(beanTopiaConfiguration); + return nextStep(); } - public BuildStep useAlreadyExistingDatabaseAsIs() { + public ConfigureValidateSchemaStep useAlreadyExistingDatabaseAsIs() { beanTopiaConfiguration.setInitSchema(false); - return new BuildStep(beanTopiaConfiguration); + return nextStep(); } - public BuildStep useHibernateUpdate() { + public ConfigureValidateSchemaStep useHibernateUpdate() { beanTopiaConfiguration.setInitSchema(true); beanTopiaConfiguration.addDeclaredService("migration", org.nuiton.topia.persistence.HibernateTopiaMigrationService.class, Collections.<String, String>emptyMap()); - return new BuildStep(beanTopiaConfiguration); + return nextStep(); } - public BuildStep useFlyway() { + public ConfigureValidateSchemaStep useFlyway() { beanTopiaConfiguration.setInitSchema(true); beanTopiaConfiguration.addDeclaredService("migration", "org.nuiton.topia.flyway.TopiaFlywayServiceImpl", Collections.<String, String>emptyMap()); - return new BuildStep(beanTopiaConfiguration); + return nextStep(); } - public BuildStep useLiquibase() { + public ConfigureValidateSchemaStep useLiquibase() { beanTopiaConfiguration.setInitSchema(true); beanTopiaConfiguration.addDeclaredService("migration", "org.nuiton.topia.flyway.TopiaLiquibaseServiceImpl", Collections.<String, String>emptyMap()); + return nextStep(); + } + + protected ConfigureValidateSchemaStep nextStep() { + return new ConfigureValidateSchemaStep(beanTopiaConfiguration); + } + + } + + public class ConfigureValidateSchemaStep { + + protected BeanTopiaConfiguration beanTopiaConfiguration; + + public ConfigureValidateSchemaStep(BeanTopiaConfiguration beanTopiaConfiguration) { + this.beanTopiaConfiguration = beanTopiaConfiguration; + } + + public BuildStep validateSchemaOnStartup() { + beanTopiaConfiguration.setValidateSchema(true); + return new BuildStep(beanTopiaConfiguration); + } + + public BuildStep doNotValidateSchemaOnStartup() { + beanTopiaConfiguration.setValidateSchema(false); return new BuildStep(beanTopiaConfiguration); } diff --git a/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/HibernateProvider.java b/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/HibernateProvider.java index f864975..bcabf44 100644 --- a/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/HibernateProvider.java +++ b/topia-persistence/src/main/java/org/nuiton/topia/persistence/internal/HibernateProvider.java @@ -136,8 +136,10 @@ public class HibernateProvider { properties.put(AvailableSettings.C3P0_TIMEOUT, 1800); properties.put(AvailableSettings.C3P0_MAX_STATEMENTS, 50); - // always validate schema - properties.put(AvailableSettings.HBM2DDL_AUTO, "validate"); + // schema validation + if (topiaConfiguration.isValidateSchema()) { + properties.put(AvailableSettings.HBM2DDL_AUTO, "validate"); + } properties.put(HibernateAvailableSettings.NAMING_STRATEGY, org.hibernate.cfg.ImprovedNamingStrategy.class.getName()); properties.put(AvailableSettings.FORMAT_SQL, true); diff --git a/topia-persistence/src/main/java/org/nuiton/topia/persistence/util/TopiaUtil.java b/topia-persistence/src/main/java/org/nuiton/topia/persistence/util/TopiaUtil.java index 27f86a0..958b13b 100644 --- a/topia-persistence/src/main/java/org/nuiton/topia/persistence/util/TopiaUtil.java +++ b/topia-persistence/src/main/java/org/nuiton/topia/persistence/util/TopiaUtil.java @@ -30,6 +30,7 @@ import com.google.common.base.Supplier; import com.google.common.collect.ImmutableSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistry; @@ -42,6 +43,7 @@ import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Table; import org.hibernate.tool.hbm2ddl.DatabaseMetadata; import org.hibernate.tool.hbm2ddl.TableMetadata; +import org.nuiton.topia.persistence.SchemaValidationTopiaException; import org.nuiton.topia.persistence.TopiaEntity; import org.nuiton.topia.persistence.TopiaException; import org.nuiton.topia.persistence.TopiaNotFoundException; @@ -582,8 +584,13 @@ public class TopiaUtil { StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder(); StandardServiceRegistry standardServiceRegistry = builder.applySettings(properties).build(); - SessionFactory result = hibernateConfiguration.buildSessionFactory(standardServiceRegistry); - + SessionFactory result; + try { + result = hibernateConfiguration.buildSessionFactory(standardServiceRegistry); + } catch (HibernateException e) { + SchemaValidationTopiaException.throwIfHibernateExceptionIsAboutSchemaValidation(e); + throw e; + } return result; } diff --git a/topia-persistence/src/test/java/org/nuiton/topia/persistence/TopiaConfigurationBuilderTest.java b/topia-persistence/src/test/java/org/nuiton/topia/persistence/TopiaConfigurationBuilderTest.java index 3c32cda..781bdb1 100644 --- a/topia-persistence/src/test/java/org/nuiton/topia/persistence/TopiaConfigurationBuilderTest.java +++ b/topia-persistence/src/test/java/org/nuiton/topia/persistence/TopiaConfigurationBuilderTest.java @@ -68,6 +68,7 @@ public class TopiaConfigurationBuilderTest { TopiaConfiguration topiaConfiguration = new TopiaConfigurationBuilder().forTestDatabase(getClass(), "build") .useHibernateUpdate() + .validateSchemaOnStartup() .build(); Assert.assertTrue("any generated topia configuration must have initSchema to true", topiaConfiguration.isInitSchema()); diff --git a/topia-service-migration/src/test/java/org/nuiton/topia/migration/TopiaMigrationEngineTest.java b/topia-service-migration/src/test/java/org/nuiton/topia/migration/TopiaMigrationEngineTest.java index 0f50f2c..6ef173f 100644 --- a/topia-service-migration/src/test/java/org/nuiton/topia/migration/TopiaMigrationEngineTest.java +++ b/topia-service-migration/src/test/java/org/nuiton/topia/migration/TopiaMigrationEngineTest.java @@ -25,13 +25,12 @@ package org.nuiton.topia.migration; */ import com.google.common.collect.ImmutableMap; -import org.hibernate.HibernateException; import org.junit.Assert; import org.junit.Test; import org.nuiton.topia.it.mapping.TopiaItMappingTopiaApplicationContext; import org.nuiton.topia.it.mapping.TopiaItMappingTopiaPersistenceContext; import org.nuiton.topia.persistence.BeanTopiaConfiguration; -import org.nuiton.topia.persistence.TopiaConfiguration; +import org.nuiton.topia.persistence.SchemaValidationTopiaException; import org.nuiton.topia.persistence.TopiaConfigurationBuilder; import org.nuiton.topia.persistence.jdbc.JdbcConfiguration; import org.nuiton.topia.persistence.jdbc.JdbcH2Helper; @@ -153,8 +152,8 @@ public class TopiaMigrationEngineTest { TopiaItMappingTopiaPersistenceContext persistenceContext = applicationContext.newPersistenceContext(); persistenceContext.close(); Assert.fail("Validation should have failed"); - } catch (HibernateException he) { - Assert.assertEquals("Missing column: name in H2.PUBLIC.B71", he.getMessage()); + } catch (SchemaValidationTopiaException e) { + Assert.assertEquals("Missing column: name in H2.PUBLIC.B71", e.getMessage()); } applicationContext.close(); -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
participants (1)
-
nuiton.org scm