X-Git-Url: https://juplo.de/gitweb/?p=hibernate4-maven-plugin;a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fde%2Fjuplo%2Fplugins%2Fhibernate%2FAbstractSchemaMojo.java;h=72ec9d4dccaf48085f1d9647662bd350c658bd9b;hp=9006f352d08ed9bb5384eb651a5b1d3968f32ddd;hb=9c64807d3af68465473aec442bd0d435c0032c3c;hpb=f92a01a5043d0ac2f6a8eaf5aeed6f724b102f34 diff --git a/src/main/java/de/juplo/plugins/hibernate/AbstractSchemaMojo.java b/src/main/java/de/juplo/plugins/hibernate/AbstractSchemaMojo.java index 9006f352..72ec9d4d 100644 --- a/src/main/java/de/juplo/plugins/hibernate/AbstractSchemaMojo.java +++ b/src/main/java/de/juplo/plugins/hibernate/AbstractSchemaMojo.java @@ -4,11 +4,13 @@ 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.time.ZonedDateTime; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; @@ -25,7 +27,6 @@ import java.util.regex.Pattern; import javax.persistence.Embeddable; import javax.persistence.Entity; import javax.persistence.MappedSuperclass; -import javax.persistence.spi.PersistenceUnitTransactionType; import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Resource; import org.apache.maven.plugin.AbstractMojo; @@ -87,13 +88,14 @@ import org.scannotation.AnnotationDB; */ public abstract class AbstractSchemaMojo extends AbstractMojo { - public final static String EXPORT = "hibernate.schema.export"; + public final static String EXECUTE = "hibernate.schema.execute"; 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"; public final static String SCAN_TESTCLASSES = "hibernate.schema.scan.test_classes"; public final static String TEST_OUTPUTDIRECTORY = "project.build.testOutputDirectory"; public final static String SKIPPED = "hibernate.schema.skipped"; + public final static String SCRIPT = "hibernate.schema.script"; private final static Pattern SPLIT = Pattern.compile("[^,\\s]+"); @@ -126,7 +128,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo /** Parameters to configure the genaration of the SQL *********************/ /** - * Export the database-schma to the database. + * Excecute the generated SQL. * If set to false, only the SQL-script is created and the * database is not touched. *

@@ -136,10 +138,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.export" default-value="true" + * @parameter property="hibernate.schema.execute" default-value="true" * @since 2.0 */ - private Boolean export; + private Boolean execute; /** * Skip execution @@ -164,10 +166,11 @@ public abstract class AbstractSchemaMojo extends AbstractMojo private boolean skip; /** - * Force execution + * Force generation/execution *

- * Force execution, even if no modified or newly added annotated classes - * where found and the dialect was not changed. + * Force the generation and (if configured) the execution of the SQL, even if + * no modified or newly added annotated classes where found and the + * configuration was not changed. *

* skip takes precedence over force. *

