HHH-7957 - Integrate Public Review Draft of the JPA 2.1 spec : schema generation

This commit is contained in:
Steve Ebersole 2013-02-03 14:31:43 -06:00
parent 6599f710bb
commit 9ab924041d
21 changed files with 1687 additions and 7 deletions

View File

@ -876,7 +876,7 @@ public class Configuration implements Serializable {
@SuppressWarnings({ "unchecked" })
private Iterator<IdentifierGenerator> iterateGenerators(Dialect dialect) throws MappingException {
public Iterator<IdentifierGenerator> iterateGenerators(Dialect dialect) throws MappingException {
TreeMap generators = new TreeMap();
String defaultCatalog = properties.getProperty( Environment.DEFAULT_CATALOG );

View File

@ -32,8 +32,6 @@ import org.hibernate.service.Service;
* @author Steve Ebersole
*/
public interface DatabaseInfoDialectResolver extends Service {
public static final int NO_VERSION = -9999;
/**
* Determine the {@link Dialect} to use based on the given information. Implementations are
* expected to return the {@link Dialect} instance to use, or {@code null} if the they did not locate a match.
@ -45,6 +43,8 @@ public interface DatabaseInfoDialectResolver extends Service {
public Dialect resolve(DatabaseInfo databaseInfo);
public static interface DatabaseInfo {
public static final int NO_VERSION = -9999;
/**
* Obtain access to the database name, as returned from {@link java.sql.DatabaseMetaData#getDatabaseProductName()}
* for the target database

View File

@ -96,6 +96,9 @@ public interface PersistentIdentifierGenerator extends IdentifierGenerator {
*/
public Object generatorKey();
public String getSchema();
public String getCatalog();
}

View File

@ -24,6 +24,8 @@
package org.hibernate.jpa;
import org.hibernate.internal.util.StringHelper;
/**
* Defines the available HEM settings, both JPA-defined as well as Hibernate-specific
* <p/>
@ -192,6 +194,171 @@ public interface AvailableSettings {
*/
public static final String CDI_BEAN_MANAGER = "javax.persistence.bean.manager";
/**
* Specifies the action to be taken by the persistence provider. The set of possible values are:<ul>
* <li>none</li>
* <li>create</li>
* <li>drop</li>
* <li>drop-and-create</li>
* </ul>
*
* If no value is specified, the default is "none".
*
* @see SchemaGenAction
*/
public static final String SCHEMA_GEN_ACTION = "javax.persistence.schema-generation-action";
/**
* Specifies whether the schema is to be created in the database, whether scripts are to be generated, or both.
* The values for this property are:<ul>
* <li>database</li>
* <li>scripts</li>
* <li>database-and-scripts</li>
* </ul>
* If no value is specified, a default is assumed as follows:<ul>
* <li>
* if script targets are specified (per {@value #SCHEMA_GEN_CREATE_SCRIPT_TARGET} and
* {@value #SCHEMA_GEN_DROP_SCRIPT_TARGET}), then the default is assumed to be "scripts"
* </li>
* <li>
* Otherwise, "database" is assumed
* </li>
* </ul>
*
* @see SchemaGenTarget
*/
public static final String SCHEMA_GEN_TARGET = "javax.persistence.schema-generation-target";
/**
* If schema creations scripts are to be generated, the target/location for these scripts must be specified. This
* target may take the form of either a {@link java.io.Writer} or a string designating a
* {@link java.net.URL}.
* <p/>
* Create and drop scripts are written separately (though the same Writer/URL could be passed).
* {@value #SCHEMA_GEN_CREATE_SCRIPT_TARGET} specifies the target for the create script.
*
* @see #SCHEMA_GEN_DROP_SCRIPT_TARGET
*/
@SuppressWarnings("JavaDoc")
public static final String SCHEMA_GEN_CREATE_SCRIPT_TARGET = "javax.persistence.ddl-create-script-target";
/**
* If schema creations scripts are to be generated, the target/location for these scripts must be specified. This
* target may take the form of either a {@link java.io.Writer} or a string designating a
* {@link java.net.URL}.
* <p/>
* Create and drop scripts are written separately (though the same Writer/URL could be passed).
* {@value #SCHEMA_GEN_DROP_SCRIPT_TARGET} specifies the target for the create script.
*
* @see #SCHEMA_GEN_CREATE_SCRIPT_TARGET
*/
@SuppressWarnings("JavaDoc")
public static final String SCHEMA_GEN_DROP_SCRIPT_TARGET = "javax.persistence.ddl-drop-script-target";
/**
* Specifies whether schema generation is to occur on the basis of the object/relational mapping metadata, DDL
* scripts, or a combination of the two. The valid values for this property are: <ul>
* <li>metadata</li>
* <li>scripts</li>
* <li>metadata-then-scripts</li>
* <li>scripts-then-metadata</li>
* </ul>
* If no value is specified, a default is assumed as follows:<ul>
* <li>
* if source scripts are specified (per {@value #SCHEMA_GEN_CREATE_SCRIPT_SOURCE} and
* {@value #SCHEMA_GEN_DROP_SCRIPT_SOURCE}),then "scripts" is assumed
* </li>
* <li>
* otherwise, "metadata" is assumed
* </li>
* </ul>
*
* @see SchemaGenSource
*/
public static final String SCHEMA_GEN_SOURCE = "javax.persistence.schema-generation-source";
/**
* Specifies the CREATE script file as either a {@link java.io.Reader} configured for reading of the DDL script
* file or a string designating a file {@link java.net.URL} for the DDL script.
*
* @see #SCHEMA_GEN_DROP_SCRIPT_SOURCE
*/
public static final String SCHEMA_GEN_CREATE_SCRIPT_SOURCE = "javax.persistence.ddl-create-script-source";
/**
* Specifies the DROP script file as either a {@link java.io.Reader} configured for reading of the DDL script
* file or a string designating a file {@link java.net.URL} for the DDL script.
*
* @see #SCHEMA_GEN_CREATE_SCRIPT_SOURCE
*/
public static final String SCHEMA_GEN_DROP_SCRIPT_SOURCE = "javax.persistence.ddl-drop-script-source";
/**
* Specifies whether the persistence provider is to create the database schema(s) in addition to creating
* database objects (tables, sequences, constraints, etc). The value of this boolean property should be set
* to {@code true} if the persistence provider is to create schemas in the database or to generate DDL that
* contains CREATE SCHEMA commands. If this property is not supplied (or is explicitly {@code false}), the
* provider should not attempt to create database schemas.
*/
public static final String SCHEMA_GEN_CREATE_SCHEMAS = "javax.persistence.create-database-schemas";
/**
* Allows passing the specific {@link java.sql.Connection} instance to be used for performing schema generation
* where the target is "database".
* <p/>
* May also be used to determine the values for {@value #SCHEMA_GEN_DB_NAME},
* {@value #SCHEMA_GEN_DB_MAJOR_VERSION} and {@value #SCHEMA_GEN_DB_MINOR_VERSION}.
*/
public static final String SCHEMA_GEN_CONNECTION = "javax.persistence.schema-generation-connection";
/**
* Specifies the name of the database provider in cases where a Connection to the underlying database is
* not available (aka, mainly in generating scripts). In such cases, a value for
* {@value #SCHEMA_GEN_DB_NAME} *must* be specified.
* <p/>
* The value of this setting is expected to match the value returned by
* {@link java.sql.DatabaseMetaData#getDatabaseProductName()} for the target database.
* <p/>
* Additionally specifying {@value #SCHEMA_GEN_DB_MAJOR_VERSION} and/or {@value #SCHEMA_GEN_DB_MINOR_VERSION}
* may be required to understand exactly how to generate the required schema commands.
*
* @see #SCHEMA_GEN_DB_MAJOR_VERSION
* @see #SCHEMA_GEN_DB_MINOR_VERSION
*/
@SuppressWarnings("JavaDoc")
public static final String SCHEMA_GEN_DB_NAME = "javax.persistence.database-product-name";
/**
* Specifies the major version of the underlying database, as would be returned by
* {@link java.sql.DatabaseMetaData#getDatabaseMajorVersion} for the target database. This value is used to
* help more precisely determine how to perform schema generation tasks for the underlying database in cases
* where {@value #SCHEMA_GEN_DB_NAME} does not provide enough distinction.
* @see #SCHEMA_GEN_DB_NAME
* @see #SCHEMA_GEN_DB_MINOR_VERSION
*/
public static final String SCHEMA_GEN_DB_MAJOR_VERSION = "javax.persistence.database-major-version";
/**
* Specifies the minor version of the underlying database, as would be returned by
* {@link java.sql.DatabaseMetaData#getDatabaseMinorVersion} for the target database. This value is used to
* help more precisely determine how to perform schema generation tasks for the underlying database in cases
* where te combination of {@value #SCHEMA_GEN_DB_NAME} and {@value #SCHEMA_GEN_DB_MAJOR_VERSION} does not provide
* enough distinction.
*
* @see #SCHEMA_GEN_DB_NAME
* @see #SCHEMA_GEN_DB_MAJOR_VERSION
*/
public static final String SCHEMA_GEN_DB_MINOR_VERSION = "javax.persistence.database-minor-version";
/**
* Specifies a {@link java.io.Reader} configured for reading of the SQL load script or a string designating the
* file {@link java.net.URL} for the SQL load script.
* <p/>
* A "SQL load script" is a script that performs some database initialization (INSERT, etc).
*/
public static final String SCHEMA_GEN_LOAD_SCRIPT_SOURCE = "javax.persistence.sql-load-script-source";
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Hibernate specific settings

View File

@ -36,6 +36,7 @@ import java.util.Map;
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
import org.hibernate.jpa.boot.spi.Bootstrap;
import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder;
import org.hibernate.jpa.boot.spi.ProviderChecker;
import org.hibernate.jpa.internal.util.PersistenceUtilHelper;
@ -56,6 +57,11 @@ public class HibernatePersistenceProvider implements PersistenceProvider {
*/
@Override
public EntityManagerFactory createEntityManagerFactory(String persistenceUnitName, Map properties) {
final EntityManagerFactoryBuilder builder = getEntityManagerFactoryBuilderOrNull( persistenceUnitName, properties );
return builder == null ? null : builder.build();
}
private EntityManagerFactoryBuilder getEntityManagerFactoryBuilderOrNull(String persistenceUnitName, Map properties) {
final Map integration = wrap( properties );
final List<ParsedPersistenceXmlDescriptor> units = PersistenceXmlParser.locatePersistenceUnits( integration );
@ -75,7 +81,7 @@ public class HibernatePersistenceProvider implements PersistenceProvider {
continue;
}
return Bootstrap.getEntityManagerFactoryBuilder( persistenceUnit, integration ).build();
return Bootstrap.getEntityManagerFactoryBuilder( persistenceUnit, integration );
}
return null;
@ -98,13 +104,18 @@ public class HibernatePersistenceProvider implements PersistenceProvider {
@Override
public void generateSchema(PersistenceUnitInfo info, Map map) {
// todo : implement
EntityManagerFactoryBuilder builder = Bootstrap.getEntityManagerFactoryBuilder( info, map );
builder.generateSchema();
}
@Override
public boolean generateSchema(String persistenceUnitName, Map map) {
// todo : implement
return false;
final EntityManagerFactoryBuilder builder = getEntityManagerFactoryBuilderOrNull( persistenceUnitName, map );
if ( builder == null ) {
return false;
}
builder.generateSchema();
return true;
}
private final ProviderUtil providerUtil = new ProviderUtil() {

View File

@ -0,0 +1,101 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa;
import org.hibernate.internal.util.StringHelper;
/**
* Describes the allowable values of the {@value AvailableSettings#SCHEMA_GEN_ACTION} setting.
*
* @see AvailableSettings#SCHEMA_GEN_ACTION
*
* @author Steve Ebersole
*/
public enum SchemaGenAction {
/**
* "none" - no actions will be performed (aka, generation is disabled).
*/
NONE( "none" ),
/**
* "create" - database creation will be generated
*/
CREATE( "create" ),
/**
* "drop" - database dropping will be generated
*/
DROP( "drop" ),
/**
* "drop-and-create" - both database creation and database dropping will be generated.
*/
BOTH( "drop-and-create" );
private final String externalName;
private SchemaGenAction(String externalName) {
this.externalName = externalName;
}
/**
* Used when processing JPA configuration to interpret the {@value AvailableSettings#SCHEMA_GEN_ACTION} setting.
*
* @param value The encountered value of {@value AvailableSettings#SCHEMA_GEN_ACTION}
*
* @return The matching enum value. An empty value will return {@link #NONE}.
*
* @throws IllegalArgumentException If the incoming value is unrecognized
*/
public static SchemaGenAction interpret(String value) {
if ( StringHelper.isEmpty( value ) ) {
// default is NONE
return NONE;
}
if ( CREATE.externalName.equals( value ) ) {
return CREATE;
}
else if ( DROP.externalName.equals( value ) ) {
return DROP;
}
else if ( BOTH.externalName.equals( value ) ) {
return BOTH;
}
throw new IllegalArgumentException(
String.format( "Unrecognized '%s' value : %s", AvailableSettings.SCHEMA_GEN_ACTION, value )
);
}
public boolean includesCreate() {
return this == CREATE || this == BOTH;
}
public boolean includesDrop() {
return this == DROP || this == BOTH;
}
@Override
public String toString() {
return getClass().getSimpleName() + "(" + externalName + ")";
}
}

View File

@ -0,0 +1,103 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa;
import org.hibernate.internal.util.StringHelper;
/**
* Describes the allowable values of the {@value AvailableSettings#SCHEMA_GEN_SOURCE} setting.
*
* @see AvailableSettings#SCHEMA_GEN_SOURCE
*
* @author Steve Ebersole
*/
public enum SchemaGenSource {
/**
* "metadata" - The O/RM metadata is used as the exclusive source for generation
*/
METADATA( "metadata" ),
/**
* "scripts" - External DDL script(s) are used as the exclusive source for generation. The scripts for schema
* creation and dropping come from different sources. The creation DDL script is identified by the
* {@value AvailableSettings#SCHEMA_GEN_CREATE_SCRIPT_SOURCE} setting; the drop DDL script is identified by the
* {@value AvailableSettings#SCHEMA_GEN_DROP_SCRIPT_SOURCE} setting.
*
* @see AvailableSettings#SCHEMA_GEN_CREATE_SCRIPT_SOURCE
* @see AvailableSettings#SCHEMA_GEN_DROP_SCRIPT_SOURCE
*/
SCRIPTS( "scripts" ),
/**
* "metadata-then-scripts" - Both the O/RM metadata and external DDL scripts are used as sources for generation,
* with the O/RM metadata being applied first.
*
* @see #METADATA
* @see #SCRIPTS
*/
METADATA_THEN_SCRIPTS( "metadata-then-scripts" ),
/**
* "scripts-then-metadata" - Both the O/RM metadata and external DDL scripts are used as sources for generation,
* with the commands from the external DDL script(s) being applied first
*
* @see #SCRIPTS
* @see #METADATA
*/
SCRIPTS_THEN_METADATA( "scripts-then-metadata" );
private final String externalName;
private SchemaGenSource(String externalName) {
this.externalName = externalName;
}
/**
* Used when processing JPA configuration to interpret the {@value AvailableSettings#SCHEMA_GEN_SOURCE} setting.
*
* @param value The encountered value of {@value AvailableSettings#SCHEMA_GEN_SOURCE}
*
* @return The matching enum value. An empty value will return {@code null}.
*
* @throws IllegalArgumentException If the incoming value is unrecognized
*/
public static SchemaGenSource interpret(String value) {
if ( StringHelper.isEmpty( value ) ) {
// empty is in fact valid as means to interpret default value based on other settings
return null;
}
if ( METADATA.externalName.equals( value ) ) {
return METADATA;
}
else if ( SCRIPTS.externalName.equals( value ) ) {
return SCRIPTS;
}
else if ( METADATA_THEN_SCRIPTS.externalName.equals( value ) ) {
return METADATA_THEN_SCRIPTS;
}
else if ( SCRIPTS_THEN_METADATA.externalName.equals( value ) ) {
return SCRIPTS_THEN_METADATA;
}
throw new IllegalArgumentException( "Unrecognized schema generation source value : " + value );
}
}

View File

@ -0,0 +1,92 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa;
import org.hibernate.internal.util.StringHelper;
/**
* Describes the allowable values of the {@value AvailableSettings#SCHEMA_GEN_TARGET} setting.
*
* @see AvailableSettings#SCHEMA_GEN_TARGET
*
* @author Steve Ebersole
*/
public enum SchemaGenTarget {
/**
* "database" - Generation commands will be executed directly against the database (via JDBC Statements).
*/
DATABASE( "database" ),
/**
* "scripts" - Generation commands will be written to script (text) "targets" as indicated by the
* {@value AvailableSettings#SCHEMA_GEN_CREATE_SCRIPT_TARGET} and
* {@value AvailableSettings#SCHEMA_GEN_DROP_SCRIPT_TARGET} settings.
*/
SCRIPTS( "scripts" ),
/**
* "database-and-scripts" - Generation commands will be sent to both.
*
* @see #DATABASE
* @see #SCRIPTS
*/
BOTH( "database-and-scripts" );
private final String externalName;
private SchemaGenTarget(String externalName) {
this.externalName = externalName;
}
/**
* Used when processing JPA configuration to interpret the {@value AvailableSettings#SCHEMA_GEN_TARGET} setting.
*
* @param value The encountered value of {@value AvailableSettings#SCHEMA_GEN_TARGET}
*
* @return The matching enum value. An empty value will return {@code null}.
*
* @throws IllegalArgumentException If the incoming value is unrecognized
*/
public static SchemaGenTarget interpret(String value) {
if ( StringHelper.isEmpty( value ) ) {
// empty is in fact valid as means to interpret default value based on other settings
return null;
}
if ( DATABASE.externalName.equals( value ) ) {
return DATABASE;
}
else if ( SCRIPTS.externalName.equals( value ) ) {
return SCRIPTS;
}
else if ( BOTH.externalName.equals( value ) ) {
return BOTH;
}
throw new IllegalArgumentException( "Unknown schema generation target value : " + value );
}
@Override
public String toString() {
return getClass().getSimpleName() + "(" + externalName + ")";
}
}

View File

@ -81,6 +81,7 @@ import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder;
import org.hibernate.jpa.boot.spi.IntegratorProvider;
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
import org.hibernate.jpa.event.spi.JpaIntegrator;
import org.hibernate.jpa.internal.schemagen.JpaSchemaGenerator;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.hibernate.jpa.internal.EntityManagerMessageLogger;
import org.hibernate.jpa.internal.util.LogHelper;
@ -731,6 +732,32 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
}
@Override
public void generateSchema() {
processProperties();
final ServiceRegistry serviceRegistry = buildServiceRegistry();
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
// IMPL NOTE : TCCL handling here is temporary.
// It is needed because this code still uses Hibernate Configuration and Hibernate commons-annotations
// in turn which relies on TCCL being set.
( (ClassLoaderServiceImpl) classLoaderService ).withTccl(
new ClassLoaderServiceImpl.Work() {
@Override
public Object perform() {
final Configuration hibernateConfiguration = buildHibernateConfiguration( serviceRegistry );
JpaSchemaGenerator.performGeneration( hibernateConfiguration, serviceRegistry );
return null;
}
}
);
// release this builder
cancel();
}
@SuppressWarnings("unchecked")
public EntityManagerFactory build() {
processProperties();

View File

@ -73,4 +73,9 @@ public interface EntityManagerFactoryBuilder {
* something having gone wrong during the bootstrap process
*/
public void cancel();
/**
* Perform an explicit schema generation (rather than an "auto" one) based on the
*/
public void generateSchema();
}

View File

@ -0,0 +1,102 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa.internal.schemagen;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
import java.sql.Statement;
import org.jboss.logging.Logger;
/**
* GenerationTarget implementation for handling generation directly to the database
*
* @see org.hibernate.jpa.SchemaGenTarget#DATABASE
* @see org.hibernate.jpa.SchemaGenTarget#BOTH
*
* @author Steve Ebersole
*/
class DatabaseTarget implements GenerationTarget {
private static final Logger log = Logger.getLogger( DatabaseTarget.class );
private final JdbcConnectionContext jdbcConnectionContext;
private Statement jdbcStatement;
DatabaseTarget(JdbcConnectionContext jdbcConnectionContext) {
this.jdbcConnectionContext = jdbcConnectionContext;
}
@Override
public void acceptCreateCommands(Iterable<String> commands) {
for ( String command : commands ) {
try {
jdbcStatement().execute( command );
}
catch (SQLException e) {
throw new PersistenceException(
"Unable to execute JPA schema generation create command [" + command + "]"
);
}
}
}
private Statement jdbcStatement() {
if ( jdbcStatement == null ) {
try {
jdbcStatement = jdbcConnectionContext.getJdbcConnection().createStatement();
}
catch (SQLException e) {
throw new PersistenceException( "Unable to generate JDBC Statement object for schema generation" );
}
}
return jdbcStatement;
}
@Override
public void acceptDropCommands(Iterable<String> commands) {
for ( String command : commands ) {
try {
jdbcStatement().execute( command );
}
catch (SQLException e) {
throw new PersistenceException(
"Unable to execute JPA schema generation drop command [" + command + "]"
);
}
}
}
@Override
public void release() {
if ( jdbcStatement != null ) {
try {
jdbcStatement.close();
}
catch (SQLException e) {
log.debug( "Unable to close JDBC statement after JPA schema generation : " + e.toString() );
}
}
}
}

View File

@ -0,0 +1,75 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa.internal.schemagen;
import javax.persistence.PersistenceException;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import org.jboss.logging.Logger;
/**
* SqlScriptReader implementation for File references. A reader is opened here and then explicitly closed on
* {@link #reader}.
*
* @author Steve Ebersole
*/
class FileScriptSource extends ReaderScriptSource implements SqlScriptReader {
private static final Logger log = Logger.getLogger( FileScriptSource.class );
public FileScriptSource(String fileUrl) {
super( toFileReader( fileUrl ) );
}
@Override
public void release() {
try {
reader().close();
}
catch (IOException e) {
log.warn( "Unable to close file reader for generation script source" );
}
}
@SuppressWarnings("ResultOfMethodCallIgnored")
private static Reader toFileReader(String fileUrl) {
final File file = new File( fileUrl );
try {
// best effort, since this is very well not allowed in EE environments
file.createNewFile();
}
catch (Exception e) {
log.debug( "Exception calling File#createNewFile : " + e.toString() );
}
try {
return new FileReader( file );
}
catch (IOException e) {
throw new PersistenceException( "Unable to open specified script target file for writing : " + fileUrl );
}
}
}

View File

@ -0,0 +1,53 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa.internal.schemagen;
/**
* Contract describing a generation source for create commands
*
* @see org.hibernate.jpa.SchemaGenSource
* @see org.hibernate.jpa.AvailableSettings#SCHEMA_GEN_SOURCE
*
* @author Steve Ebersole
*/
interface GenerationSource {
/**
* Retrieve the create generation commands from this source.
*
* @return The generation commands
*/
public Iterable<String> getCreateCommands();
/**
* Retrieve the drop generation commands from this source
*
* @return The generation commands
*/
public Iterable<String> getDropCommands();
/**
* Release this source. Give it a change to release its resources, if any.
*/
public void release();
}

View File

@ -0,0 +1,53 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa.internal.schemagen;
/**
* Describes a schema generation target
*
* @see org.hibernate.jpa.SchemaGenTarget
* @see org.hibernate.jpa.AvailableSettings#SCHEMA_GEN_TARGET
*
* @author Steve Ebersole
*/
interface GenerationTarget {
/**
* Accept a group of create generation commands
*
* @param commands The commands
*/
public void acceptCreateCommands(Iterable<String> commands);
/**
* Accept a group of drop generation commands.
*
* @param commands The commands
*/
public void acceptDropCommands(Iterable<String> commands);
/**
* Release this target, giving it a change to release its resources.
*/
public void release();
}

View File

@ -0,0 +1,67 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa.internal.schemagen;
import javax.persistence.PersistenceException;
import java.sql.Connection;
import java.sql.SQLException;
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
/**
* Defines access to a JDBC Connection for use in Schema generation
*
* @author Steve Ebersole
*/
class JdbcConnectionContext {
private final JdbcConnectionAccess jdbcConnectionAccess;
private Connection jdbcConnection;
JdbcConnectionContext(JdbcConnectionAccess jdbcConnectionAccess) {
this.jdbcConnectionAccess = jdbcConnectionAccess;
}
public Connection getJdbcConnection() {
if ( jdbcConnection == null ) {
try {
this.jdbcConnection = jdbcConnectionAccess.obtainConnection();
}
catch (SQLException e) {
throw new PersistenceException( "Unable to obtain JDBC Connection", e );
}
}
return jdbcConnection;
}
public void release() {
if ( jdbcConnection != null ) {
try {
jdbcConnectionAccess.releaseConnection( jdbcConnection );
}
catch (SQLException e) {
throw new PersistenceException( "Unable to release JDBC Connection", e );
}
}
}
}

View File

@ -0,0 +1,428 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa.internal.schemagen;
import javax.persistence.PersistenceException;
import java.io.Reader;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import org.jboss.logging.Logger;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.dialect.spi.DatabaseInfoDialectResolver;
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.SchemaGenAction;
import org.hibernate.jpa.SchemaGenSource;
import org.hibernate.jpa.SchemaGenTarget;
import org.hibernate.mapping.Table;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor;
/**
* Class responsible for the JPA-defined schema generation behavior.
*
* @author Steve Ebersole
*/
public class JpaSchemaGenerator {
private static final Logger log = Logger.getLogger( JpaSchemaGenerator.class );
public static void performGeneration(Configuration hibernateConfiguration, ServiceRegistry serviceRegistry) {
// First, determine the actions (if any) to be performed ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final SchemaGenAction action = SchemaGenAction.interpret(
hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_ACTION )
);
if ( action == SchemaGenAction.NONE ) {
// no generation requested
return;
}
// Figure out the JDBC Connection context, if any ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final JdbcConnectionContext jdbcConnectionContext = determineAppropriateJdbcConnectionContext(
hibernateConfiguration,
serviceRegistry
);
final Dialect dialect = determineDialect( jdbcConnectionContext, hibernateConfiguration, serviceRegistry );
final ImportSqlCommandExtractor scriptCommandExtractor = serviceRegistry.getService( ImportSqlCommandExtractor.class );
// Next, determine the targets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final List<GenerationTarget> generationTargetList = new ArrayList<GenerationTarget>();
SchemaGenTarget target = SchemaGenTarget.interpret(
hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_TARGET )
);
// the default is dependent upon whether script targets were also specified...
final Object createScriptTargetSetting = hibernateConfiguration.getProperties().get(
AvailableSettings.SCHEMA_GEN_CREATE_SCRIPT_TARGET
);
final Object dropScriptTargetSetting = hibernateConfiguration.getProperties().get(
AvailableSettings.SCHEMA_GEN_CREATE_SCRIPT_TARGET
);
if ( target == null ) {
if ( createScriptTargetSetting != null && dropScriptTargetSetting != null ) {
target = SchemaGenTarget.SCRIPTS;
}
else {
target = SchemaGenTarget.DATABASE;
}
}
if ( target == SchemaGenTarget.DATABASE || target == SchemaGenTarget.BOTH ) {
generationTargetList.add( new DatabaseTarget( jdbcConnectionContext ) );
}
if ( target == SchemaGenTarget.SCRIPTS || target == SchemaGenTarget.BOTH ) {
// both create and drop scripts are expected per JPA spec
if ( createScriptTargetSetting == null ) {
throw new IllegalArgumentException( "For schema generation creation script target missing" );
}
if ( dropScriptTargetSetting == null ) {
throw new IllegalArgumentException( "For schema generation drop script target missing" );
}
generationTargetList.add( new ScriptsTarget( createScriptTargetSetting, dropScriptTargetSetting ) );
}
// determine sources ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final List<GenerationSource> generationSourceList = new ArrayList<GenerationSource>();
SchemaGenSource source = SchemaGenSource.interpret(
hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_SOURCE )
);
// the default for sources is dependent upon whether script sources were specified...
final Object createScriptSourceSetting = hibernateConfiguration.getProperties().get(
AvailableSettings.SCHEMA_GEN_CREATE_SCRIPT_SOURCE
);
final Object dropScriptSourceSetting = hibernateConfiguration.getProperties().get(
AvailableSettings.SCHEMA_GEN_DROP_SCRIPT_SOURCE
);
if ( source == null ) {
if ( createScriptSourceSetting != null && dropScriptSourceSetting != null ) {
source = SchemaGenSource.SCRIPTS;
}
else {
source = SchemaGenSource.METADATA;
}
}
final boolean createSchemas = ConfigurationHelper.getBoolean(
AvailableSettings.SCHEMA_GEN_CREATE_SCHEMAS,
hibernateConfiguration.getProperties(),
false
);
if ( createSchemas ) {
// todo : does it make sense to generate schema(s) defined in metadata if only script sources are to be used?
generationSourceList.add( new CreateSchemaCommandSource( hibernateConfiguration, dialect ) );
}
if ( source == SchemaGenSource.METADATA ) {
generationSourceList.add( new MetadataSource( hibernateConfiguration, dialect ) );
}
else if ( source == SchemaGenSource.SCRIPTS ) {
generationSourceList.add( new ScriptSource( createScriptSourceSetting, dropScriptSourceSetting, scriptCommandExtractor ) );
}
else if ( source == SchemaGenSource.METADATA_THEN_SCRIPTS ) {
generationSourceList.add( new MetadataSource( hibernateConfiguration, dialect ) );
generationSourceList.add( new ScriptSource( createScriptSourceSetting, dropScriptSourceSetting, scriptCommandExtractor ) );
}
else if ( source == SchemaGenSource.SCRIPTS_THEN_METADATA ) {
generationSourceList.add( new ScriptSource( createScriptSourceSetting, dropScriptSourceSetting, scriptCommandExtractor ) );
generationSourceList.add( new MetadataSource( hibernateConfiguration, dialect ) );
}
final Object importScriptSetting = hibernateConfiguration.getProperties().get(
AvailableSettings.SCHEMA_GEN_LOAD_SCRIPT_SOURCE
);
if ( importScriptSetting != null ) {
generationSourceList.add( new ImportScriptSource( importScriptSetting, scriptCommandExtractor ) );
}
// do the generation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
try {
doGeneration( action, generationSourceList, generationTargetList );
}
finally {
releaseResources( generationSourceList, generationTargetList, jdbcConnectionContext );
}
}
private static JdbcConnectionContext determineAppropriateJdbcConnectionContext(
Configuration hibernateConfiguration,
ServiceRegistry serviceRegistry) {
// see if a specific connection has been provided:
final Connection providedConnection = (Connection) hibernateConfiguration.getProperties().get(
AvailableSettings.SCHEMA_GEN_CONNECTION
);
if ( providedConnection != null ) {
return new JdbcConnectionContext(
new JdbcConnectionAccess() {
@Override
public Connection obtainConnection() throws SQLException {
return providedConnection;
}
@Override
public void releaseConnection(Connection connection) throws SQLException {
// do nothing
}
@Override
public boolean supportsAggressiveRelease() {
return false;
}
}
);
}
final ConnectionProvider connectionProvider = serviceRegistry.getService( ConnectionProvider.class );
if ( connectionProvider != null ) {
return new JdbcConnectionContext(
new JdbcConnectionAccess() {
@Override
public Connection obtainConnection() throws SQLException {
return connectionProvider.getConnection();
}
@Override
public void releaseConnection(Connection connection) throws SQLException {
connectionProvider.closeConnection( connection );
}
@Override
public boolean supportsAggressiveRelease() {
return connectionProvider.supportsAggressiveRelease();
}
}
);
}
// otherwise, return a no-op impl
return new JdbcConnectionContext( null ) {
@Override
public Connection getJdbcConnection() {
throw new PersistenceException( "No connection information supplied" );
}
};
}
private static Dialect determineDialect(
JdbcConnectionContext jdbcConnectionContext,
Configuration hibernateConfiguration,
ServiceRegistry serviceRegistry) {
final String explicitDbName = hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_DB_NAME );
final String explicitDbMajor = hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_DB_MAJOR_VERSION );
final String explicitDbMinor = hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_DB_MINOR_VERSION );
if ( StringHelper.isNotEmpty( explicitDbName ) ) {
serviceRegistry.getService( DatabaseInfoDialectResolver.class ).resolve(
new DatabaseInfoDialectResolver.DatabaseInfo() {
@Override
public String getDatabaseName() {
return explicitDbName;
}
@Override
public int getDatabaseMajorVersion() {
return StringHelper.isEmpty( explicitDbMajor )
? NO_VERSION
: Integer.parseInt( explicitDbMajor );
}
@Override
public int getDatabaseMinorVersion() {
return StringHelper.isEmpty( explicitDbMinor )
? NO_VERSION
: Integer.parseInt( explicitDbMinor );
}
}
);
}
return serviceRegistry.getService( JdbcServices.class ).getDialect();
}
private static void doGeneration(
SchemaGenAction action,
List<GenerationSource> generationSourceList,
List<GenerationTarget> generationTargetList) {
for ( GenerationSource source : generationSourceList ) {
if ( action.includesCreate() ) {
final Iterable<String> createCommands = source.getCreateCommands();
for ( GenerationTarget target : generationTargetList ) {
target.acceptCreateCommands( createCommands );
}
}
if ( action.includesDrop() ) {
final Iterable<String> dropCommands = source.getDropCommands();
for ( GenerationTarget target : generationTargetList ) {
target.acceptDropCommands( dropCommands );
}
}
}
}
private static void releaseResources(
List<GenerationSource> generationSourceList,
List<GenerationTarget> generationTargetList,
JdbcConnectionContext jdbcConnectionContext) {
for ( GenerationTarget target : generationTargetList ) {
try {
target.release();
}
catch (Exception e) {
log.debug( "Problem releasing generation target : " + e.toString() );
}
}
for ( GenerationSource source : generationSourceList ) {
try {
source.release();
}
catch (Exception e) {
log.debug( "Problem releasing generation source : " + e.toString() );
}
}
try {
jdbcConnectionContext.release();
}
catch (Exception e) {
log.debug( "Unable to release JDBC connection after generation" );
}
}
private static class CreateSchemaCommandSource implements GenerationSource {
private final List<String> commands;
private CreateSchemaCommandSource(Configuration hibernateConfiguration, Dialect dialect) {
final HashSet<String> schemas = new HashSet<String>();
// final HashSet<String> catalogs = new HashSet<String>();
final Iterator<Table> tables = hibernateConfiguration.getTableMappings();
while ( tables.hasNext() ) {
final Table table = tables.next();
// catalogs.add( table.getCatalog() );
schemas.add( table.getSchema() );
}
final Iterator<IdentifierGenerator> generators = hibernateConfiguration.iterateGenerators( dialect );
while ( generators.hasNext() ) {
final IdentifierGenerator generator = generators.next();
if ( PersistentIdentifierGenerator.class.isInstance( generator ) ) {
// catalogs.add( ( (PersistentIdentifierGenerator) generator ).getCatalog() );
schemas.add( ( (PersistentIdentifierGenerator) generator ).getCatalog() );
}
}
// if ( schemas.isEmpty() && catalogs.isEmpty() ) {
if ( schemas.isEmpty() ) {
commands = Collections.emptyList();
return;
}
commands = new ArrayList<String>();
for ( String schema : schemas ) {
commands.add( dialect.getCreateSchemaCommand( schema ) );
}
// generate "create catalog" commands
}
@Override
public Iterable<String> getCreateCommands() {
return commands;
}
@Override
public Iterable<String> getDropCommands() {
return Collections.emptyList();
}
@Override
public void release() {
// nothing to do
}
}
private static class ImportScriptSource implements GenerationSource {
private final SqlScriptReader sourceReader;
private final ImportSqlCommandExtractor scriptCommandExtractor;
public ImportScriptSource(Object scriptSourceSetting, ImportSqlCommandExtractor scriptCommandExtractor) {
this.scriptCommandExtractor = scriptCommandExtractor;
if ( Reader.class.isInstance( scriptSourceSetting ) ) {
sourceReader = new ReaderScriptSource( (Reader) scriptSourceSetting );
}
else {
sourceReader = new FileScriptSource( scriptSourceSetting.toString() );
}
}
@Override
public Iterable<String> getCreateCommands() {
return sourceReader.read( scriptCommandExtractor );
}
@Override
public Iterable<String> getDropCommands() {
return Collections.emptyList();
}
@Override
public void release() {
sourceReader.release();
}
}
}

