X-Git-Url: http://juplo.de/gitweb/?p=hibernate4-maven-plugin;a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fde%2Fjuplo%2Fplugins%2Fhibernate%2FAbstractSchemaMojo.java;h=922b77db69fdab1bf77ad09f732f7cfebe88c1f7;hp=2295968392e240bfe5a9b55c1b7ed4e74250fb19;hb=c81cd2f66c77e823cf03591db42d50811706c0de;hpb=08649780d2cd70f2861298d683aa6b1945d43cda diff --git a/src/main/java/de/juplo/plugins/hibernate/AbstractSchemaMojo.java b/src/main/java/de/juplo/plugins/hibernate/AbstractSchemaMojo.java index 22959683..922b77db 100644 --- a/src/main/java/de/juplo/plugins/hibernate/AbstractSchemaMojo.java +++ b/src/main/java/de/juplo/plugins/hibernate/AbstractSchemaMojo.java @@ -4,12 +4,15 @@ package de.juplo.plugins.hibernate; import com.pyx4j.log4j.MavenLogAppender; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.security.NoSuchAlgorithmException; import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; @@ -45,25 +48,34 @@ import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.registry.selector.spi.StrategySelector; import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.AvailableSettings; import static org.hibernate.cfg.AvailableSettings.DIALECT; import static org.hibernate.cfg.AvailableSettings.DRIVER; import static org.hibernate.cfg.AvailableSettings.FORMAT_SQL; +import static org.hibernate.cfg.AvailableSettings.HBM2DDL_DELIMITER; import static org.hibernate.cfg.AvailableSettings.HBM2DLL_CREATE_NAMESPACES; import static org.hibernate.cfg.AvailableSettings.IMPLICIT_NAMING_STRATEGY; +import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_DRIVER; +import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_PASSWORD; +import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_URL; +import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_USER; import static org.hibernate.cfg.AvailableSettings.PASS; import static org.hibernate.cfg.AvailableSettings.PHYSICAL_NAMING_STRATEGY; import static org.hibernate.cfg.AvailableSettings.SHOW_SQL; import static org.hibernate.cfg.AvailableSettings.USER; import static org.hibernate.cfg.AvailableSettings.URL; +import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.internal.util.config.ConfigurationException; -import static org.hibernate.jpa.AvailableSettings.JDBC_DRIVER; -import static org.hibernate.jpa.AvailableSettings.JDBC_PASSWORD; -import static org.hibernate.jpa.AvailableSettings.JDBC_URL; -import static org.hibernate.jpa.AvailableSettings.JDBC_USER; import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor; import org.hibernate.jpa.boot.internal.PersistenceXmlParser; -import org.hibernate.jpa.boot.spi.ProviderChecker; +import org.hibernate.tool.schema.TargetType; +import org.hibernate.tool.schema.internal.ExceptionHandlerCollectingImpl; +import org.hibernate.tool.schema.internal.exec.ScriptTargetOutputToFile; +import org.hibernate.tool.schema.spi.ExecutionOptions; +import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator; +import org.hibernate.tool.schema.spi.ScriptTargetOutput; +import org.hibernate.tool.schema.spi.TargetDescriptor; import org.scannotation.AnnotationDB; @@ -77,7 +89,6 @@ import org.scannotation.AnnotationDB; public abstract class AbstractSchemaMojo extends AbstractMojo { public final static String EXPORT = "hibernate.schema.export"; - public final static String DELIMITER = "hibernate.schema.delimiter"; public final static String OUTPUTDIRECTORY = "project.build.outputDirectory"; public final static String SCAN_CLASSES = "hibernate.schema.scan.classes"; public final static String SCAN_DEPENDENCIES = "hibernate.schema.scan.dependencies"; @@ -89,6 +100,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo private final Set packages = new HashSet(); + /** * The maven project. *

