/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
 */
package org.hibernate.tool.hbm2ddl;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tool.schema.SourceType;
import org.hibernate.tool.schema.TargetType;
import org.hibernate.tool.schema.internal.ExceptionHandlerCollectingImpl;
import org.hibernate.tool.schema.internal.ExceptionHandlerHaltImpl;
import org.hibernate.tool.schema.internal.Helper;
import org.hibernate.tool.schema.internal.SchemaCreatorImpl;
import org.hibernate.tool.schema.spi.ExceptionHandler;
import org.hibernate.tool.schema.spi.ExecutionOptions;
import org.hibernate.tool.schema.spi.SchemaManagementException;
import org.hibernate.tool.schema.spi.SchemaManagementTool;
import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator;
import org.hibernate.tool.schema.spi.ScriptSourceInput;
import org.hibernate.tool.schema.spi.ScriptTargetOutput;
import org.hibernate.tool.schema.spi.SourceDescriptor;
import org.hibernate.tool.schema.spi.TargetDescriptor;

Command-line tool for exporting (create and/or drop) a database schema. The export can be sent directly to the database, written to script or both.
Author:Daniel Bradby, Gavin King, Steve Ebersole
/** * Command-line tool for exporting (create and/or drop) a database schema. The export can * be sent directly to the database, written to script or both. * * @author Daniel Bradby * @author Gavin King * @author Steve Ebersole */
public class SchemaExport { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( SchemaExport.class ); public static enum Type { CREATE( Action.CREATE ), DROP( Action.DROP ), NONE( Action.NONE ), BOTH( Action.BOTH ); private final Action actionReplacement; Type(Action actionReplacement) { this.actionReplacement = actionReplacement; } public boolean doCreate() { return actionReplacement.doCreate(); } public boolean doDrop() { return actionReplacement.doDrop(); } } public static enum Action {
None - duh :P
/** * None - duh :P */
NONE,
Create only
/** * Create only */
CREATE,
Drop only
/** * Drop only */
DROP,
Drop and then create
/** * Drop and then create */
BOTH; public boolean doCreate() { return this == BOTH || this == CREATE; } public boolean doDrop() { return this == BOTH || this == DROP; } private static Action interpret(boolean justDrop, boolean justCreate) { if ( justDrop ) { return Action.DROP; } else if ( justCreate ) { return Action.CREATE; } else { return Action.BOTH; } } public static Action parseCommandLineOption(String actionText) { if ( actionText.equalsIgnoreCase( "create" ) ) { return CREATE; } else if ( actionText.equalsIgnoreCase( "drop" ) ) { return DROP; } else if ( actionText.equalsIgnoreCase( "drop-and-create" ) ) { return BOTH; } else { return NONE; } } } boolean haltOnError = false; boolean format = false; boolean manageNamespaces = false; String delimiter = null; String outputFile = null; private String importFiles; private final List<Exception> exceptions = new ArrayList<Exception>();
For generating a export script file, this is the file which will be written.
Params:
  • filename – The name of the file to which to write the export script.
Returns:this
/** * For generating a export script file, this is the file which will be written. * * @param filename The name of the file to which to write the export script. * * @return this */
public SchemaExport setOutputFile(String filename) { outputFile = filename; return this; }
Comma-separated list of resource names to use for database init commands on create.
Params:
  • importFiles – The comma-separated list of init file resources names
Returns:this
/** * Comma-separated list of resource names to use for database init commands on create. * * @param importFiles The comma-separated list of init file resources names * * @return this */
public SchemaExport setImportFiles(String importFiles) { this.importFiles = importFiles; return this; }
Set the end of statement delimiter
Params:
  • delimiter – The delimiter
Returns:this
/** * Set the end of statement delimiter * * @param delimiter The delimiter * * @return this */
public SchemaExport setDelimiter(String delimiter) { this.delimiter = delimiter; return this; }
Should we format the sql strings?
Params:
  • format – Should we format SQL strings
Returns:this
/** * Should we format the sql strings? * * @param format Should we format SQL strings * * @return this */
public SchemaExport setFormat(boolean format) { this.format = format; return this; }
Should we stop once an error occurs?
Params:
  • haltOnError – True if export should stop after error.
Returns:this
/** * Should we stop once an error occurs? * * @param haltOnError True if export should stop after error. * * @return this */
public SchemaExport setHaltOnError(boolean haltOnError) { this.haltOnError = haltOnError; return this; } public SchemaExport setManageNamespaces(boolean manageNamespaces) { this.manageNamespaces = manageNamespaces; return this; } public void drop(EnumSet<TargetType> targetTypes, Metadata metadata) { execute( targetTypes, Action.DROP, metadata ); } public void create(EnumSet<TargetType> targetTypes, Metadata metadata) { execute( targetTypes, Action.BOTH, metadata ); } public void createOnly(EnumSet<TargetType> targetTypes, Metadata metadata) { execute( targetTypes, Action.CREATE, metadata ); } public void execute(EnumSet<TargetType> targetTypes, Action action, Metadata metadata) { execute( targetTypes, action, metadata, ( (MetadataImplementor) metadata ).getMetadataBuildingOptions().getServiceRegistry() ); } @SuppressWarnings("unchecked") public void execute(EnumSet<TargetType> targetTypes, Action action, Metadata metadata, ServiceRegistry serviceRegistry) { if ( action == Action.NONE ) { LOG.debug( "Skipping SchemaExport as Action.NONE was passed" ); return; } if ( targetTypes.isEmpty() ) { LOG.debug( "Skipping SchemaExport as no targets were specified" ); return; } exceptions.clear(); LOG.runningHbm2ddlSchemaExport(); final TargetDescriptor targetDescriptor = buildTargetDescriptor( targetTypes, outputFile, serviceRegistry ); doExecution( action, needsJdbcConnection( targetTypes ), metadata, serviceRegistry, targetDescriptor ); } public void doExecution( Action action, boolean needsJdbc, Metadata metadata, ServiceRegistry serviceRegistry, TargetDescriptor targetDescriptor) { Map config = new HashMap(); config.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); config.put( AvailableSettings.HBM2DDL_DELIMITER, delimiter ); config.put( AvailableSettings.FORMAT_SQL, format ); config.put( AvailableSettings.HBM2DDL_IMPORT_FILES, importFiles ); final SchemaManagementTool tool = serviceRegistry.getService( SchemaManagementTool.class ); final ExceptionHandler exceptionHandler = haltOnError ? ExceptionHandlerHaltImpl.INSTANCE : new ExceptionHandlerCollectingImpl(); final ExecutionOptions executionOptions = SchemaManagementToolCoordinator.buildExecutionOptions( config, exceptionHandler ); final SourceDescriptor sourceDescriptor = new SourceDescriptor() { @Override public SourceType getSourceType() { return SourceType.METADATA; } @Override public ScriptSourceInput getScriptSourceInput() { return null; } }; try { if ( action.doDrop() ) { tool.getSchemaDropper( config ).doDrop( metadata, executionOptions, sourceDescriptor, targetDescriptor ); } if ( action.doCreate() ) { tool.getSchemaCreator( config ).doCreation( metadata, executionOptions, sourceDescriptor, targetDescriptor ); } } finally { if ( exceptionHandler instanceof ExceptionHandlerCollectingImpl ) { exceptions.addAll( ( (ExceptionHandlerCollectingImpl) exceptionHandler ).getExceptions() ); } } } private boolean needsJdbcConnection(EnumSet<TargetType> targetTypes) { return targetTypes.contains( TargetType.DATABASE ); } public static TargetDescriptor buildTargetDescriptor( EnumSet<TargetType> targetTypes, String outputFile, ServiceRegistry serviceRegistry) { final ScriptTargetOutput scriptTarget; if ( targetTypes.contains( TargetType.SCRIPT ) ) { if ( outputFile == null ) { throw new SchemaManagementException( "Writing to script was requested, but no script file was specified" ); } scriptTarget = Helper.interpretScriptTargetSetting( outputFile, serviceRegistry.getService( ClassLoaderService.class ), (String) serviceRegistry.getService( ConfigurationService.class ).getSettings().get( AvailableSettings.HBM2DDL_CHARSET_NAME ) ); } else { scriptTarget = null; } return new TargetDescriptorImpl( targetTypes, scriptTarget ); }
For testing use
/** * For testing use */
public void perform(Action action, Metadata metadata, ScriptTargetOutput target) { doExecution( action, false, metadata, ( (MetadataImplementor) metadata ).getMetadataBuildingOptions().getServiceRegistry(), new TargetDescriptorImpl( EnumSet.of( TargetType.SCRIPT ), target ) ); } public static void main(String[] args) { try { final CommandLineArgs commandLineArgs = CommandLineArgs.parseCommandLineArgs( args ); execute( commandLineArgs ); } catch (Exception e) { LOG.unableToCreateSchema( e ); } } public static void execute(CommandLineArgs commandLineArgs) throws Exception { StandardServiceRegistry serviceRegistry = buildStandardServiceRegistry( commandLineArgs ); try { final MetadataImplementor metadata = buildMetadata( commandLineArgs, serviceRegistry ); new SchemaExport() .setHaltOnError( commandLineArgs.halt ) .setOutputFile( commandLineArgs.outputFile ) .setDelimiter( commandLineArgs.delimiter ) .setFormat( commandLineArgs.format ) .setManageNamespaces( commandLineArgs.manageNamespaces ) .setImportFiles( commandLineArgs.importFile ) .execute( commandLineArgs.targetTypes, commandLineArgs.action, metadata, serviceRegistry ); } finally { StandardServiceRegistryBuilder.destroy( serviceRegistry ); } } private static StandardServiceRegistry buildStandardServiceRegistry(CommandLineArgs commandLineArgs) throws Exception { final BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder().build(); final StandardServiceRegistryBuilder ssrBuilder = new StandardServiceRegistryBuilder( bsr ); if ( commandLineArgs.cfgXmlFile != null ) { ssrBuilder.configure( commandLineArgs.cfgXmlFile ); } Properties properties = new Properties(); if ( commandLineArgs.propertiesFile != null ) { properties.load( new FileInputStream( commandLineArgs.propertiesFile ) ); } ssrBuilder.applySettings( properties ); return ssrBuilder.build(); } private static MetadataImplementor buildMetadata( CommandLineArgs parsedArgs, StandardServiceRegistry serviceRegistry) throws Exception { final MetadataSources metadataSources = new MetadataSources( serviceRegistry ); for ( String filename : parsedArgs.hbmXmlFiles ) { metadataSources.addFile( filename ); } for ( String filename : parsedArgs.jarFiles ) { metadataSources.addJar( new File( filename ) ); } final MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder(); final StrategySelector strategySelector = serviceRegistry.getService( StrategySelector.class ); if ( parsedArgs.implicitNamingStrategyImplName != null ) { metadataBuilder.applyImplicitNamingStrategy( strategySelector.resolveStrategy( ImplicitNamingStrategy.class, parsedArgs.implicitNamingStrategyImplName ) ); } if ( parsedArgs.physicalNamingStrategyImplName != null ) { metadataBuilder.applyPhysicalNamingStrategy( strategySelector.resolveStrategy( PhysicalNamingStrategy.class, parsedArgs.physicalNamingStrategyImplName ) ); } return (MetadataImplementor) metadataBuilder.build(); }
Intended for test usage only. Builds a Metadata using the same algorithm as main
Params:
  • args – The "command line args"