View File

@ -0,0 +1,57 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa.internal.schemagen;
import java.util.Arrays;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.Dialect;
/**
* @author Steve Ebersole
*/
public class MetadataSource implements GenerationSource {
private final Configuration hibernateConfiguration;
private final Dialect dialect;
public MetadataSource(Configuration hibernateConfiguration, Dialect dialect) {
this.hibernateConfiguration = hibernateConfiguration;
this.dialect = dialect;
}
@Override
public Iterable<String> getCreateCommands() {
return Arrays.asList( hibernateConfiguration.generateSchemaCreationScript( dialect ) );
}
@Override
public Iterable<String> getDropCommands() {
return Arrays.asList( hibernateConfiguration.generateDropSchemaScript( dialect ) );
}
@Override
public void release() {
// nothing to do
}
}

View File

@ -0,0 +1,63 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa.internal.schemagen;
import java.io.Reader;
import java.util.Arrays;
import java.util.Collections;
import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor;
/**
* SqlScriptReader implementation for explicitly given Readers. The readers are not released by this class.
*
* @author Steve Ebersole
*/
class ReaderScriptSource implements SqlScriptReader {
private final Reader reader;
public ReaderScriptSource(Reader reader) {
this.reader = reader;
}
@Override
public Iterable<String> read(ImportSqlCommandExtractor commandExtractor) {
final String[] commands = commandExtractor.extractCommands( reader );
if ( commands == null ) {
return Collections.emptyList();
}
else {
return Arrays.asList( commands );
}
}
@Override
public void release() {
// nothing to do here
}
protected Reader reader() {
return reader;
}
}