@@ -109,7 +121,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo * @required * @readonly */ - String buildDirectory; + private String buildDirectory; /** Parameters to configure the genaration of the SQL *********************/ @@ -128,7 +140,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo * @parameter property="hibernate.schema.export" default-value="true" * @since 2.0 */ - Boolean export; + private Boolean export; /** * Skip execution @@ -136,7 +148,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo * If set to true, the execution is skipped. *

* A skipped execution is signaled via the maven-property - * ${hibernate.export.skipped}. + * ${hibernate.schema.skipped}. *

* The execution is skipped automatically, if no modified or newly added * annotated classes are found and the dialect was not changed. @@ -188,10 +200,10 @@ public abstract class AbstractSchemaMojo extends AbstractMojo * it is not known by Hibernate nor JPA and, hence, not picked up from * their configuration! * - * @parameter property="hibernate.schema.delimiter" default-value=";" + * @parameter property="hibernate.hbm2ddl.delimiter" default-value=";" * @since 1.0 */ - String delimiter; + private String delimiter; /** * Show the generated SQL in the command-line output. @@ -199,7 +211,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo * @parameter property="hibernate.show_sql" * @since 1.0 */ - Boolean show; + private Boolean show; /** * Format output-file. @@ -207,7 +219,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo * @parameter property="hibernate.format_sql" * @since 1.0 */ - Boolean format; + private Boolean format; /** * Specifies whether to automatically create also the database schema/catalog. @@ -215,7 +227,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo * @parameter property="hibernate.hbm2dll.create_namespaces" default-value="false" * @since 2.0 */ - Boolean createNamespaces; + private Boolean createNamespaces; /** * Implicit naming strategy @@ -445,7 +457,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo throw new MojoFailureException("Digest-Algorithm MD5 is missing!", e); } - SimpleConnectionProvider connectionProvider = + final SimpleConnectionProvider connectionProvider = new SimpleConnectionProvider(getLog()); try @@ -489,13 +501,16 @@ public abstract class AbstractSchemaMojo extends AbstractMojo else getLog().debug("Configuration unchanged."); + /** Check, that the outputfile is writable */ + final File output = getOutputFile(filename); + /** Configure Hibernate */ - StandardServiceRegistry serviceRegistry = + final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder(bootstrapServiceRegitry) .applySettings(properties) .addService(ConnectionProvider.class, connectionProvider) .build(); - MetadataSources sources = new MetadataSources(serviceRegistry); + final MetadataSources sources = new MetadataSources(serviceRegistry); /** Add the remaining class-path-elements */ completeClassPath(classLoader); @@ -546,30 +561,60 @@ public abstract class AbstractSchemaMojo extends AbstractMojo * Add mappings from the default mapping-file * META-INF/orm.xml, if present */ - try + boolean error = false; + InputStream is; + is = classLoader.getResourceAsStream("META-INF/orm.xml"); + if (is != null) { - InputStream is = classLoader.getResourceAsStream("META-INF/orm.xml"); - if (is != null) + getLog().info("Adding default JPA-XML-mapping from META-INF/orm.xml"); + try { - getLog().info("Adding default JPA-XML-mapping from META-INF/orm.xml"); tracker.track("META-INF/orm.xml", is); sources.addResource("META-INF/orm.xml"); } - /** - * Add mappings from files, that are explicitly configured in the - * persistence unit - */ - for (String mapping : unit.getMappingFileNames()) + catch (IOException e) { - getLog().info("Adding explicitly configured mapping from " + mapping); - tracker.track(mapping, classLoader.getResourceAsStream(mapping)); - sources.addResource(mapping); + getLog().error("cannot read META-INF/orm.xml: " + e); + error = true; } } - catch (IOException e) + else { - throw new MojoFailureException("Error reading XML-mappings", e); + getLog().debug("no META-INF/orm.xml found"); } + /** + * Add mappings from files, that are explicitly configured in the + * persistence unit + */ + for (String mapping : unit.getMappingFileNames()) + { + getLog().info("Adding explicitly configured mapping from " + mapping); + is = classLoader.getResourceAsStream(mapping); + if (is != null) + { + try + { + tracker.track(mapping, is); + sources.addResource(mapping); + } + catch (IOException e) + { + getLog().info("cannot read mapping-file " + mapping + ": " + e); + error = true; + } + } + else + { + getLog().error("cannot find mapping-file " + mapping); + error = true; + } + } + if (error) + throw new MojoFailureException( + "error, while reading mappings configured in persistence-unit \"" + + unit.getName() + + "\"" + ); } /** Add the configured/collected annotated classes */ @@ -596,6 +641,20 @@ public abstract class AbstractSchemaMojo extends AbstractMojo } + /** Truncate output file */ + try + { + new FileOutputStream(output).getChannel().truncate(0).close(); + } + catch (IOException e) + { + String error = + "Error while truncating " + output.getAbsolutePath() + ": " + + e.getMessage(); + getLog().warn(error); + throw new MojoExecutionException(error); + } + /** Create a connection, if sufficient configuration infromation is available */ connectionProvider.open(classLoaderService, properties); @@ -624,6 +683,42 @@ public abstract class AbstractSchemaMojo extends AbstractMojo ); } + /** Prepare the generation of the SQL */ + Map settings = new HashMap(); + settings.putAll( + serviceRegistry + .getService(ConfigurationService.class) + .getSettings() + ); + ExceptionHandlerCollectingImpl handler = + new ExceptionHandlerCollectingImpl(); + ExecutionOptions options = + SchemaManagementToolCoordinator + .buildExecutionOptions(settings, handler); + final EnumSet targetTypes = EnumSet.of(TargetType.SCRIPT); + if (export) + targetTypes.add(TargetType.DATABASE); + TargetDescriptor target = new TargetDescriptor() + { + @Override + public EnumSet getTargetTypes() + { + return targetTypes; + } + + @Override + public ScriptTargetOutput getScriptTargetOutput() + { + String charset = + (String) + serviceRegistry + .getService(ConfigurationService.class) + .getSettings() + .get(AvailableSettings.HBM2DDL_CHARSET_NAME); + return new ScriptTargetOutputToFile(output, charset); + } + }; + /** * Change class-loader of current thread. * This is necessary, because still not all parts of Hibernate 5 use @@ -634,13 +729,30 @@ public abstract class AbstractSchemaMojo extends AbstractMojo try { thread.setContextClassLoader(classLoader); - build((MetadataImplementor)metadataBuilder.build()); + build((MetadataImplementor)metadataBuilder.build(), options, target); } finally { thread.setContextClassLoader(contextClassLoader); + for (Exception e : handler.getExceptions()) + getLog().error(e.getMessage()); } } + catch (MojoExecutionException e) + { + tracker.failed(); + throw e; + } + catch (MojoFailureException e) + { + tracker.failed(); + throw e; + } + catch (RuntimeException e) + { + tracker.failed(); + throw e; + } finally { /** Remember mappings and configuration */ @@ -655,7 +767,11 @@ public abstract class AbstractSchemaMojo extends AbstractMojo } - abstract void build(MetadataImplementor metadata) + abstract void build( + MetadataImplementor metadata, + ExecutionOptions options, + TargetDescriptor target + ) throws MojoFailureException, MojoExecutionException; @@ -811,12 +927,12 @@ public abstract class AbstractSchemaMojo extends AbstractMojo * Overwrite values from properties-file if the configuration parameter is * known to Hibernate. */ - dialect = configure(properties, dialect, DIALECT); - tracker.track(DELIMITER, delimiter); // << not reflected in hibernate configuration! - format = configure(properties, format, FORMAT_SQL); - createNamespaces = configure(properties, createNamespaces, HBM2DLL_CREATE_NAMESPACES); - implicitNamingStrategy = configure(properties, implicitNamingStrategy, IMPLICIT_NAMING_STRATEGY); - physicalNamingStrategy = configure(properties, physicalNamingStrategy, PHYSICAL_NAMING_STRATEGY); + configure(properties, dialect, DIALECT); + configure(properties, delimiter, HBM2DDL_DELIMITER); + configure(properties, format, FORMAT_SQL); + configure(properties, createNamespaces, HBM2DLL_CREATE_NAMESPACES); + configure(properties, implicitNamingStrategy, IMPLICIT_NAMING_STRATEGY); + configure(properties, physicalNamingStrategy, PHYSICAL_NAMING_STRATEGY); tracker.track(OUTPUTDIRECTORY, outputDirectory); // << not reflected in hibernate configuration! tracker.track(SCAN_DEPENDENCIES, scanDependencies); // << not reflected in hibernate configuration! tracker.track(SCAN_TESTCLASSES, scanTestClasses.toString()); // << not reflected in hibernate configuration! @@ -836,10 +952,10 @@ public abstract class AbstractSchemaMojo extends AbstractMojo * Configure the connection parameters. * Overwrite values from properties-file. */ - driver = configure(properties, driver, DRIVER, JDBC_DRIVER); - url = configure(properties, url, URL, JDBC_URL); - username = configure(properties, username, USER, JDBC_USER); - password = configure(properties, password, PASS, JDBC_PASSWORD); + configure(properties, driver, DRIVER, JPA_JDBC_DRIVER); + configure(properties, url, URL, JPA_JDBC_URL); + configure(properties, username, USER, JPA_JDBC_USER); + configure(properties, password, PASS, JPA_JDBC_PASSWORD); if (properties.isEmpty()) { @@ -852,59 +968,115 @@ public abstract class AbstractSchemaMojo extends AbstractMojo getLog().info(" " + entry.getKey() + " = " + entry.getValue()); } - private String configure( + private void configure( Properties properties, String value, String key, String alternativeKey ) { - value = configure(properties, value, key); - if (value == null) - return properties.getProperty(alternativeKey); + configure(properties, value, key); if (properties.containsKey(alternativeKey)) { - getLog().warn( - "Ignoring property " + alternativeKey + "=" + - properties.getProperty(alternativeKey) + " in favour for property " + - key + "=" + properties.getProperty(key) - ); - properties.remove(alternativeKey); + if (properties.containsKey(key)) + { + getLog().warn( + "Ignoring property " + alternativeKey + "=\"" + + properties.getProperty(alternativeKey) + + "\" in favour for property " + key + "=\"" + + properties.getProperty(key) + "\"" + ); + properties.remove(alternativeKey); + } + else + { + value = properties.getProperty(alternativeKey); + properties.remove(alternativeKey); + getLog().info( + "Using value \"" + value + "\" from property " + alternativeKey + + " for property " + key + ); + properties.setProperty(key, value); + } } - return properties.getProperty(alternativeKey); } - private String configure(Properties properties, String value, String key) + private void configure(Properties properties, String value, String key) { if (value != null) { if (properties.containsKey(key)) - getLog().debug( - "Overwriting property " + key + "=" + properties.getProperty(key) + - " with the value " + value + getLog().info( + "Overwriting property " + key + "=\"" + + properties.getProperty(key) + + "\" with value \"" + value + "\"" ); else - getLog().debug("Using the value " + value + " for property " + key); + getLog().debug("Using value \"" + value + "\" for property " + key); properties.setProperty(key, value); } - return properties.getProperty(key); } - private boolean configure(Properties properties, Boolean value, String key) + private void configure(Properties properties, Boolean value, String key) { - if (value != null) + configure(properties, value == null ? null : value.toString(), key); + } + + private File getOutputFile(String filename) + throws + MojoExecutionException + { + File output = new File(filename); + + if (!output.isAbsolute()) { - if (properties.containsKey(key)) - getLog().debug( - "Overwriting property " + key + "=" + properties.getProperty(key) + - " with the value " + value + // Interpret relative file path relative to build directory + output = new File(buildDirectory, filename); + } + getLog().debug("Output file: " + output.getPath()); + + // Ensure that directory path for specified file exists + File outFileParentDir = output.getParentFile(); + if (null != outFileParentDir && !outFileParentDir.exists()) + { + try + { + getLog().info( + "Creating directory path for output file:" + + outFileParentDir.getPath() ); - else - getLog().debug("Using the value " + value + " for property " + key); - properties.setProperty(key, value.toString()); + outFileParentDir.mkdirs(); + } + catch (Exception e) + { + String error = + "Error creating directory path for output file: " + e.getMessage(); + getLog().error(error); + throw new MojoExecutionException(error); + } + } + + try + { + output.createNewFile(); } - return Boolean.valueOf(properties.getProperty(key)); + catch (IOException e) + { + String error = "Error creating output file: " + e.getMessage(); + getLog().error(error); + throw new MojoExecutionException(error); + } + + if (!output.canWrite()) + { + String error = + "Output file " + output.getAbsolutePath() + " is not writable!"; + getLog().error(error); + throw new MojoExecutionException(error); + } + + return output; } private void addMappings(MetadataSources sources, ModificationTracker tracker) @@ -1042,8 +1214,9 @@ public abstract class AbstractSchemaMojo extends AbstractMojo try { getLog().info("Adding annotated resource: " + name); - String packageName; + String packageName = null; + boolean error = false; try { Class annotatedClass = classLoaderService.classForName(name); @@ -1054,20 +1227,34 @@ public abstract class AbstractSchemaMojo extends AbstractMojo resourceName.length() ) + ".class"; InputStream is = annotatedClass.getResourceAsStream(resourceName); - if (tracker.track(name, is)) - getLog().debug("New or modified class: " + name); + if (is != null) + { + if (tracker.track(name, is)) + getLog().debug("New or modified class: " + name); + else + getLog().debug("Unchanged class: " + name); + sources.addAnnotatedClass(annotatedClass); + packageName = annotatedClass.getPackage().getName(); + } else - getLog().debug("Unchanged class: " + name); - sources.addAnnotatedClass(annotatedClass); - packageName = annotatedClass.getPackage().getName(); + { + getLog().error("cannot find ressource " + resourceName + " for class " + name); + error = true; + } } catch(ClassLoadingException e) { packageName = name; } + if (error) + { + throw new MojoExecutionException("error while inspecting annotated class " + name); + } - if (!packages.contains(packageName)) + while (packageName != null) { + if (packages.contains(packageName)) + return; String resource = packageName.replace('.', '/') + "/package-info.class"; InputStream is = classLoaderService.locateResourceStream(resource); if (is == null) @@ -1085,6 +1272,11 @@ public abstract class AbstractSchemaMojo extends AbstractMojo sources.addPackage(packageName); } packages.add(packageName); + int i = packageName.lastIndexOf('.'); + if (i < 0) + packageName = null; + else + packageName = packageName.substring(0,i); } } catch (Exception e) @@ -1107,48 +1299,41 @@ public abstract class AbstractSchemaMojo extends AbstractMojo PersistenceUnitTransactionType.RESOURCE_LOCAL ); - List units = parser.doResolve(properties); + Map units = + parser.doResolve(properties); if (persistenceUnit == null) { - switch (units.size()) + Iterator names = units.keySet().iterator(); + if (!names.hasNext()) { - case 0: - getLog().info("Found no META-INF/persistence.xml."); - return null; - case 1: - getLog().info("Using persistence-unit " + units.get(0).getName()); - return units.get(0); - default: - StringBuilder builder = new StringBuilder(); - builder.append("No name provided and multiple persistence units found: "); - Iterator it = units.iterator(); - builder.append(it.next().getName()); - while (it.hasNext()) - { - builder.append(", "); - builder.append(it.next().getName()); - } - builder.append('.'); - throw new MojoFailureException(builder.toString()); + getLog().info("Found no META-INF/persistence.xml."); + return null; } - } - for (ParsedPersistenceXmlDescriptor unit : units) - { - getLog().debug("Found persistence-unit " + unit.getName()); - if (!unit.getName().equals(persistenceUnit)) - continue; + String name = names.next(); + if (!names.hasNext()) + { + getLog().info("Using persistence-unit " + name); + return units.get(name); + } - // See if we (Hibernate) are the persistence provider - if (!ProviderChecker.isProvider(unit, properties)) + StringBuilder builder = new StringBuilder(); + builder.append("No name provided and multiple persistence units found: "); + builder.append(name); + while(names.hasNext()) { - getLog().debug("Wrong provider: " + unit.getProviderClassName()); - continue; + builder.append(", "); + builder.append(names.next()); } + builder.append('.'); + throw new MojoFailureException(builder.toString()); + } - getLog().info("Using persistence-unit " + unit.getName()); - return unit; + if (units.containsKey(persistenceUnit)) + { + getLog().info("Using configured persistence-unit " + persistenceUnit); + return units.get(persistenceUnit); } throw new MojoFailureException("Could not find persistence-unit " + persistenceUnit);