Index: extensions/modeshape-connector-store-jpa/src/main/java/org/modeshape/connector/store/jpa/JpaConnectorI18n.java =================================================================== --- extensions/modeshape-connector-store-jpa/src/main/java/org/modeshape/connector/store/jpa/JpaConnectorI18n.java (revision 2578) +++ extensions/modeshape-connector-store-jpa/src/main/java/org/modeshape/connector/store/jpa/JpaConnectorI18n.java (working copy) @@ -49,6 +49,7 @@ public final class JpaConnectorI18n { public static I18n invalidReferences; public static I18n invalidIsolationLevel; public static I18n unableToDeleteBecauseOfReferences; + public static I18n dialectCouldNotBeDeterminedAndMustBeSpecified; public static I18n workspaceAlreadyExists; public static I18n workspaceDoesNotExist; Index: extensions/modeshape-connector-store-jpa/src/main/java/org/modeshape/connector/store/jpa/JpaSource.java =================================================================== --- extensions/modeshape-connector-store-jpa/src/main/java/org/modeshape/connector/store/jpa/JpaSource.java (revision 2578) +++ extensions/modeshape-connector-store-jpa/src/main/java/org/modeshape/connector/store/jpa/JpaSource.java (working copy) @@ -46,8 +46,10 @@ import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import net.jcip.annotations.Immutable; import net.jcip.annotations.ThreadSafe; +import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.ejb.Ejb3Configuration; +import org.hibernate.engine.SessionFactoryImplementor; import org.modeshape.common.annotation.AllowedValues; import org.modeshape.common.annotation.Category; import org.modeshape.common.annotation.Description; @@ -1123,7 +1125,10 @@ public class JpaSource implements RepositorySource, ObjectFactory { configurator.addAnnotatedClass(StoreOptionEntity.class); // Set the Hibernate properties used in all situations ... - setProperty(configurator, "hibernate.dialect", this.dialect); + if (this.dialect != null) { + // The dialect may be auto-determined ... + setProperty(configurator, "hibernate.dialect", this.dialect); + } if (this.isolationLevel != null) { setProperty(configurator, "hibernate.connection.isolation", this.isolationLevel); } @@ -1226,6 +1231,17 @@ public class JpaSource implements RepositorySource, ObjectFactory { throw new RepositorySourceException(msg); } } + + // Determine the dialect, if it was to be automatically discovered ... + if (this.dialect == null || this.dialect.trim().length() == 0) { + this.dialect = determineDialect(entityManager); + } + if (this.dialect == null || this.dialect.trim().length() == 0) { + // The dialect could not be determined ... + String msg = JpaConnectorI18n.dialectCouldNotBeDeterminedAndMustBeSpecified.text(name); + throw new RepositorySourceException(msg); + } + } finally { entityManager.close(); } @@ -1261,6 +1277,19 @@ public class JpaSource implements RepositorySource, ObjectFactory { } /** + * Automatically determine the dialect. + * + * @param entityManager the EntityManager instance; may not be null + * @return the name of the dialect, or null if the dialect cannot be determined + */ + protected String determineDialect( EntityManager entityManager ) { + // We need the connection in order to determine the dialect ... + SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor)entityManager.unwrap(Session.class) + .getSessionFactory(); + return sessionFactory.getDialect().toString(); + } + + /** * Set up the JPA configuration using Hibernate, except for the entity classes (which will already be configured when this * method is called) and the data source or connection information (which will be set after this method returns). Subclasses * may override this method to customize the configuration. Index: extensions/modeshape-connector-store-jpa/src/main/java/org/modeshape/connector/store/jpa/model/simple/LargeValueEntity.java =================================================================== --- extensions/modeshape-connector-store-jpa/src/main/java/org/modeshape/connector/store/jpa/model/simple/LargeValueEntity.java (revision 2578) +++ extensions/modeshape-connector-store-jpa/src/main/java/org/modeshape/connector/store/jpa/model/simple/LargeValueEntity.java (working copy) @@ -197,7 +197,7 @@ public class LargeValueEntity { assert manager != null; int result = 0; - if (dialect.toLowerCase().indexOf("mysql") != -1) { + if (dialect != null && dialect.toLowerCase().indexOf("mysql") != -1) { // Unfortunately, we cannot delete all the unused large values in a single statement // because of MySQL (see MODE-691). Therefore, we need to do this in multiple steps: // 1) Find the set of hashes that are not used anymore Index: extensions/modeshape-connector-store-jpa/src/main/resources/org/modeshape/connector/store/jpa/JpaConnectorI18n.properties =================================================================== --- extensions/modeshape-connector-store-jpa/src/main/resources/org/modeshape/connector/store/jpa/JpaConnectorI18n.properties (revision 2578) +++ extensions/modeshape-connector-store-jpa/src/main/resources/org/modeshape/connector/store/jpa/JpaConnectorI18n.properties (working copy) @@ -37,7 +37,7 @@ invalidUuidForWorkspace = There is no node with UUID "{0}" in workspace "{1}" invalidReferences = One or more references were invalid in {0} unableToDeleteBecauseOfReferences = At least one deleted node is referenced by a node that is not being deleted invalidIsolationLevel = An invalid isolation level "{0}" was specified. Valid isolation levels are '0' for TRANSACTION_NONE, '1' for TRANSACTION_READ_UNCOMMITTED, '2' for TRANSACTION_READ_COMMITTED, '4' for TRANSACTION_REPEATABLE_READ, and '8' for TRANSACTION_SERIALIZABLE (as defined in the java.sql.Connection class). The default is to not set this, which means that the isolation will not be set (and the JDBC DataSource's own isolation level will be used). - +dialectCouldNotBeDeterminedAndMustBeSpecified = The Hibernate dialect could not be automatically determined, and therefore must be specified on the specification for the '{0}' repository source. workspaceAlreadyExists = The source {0} already has a workspace named "{1}" @@ -74,7 +74,7 @@ dataSourceJndiNamePropertyDescription = The JNDI name of the JDBC DataSource ins dataSourceJndiNamePropertyLabel = JNDI Name of Data Source dataSourceJndiNamePropertyCategory = Data Source -dialectPropertyDescription = The dialect of the database. This must match one of the Hibernate dialect names, and must correspond to the type of driver being used. Examples include (but are not limited to) "org.hibernate.dialect.MySQLInnoDBDialect", "org.hibernate.dialect.Oracle10gDialect", "org.hibernate.dialect.PostgreSQLDialect", and "org.hibernate.dialect.HSQLDialect". For details, see the Hibernate documentation. +dialectPropertyDescription = The dialect of the database. If not specified, it will be auto-determined. Otherwise, this must match one of the Hibernate dialect names, and must correspond to the type of driver being used. Examples include (but are not limited to) "org.hibernate.dialect.MySQLInnoDBDialect", "org.hibernate.dialect.Oracle10gDialect", "org.hibernate.dialect.PostgreSQLDialect", and "org.hibernate.dialect.HSQLDialect". For details, see the Hibernate documentation. dialectPropertyLabel = Dialect dialectPropertyCategory = Index: extensions/modeshape-connector-store-jpa/src/test/java/org/modeshape/connector/store/jpa/JdbcConnectionTest.java =================================================================== --- extensions/modeshape-connector-store-jpa/src/test/java/org/modeshape/connector/store/jpa/JdbcConnectionTest.java (revision 2578) +++ extensions/modeshape-connector-store-jpa/src/test/java/org/modeshape/connector/store/jpa/JdbcConnectionTest.java (working copy) @@ -24,6 +24,7 @@ package org.modeshape.connector.store.jpa; import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNull.notNullValue; import static org.junit.Assert.assertThat; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; @@ -33,6 +34,7 @@ import org.junit.Before; import org.junit.Test; import org.modeshape.connector.store.jpa.model.common.WorkspaceEntity; import org.modeshape.connector.store.jpa.model.simple.SimpleModel; +import org.modeshape.graph.connector.RepositoryConnection; /** * Simple unit test that simply verifies the database connection. @@ -112,4 +114,23 @@ public class JdbcConnectionTest { manager.getTransaction().rollback(); } } + + @Test + public void shouldAutoDetectDialectAndSetOnJpaSource() { + // Set the connection properties using the environment defined in the POM files ... + JpaSource source = TestEnvironment.configureJpaSource("Test Repository", this); + String expectedDialect = source.getDialect(); + + source.setDialect(null); + RepositoryConnection connection = null; + try { + connection = source.getConnection(); + assertThat(source.getDialect(), is(notNullValue())); + if (expectedDialect != null) { + assertThat(source.getDialect(), is(expectedDialect)); + } + } finally { + if (connection != null) connection.close(); + } + } }