View File

@ -0,0 +1,84 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa.internal.schemagen;
import javax.persistence.PersistenceException;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import org.jboss.logging.Logger;
import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor;
/**
* @author Steve Ebersole
*/
public class ScriptSource implements GenerationSource {
private static final Logger log = Logger.getLogger( ScriptSource.class );
private final SqlScriptReader createSource;
private final SqlScriptReader dropSource;
private final ImportSqlCommandExtractor scriptCommandExtractor;
public ScriptSource(
Object createScriptSourceSetting,
Object dropScriptSourceSetting,
ImportSqlCommandExtractor scriptCommandExtractor) {
this.scriptCommandExtractor = scriptCommandExtractor;
if ( Reader.class.isInstance( createScriptSourceSetting ) ) {
createSource = new ReaderScriptSource( (Reader) createScriptSourceSetting );
}
else {
createSource = new FileScriptSource( createScriptSourceSetting.toString() );
}
if ( Writer.class.isInstance( dropScriptSourceSetting ) ) {
dropSource = new ReaderScriptSource( (Reader) dropScriptSourceSetting );
}
else {
dropSource = new FileScriptSource( dropScriptSourceSetting.toString() );
}
}
@Override
public Iterable<String> getCreateCommands() {
return createSource.read( scriptCommandExtractor );
}
@Override
public Iterable<String> getDropCommands() {
return dropSource.read( scriptCommandExtractor );
}
@Override
public void release() {
createSource.release();
dropSource.release();
}
}