@@ -481,13 +484,18 @@ public abstract class AbstractSchemaMojo extends AbstractMojo Properties properties = new Properties(); ConfigLoader configLoader = new ConfigLoader(bootstrapServiceRegitry); - /** Loading and merging configuration */ + /** Loading configuration */ properties.putAll(loadProperties(configLoader)); LoadedConfig config = loadConfig(configLoader); if (config != null) properties.putAll(config.getConfigurationValues()); + + /** Add the remaining class-path-elements */ + addDirectDependenciesClassPath(classLoader); + + /** Loading and merging configuration from persistence-unit(s) */ ParsedPersistenceXmlDescriptor unit = - loadPersistenceUnit(classLoaderService, properties); + loadPersistenceUnit(classLoader, properties); if (unit != null) properties.putAll(unit.getProperties()); @@ -502,6 +510,8 @@ public abstract class AbstractSchemaMojo extends AbstractMojo /** Check, that the outputfile is writable */ final File output = getOutputFile(filename); + /** Check, if the outputfile is missing or was changed */ + checkOutputFile(output, tracker); /** Configure Hibernate */ final StandardServiceRegistry serviceRegistry = @@ -512,7 +522,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo final MetadataSources sources = new MetadataSources(serviceRegistry); /** Add the remaining class-path-elements */ - completeClassPath(classLoader); + addAllDependenciesToClassPath(classLoader); /** Apply mappings from hibernate-configuration, if present */ if (config != null) @@ -528,6 +538,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo if (scanClasses == null) scanClasses = true; Set urls = new HashSet(); + getLog().debug("Compiling the dependencies, that are scanned for annotated classes"); if (scanClasses) addRoot(urls, outputDirectory); if (scanTestClasses) @@ -540,19 +551,28 @@ public abstract class AbstractSchemaMojo extends AbstractMojo /** Follow configuration in persisten unit */ if (scanClasses == null) scanClasses = !unit.isExcludeUnlistedClasses(); + getLog().debug("Compiling the dependencies, that are scanned for annotated classes"); + Set urls = new HashSet(); if (scanClasses) { + getLog().debug("Only dependencies relative to persistent-unit " + unit.getName() + " are scanned!"); /** * Scan the root of the persiten unit and configured jars for * annotated classes */ + getLog().debug(" - adding " + unit.getPersistenceUnitRootUrl()); urls.add(unit.getPersistenceUnitRootUrl()); for (URL url : unit.getJarFileUrls()) + { + getLog().debug(" - adding " + url); urls.add(url); + } + if (scanTestClasses) + addRoot(urls, testOutputDirectory); } - if (scanTestClasses) - addRoot(urls, testOutputDirectory); + else + getLog().debug("Scanning of unlisted classes is prohibited in persistent-unit " + unit.getName()); classes = scanUrls(urls); for (String className : unit.getManagedClassNames()) classes.add(className); @@ -585,9 +605,10 @@ public abstract class AbstractSchemaMojo extends AbstractMojo * Add mappings from files, that are explicitly configured in the * persistence unit */ + getLog().info("Adding mappings from persistence-unit " + unit.getName()); for (String mapping : unit.getMappingFileNames()) { - getLog().info("Adding explicitly configured mapping from " + mapping); + getLog().info(" - adding " + mapping); is = classLoader.getResourceAsStream(mapping); if (is != null) { @@ -626,11 +647,9 @@ public abstract class AbstractSchemaMojo extends AbstractMojo /** Skip execution, if mapping and configuration is unchanged */ if (!tracker.modified()) { - getLog().info( - "Mapping and configuration unchanged." - ); + getLog().info("Mapping and configuration unchanged."); if (force) - getLog().info("Schema generation is forced!"); + getLog().info("Generation/execution is forced!"); else { getLog().info("Skipping schema generation!"); @@ -640,6 +659,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); @@ -681,7 +714,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo SchemaManagementToolCoordinator .buildExecutionOptions(settings, handler); final EnumSet targetTypes = EnumSet.of(TargetType.SCRIPT); - if (export) + if (execute) targetTypes.add(TargetType.DATABASE); TargetDescriptor target = new TargetDescriptor() { @@ -715,12 +748,27 @@ public abstract class AbstractSchemaMojo extends AbstractMojo { thread.setContextClassLoader(classLoader); build((MetadataImplementor)metadataBuilder.build(), options, target); + if (handler.getExceptions().size() > 0) + { + StringBuilder builder = new StringBuilder(); + builder.append("Hibernate failed:"); + for (Exception e : handler.getExceptions()) + { + builder.append("\n * "); + builder.append(e.getMessage()); + AbstractSchemaMojo.printStrackTrace(builder, e); + builder.append("\n"); + } + String error = builder.toString(); + getLog().error(error); + throw new MojoFailureException(error); + } } finally { thread.setContextClassLoader(contextClassLoader); - for (Exception e : handler.getExceptions()) - getLog().error(e.getMessage()); + /** Track, the content of the generated script */ + checkOutputFile(output, tracker); } } catch (MojoExecutionException e) @@ -795,20 +843,39 @@ public abstract class AbstractSchemaMojo extends AbstractMojo } } - private void completeClassPath(MutableClassLoader classLoader) + private void addDirectDependenciesClassPath(MutableClassLoader classLoader) throws MojoExecutionException { try { - getLog().debug("Completing class-paths of the ClassLoader for project-dependencies..."); - List classpathFiles = project.getCompileClasspathElements(); + getLog().debug("Adding all direct project-dependencies to the ClassLoader..."); + LinkedHashSet urls = new LinkedHashSet(); + addDependencies(urls); if (scanTestClasses) - classpathFiles.addAll(project.getTestClasspathElements()); + addRoot(urls, testOutputDirectory); + classLoader.add(urls); + } + catch (Exception e) + { + getLog().error("Error while creating ClassLoader!", e); + throw new MojoExecutionException(e.getMessage()); + } + } + + private void addAllDependenciesToClassPath(MutableClassLoader classLoader) + throws + MojoExecutionException + { + try + { + getLog().debug("Adding all project-dependencies to the ClassLoader..."); + List classpathFiles = project.getCompileClasspathElements(); + classpathFiles.addAll(project.getTestClasspathElements()); LinkedHashSet urls = new LinkedHashSet(); for (String pathElement : classpathFiles) { - getLog().debug("Dependency: " + pathElement); + getLog().debug(" - adding " + pathElement); urls.add(new File(pathElement).toURI().toURL()); } classLoader.add(urls); @@ -901,11 +968,18 @@ public abstract class AbstractSchemaMojo extends AbstractMojo throws MojoFailureException { /** - * Special treatment for the configuration-value "export": if it is + * Special treatment for the configuration-value "execute": if it is * switched to "true", the genearation fo the schema should be forced! */ - if (tracker.check(EXPORT, export.toString()) && export) + if (tracker.check(EXECUTE, execute.toString()) && execute) + { + getLog().info( + "hibernate.schema.execute was switched on: " + + "forcing generation/execution of SQL" + ); tracker.touch(); + } + configure(properties, execute, EXECUTE); /** * Configure the generation of the SQL. @@ -918,10 +992,10 @@ public abstract class AbstractSchemaMojo extends AbstractMojo 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! - tracker.track(TEST_OUTPUTDIRECTORY, testOutputDirectory); // << not reflected in hibernate configuration! + configure(properties, outputDirectory, OUTPUTDIRECTORY); + configure(properties, scanDependencies, SCAN_DEPENDENCIES); + configure(properties, scanTestClasses, SCAN_TESTCLASSES); + configure(properties, testOutputDirectory, TEST_OUTPUTDIRECTORY); /** * Special treatment for the configuration-value "show": a change of its @@ -948,7 +1022,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo throw new MojoFailureException("Hibernate configuration is missing!"); } - getLog().info("Gathered hibernate-configuration (turn on debugging for details):"); + getLog().info("Gathered configuration:"); for (Entry entry : properties.entrySet()) getLog().info(" " + entry.getKey() + " = " + entry.getValue()); } @@ -992,14 +1066,22 @@ public abstract class AbstractSchemaMojo extends AbstractMojo if (value != null) { if (properties.containsKey(key)) - getLog().info( - "Overwriting property " + key + "=\"" + - properties.getProperty(key) + - "\" with value \"" + value + "\"" - ); + { + if (!properties.getProperty(key).equals(value)) + { + getLog().info( + "Overwriting property " + key + "=\"" + + properties.getProperty(key) + + "\" with value \"" + value + "\"" + ); + properties.setProperty(key, value); + } + } else + { getLog().debug("Using value \"" + value + "\" for property " + key); - properties.setProperty(key, value); + properties.setProperty(key, value); + } } } @@ -1064,6 +1146,26 @@ public abstract class AbstractSchemaMojo extends AbstractMojo return output; } + private void checkOutputFile(File output, ModificationTracker tracker) + throws + MojoExecutionException + { + try + { + if (output.exists()) + tracker.track(SCRIPT, new FileInputStream(output)); + else + tracker.track(SCRIPT, ZonedDateTime.now().toString()); + } + catch (IOException e) + { + String error = + "Error while checking the generated script: " + e.getMessage(); + getLog().error(error); + throw new MojoExecutionException(error); + } + } + private void addMappings(MetadataSources sources, ModificationTracker tracker) throws MojoFailureException { @@ -1092,9 +1194,9 @@ public abstract class AbstractSchemaMojo extends AbstractMojo // TODO: add support to read all mappings under a directory throw new MojoFailureException(file.getAbsolutePath() + " is a directory"); if (tracker.track(filename, new FileInputStream(file))) - getLog().debug("Found new or modified mapping-file: " + filename); + getLog().debug(" - found new or modified mapping-file: " + filename); else - getLog().debug("Mapping-file unchanged: " + filename); + getLog().debug(" - mapping-file unchanged: " + filename); sources.addFile(file); } @@ -1113,12 +1215,18 @@ public abstract class AbstractSchemaMojo extends AbstractMojo { try { - File dir = new File(outputDirectory); + File dir = new File(path); if (dir.exists()) { - getLog().info("Adding " + dir.getAbsolutePath() + " to the list of roots to scan..."); + getLog().info(" - adding " + dir.getAbsolutePath()); urls.add(dir.toURI().toURL()); } + else + getLog().warn( + "The directory cannot be scanned for annotated classes, " + + "because it does not exist: " + + dir.getAbsolutePath() + ); } catch (MalformedURLException e) { @@ -1136,7 +1244,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo Matcher matcher = SPLIT.matcher(scanDependencies); while (matcher.find()) { - getLog().info("Adding dependencies from scope " + matcher.group() + " to the list of roots to scan"); + getLog().debug("Adding dependencies from scope " + matcher.group() + " to the list of roots to scan"); for (Artifact artifact : project.getDependencyArtifacts()) { if (!artifact.getScope().equalsIgnoreCase(matcher.group())) @@ -1146,7 +1254,7 @@ public abstract class AbstractSchemaMojo extends AbstractMojo getLog().warn("Cannot add dependency " + artifact.getId() + ": no JAR-file available!"); continue; } - getLog().info("Adding dependencies from scope " + artifact.getId() + " to the list of roots to scan"); + getLog().debug(" - adding " + artifact.getId()); urls.add(artifact.getFile().toURI().toURL()); } } @@ -1272,20 +1380,36 @@ public abstract class AbstractSchemaMojo extends AbstractMojo } private ParsedPersistenceXmlDescriptor loadPersistenceUnit( - ClassLoaderService classLoaderService, + ClassLoader classLoader, Properties properties ) throws MojoFailureException { - PersistenceXmlParser parser = - new PersistenceXmlParser( - classLoaderService, - PersistenceUnitTransactionType.RESOURCE_LOCAL - ); + Map settings = + Collections.singletonMap( + AvailableSettings.CLASSLOADERS, + Collections.singletonList(classLoader) + ); + // Find all available persistent unit descriptors + List descriptors = + PersistenceXmlParser.locatePersistenceUnits(settings); + // Find all persistent units in the located descriptors Map units = - parser.doResolve(properties); + new HashMap(); + for (ParsedPersistenceXmlDescriptor descriptor : descriptors) + { + String unit = descriptor.getName(); + if (units.containsKey(unit)) + getLog().warn( + "Persistence unit " + unit + + " from " + descriptor.getPersistenceUnitRootUrl() + + " overwrites unit with the same name from " + + units.get(unit).getPersistenceUnitRootUrl() + ); + units.put(unit, descriptor); + } if (persistenceUnit == null) { @@ -1323,4 +1447,24 @@ public abstract class AbstractSchemaMojo extends AbstractMojo throw new MojoFailureException("Could not find persistence-unit " + persistenceUnit); } + + + public static void printStrackTrace(StringBuilder builder, Throwable t) + { + while (t != null) + { + builder.append("\n\tCause: "); + builder.append(t.getMessage() == null ? "" : t.getMessage().replaceAll("\\s+", " ")); + for (StackTraceElement trace : t.getStackTrace()) + { + builder.append("\n\t"); + builder.append(trace.getClassName()); + builder.append("."); + builder.append(trace.getMethodName()); + builder.append("():"); + builder.append(trace.getLineNumber()); + } + t = t.getCause(); + } + } }