diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/GenerationSourceFromScript.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/GenerationSourceFromScript.java index 3c45e56a9c..1dda8e3293 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/GenerationSourceFromScript.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/GenerationSourceFromScript.java @@ -23,8 +23,6 @@ */ package org.hibernate.jpa.internal.schemagen; -import java.io.Reader; - import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor; /** @@ -33,28 +31,22 @@ import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor; * @author Steve Ebersole */ public class GenerationSourceFromScript implements GenerationSource { - private final SqlScriptInput reader; + private final ScriptSourceInput inputSource; private final ImportSqlCommandExtractor scriptCommandExtractor; - public GenerationSourceFromScript(Object scriptSourceSetting, ImportSqlCommandExtractor scriptCommandExtractor) { + public GenerationSourceFromScript(ScriptSourceInput inputSource, ImportSqlCommandExtractor scriptCommandExtractor) { + this.inputSource = inputSource; this.scriptCommandExtractor = scriptCommandExtractor; - - if ( Reader.class.isInstance( scriptSourceSetting ) ) { - reader = new SqlScriptReaderInput( (Reader) scriptSourceSetting ); - } - else { - reader = new SqlScriptFileInput( scriptSourceSetting.toString() ); - } } @Override public Iterable getCommands() { - return reader.read( scriptCommandExtractor ); + return inputSource.read( scriptCommandExtractor ); } @Override public void release() { - reader.release(); + inputSource.release(); } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/GenerationTargetToScript.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/GenerationTargetToScript.java index 677e38cb07..5dd7cf9668 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/GenerationTargetToScript.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/GenerationTargetToScript.java @@ -23,15 +23,6 @@ */ 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; - -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.SchemaGenAction; /** @@ -40,59 +31,17 @@ import org.hibernate.jpa.SchemaGenAction; * @author Steve Ebersole */ class GenerationTargetToScript implements GenerationTarget { - private static final Logger log = Logger.getLogger( GenerationTargetToScript.class ); - - private final ScriptTargetTarget createScriptTarget; - private final ScriptTargetTarget dropScriptTarget; + private final ScriptTargetOutput createScriptTarget; + private final ScriptTargetOutput dropScriptTarget; private final SchemaGenAction scriptsAction; public GenerationTargetToScript( - Object createScriptTargetSetting, - Object dropScriptTargetSetting, + ScriptTargetOutput createScriptTarget, + ScriptTargetOutput dropScriptTarget, SchemaGenAction scriptsAction) { + this.createScriptTarget = createScriptTarget; + this.dropScriptTarget = dropScriptTarget; this.scriptsAction = scriptsAction; - - if ( scriptsAction.includesCreate() ) { - if ( Writer.class.isInstance( createScriptTargetSetting ) ) { - createScriptTarget = new WriterScriptTarget( (Writer) createScriptTargetSetting ); - } - else { - createScriptTarget = new FileScriptTarget( createScriptTargetSetting.toString() ); - } - } - else { - if ( createScriptTargetSetting != null ) { - // the wording in the spec hints that this maybe should be an error, but does not explicitly - // call out an exception to use. - log.debugf( - "Value was specified for '%s' [%s], but create scripting was not requested", - AvailableSettings.SCHEMA_GEN_SCRIPTS_CREATE_TARGET, - createScriptTargetSetting - ); - } - createScriptTarget = null; - } - - if ( scriptsAction.includesDrop() ) { - if ( Writer.class.isInstance( dropScriptTargetSetting ) ) { - dropScriptTarget = new WriterScriptTarget( (Writer) dropScriptTargetSetting ); - } - else { - dropScriptTarget = new FileScriptTarget( dropScriptTargetSetting.toString() ); - } - } - else { - if ( dropScriptTargetSetting != null ) { - // the wording in the spec hints that this maybe should be an error, but does not explicitly - // call out an exception to use. - log.debugf( - "Value was specified for '%s' [%s], but drop scripting was not requested", - AvailableSettings.SCHEMA_GEN_SCRIPTS_DROP_TARGET, - dropScriptTargetSetting - ); - } - dropScriptTarget = null; - } } @Override @@ -123,73 +72,4 @@ class GenerationTargetToScript implements GenerationTarget { 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, e ); - } - } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/JpaSchemaGenerator.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/JpaSchemaGenerator.java index 8f692ecbb9..d05e9e4efe 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/JpaSchemaGenerator.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/JpaSchemaGenerator.java @@ -24,7 +24,11 @@ package org.hibernate.jpa.internal.schemagen; import javax.persistence.PersistenceException; +import java.io.File; import java.io.Reader; +import java.io.Writer; +import java.net.MalformedURLException; +import java.net.URL; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; @@ -38,6 +42,7 @@ import java.util.List; import org.jboss.logging.Logger; import org.hibernate.HibernateException; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.selector.spi.StrategySelector; import org.hibernate.cfg.Configuration; import org.hibernate.dialect.Dialect; @@ -64,188 +69,328 @@ import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor; public class JpaSchemaGenerator { private static final Logger log = Logger.getLogger( JpaSchemaGenerator.class ); + private JpaSchemaGenerator() { + } + public static void performGeneration(Configuration hibernateConfiguration, ServiceRegistry serviceRegistry) { + new Generation( serviceRegistry ).execute( hibernateConfiguration ); + } - // First, determine the actions (if any) to be performed ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + /** + * Defines the process of performing a schema generation + */ + public static class Generation { + private final ServiceRegistry serviceRegistry; + private final ImportSqlCommandExtractor scriptCommandExtractor; + private final ClassLoaderService classLoaderService; - final SchemaGenAction databaseAction = SchemaGenAction.interpret( - hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_DATABASE_ACTION ) - ); - final SchemaGenAction scriptsAction = SchemaGenAction.interpret( - hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_SCRIPTS_ACTION ) - ); - - if ( databaseAction == SchemaGenAction.NONE && scriptsAction == SchemaGenAction.NONE ) { - // no actions needed - return; + /** + * Constructs a generation process + * + * @param serviceRegistry The Hibernate service registry to use + */ + public Generation(ServiceRegistry serviceRegistry) { + this.serviceRegistry = serviceRegistry; + this.scriptCommandExtractor = serviceRegistry.getService( ImportSqlCommandExtractor.class ); + this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); } + /** + * Perform the generation, as indicated by the settings + * + * @param hibernateConfiguration + */ + public void execute(Configuration hibernateConfiguration) { + // First, determine the actions (if any) to be performed ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // Figure out the JDBC Connection context, if any ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - final JdbcConnectionContext jdbcConnectionContext = determineAppropriateJdbcConnectionContext( - hibernateConfiguration, - serviceRegistry - ); - - try { - final Dialect dialect = determineDialect( jdbcConnectionContext, hibernateConfiguration, serviceRegistry ); - - - // determine sources ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - final List createSourceList = databaseAction.includesCreate() || scriptsAction.includesCreate() - ? buildCreateSourceList( hibernateConfiguration, serviceRegistry, dialect ) - : Collections.emptyList(); - - final List dropSourceList = databaseAction.includesDrop() || scriptsAction.includesDrop() - ? buildDropSourceList( hibernateConfiguration, serviceRegistry, dialect ) - : Collections.emptyList(); - - - // determine targets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - final GenerationTarget databaseTarget = new GenerationTargetToDatabase( jdbcConnectionContext, databaseAction ); - - final Object createScriptTargetSetting = hibernateConfiguration.getProperties().get( - AvailableSettings.SCHEMA_GEN_SCRIPTS_CREATE_TARGET + final SchemaGenAction databaseAction = SchemaGenAction.interpret( + hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_DATABASE_ACTION ) ); - final Object dropScriptTargetSetting = hibernateConfiguration.getProperties().get( - AvailableSettings.SCHEMA_GEN_SCRIPTS_DROP_TARGET + final SchemaGenAction scriptsAction = SchemaGenAction.interpret( + hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_SCRIPTS_ACTION ) ); - final GenerationTarget scriptsTarget = new GenerationTargetToScript( createScriptTargetSetting, dropScriptTargetSetting, scriptsAction ); - final List targets = Arrays.asList( databaseTarget, scriptsTarget ); - - - // See if native Hibernate schema generation has also been requested and warn the user if so... - - final String hbm2ddl = hibernateConfiguration.getProperty( org.hibernate.cfg.AvailableSettings.HBM2DDL_AUTO ); - if ( StringHelper.isNotEmpty( hbm2ddl ) ) { - log.warnf( - "Hibernate hbm2ddl-auto setting was specified [%s] in combination with JPA schema-generation; " + - "combination will likely cause trouble", - hbm2ddl - ); + if ( databaseAction == SchemaGenAction.NONE && scriptsAction == SchemaGenAction.NONE ) { + // no actions needed + return; } - // finally, do the generation + // Figure out the JDBC Connection context, if any ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + final JdbcConnectionContext jdbcConnectionContext = determineAppropriateJdbcConnectionContext( + hibernateConfiguration, + serviceRegistry + ); try { - doGeneration( createSourceList, dropSourceList, targets ); + final Dialect dialect = determineDialect( jdbcConnectionContext, hibernateConfiguration, serviceRegistry ); + + + // determine sources ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + final List createSourceList = databaseAction.includesCreate() || scriptsAction.includesCreate() + ? buildCreateSourceList( hibernateConfiguration, dialect ) + : Collections.emptyList(); + + final List dropSourceList = databaseAction.includesDrop() || scriptsAction.includesDrop() + ? buildDropSourceList( hibernateConfiguration, dialect ) + : Collections.emptyList(); + + + // determine targets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + final GenerationTarget databaseTarget = new GenerationTargetToDatabase( jdbcConnectionContext, databaseAction ); + + final Object createScriptTargetSetting = hibernateConfiguration.getProperties().get( + AvailableSettings.SCHEMA_GEN_SCRIPTS_CREATE_TARGET + ); + final Object dropScriptTargetSetting = hibernateConfiguration.getProperties().get( + AvailableSettings.SCHEMA_GEN_SCRIPTS_DROP_TARGET + ); + final GenerationTarget scriptsTarget = new GenerationTargetToScript( + interpretScriptTargetSetting( + createScriptTargetSetting, + scriptsAction.includesCreate(), + AvailableSettings.SCHEMA_GEN_SCRIPTS_CREATE_TARGET + ), + interpretScriptTargetSetting( + dropScriptTargetSetting, + scriptsAction.includesDrop(), + AvailableSettings.SCHEMA_GEN_SCRIPTS_DROP_TARGET + ), + scriptsAction + ); + + final List targets = Arrays.asList( databaseTarget, scriptsTarget ); + + + // See if native Hibernate schema generation has also been requested and warn the user if so... + + final String hbm2ddl = hibernateConfiguration.getProperty( org.hibernate.cfg.AvailableSettings.HBM2DDL_AUTO ); + if ( StringHelper.isNotEmpty( hbm2ddl ) ) { + log.warnf( + "Hibernate hbm2ddl-auto setting was specified [%s] in combination with JPA schema-generation; " + + "combination will likely cause trouble", + hbm2ddl + ); + } + + + // finally, do the generation + + try { + doGeneration( createSourceList, dropSourceList, targets ); + } + finally { + releaseTargets( targets ); + releaseSources( createSourceList ); + releaseSources( dropSourceList ); + } } finally { - releaseTargets( targets ); - releaseSources( createSourceList ); - releaseSources( dropSourceList ); + releaseJdbcConnectionContext( jdbcConnectionContext ); } } - finally { - releaseJdbcConnectionContext( jdbcConnectionContext ); - } - } - private static List buildCreateSourceList( - Configuration hibernateConfiguration, - ServiceRegistry serviceRegistry, - Dialect dialect) { - final List generationSourceList = new ArrayList(); - - final boolean createSchemas = ConfigurationHelper.getBoolean( - AvailableSettings.SCHEMA_GEN_CREATE_SCHEMAS, - hibernateConfiguration.getProperties(), - false - ); - if ( createSchemas ) { - generationSourceList.add( new CreateSchemaCommandSource( hibernateConfiguration, dialect ) ); - } - - SchemaGenSource sourceType = SchemaGenSource.interpret( - hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_CREATE_SOURCE ) - ); - - final Object createScriptSourceSetting = hibernateConfiguration.getProperties().get( - AvailableSettings.SCHEMA_GEN_CREATE_SCRIPT_SOURCE - ); - - if ( sourceType == null ) { - if ( createScriptSourceSetting != null ) { - sourceType = SchemaGenSource.SCRIPT; + private ScriptTargetOutput interpretScriptTargetSetting( + Object scriptTargetSetting, + boolean actionIndicatedScripting, + String settingName) { + if ( actionIndicatedScripting ) { + if ( scriptTargetSetting == null ) { + throw new PersistenceException( "Scripting was requested, but no target was specified" ); + } + if ( Writer.class.isInstance( scriptTargetSetting ) ) { + return new ScriptTargetOutputToWriter( (Writer) scriptTargetSetting ); + } + else { + final String scriptTargetSettingString = scriptTargetSetting.toString(); + try { + final URL url = new URL( scriptTargetSettingString ); + return new ScriptTargetOutputToUrl( url ); + } + catch (MalformedURLException ignore) { + } + return new ScriptTargetOutputToFile( new File( scriptTargetSettingString ) ); + } } else { - sourceType = SchemaGenSource.METADATA; + if ( scriptTargetSetting != null ) { + // the wording in the spec hints that this maybe should be an error, but does not explicitly + // call out an exception to use. + log.debugf( + "Value was specified for '%s' [%s], but scripting action was not requested", + settingName, + scriptTargetSetting + ); + } + return NoOpScriptTargetOutput.INSTANCE; } } - final ImportSqlCommandExtractor scriptCommandExtractor = serviceRegistry.getService( ImportSqlCommandExtractor.class ); + private static class NoOpScriptTargetOutput implements ScriptTargetOutput { + /** + * Singleton access + */ + public static final NoOpScriptTargetOutput INSTANCE = new NoOpScriptTargetOutput(); - if ( sourceType == SchemaGenSource.METADATA ) { - generationSourceList.add( new GenerationSourceFromMetadata( hibernateConfiguration, dialect, true ) ); - } - else if ( sourceType == SchemaGenSource.SCRIPT ) { - generationSourceList.add( new GenerationSourceFromScript( createScriptSourceSetting, scriptCommandExtractor ) ); - } - else if ( sourceType == SchemaGenSource.METADATA_THEN_SCRIPT ) { - generationSourceList.add( new GenerationSourceFromMetadata( hibernateConfiguration, dialect, true ) ); - generationSourceList.add( new GenerationSourceFromScript( createScriptSourceSetting, scriptCommandExtractor ) ); - } - else if ( sourceType == SchemaGenSource.SCRIPT_THEN_METADATA ) { - generationSourceList.add( new GenerationSourceFromScript( createScriptSourceSetting, scriptCommandExtractor ) ); - generationSourceList.add( new GenerationSourceFromMetadata( hibernateConfiguration, dialect, true ) ); + @Override + public void accept(String command) { + } + + @Override + public void release() { + } } - final Object importScriptSetting = hibernateConfiguration.getProperties().get( - AvailableSettings.SCHEMA_GEN_LOAD_SCRIPT_SOURCE - ); - if ( importScriptSetting != null ) { - generationSourceList.add( new ImportScriptSource( importScriptSetting, scriptCommandExtractor ) ); + private List buildCreateSourceList(Configuration hibernateConfiguration, Dialect dialect) { + final List generationSourceList = new ArrayList(); + + // If we are asked to perform CREATE SCHEMA commands do them first ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + final boolean createSchemas = ConfigurationHelper.getBoolean( + AvailableSettings.SCHEMA_GEN_CREATE_SCHEMAS, + hibernateConfiguration.getProperties(), + false + ); + if ( createSchemas ) { + generationSourceList.add( new CreateSchemaCommandSource( hibernateConfiguration, dialect ) ); + } + + + // Next figure out the intended sources of generation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + SchemaGenSource sourceType = SchemaGenSource.interpret( + hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_CREATE_SOURCE ) + ); + + final Object createScriptSourceSetting = hibernateConfiguration.getProperties().get( + AvailableSettings.SCHEMA_GEN_CREATE_SCRIPT_SOURCE + ); + + if ( sourceType == null ) { + if ( createScriptSourceSetting != null ) { + sourceType = SchemaGenSource.SCRIPT; + } + else { + sourceType = SchemaGenSource.METADATA; + } + } + + final boolean includesScripts = sourceType != SchemaGenSource.METADATA; + if ( includesScripts && createScriptSourceSetting == null ) { + throw new PersistenceException( + "Schema generation configuration indicated to include CREATE scripts, but no script was specified" + ); + } + final ScriptSourceInput scriptSourceInput = includesScripts + ? interpretScriptSourceSetting( createScriptSourceSetting ) + : null; + + if ( sourceType == SchemaGenSource.METADATA ) { + generationSourceList.add( new GenerationSourceFromMetadata( hibernateConfiguration, dialect, true ) ); + } + else if ( sourceType == SchemaGenSource.SCRIPT ) { + generationSourceList.add( new GenerationSourceFromScript( scriptSourceInput, scriptCommandExtractor ) ); + } + else if ( sourceType == SchemaGenSource.METADATA_THEN_SCRIPT ) { + generationSourceList.add( new GenerationSourceFromMetadata( hibernateConfiguration, dialect, true ) ); + generationSourceList.add( new GenerationSourceFromScript( scriptSourceInput, scriptCommandExtractor ) ); + } + else if ( sourceType == SchemaGenSource.SCRIPT_THEN_METADATA ) { + generationSourceList.add( new GenerationSourceFromScript( scriptSourceInput, scriptCommandExtractor ) ); + generationSourceList.add( new GenerationSourceFromMetadata( hibernateConfiguration, dialect, true ) ); + } + + + // finally, see if there is an import script specified ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + final Object importScriptSetting = hibernateConfiguration.getProperties().get( + AvailableSettings.SCHEMA_GEN_LOAD_SCRIPT_SOURCE + ); + if ( importScriptSetting != null ) { + final ScriptSourceInput importScriptInput = interpretScriptSourceSetting( importScriptSetting ); + generationSourceList.add( new ImportScriptSource( importScriptInput, scriptCommandExtractor ) ); + } + + return generationSourceList; } - return generationSourceList; - } - - private static List buildDropSourceList( - Configuration hibernateConfiguration, - ServiceRegistry serviceRegistry, - Dialect dialect) { - final List generationSourceList = new ArrayList(); - - SchemaGenSource sourceType = SchemaGenSource.interpret( - hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_DROP_SOURCE ) - ); - - final Object dropScriptSourceSetting = hibernateConfiguration.getProperties().get( - AvailableSettings.SCHEMA_GEN_DROP_SCRIPT_SOURCE - ); - - if ( sourceType == null ) { - if ( dropScriptSourceSetting != null ) { - sourceType = SchemaGenSource.SCRIPT; + private ScriptSourceInput interpretScriptSourceSetting(Object scriptSourceSetting) { + if ( Reader.class.isInstance( scriptSourceSetting ) ) { + return new ScriptSourceInputFromReader( (Reader) scriptSourceSetting ); } else { - sourceType = SchemaGenSource.METADATA; + final String scriptSourceSettingString = scriptSourceSetting.toString(); + log.debugf( "Attempting to resolve script source setting : %s", scriptSourceSettingString ); + + // setting could be either: + // 1) string URL representation (i.e., "file://...") + // 2) relative file path (resource lookup) + // 3) absolute file path + + log.trace( "Trying as URL..." ); + // ClassLoaderService.locateResource() first tries the given resource name as url form... + final URL url = classLoaderService.locateResource( scriptSourceSettingString ); + if ( url != null ) { + return new ScriptSourceInputFromUrl( url ); + } + + // assume it is a File path + final File file = new File( scriptSourceSettingString ); + return new ScriptSourceInputFromFile( file ); } } - final ImportSqlCommandExtractor scriptCommandExtractor = serviceRegistry.getService( ImportSqlCommandExtractor.class ); + private List buildDropSourceList(Configuration hibernateConfiguration, Dialect dialect) { + final List generationSourceList = new ArrayList(); - if ( sourceType == SchemaGenSource.METADATA ) { - generationSourceList.add( new GenerationSourceFromMetadata( hibernateConfiguration, dialect, false ) ); - } - else if ( sourceType == SchemaGenSource.SCRIPT ) { - generationSourceList.add( new GenerationSourceFromScript( dropScriptSourceSetting, scriptCommandExtractor ) ); - } - else if ( sourceType == SchemaGenSource.METADATA_THEN_SCRIPT ) { - generationSourceList.add( new GenerationSourceFromMetadata( hibernateConfiguration, dialect, false ) ); - generationSourceList.add( new GenerationSourceFromScript( dropScriptSourceSetting, scriptCommandExtractor ) ); - } - else if ( sourceType == SchemaGenSource.SCRIPT_THEN_METADATA ) { - generationSourceList.add( new GenerationSourceFromScript( dropScriptSourceSetting, scriptCommandExtractor ) ); - generationSourceList.add( new GenerationSourceFromMetadata( hibernateConfiguration, dialect, false ) ); - } + SchemaGenSource sourceType = SchemaGenSource.interpret( + hibernateConfiguration.getProperty( AvailableSettings.SCHEMA_GEN_DROP_SOURCE ) + ); - return generationSourceList; + final Object dropScriptSourceSetting = hibernateConfiguration.getProperties().get( + AvailableSettings.SCHEMA_GEN_DROP_SCRIPT_SOURCE + ); + + if ( sourceType == null ) { + if ( dropScriptSourceSetting != null ) { + sourceType = SchemaGenSource.SCRIPT; + } + else { + sourceType = SchemaGenSource.METADATA; + } + } + + + final boolean includesScripts = sourceType != SchemaGenSource.METADATA; + if ( includesScripts && dropScriptSourceSetting == null ) { + throw new PersistenceException( + "Schema generation configuration indicated to include CREATE scripts, but no script was specified" + ); + } + final ScriptSourceInput scriptSourceInput = includesScripts + ? interpretScriptSourceSetting( dropScriptSourceSetting ) + : null; + + if ( sourceType == SchemaGenSource.METADATA ) { + generationSourceList.add( new GenerationSourceFromMetadata( hibernateConfiguration, dialect, false ) ); + } + else if ( sourceType == SchemaGenSource.SCRIPT ) { + generationSourceList.add( new GenerationSourceFromScript( scriptSourceInput, scriptCommandExtractor ) ); + } + else if ( sourceType == SchemaGenSource.METADATA_THEN_SCRIPT ) { + generationSourceList.add( new GenerationSourceFromMetadata( hibernateConfiguration, dialect, false ) ); + generationSourceList.add( new GenerationSourceFromScript( scriptSourceInput, scriptCommandExtractor ) ); + } + else if ( sourceType == SchemaGenSource.SCRIPT_THEN_METADATA ) { + generationSourceList.add( new GenerationSourceFromScript( scriptSourceInput, scriptCommandExtractor ) ); + generationSourceList.add( new GenerationSourceFromMetadata( hibernateConfiguration, dialect, false ) ); + } + + return generationSourceList; + } } private static JdbcConnectionContext determineAppropriateJdbcConnectionContext( @@ -383,7 +528,7 @@ public class JpaSchemaGenerator { private static Dialect determineDialectBasedOnJdbcMetadata( JdbcConnectionContext jdbcConnectionContext, ServiceRegistry serviceRegistry) { - DialectResolver dialectResolver = serviceRegistry.getService( DialectResolver.class ); + final DialectResolver dialectResolver = serviceRegistry.getService( DialectResolver.class ); try { final DatabaseMetaData databaseMetaData = jdbcConnectionContext.getJdbcConnection().getMetaData(); final Dialect dialect = dialectResolver.resolveDialect( databaseMetaData ); @@ -508,18 +653,12 @@ public class JpaSchemaGenerator { } private static class ImportScriptSource implements GenerationSource { - private final SqlScriptInput sourceReader; + private final ScriptSourceInput sourceReader; private final ImportSqlCommandExtractor scriptCommandExtractor; - public ImportScriptSource(Object scriptSourceSetting, ImportSqlCommandExtractor scriptCommandExtractor) { + public ImportScriptSource(ScriptSourceInput sourceReader, ImportSqlCommandExtractor scriptCommandExtractor) { + this.sourceReader = sourceReader; this.scriptCommandExtractor = scriptCommandExtractor; - - if ( Reader.class.isInstance( scriptSourceSetting ) ) { - sourceReader = new SqlScriptReaderInput( (Reader) scriptSourceSetting ); - } - else { - sourceReader = new SqlScriptFileInput( scriptSourceSetting.toString() ); - } } @Override diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptSourceInput.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptSourceInput.java new file mode 100644 index 0000000000..fac700f86e --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptSourceInput.java @@ -0,0 +1,48 @@ +/* + * 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 hiding the differences between a passed Reader, File or URL in terms of how we read input + * scripts. + * + * @author Steve Ebersole + */ +public interface ScriptSourceInput { + /** + * Read the abstracted script, using the given extractor to split up the input into individual commands. + * + * @param commandExtractor The extractor for individual commands within the input. + * + * @return The scripted commands + */ + public Iterable read(ImportSqlCommandExtractor commandExtractor); + + /** + * Release this input. + */ + public void release(); +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/SqlScriptFileInput.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptSourceInputFromFile.java similarity index 75% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/SqlScriptFileInput.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptSourceInputFromFile.java index 6ef61de161..61bf58289c 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/SqlScriptFileInput.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptSourceInputFromFile.java @@ -32,16 +32,21 @@ import java.io.Reader; import org.jboss.logging.Logger; /** - * SqlScriptInput implementation for File references. A reader is opened here and then explicitly closed on + * ScriptSourceInput implementation for File references. A reader is opened here and then explicitly closed on * {@link #release}. * * @author Steve Ebersole */ -class SqlScriptFileInput extends SqlScriptReaderInput implements SqlScriptInput { - private static final Logger log = Logger.getLogger( SqlScriptFileInput.class ); +public class ScriptSourceInputFromFile extends ScriptSourceInputFromReader implements ScriptSourceInput { + private static final Logger log = Logger.getLogger( ScriptSourceInputFromFile.class ); - public SqlScriptFileInput(String fileUrl) { - super( toFileReader( fileUrl ) ); + /** + * Constructs a ScriptSourceInputFromFile + * + * @param file The file to read from + */ + public ScriptSourceInputFromFile(File file) { + super( toFileReader( file ) ); } @Override @@ -55,10 +60,9 @@ class SqlScriptFileInput extends SqlScriptReaderInput implements SqlScriptInput } @SuppressWarnings("ResultOfMethodCallIgnored") - private static Reader toFileReader(String fileUrl) { - final File file = new File( fileUrl ); + private static Reader toFileReader(File file) { if ( ! file.exists() ) { - log.warnf( "Specified schema generation script file [%s] did not exist for reading", fileUrl ); + log.warnf( "Specified schema generation script file [%s] did not exist for reading", file ); return new Reader() { @Override public int read(char[] cbuf, int off, int len) throws IOException { @@ -76,7 +80,7 @@ class SqlScriptFileInput extends SqlScriptReaderInput implements SqlScriptInput } catch (IOException e) { throw new PersistenceException( - "Unable to open specified script target file [" + fileUrl + "] for reading", + "Unable to open specified script target file [" + file + "] for reading", e ); } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/SqlScriptReaderInput.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptSourceInputFromReader.java similarity index 83% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/SqlScriptReaderInput.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptSourceInputFromReader.java index 5b0bb7db48..da5f230730 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/SqlScriptReaderInput.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptSourceInputFromReader.java @@ -30,14 +30,19 @@ import java.util.Collections; import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor; /** - * SqlScriptInput implementation for explicitly given Readers. The readers are not released by this class. + * ScriptSourceInput implementation for explicitly given Readers. The readers are not released by this class. * * @author Steve Ebersole */ -class SqlScriptReaderInput implements SqlScriptInput { +public class ScriptSourceInputFromReader implements ScriptSourceInput { private final Reader reader; - public SqlScriptReaderInput(Reader reader) { + /** + * Constructs a ScriptSourceInputFromReader + * + * @param reader The reader to read from + */ + public ScriptSourceInputFromReader(Reader reader) { this.reader = reader; } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptSourceInputFromUrl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptSourceInputFromUrl.java new file mode 100644 index 0000000000..9434e56f4e --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptSourceInputFromUrl.java @@ -0,0 +1,74 @@ +/* + * 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.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; + +import org.jboss.logging.Logger; + +/** + * ScriptSourceInput implementation for URL references. A reader is opened here and then explicitly closed on + * {@link #release}. + * + * @author Christian Beikov + * @author Steve Ebersole + */ +public class ScriptSourceInputFromUrl extends ScriptSourceInputFromReader implements ScriptSourceInput { + private static final Logger log = Logger.getLogger( ScriptSourceInputFromFile.class ); + + /** + * Constructs a ScriptSourceInputFromUrl instance + * + * @param url The url to read from + */ + public ScriptSourceInputFromUrl(URL url) { + super( toReader( url ) ); + } + + @Override + public void release() { + try { + reader().close(); + } + catch (IOException e) { + log.warn( "Unable to close file reader for generation script source" ); + } + } + + private static Reader toReader(URL url) { + try { + return new InputStreamReader( url.openStream() ); + + } + catch (IOException e) { + throw new PersistenceException( + "Unable to open specified script source url [" + url + "] for reading" + ); + } + } +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/SqlScriptInput.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptTargetOutput.java similarity index 77% rename from hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/SqlScriptInput.java rename to hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptTargetOutput.java index 4d96f35d5d..0df131c508 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/SqlScriptInput.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptTargetOutput.java @@ -23,14 +23,22 @@ */ package org.hibernate.jpa.internal.schemagen; -import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor; - /** - * Contract for handling Reader/File differences + * Contract for hiding the differences between a passed Writer, File or URL in terms of how we write output + * scripts. * * @author Steve Ebersole */ -public interface SqlScriptInput { - public Iterable read(ImportSqlCommandExtractor commandExtractor); +public interface ScriptTargetOutput { + /** + * Accept the given command and write it to the abstracted script + * + * @param command The command + */ + public void accept(String command); + + /** + * Release this output + */ public void release(); } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptTargetOutputToFile.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptTargetOutputToFile.java new file mode 100644 index 0000000000..29f5757fdb --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptTargetOutputToFile.java @@ -0,0 +1,79 @@ +/* + * 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; + +import org.hibernate.jpa.internal.HEMLogging; + +/** + * ScriptTargetOutput implementation for writing to supplied File references + * + * @author Steve Ebersole + */ +public class ScriptTargetOutputToFile extends ScriptTargetOutputToWriter implements ScriptTargetOutput { + private static final Logger log = HEMLogging.logger( ScriptTargetOutputToFile.class ); + + /** + * Constructs a ScriptTargetOutputToFile + * + * @param file The file to write to + */ + public ScriptTargetOutputToFile(File file) { + super( toFileWriter( file ) ); + } + + @Override + public void release() { + try { + writer().close(); + } + catch (IOException e) { + throw new PersistenceException( "Unable to close file writer : " + e.toString() ); + } + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + static Writer toFileWriter(File file) { + 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 : " + file, e ); + } + } +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptTargetOutputToUrl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptTargetOutputToUrl.java new file mode 100644 index 0000000000..0f964c0d80 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptTargetOutputToUrl.java @@ -0,0 +1,82 @@ +/* + * 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.IOException; +import java.io.Writer; +import java.net.URISyntaxException; +import java.net.URL; + +import org.jboss.logging.Logger; + +import org.hibernate.jpa.internal.HEMLogging; + +/** + * ScriptTargetOutput implementation for writing to supplied URL references + * + * @author Steve Ebersole + */ +public class ScriptTargetOutputToUrl extends ScriptTargetOutputToWriter implements ScriptTargetOutput { + private static final Logger log = HEMLogging.logger( ScriptTargetOutputToUrl.class ); + + /** + * Constructs a ScriptTargetOutputToUrl + * + * @param url The url to write to + */ + public ScriptTargetOutputToUrl(URL url) { + super( toWriter( url ) ); + } + + @Override + public void release() { + try { + writer().close(); + } + catch (IOException e) { + throw new PersistenceException( "Unable to close file writer : " + e.toString() ); + } + } + + + private static Writer toWriter(URL url) { + log.debug( "Attempting to resolve writer for URL : " + url ); + // technically only "strings corresponding to file URLs" are supported, which I take to mean URLs whose + // protocol is "file" + try { + return ScriptTargetOutputToFile.toFileWriter( new File( url.toURI() ) ); + } + catch (URISyntaxException e) { + throw new PersistenceException( + String.format( + "Could not convert specified URL[%s] to a File reference", + url + ), + e + ); + } + } +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptTargetOutputToWriter.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptTargetOutputToWriter.java new file mode 100644 index 0000000000..af80540c4e --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/ScriptTargetOutputToWriter.java @@ -0,0 +1,66 @@ +/* + * 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.IOException; +import java.io.Writer; + +/** + * ScriptTargetOutput implementation for supplied Writer references + * + * @author Steve Ebersole + */ +public class ScriptTargetOutputToWriter implements ScriptTargetOutput { + private final Writer writer; + + /** + * Constructs a ScriptTargetOutputToWriter + * + * @param writer The writer to write to + */ + public ScriptTargetOutputToWriter(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; + } +} diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/package-info.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/package-info.java new file mode 100644 index 0000000000..21da20a909 --- /dev/null +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/schemagen/package-info.java @@ -0,0 +1,7 @@ +/** + * Support for JPA 2.1 defined database schema generation. The main class in this package is + * {@link org.hibernate.jpa.internal.schemagen.JpaSchemaGenerator}. + *

+ * @see org.hibernate.jpa.SchemaGenAction + */ +package org.hibernate.jpa.internal.schemagen; diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/schemagen/Item.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/schemagen/Item.java new file mode 100644 index 0000000000..f968abcfab --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/schemagen/Item.java @@ -0,0 +1,69 @@ +/* + * 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.test.schemagen; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import java.io.Serializable; + +/** + * Test entity + * + * @author Christian Beikov + * @author Steve Ebersole + */ +@Entity(name = "Item") +public class Item implements Serializable { + + private String name; + private String descr; + + public Item() { + } + + public Item(String name, String desc) { + this.name = name; + this.descr = desc; + } + + @Column(length = 200) + public String getDescr() { + return descr; + } + + public void setDescr(String desc) { + this.descr = desc; + } + + @Id + @Column(length = 30) + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/schemagen/JpaSchemaGeneratorTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/schemagen/JpaSchemaGeneratorTest.java new file mode 100644 index 0000000000..e38869fce7 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/schemagen/JpaSchemaGeneratorTest.java @@ -0,0 +1,159 @@ +/* + * 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.test.schemagen; + +import java.net.URL; +import java.util.Map; + +import javax.persistence.EntityManagerFactory; + +import org.hibernate.jpa.AvailableSettings; +import org.hibernate.jpa.boot.spi.Bootstrap; +import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; +import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.hibernate.testing.TestForIssue; +import org.junit.Assert; +import org.junit.Test; + +/** + * Basic tests for JPA 2.1 schema export + * + * @author Christian Beikov + * @author Steve Ebersole + */ +public class JpaSchemaGeneratorTest extends BaseEntityManagerFunctionalTestCase { + private static final String LOAD_SQL = "org/hibernate/jpa/test/schemagen/load-script-source.sql"; + private static final String CREATE_SQL = "org/hibernate/jpa/test/schemagen/create-script-source.sql"; + private static final String DROP_SQL = "org/hibernate/jpa/test/schemagen/drop-script-source.sql"; + + private static int schemagenNumber = 0; + + @Override + public Class[] getAnnotatedClasses() { + return new Class[] { Item.class }; + } + + @SuppressWarnings("unchecked") + @Test + @TestForIssue(jiraKey = "HHH-8271") + public void testSqlLoadScriptSourceClasspath() throws Exception { + Map settings = buildSettings(); + settings.put( AvailableSettings.SCHEMA_GEN_DATABASE_ACTION, "drop-and-create" ); + settings.put( AvailableSettings.SCHEMA_GEN_LOAD_SCRIPT_SOURCE, LOAD_SQL ); + doTest( settings ); + } + + + @SuppressWarnings("unchecked") + @Test + @TestForIssue(jiraKey = "HHH-8271") + public void testSqlLoadScriptSourceUrl() throws Exception { + Map settings = buildSettings(); + settings.put( AvailableSettings.SCHEMA_GEN_DATABASE_ACTION, "drop-and-create" ); + settings.put( AvailableSettings.SCHEMA_GEN_LOAD_SCRIPT_SOURCE, getResourceUrlString( LOAD_SQL ) ); + doTest( settings ); + } + + private String getResourceUrlString(String resource) { + final URL url = getClass().getClassLoader().getResource( resource ); + if ( url == null ) { + throw new RuntimeException( "Unable to locate requested resource [" + resource + "]" ); + } + return url.toString(); + } + + @SuppressWarnings("unchecked") + @Test + @TestForIssue(jiraKey = "HHH-8271") + public void testSqlCreateScriptSourceClasspath() throws Exception { + Map settings = buildSettings(); + settings.put( AvailableSettings.SCHEMA_GEN_DATABASE_ACTION, "drop-and-create" ); + settings.put( AvailableSettings.SCHEMA_GEN_CREATE_SOURCE, "metadata-then-script" ); + settings.put( AvailableSettings.SCHEMA_GEN_CREATE_SCRIPT_SOURCE, CREATE_SQL ); + doTest( settings ); + } + + @SuppressWarnings("unchecked") + @Test + @TestForIssue(jiraKey = "HHH-8271") + public void testSqlCreateScriptSourceUrl() throws Exception { + Map settings = buildSettings(); + settings.put( AvailableSettings.SCHEMA_GEN_DATABASE_ACTION, "drop-and-create" ); + settings.put( AvailableSettings.SCHEMA_GEN_CREATE_SOURCE, "metadata-then-script" ); + settings.put( AvailableSettings.SCHEMA_GEN_CREATE_SCRIPT_SOURCE, getResourceUrlString( CREATE_SQL ) ); + doTest( settings ); + } + + + @SuppressWarnings("unchecked") + @Test + @TestForIssue(jiraKey = "HHH-8271") + public void testSqlDropScriptSourceClasspath() throws Exception { + Map settings = buildSettings(); + settings.put( AvailableSettings.SCHEMA_GEN_DROP_SOURCE, "metadata-then-script" ); + settings.put( AvailableSettings.SCHEMA_GEN_DATABASE_ACTION, "drop" ); + settings.put( AvailableSettings.SCHEMA_GEN_DROP_SCRIPT_SOURCE, DROP_SQL ); + doTest( settings ); + } + + @SuppressWarnings("unchecked") + @Test + @TestForIssue(jiraKey = "HHH-8271") + public void testSqlDropScriptSourceUrl() throws Exception { + Map settings = buildSettings(); + settings.put( AvailableSettings.SCHEMA_GEN_DROP_SOURCE, "metadata-then-script" ); + settings.put( AvailableSettings.SCHEMA_GEN_DATABASE_ACTION, "drop" ); + settings.put( AvailableSettings.SCHEMA_GEN_DROP_SCRIPT_SOURCE, getResourceUrlString( DROP_SQL ) ); + doTest( settings ); + } + + @SuppressWarnings("unchecked") + private void doTest(Map settings) { + // We want a fresh db after emf close + // Unfortunately we have to use this dirty hack because the db seems not to be closed otherwise + settings.put( "hibernate.connection.url", "jdbc:h2:mem:db-schemagen" + schemagenNumber++ + + ";MVCC=TRUE;LOCK_TIMEOUT=10000" ); + EntityManagerFactoryBuilder emfb = Bootstrap.getEntityManagerFactoryBuilder( buildPersistenceUnitDescriptor(), + settings ); + + EntityManagerFactory emf = emfb.build(); + + Assert.assertNotNull( emf.createEntityManager().find( Item.class, "schemagen-test" ) ); + + emf.close(); + emfb.cancel(); + } + + private PersistenceUnitDescriptor buildPersistenceUnitDescriptor() { + return new TestingPersistenceUnitDescriptorImpl( getClass().getSimpleName() ); + } + + /* Disable hibernate schema export */ + @Override + protected boolean createSchema() { + return false; + } + +} \ No newline at end of file diff --git a/hibernate-entitymanager/src/test/resources/org/hibernate/jpa/test/schemagen/create-script-source.sql b/hibernate-entitymanager/src/test/resources/org/hibernate/jpa/test/schemagen/create-script-source.sql new file mode 100644 index 0000000000..49fb00c312 --- /dev/null +++ b/hibernate-entitymanager/src/test/resources/org/hibernate/jpa/test/schemagen/create-script-source.sql @@ -0,0 +1 @@ +INSERT INTO Item(name) VALUES('schemagen-test'); diff --git a/hibernate-entitymanager/src/test/resources/org/hibernate/jpa/test/schemagen/drop-script-source.sql b/hibernate-entitymanager/src/test/resources/org/hibernate/jpa/test/schemagen/drop-script-source.sql new file mode 100644 index 0000000000..1fe051373b --- /dev/null +++ b/hibernate-entitymanager/src/test/resources/org/hibernate/jpa/test/schemagen/drop-script-source.sql @@ -0,0 +1,2 @@ +create table Item ( name varchar(30) not null, descr varchar(200), primary key (name)); +INSERT INTO Item(name) VALUES('schemagen-test'); diff --git a/hibernate-entitymanager/src/test/resources/org/hibernate/jpa/test/schemagen/load-script-source.sql b/hibernate-entitymanager/src/test/resources/org/hibernate/jpa/test/schemagen/load-script-source.sql new file mode 100644 index 0000000000..49fb00c312 --- /dev/null +++ b/hibernate-entitymanager/src/test/resources/org/hibernate/jpa/test/schemagen/load-script-source.sql @@ -0,0 +1 @@ +INSERT INTO Item(name) VALUES('schemagen-test');