Throws:
Returns:The built Metadata
/** * Intended for test usage only. Builds a Metadata using the same algorithm as * {@link #main} * * @param args The "command line args" * * @return The built Metadata * * @throws Exception Problems building the Metadata */
public static MetadataImplementor buildMetadataFromMainArgs(String[] args) throws Exception { final CommandLineArgs commandLineArgs = CommandLineArgs.parseCommandLineArgs( args ); StandardServiceRegistry serviceRegistry = buildStandardServiceRegistry( commandLineArgs ); try { return buildMetadata( commandLineArgs, serviceRegistry ); } finally { StandardServiceRegistryBuilder.destroy( serviceRegistry ); } }
Returns a List of all Exceptions which occurred during the export.
Returns:A List containing the Exceptions occurred during the export
/** * Returns a List of all Exceptions which occurred during the export. * * @return A List containing the Exceptions occurred during the export */
public List getExceptions() { return exceptions; } private static class CommandLineArgs { EnumSet<TargetType> targetTypes; Action action; boolean halt = false; boolean format = false; boolean manageNamespaces = false; String delimiter = null; String outputFile = null; String importFile = SchemaCreatorImpl.DEFAULT_IMPORT_FILE; String propertiesFile = null; String cfgXmlFile = null; String implicitNamingStrategyImplName = null; String physicalNamingStrategyImplName = null; List<String> hbmXmlFiles = new ArrayList<String>(); List<String> jarFiles = new ArrayList<String>(); public static CommandLineArgs parseCommandLineArgs(String[] args) { String targetText = null; boolean script = true; boolean export = true; String actionText = null; boolean drop = false; boolean create = false; CommandLineArgs parsedArgs = new CommandLineArgs(); for ( String arg : args ) { if ( arg.startsWith( "--" ) ) { if ( arg.equals( "--quiet" ) ) { script = false; } else if ( arg.equals( "--text" ) ) { export = false; } else if ( arg.equals( "--drop" ) ) { drop = true; } else if ( arg.equals( "--create" ) ) { create = true; } else if ( arg.startsWith( "--action=" ) ) { actionText = arg.substring( 9 ); } else if ( arg.startsWith( "--target=" ) ) { targetText = arg.substring( 9 ); } else if ( arg.equals( "--schemas" ) ) { parsedArgs.manageNamespaces = true; } else if ( arg.equals( "--haltonerror" ) ) { parsedArgs.halt = true; } else if ( arg.startsWith( "--output=" ) ) { parsedArgs.outputFile = arg.substring( 9 ); } else if ( arg.startsWith( "--import=" ) ) { parsedArgs.importFile = arg.substring( 9 ); } else if ( arg.startsWith( "--properties=" ) ) { parsedArgs.propertiesFile = arg.substring( 13 ); } else if ( arg.equals( "--format" ) ) { parsedArgs.format = true; } else if ( arg.startsWith( "--delimiter=" ) ) { parsedArgs.delimiter = arg.substring( 12 ); } else if ( arg.startsWith( "--config=" ) ) { parsedArgs.cfgXmlFile = arg.substring( 9 ); } else if ( arg.startsWith( "--naming=" ) ) { DeprecationLogger.DEPRECATION_LOGGER.logDeprecatedNamingStrategyArgument(); } else if ( arg.startsWith( "--implicit-naming=" ) ) { parsedArgs.implicitNamingStrategyImplName = arg.substring( 18 ); } else if ( arg.startsWith( "--physical-naming=" ) ) { parsedArgs.physicalNamingStrategyImplName = arg.substring( 18 ); } } else { if ( arg.endsWith( ".jar" ) ) { parsedArgs.jarFiles.add( arg ); } else { parsedArgs.hbmXmlFiles.add( arg ); } } } if ( actionText == null ) { parsedArgs.action = Action.interpret( drop, create ); } else { if ( drop || create ) { LOG.warn( "--drop or --create was used; prefer --action=none|create|drop|drop-and-create instead" ); } parsedArgs.action = Action.parseCommandLineOption( actionText ); } if ( targetText == null ) { parsedArgs.targetTypes = TargetTypeHelper.parseLegacyCommandLineOptions( script, export, parsedArgs.outputFile ); } else { if ( !script || !export ) { LOG.warn( "--text or --quiet was used; prefer --target=none|(stdout|database|script)*" ); } parsedArgs.targetTypes = TargetTypeHelper.parseCommandLineOptions( targetText ); } return parsedArgs; } } private static class TargetDescriptorImpl implements TargetDescriptor { private final EnumSet<TargetType> targetTypes; private final ScriptTargetOutput scriptTarget; public TargetDescriptorImpl( EnumSet<TargetType> targetTypes, ScriptTargetOutput scriptTarget) { this.targetTypes = targetTypes; this.scriptTarget = scriptTarget; } @Override public EnumSet<TargetType> getTargetTypes() { return targetTypes; } @Override public ScriptTargetOutput getScriptTargetOutput() { return scriptTarget; } } }