From ee2dd0ddf5d42ff5343a97bfb7e4a7938ab36eec Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Wed, 30 Mar 2011 16:58:15 -0500 Subject: [PATCH] HHH-5996 - Wire in JdbcServices into SchemaUpdateTask, SchemaExportTask, SchemaValidatorTask, HibernateService.dropSchema(), HibernateService.createSchema() --- .../hibernate/impl/SessionFactoryImpl.java | 8 +- .../tool/hbm2ddl/DatabaseExporter.java | 85 ++++ .../org/hibernate/tool/hbm2ddl/Exporter.java | 33 ++ .../hibernate/tool/hbm2ddl/FileExporter.java | 54 +++ .../tool/hbm2ddl/ImportScriptException.java | 39 ++ .../hibernate/tool/hbm2ddl/SchemaExport.java | 454 +++++++++--------- .../hibernate/tool/hbm2ddl/SchemaUpdate.java | 91 ++-- .../tool/hbm2ddl/SchemaValidator.java | 23 +- .../tool/hbm2ddl/ScriptExporter.java | 43 ++ .../org/hibernate/tool/hbm2ddl/Target.java | 51 ++ .../test/annotations/EntityTest.java | 2 +- .../test/schemaupdate/MigrationTest.java | 6 +- 12 files changed, 610 insertions(+), 279 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/DatabaseExporter.java create mode 100644 hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/Exporter.java create mode 100644 hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/FileExporter.java create mode 100644 hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/ImportScriptException.java create mode 100644 hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/ScriptExporter.java create mode 100644 hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/Target.java diff --git a/hibernate-core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java index 9a8851ebad..ee63c1f39c 100644 --- a/hibernate-core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java @@ -388,16 +388,16 @@ public final class SessionFactoryImpl LOG.debugf("Instantiated session factory"); if ( settings.isAutoCreateSchema() ) { - new SchemaExport( getJdbcServices(), cfg ).create( false, true ); + new SchemaExport( serviceRegistry, cfg ).create( false, true ); } if ( settings.isAutoUpdateSchema() ) { - new SchemaUpdate( getJdbcServices(), cfg ).execute( false, true ); + new SchemaUpdate( serviceRegistry, cfg ).execute( false, true ); } if ( settings.isAutoValidateSchema() ) { - new SchemaValidator( getJdbcServices(), cfg ).validate(); + new SchemaValidator( serviceRegistry, cfg ).validate(); } if ( settings.isAutoDropSchema() ) { - schemaExport = new SchemaExport( getJdbcServices(), cfg ); + schemaExport = new SchemaExport( serviceRegistry, cfg ); } currentSessionContext = buildCurrentSessionContext(); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/DatabaseExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/DatabaseExporter.java new file mode 100644 index 0000000000..16b5e2f764 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/DatabaseExporter.java @@ -0,0 +1,85 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.tool.hbm2ddl; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.Statement; + +import org.jboss.logging.Logger; + +import org.hibernate.HibernateLogger; +import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; + +/** +* @author Steve Ebersole +*/ +class DatabaseExporter implements Exporter { + private static final HibernateLogger LOG = Logger.getMessageLogger( HibernateLogger.class, DatabaseExporter.class.getName() ); + + private final ConnectionHelper connectionHelper; + private final SqlExceptionHelper sqlExceptionHelper; + + private final Connection connection; + private final Statement statement; + + public DatabaseExporter(ConnectionHelper connectionHelper, SqlExceptionHelper sqlExceptionHelper) throws SQLException { + this.connectionHelper = connectionHelper; + this.sqlExceptionHelper = sqlExceptionHelper; + + connectionHelper.prepare( true ); + connection = connectionHelper.getConnection(); + statement = connection.createStatement(); + } + + @Override + public boolean acceptsImportScripts() { + return true; + } + + @Override + public void export(String string) throws Exception { + statement.executeUpdate( string ); + try { + SQLWarning warnings = statement.getWarnings(); + if ( warnings != null) { + sqlExceptionHelper.logAndClearWarnings( connection ); + } + } + catch( SQLException e ) { + LOG.unableToLogSqlWarnings( e ); + } + } + + @Override + public void release() throws Exception { + try { + statement.close(); + } + finally { + connectionHelper.release(); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/Exporter.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/Exporter.java new file mode 100644 index 0000000000..9fc428907e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/Exporter.java @@ -0,0 +1,33 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.tool.hbm2ddl; + +/** +* @author Steve Ebersole +*/ +interface Exporter { + public boolean acceptsImportScripts(); + public void export(String string) throws Exception; + public void release() throws Exception; +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/FileExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/FileExporter.java new file mode 100644 index 0000000000..c5ae56d57b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/FileExporter.java @@ -0,0 +1,54 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.tool.hbm2ddl; + +import java.io.FileWriter; +import java.io.IOException; + +/** + * @author Steve Ebersole + */ +class FileExporter implements Exporter { + private final FileWriter writer; + + public FileExporter(String outputFile) throws IOException { + this.writer = new FileWriter( outputFile ); + } + + @Override + public boolean acceptsImportScripts() { + return false; + } + + @Override + public void export(String string) throws Exception { + writer.write( string + '\n'); + } + + @Override + public void release() throws Exception { + writer.flush(); + writer.close(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/ImportScriptException.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/ImportScriptException.java new file mode 100644 index 0000000000..d4da557ce3 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/ImportScriptException.java @@ -0,0 +1,39 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.tool.hbm2ddl; + +import org.hibernate.HibernateException; + +/** + * @author Steve Ebersole + */ +public class ImportScriptException extends HibernateException { + public ImportScriptException(String s) { + super( s ); + } + + public ImportScriptException(String string, Throwable root) { + super( string, root ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java index 438ce25ea1..8cabd2c9e0 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2008-2011, 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 Middleware LLC. + * 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 @@ -20,14 +20,12 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate.tool.hbm2ddl; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; -import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -40,9 +38,11 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.Properties; + +import org.jboss.logging.Logger; + import org.hibernate.HibernateException; import org.hibernate.HibernateLogger; -import org.hibernate.JDBCException; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.cfg.NamingStrategy; @@ -55,106 +55,136 @@ import org.hibernate.engine.jdbc.spi.SqlStatementLogger; import org.hibernate.internal.util.ConfigHelper; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.config.ConfigurationHelper; +import org.hibernate.service.ServiceRegistry; import org.hibernate.service.internal.BasicServiceRegistryImpl; - -import org.jboss.logging.Logger; +import org.hibernate.service.jdbc.connections.spi.ConnectionProvider; /** * Commandline tool to export table schema to the database. This class may also be called from inside an application. * * @author Daniel Bradby * @author Gavin King + * @author Steve Ebersole */ public class SchemaExport { - private static final HibernateLogger LOG = Logger.getMessageLogger(HibernateLogger.class, SchemaExport.class.getName()); - - private ConnectionHelper connectionHelper; - private String[] dropSQL; - private String[] createSQL; - private String outputFile = null; - private String importFiles; - private Dialect dialect; - private String delimiter; - private final List exceptions = new ArrayList(); - private boolean haltOnError = false; - private Formatter formatter; - private SqlStatementLogger sqlStatementLogger; private static final String DEFAULT_IMPORT_FILE = "/import.sql"; + public static enum Type { + CREATE, + DROP, + NONE, + BOTH; + + public boolean doCreate() { + return this == BOTH || this == CREATE; + } + + public boolean doDrop() { + return this == BOTH || this == DROP; + } + } + + private final ConnectionHelper connectionHelper; + private final SqlStatementLogger sqlStatementLogger; + private final SqlExceptionHelper sqlExceptionHelper; + private final String[] dropSQL; + private final String[] createSQL; + private final String importFiles; + + private final List exceptions = new ArrayList(); + + private Formatter formatter; + + private String outputFile = null; + private String delimiter; + private boolean haltOnError = false; + + public SchemaExport(ServiceRegistry serviceRegistry, Configuration configuration) { + this.connectionHelper = new SuppliedConnectionProviderConnectionHelper( + serviceRegistry.getService( ConnectionProvider.class ) + ); + this.sqlStatementLogger = serviceRegistry.getService( JdbcServices.class ).getSqlStatementLogger(); + this.formatter = ( sqlStatementLogger.isFormat() ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter(); + this.sqlExceptionHelper = serviceRegistry.getService( JdbcServices.class ).getSqlExceptionHelper(); + + this.importFiles = ConfigurationHelper.getString( + Environment.HBM2DDL_IMPORT_FILES, + configuration.getProperties(), + DEFAULT_IMPORT_FILE + ); + + final Dialect dialect = serviceRegistry.getService( JdbcServices.class ).getDialect(); + this.dropSQL = configuration.generateDropSchemaScript( dialect ); + this.createSQL = configuration.generateSchemaCreationScript( dialect ); + } + /** * Create a schema exporter for the given Configuration * - * @param cfg The configuration from which to build a schema export. + * @param configuration The configuration from which to build a schema export. * @throws HibernateException Indicates problem preparing for schema export. */ - public SchemaExport(Configuration cfg) throws HibernateException { - this( cfg, cfg.getProperties() ); - } - - /** - * Create a schema exporter for the given Configuration and given settings - * - * @param cfg The configuration from which to build a schema export. - * @param jdbcServices The jdbc services - * @throws HibernateException Indicates problem preparing for schema export. - */ - public SchemaExport(JdbcServices jdbcServices, Configuration cfg) throws HibernateException { - dialect = jdbcServices.getDialect(); - connectionHelper = new SuppliedConnectionProviderConnectionHelper( jdbcServices.getConnectionProvider() ); - dropSQL = cfg.generateDropSchemaScript( dialect ); - createSQL = cfg.generateSchemaCreationScript( dialect ); - sqlStatementLogger = jdbcServices.getSqlStatementLogger(); - formatter = ( sqlStatementLogger.isFormat() ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter(); - importFiles = ConfigurationHelper.getString( - Environment.HBM2DDL_IMPORT_FILES, cfg.getProperties(), - DEFAULT_IMPORT_FILE - ); + public SchemaExport(Configuration configuration) { + this( configuration, configuration.getProperties() ); } /** * Create a schema exporter for the given Configuration, with the given * database connection properties. * - * @param cfg The configuration from which to build a schema export. + * @param configuration The configuration from which to build a schema export. * @param properties The properties from which to configure connectivity etc. * @throws HibernateException Indicates problem preparing for schema export. * * @deprecated properties may be specified via the Configuration object */ @Deprecated - public SchemaExport(Configuration cfg, Properties properties) throws HibernateException { - dialect = Dialect.getDialect( properties ); + public SchemaExport(Configuration configuration, Properties properties) throws HibernateException { + final Dialect dialect = Dialect.getDialect( properties ); Properties props = new Properties(); props.putAll( dialect.getDefaultProperties() ); props.putAll( properties ); + this.connectionHelper = new ManagedProviderConnectionHelper( props ); - connectionHelper = new ManagedProviderConnectionHelper( props ); - dropSQL = cfg.generateDropSchemaScript( dialect ); - createSQL = cfg.generateSchemaCreationScript( dialect ); + this.sqlStatementLogger = new SqlStatementLogger( false, true ); + this.formatter = FormatStyle.DDL.getFormatter(); + this.sqlExceptionHelper = new SqlExceptionHelper(); - formatter = ( ConfigurationHelper.getBoolean( Environment.FORMAT_SQL, props ) ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter(); + this.importFiles = ConfigurationHelper.getString( + Environment.HBM2DDL_IMPORT_FILES, + properties, + DEFAULT_IMPORT_FILE + ); - importFiles = ConfigurationHelper.getString( Environment.HBM2DDL_IMPORT_FILES, props, DEFAULT_IMPORT_FILE ); + this.dropSQL = configuration.generateDropSchemaScript( dialect ); + this.createSQL = configuration.generateSchemaCreationScript( dialect ); } /** * Create a schema exporter for the given Configuration, using the supplied connection for connectivity. * - * @param cfg The configuration to use. + * @param configuration The configuration to use. * @param connection The JDBC connection to use. * @throws HibernateException Indicates problem preparing for schema export. */ - public SchemaExport(Configuration cfg, Connection connection) throws HibernateException { + public SchemaExport(Configuration configuration, Connection connection) throws HibernateException { this.connectionHelper = new SuppliedConnectionHelper( connection ); - dialect = Dialect.getDialect( cfg.getProperties() ); - dropSQL = cfg.generateDropSchemaScript( dialect ); - createSQL = cfg.generateSchemaCreationScript( dialect ); - formatter = ( ConfigurationHelper.getBoolean( Environment.FORMAT_SQL, cfg.getProperties() ) ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter(); - importFiles = ConfigurationHelper.getString( Environment.HBM2DDL_IMPORT_FILES, cfg.getProperties(), + + this.sqlStatementLogger = new SqlStatementLogger( false, true ); + this.formatter = FormatStyle.DDL.getFormatter(); + this.sqlExceptionHelper = new SqlExceptionHelper(); + + this.importFiles = ConfigurationHelper.getString( + Environment.HBM2DDL_IMPORT_FILES, + configuration.getProperties(), DEFAULT_IMPORT_FILE ); + + final Dialect dialect = Dialect.getDialect( configuration.getProperties() ); + this.dropSQL = configuration.generateDropSchemaScript( dialect ); + this.createSQL = configuration.generateSchemaCreationScript( dialect ); } public SchemaExport( @@ -165,6 +195,8 @@ public class SchemaExport { this.dropSQL = dropSql; this.createSQL = createSql; this.importFiles = ""; + this.sqlStatementLogger = new SqlStatementLogger( false, true ); + this.sqlExceptionHelper = new SqlExceptionHelper(); this.formatter = FormatStyle.DDL.getFormatter(); } @@ -179,19 +211,6 @@ public class SchemaExport { return this; } - /** - * An import file, containing raw SQL statements to be executed. - * - * @param filename The import file name. - * @return this - * @deprecated use {@link org.hibernate.cfg.Environment#HBM2DDL_IMPORT_FILES} - */ - @Deprecated - public SchemaExport setImportFile(String filename) { - importFiles = filename; - return this; - } - /** * Set the end of statement delimiter * @@ -232,7 +251,11 @@ public class SchemaExport { * @param export export the script to the database */ public void create(boolean script, boolean export) { - execute( script, export, false, false ); + create( Target.interpret( script, export ) ); + } + + public void create(Target output) { + execute( output, Type.CREATE ); } /** @@ -242,103 +265,154 @@ public class SchemaExport { * @param export export the script to the database */ public void drop(boolean script, boolean export) { - execute( script, export, true, false ); + drop( Target.interpret( script, export ) ); + } + + public void drop(Target output) { + execute( output, Type.DROP ); } public void execute(boolean script, boolean export, boolean justDrop, boolean justCreate) { + execute( Target.interpret( script, export ), interpretType( justDrop, justCreate ) ); + } - LOG.runningHbm2ddlSchemaExport(); - - Connection connection = null; - Writer outputFileWriter = null; - List importFileReaders = new ArrayList(); - Statement statement = null; - - exceptions.clear(); - - try { - - for ( String currentFile : importFiles.split(",") ) { - try { - final String resourceName = currentFile.trim(); - InputStream stream = ConfigHelper.getResourceAsStream( resourceName ); - importFileReaders.add( new NamedReader( resourceName, stream ) ); - } - catch ( HibernateException e ) { - LOG.debugf("Import file not found: %s", currentFile); - } - } - - if ( outputFile != null ) { - LOG.writingGeneratedSchemaToFile(outputFile); - outputFileWriter = new FileWriter( outputFile ); - } - - if ( export ) { - LOG.exportingGeneratedSchemaToDatabase(); - connectionHelper.prepare( true ); - connection = connectionHelper.getConnection(); - statement = connection.createStatement(); - } - - if ( !justCreate ) { - drop( script, export, outputFileWriter, statement ); - } - - if ( !justDrop ) { - create( script, export, outputFileWriter, statement ); - if ( export && importFileReaders.size() > 0 ) { - for (NamedReader reader : importFileReaders) { - importScript( reader, statement ); - } - } - } - - LOG.schemaExportComplete(); - + private Type interpretType(boolean justDrop, boolean justCreate) { + if ( justDrop ) { + return Type.DROP; } - - catch ( Exception e ) { - exceptions.add( e ); - LOG.schemaExportUnsuccessful(e); + else if ( justCreate ) { + return Type.CREATE; } - - finally { - - try { - if ( statement != null ) { - statement.close(); - } - if ( connection != null ) { - connectionHelper.release(); - } - } - catch ( Exception e ) { - exceptions.add( e ); - LOG.unableToCloseConnection(e); - } - - try { - if ( outputFileWriter != null ) { - outputFileWriter.close(); - } - } - catch ( IOException ioe ) { - exceptions.add( ioe ); - LOG.unableToCloseOutputFile(outputFile, ioe); - } - for (NamedReader reader : importFileReaders) { - try { - reader.getReader().close(); - } catch (IOException ioe) { - exceptions.add(ioe); - LOG.unableToCloseInputFiles(reader.getName(), ioe); - } - } + else { + return Type.BOTH; } } - private class NamedReader { + public void execute(Target output, Type type) { + if ( output == Target.NONE || type == SchemaExport.Type.NONE ) { + return; + } + exceptions.clear(); + + LOG.runningHbm2ddlSchemaExport(); + + final List importFileReaders = new ArrayList(); + for ( String currentFile : importFiles.split(",") ) { + try { + final String resourceName = currentFile.trim(); + InputStream stream = ConfigHelper.getResourceAsStream( resourceName ); + importFileReaders.add( new NamedReader( resourceName, stream ) ); + } + catch ( HibernateException e ) { + LOG.debugf("Import file not found: %s", currentFile); + } + } + + final List exporters = new ArrayList(); + try { + // prepare exporters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + if ( output.doScript() ) { + exporters.add( new ScriptExporter() ); + } + if ( outputFile != null ) { + exporters.add( new FileExporter( outputFile ) ); + } + if ( output.doExport() ) { + exporters.add( new DatabaseExporter( connectionHelper, sqlExceptionHelper ) ); + } + + // perform exporters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + if ( type.doDrop() ) { + perform( dropSQL, exporters ); + } + if ( type.doCreate() ) { + perform( createSQL, exporters ); + if ( ! importFileReaders.isEmpty() ) { + for ( NamedReader namedReader : importFileReaders ) { + importScript( namedReader, exporters ); + } + } + } + } + catch (Exception e) { + exceptions.add( e ); + LOG.schemaExportUnsuccessful( e ); + } + finally { + // release exporters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + for ( Exporter exporter : exporters ) { + try { + exporter.release(); + } + catch (Exception ignore) { + } + } + + // release the named readers from import scripts + for ( NamedReader namedReader : importFileReaders ) { + try { + namedReader.getReader().close(); + } + catch (Exception ignore) { + } + } + LOG.schemaExportComplete(); + } + } + + private void perform(String[] sqlCommands, List exporters) { + for ( String sqlCommand : sqlCommands ) { + String formatted = formatter.format( sqlCommand ); + if ( delimiter != null ) { + formatted += delimiter; + } + sqlStatementLogger.logStatement( formatted ); + for ( Exporter exporter : exporters ) { + try { + exporter.export( formatted ); + } + catch (Exception e) { + if ( haltOnError ) { + throw new HibernateException( "Error during DDL export", e ); + } + exceptions.add( e ); + LOG.unsuccessfulCreate( sqlCommand ); + LOG.error( e.getMessage() ); + } + } + } + } + + private void importScript(NamedReader namedReader, List exporters) throws Exception { + BufferedReader reader = new BufferedReader( namedReader.getReader() ); + long lineNo = 0; + for ( String sql = reader.readLine(); sql != null; sql = reader.readLine() ) { + try { + lineNo++; + String trimmedSql = sql.trim(); + if ( trimmedSql.length() == 0 || + trimmedSql.startsWith( "--" ) || + trimmedSql.startsWith( "//" ) || + trimmedSql.startsWith( "/*" ) ) { + continue; + } + if ( trimmedSql.endsWith(";") ) { + trimmedSql = trimmedSql.substring(0, trimmedSql.length() - 1); + } + LOG.debugf( trimmedSql ); + for ( Exporter exporter: exporters ) { + if ( exporter.acceptsImportScripts() ) { + exporter.export( trimmedSql ); + } + } + } + catch ( Exception e ) { + throw new ImportScriptException( "Error during import script execution at line " + lineNo, e ); + } + } + } + + private static class NamedReader { private final Reader reader; private final String name; @@ -356,62 +430,6 @@ public class SchemaExport { } } - private void importScript(NamedReader importFileReader, Statement statement) - throws IOException { - LOG.executingImportScript(importFileReader.getName()); - BufferedReader reader = new BufferedReader( importFileReader.getReader() ); - long lineNo = 0; - for ( String sql = reader.readLine(); sql != null; sql = reader.readLine() ) { - try { - lineNo++; - String trimmedSql = sql.trim(); - if ( trimmedSql.length() == 0 || - trimmedSql.startsWith( "--" ) || - trimmedSql.startsWith( "//" ) || - trimmedSql.startsWith( "/*" ) ) { - continue; - } - if (trimmedSql.endsWith(";")) trimmedSql = trimmedSql.substring(0, trimmedSql.length() - 1); - LOG.debugf(trimmedSql); - statement.execute(trimmedSql); - } - catch ( SQLException e ) { - throw new JDBCException( "Error during import script execution at line " + lineNo, e ); - } - } - } - - private void create(boolean script, boolean export, Writer fileOutput, Statement statement) - throws IOException { - for ( int j = 0; j < createSQL.length; j++ ) { - try { - execute( script, export, fileOutput, statement, createSQL[j] ); - } - catch ( SQLException e ) { - if ( haltOnError ) { - throw new JDBCException( "Error during DDL export", e ); - } - exceptions.add( e ); - LOG.unsuccessfulCreate(createSQL[j]); - LOG.error(e.getMessage()); - } - } - } - - private void drop(boolean script, boolean export, Writer fileOutput, Statement statement) - throws IOException { - for ( int i = 0; i < dropSQL.length; i++ ) { - try { - execute( script, export, fileOutput, statement, dropSQL[i] ); - } - catch ( SQLException e ) { - exceptions.add( e ); - LOG.debugf("Unsuccessful: %s", dropSQL[i]); - LOG.debugf(e.getMessage()); - } - } - } - private void execute(boolean script, boolean export, Writer fileOutput, Statement statement, final String sql) throws IOException, SQLException { final SqlExceptionHelper sqlExceptionHelper = new SqlExceptionHelper(); @@ -437,7 +455,6 @@ public class SchemaExport { } } - } private static BasicServiceRegistryImpl createServiceRegistry(Properties properties) { @@ -528,7 +545,7 @@ public class SchemaExport { BasicServiceRegistryImpl serviceRegistry = createServiceRegistry( cfg.getProperties() ); try { - SchemaExport se = new SchemaExport( serviceRegistry.getService( JdbcServices.class ), cfg ) + SchemaExport se = new SchemaExport( serviceRegistry, cfg ) .setHaltOnError( halt ) .setOutputFile( outFile ) .setDelimiter( delim ); @@ -555,4 +572,5 @@ public class SchemaExport { public List getExceptions() { return exceptions; } + } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java index 2b1c6e1878..fadf2639c5 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2008-2011, 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 Middleware LLC. + * 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 @@ -20,7 +20,6 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate.tool.hbm2ddl; @@ -33,6 +32,9 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.Properties; + +import org.jboss.logging.Logger; + import org.hibernate.HibernateException; import org.hibernate.HibernateLogger; import org.hibernate.JDBCException; @@ -43,57 +45,65 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.internal.FormatStyle; import org.hibernate.engine.jdbc.internal.Formatter; import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; import org.hibernate.engine.jdbc.spi.SqlStatementLogger; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.config.ConfigurationHelper; +import org.hibernate.service.ServiceRegistry; import org.hibernate.service.internal.BasicServiceRegistryImpl; -import org.jboss.logging.Logger; - /** - * A commandline tool to update a database schema. May also be called from - * inside an application. + * A commandline tool to update a database schema. May also be called from inside an application. * * @author Christoph Sturm + * @author Steve Ebersole */ public class SchemaUpdate { - private static final HibernateLogger LOG = Logger.getMessageLogger(HibernateLogger.class, SchemaUpdate.class.getName()); - private ConnectionHelper connectionHelper; - private Configuration configuration; - private Dialect dialect; - private List exceptions; + + private final Configuration configuration; + private final ConnectionHelper connectionHelper; + private final SqlStatementLogger sqlStatementLogger; + private final SqlExceptionHelper sqlExceptionHelper; + private final Dialect dialect; + + private final List exceptions = new ArrayList(); + + private Formatter formatter; + private boolean haltOnError = false; private boolean format = true; private String outputFile = null; private String delimiter; - private Formatter formatter; - private SqlStatementLogger sqlStatementLogger; public SchemaUpdate(Configuration cfg) throws HibernateException { this( cfg, cfg.getProperties() ); } - public SchemaUpdate(Configuration cfg, Properties connectionProperties) throws HibernateException { - this.configuration = cfg; - dialect = Dialect.getDialect( connectionProperties ); + public SchemaUpdate(Configuration configuration, Properties properties) throws HibernateException { + this.configuration = configuration; + this.dialect = Dialect.getDialect( properties ); + Properties props = new Properties(); props.putAll( dialect.getDefaultProperties() ); - props.putAll( connectionProperties ); - connectionHelper = new ManagedProviderConnectionHelper( props ); - exceptions = new ArrayList(); - formatter = ( ConfigurationHelper.getBoolean( Environment.FORMAT_SQL, props ) ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter(); + props.putAll( properties ); + this.connectionHelper = new ManagedProviderConnectionHelper( props ); + + this.sqlExceptionHelper = new SqlExceptionHelper(); + this.sqlStatementLogger = new SqlStatementLogger( false, true ); + this.formatter = FormatStyle.DDL.getFormatter(); } - public SchemaUpdate(JdbcServices jdbcServices, Configuration cfg) throws HibernateException { + public SchemaUpdate(ServiceRegistry serviceRegistry, Configuration cfg) throws HibernateException { this.configuration = cfg; - dialect = jdbcServices.getDialect(); - connectionHelper = new SuppliedConnectionProviderConnectionHelper( - jdbcServices.getConnectionProvider() - ); - exceptions = new ArrayList(); - sqlStatementLogger = jdbcServices.getSqlStatementLogger(); - formatter = ( sqlStatementLogger.isFormat() ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter(); + + final JdbcServices jdbcServices = serviceRegistry.getService( JdbcServices.class ); + this.dialect = jdbcServices.getDialect(); + this.connectionHelper = new SuppliedConnectionProviderConnectionHelper( jdbcServices.getConnectionProvider() ); + + this.sqlExceptionHelper = new SqlExceptionHelper(); + this.sqlStatementLogger = jdbcServices.getSqlStatementLogger(); + this.formatter = ( sqlStatementLogger.isFormat() ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter(); } private static BasicServiceRegistryImpl createServiceRegistry(Properties properties) { @@ -146,7 +156,7 @@ public class SchemaUpdate { BasicServiceRegistryImpl serviceRegistry = createServiceRegistry( cfg.getProperties() ); try { - new SchemaUpdate( serviceRegistry.getService( JdbcServices.class ), cfg ).execute( script, doUpdate ); + new SchemaUpdate( serviceRegistry, cfg ).execute( script, doUpdate ); } finally { serviceRegistry.destroy(); @@ -164,7 +174,10 @@ public class SchemaUpdate { * @param script print all DDL to the console */ public void execute(boolean script, boolean doUpdate) { - + execute( Target.interpret( script, doUpdate ) ); + } + + public void execute(Target target) { LOG.runningHbm2ddlSchemaUpdate(); Connection connection = null; @@ -174,7 +187,6 @@ public class SchemaUpdate { exceptions.clear(); try { - DatabaseMetadata meta; try { LOG.fetchingDatabaseMetadata(); @@ -191,29 +203,26 @@ public class SchemaUpdate { LOG.updatingSchema(); - if ( outputFile != null ) { - LOG.writingGeneratedSchemaToFile(outputFile); + LOG.writingGeneratedSchemaToFile( outputFile ); outputFileWriter = new FileWriter( outputFile ); } - String[] createSQL = configuration.generateSchemaUpdateScript( dialect, meta ); - for ( int j = 0; j < createSQL.length; j++ ) { - - final String sql = createSQL[j]; + String[] sqlStrings = configuration.generateSchemaUpdateScript( dialect, meta ); + for ( String sql : sqlStrings ) { String formatted = formatter.format( sql ); try { if ( delimiter != null ) { formatted += delimiter; } - if ( script ) { + if ( target.doScript() ) { System.out.println( formatted ); } if ( outputFile != null ) { outputFileWriter.write( formatted + "\n" ); } - if ( doUpdate ) { - LOG.debugf(sql); + if ( target.doExport() ) { + LOG.debugf( sql ); stmt.executeUpdate( formatted ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java index ea74e62b50..02007efc35 100755 --- a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2008-2011, 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 Middleware LLC. + * 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 @@ -20,7 +20,6 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate.tool.hbm2ddl; @@ -28,6 +27,9 @@ import java.io.FileInputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; + +import org.jboss.logging.Logger; + import org.hibernate.HibernateException; import org.hibernate.HibernateLogger; import org.hibernate.cfg.Configuration; @@ -37,10 +39,9 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.config.ConfigurationHelper; +import org.hibernate.service.ServiceRegistry; import org.hibernate.service.internal.BasicServiceRegistryImpl; -import org.jboss.logging.Logger; - /** * A commandline tool to update a database schema. May also be called from * inside an application. @@ -48,7 +49,6 @@ import org.jboss.logging.Logger; * @author Christoph Sturm */ public class SchemaValidator { - private static final HibernateLogger LOG = Logger.getMessageLogger(HibernateLogger.class, SchemaValidator.class.getName()); private ConnectionHelper connectionHelper; @@ -68,12 +68,11 @@ public class SchemaValidator { connectionHelper = new ManagedProviderConnectionHelper( props ); } - public SchemaValidator(JdbcServices jdbcServices, Configuration cfg ) throws HibernateException { + public SchemaValidator(ServiceRegistry serviceRegistry, Configuration cfg ) throws HibernateException { this.configuration = cfg; - dialect = jdbcServices.getDialect(); - connectionHelper = new SuppliedConnectionProviderConnectionHelper( - jdbcServices.getConnectionProvider() - ); + final JdbcServices jdbcServices = serviceRegistry.getService( JdbcServices.class ); + this.dialect = jdbcServices.getDialect(); + this.connectionHelper = new SuppliedConnectionProviderConnectionHelper( jdbcServices.getConnectionProvider() ); } private static BasicServiceRegistryImpl createServiceRegistry(Properties properties) { @@ -117,7 +116,7 @@ public class SchemaValidator { BasicServiceRegistryImpl serviceRegistry = createServiceRegistry( cfg.getProperties() ); try { - new SchemaValidator( serviceRegistry.getService( JdbcServices.class ), cfg ).validate(); + new SchemaValidator( serviceRegistry, cfg ).validate(); } finally { serviceRegistry.destroy(); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/ScriptExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/ScriptExporter.java new file mode 100644 index 0000000000..13907cac68 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/ScriptExporter.java @@ -0,0 +1,43 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.tool.hbm2ddl; + +/** + * @author Steve Ebersole + */ +class ScriptExporter implements Exporter { + @Override + public boolean acceptsImportScripts() { + return false; + } + + @Override + public void export(String string) throws Exception { + System.out.println( string ); + } + + @Override + public void release() throws Exception { + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/Target.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/Target.java new file mode 100644 index 0000000000..b1c2321043 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/Target.java @@ -0,0 +1,51 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.tool.hbm2ddl; + +/** + * @author Steve Ebersole + */ +public enum Target { + EXPORT, + SCRIPT, + NONE, + BOTH; + + public boolean doExport() { + return this == BOTH || this == EXPORT; + } + + public boolean doScript() { + return this == BOTH || this == SCRIPT; + } + + public static Target interpret(boolean script, boolean export) { + if ( script ) { + return export ? BOTH : SCRIPT; + } + else { + return export ? EXPORT : NONE; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/EntityTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/EntityTest.java index 8da5d5a7b1..50afb9c80a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/EntityTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/EntityTest.java @@ -435,7 +435,7 @@ public class EntityTest extends BaseCoreFunctionalTestCase { } private SchemaExport schemaExport() { - return new SchemaExport( serviceRegistry().getService( JdbcServices.class ), configuration() ); + return new SchemaExport( serviceRegistry(), configuration() ); } @After diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/MigrationTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/MigrationTest.java index a5e94a44b6..027bf7bb1e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/MigrationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/MigrationTest.java @@ -69,7 +69,7 @@ public class MigrationTest extends BaseUnitTestCase { v1cfg.addResource( resource1 ); new SchemaExport( v1cfg ).execute( false, true, true, false ); - SchemaUpdate v1schemaUpdate = new SchemaUpdate( getJdbcServices(), v1cfg ); + SchemaUpdate v1schemaUpdate = new SchemaUpdate( serviceRegistry, v1cfg ); v1schemaUpdate.execute( true, true ); assertEquals( 0, v1schemaUpdate.getExceptions().size() ); @@ -77,11 +77,11 @@ public class MigrationTest extends BaseUnitTestCase { Configuration v2cfg = new Configuration(); v2cfg.addResource( resource2 ); - SchemaUpdate v2schemaUpdate = new SchemaUpdate( getJdbcServices(), v2cfg ); + SchemaUpdate v2schemaUpdate = new SchemaUpdate( serviceRegistry, v2cfg ); v2schemaUpdate.execute( true, true ); assertEquals( 0, v2schemaUpdate.getExceptions().size() ); - new SchemaExport( getJdbcServices(), v2cfg ).drop( false, true ); + new SchemaExport( serviceRegistry, v2cfg ).drop( false, true ); }