View File

@ -0,0 +1,153 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa.internal.schemagen;
import javax.persistence.PersistenceException;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import org.jboss.logging.Logger;
/**
* GenerationTarget implementation for handling generation to scripts
*
* @see org.hibernate.jpa.SchemaGenTarget#SCRIPTS
* @see org.hibernate.jpa.SchemaGenTarget#BOTH
*
* @author Steve Ebersole
*/
class ScriptsTarget implements GenerationTarget {
private static final Logger log = Logger.getLogger( ScriptsTarget.class );
private final ScriptTargetTarget createScriptTarget;
private final ScriptTargetTarget dropScriptTarget;
public ScriptsTarget(Object createScriptTargetSetting, Object dropScriptTargetSetting) {
if ( Writer.class.isInstance( createScriptTargetSetting ) ) {
createScriptTarget = new WriterScriptTarget( (Writer) createScriptTargetSetting );
}
else {
createScriptTarget = new FileScriptTarget( createScriptTargetSetting.toString() );
}
if ( Writer.class.isInstance( dropScriptTargetSetting ) ) {
dropScriptTarget = new WriterScriptTarget( (Writer) dropScriptTargetSetting );
}
else {
dropScriptTarget = new FileScriptTarget( dropScriptTargetSetting.toString() );
}
}
@Override
public void acceptCreateCommands(Iterable<String> commands) {
for ( String command : commands ) {
createScriptTarget.accept( command );
}
}
@Override
public void acceptDropCommands(Iterable<String> commands) {
for ( String command : commands ) {
dropScriptTarget.accept( command );
}
}
@Override
public void release() {
createScriptTarget.release();
dropScriptTarget.release();
}
/**
* Internal contract for handling Writer/File differences
*/
private static interface ScriptTargetTarget {
public void accept(String command);
public void release();
}
private static class WriterScriptTarget implements ScriptTargetTarget {
private final Writer writer;
public WriterScriptTarget(Writer writer) {
this.writer = writer;
}
@Override
public void accept(String command) {
try {
writer.write( command );
writer.flush();
}
catch (IOException e) {
throw new PersistenceException( "Could not write to target script file", e );
}
}
@Override
public void release() {
// nothing to do for a supplied writer
}
protected Writer writer() {
return writer;
}
}
private static class FileScriptTarget extends WriterScriptTarget implements ScriptTargetTarget {
public FileScriptTarget(String fileUrl) {
super( toFileWriter( fileUrl ) );
}
@Override
public void release() {
try {
writer().close();
}
catch (IOException e) {
throw new PersistenceException( "Unable to close file writer : " + e.toString() );
}
}
}
@SuppressWarnings("ResultOfMethodCallIgnored")
private static Writer toFileWriter(String fileUrl) {
final File file = new File( fileUrl );
try {
// best effort, since this is very well not allowed in EE environments
file.createNewFile();
}
catch (Exception e) {
log.debug( "Exception calling File#createNewFile : " + e.toString() );
}
try {
return new FileWriter( file );
}
catch (IOException e) {
throw new PersistenceException( "Unable to open specified script target file for writing : " + fileUrl );
}
}
}

View File

@ -0,0 +1,36 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jpa.internal.schemagen;
import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor;
/**
* Contract for handling Reader/File differences
*
* @author Steve Ebersole
*/
public interface SqlScriptReader {
public Iterable<String> read(ImportSqlCommandExtractor commandExtractor);
public void release();
}