X-Git-Url: https://juplo.de/gitweb/?p=website;a=blobdiff_plain;f=dist%2Fhibernate-maven-plugin-2.1.0%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate%2FAbstractSchemaMojo.html;fp=dist%2Fhibernate-maven-plugin-2.1.0%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate%2FAbstractSchemaMojo.html;h=8522d9a69900b9de3fcaffb2e67ad95f4f673913;hp=0000000000000000000000000000000000000000;hb=a53595184bd6e57bdc45292cc92c393c4e2dfe6e;hpb=c48c9ee0e9faa89a4c0a5323b367b9f5a6abe602 diff --git a/dist/hibernate-maven-plugin-2.1.0/xref/de/juplo/plugins/hibernate/AbstractSchemaMojo.html b/dist/hibernate-maven-plugin-2.1.0/xref/de/juplo/plugins/hibernate/AbstractSchemaMojo.html new file mode 100644 index 00000000..8522d9a6 --- /dev/null +++ b/dist/hibernate-maven-plugin-2.1.0/xref/de/juplo/plugins/hibernate/AbstractSchemaMojo.html @@ -0,0 +1,1433 @@ + + +
++1 package de.juplo.plugins.hibernate; +2 +3 +4 import com.pyx4j.log4j.MavenLogAppender; +5 import java.io.File; +6 import java.io.FileInputStream; +7 import java.io.FileOutputStream; +8 import java.io.IOException; +9 import java.io.InputStream; +10 import java.net.MalformedURLException; +11 import java.net.URL; +12 import java.security.NoSuchAlgorithmException; +13 import java.time.ZonedDateTime; +14 import java.util.Collections; +15 import java.util.EnumSet; +16 import java.util.HashMap; +17 import java.util.HashSet; +18 import java.util.Iterator; +19 import java.util.LinkedHashSet; +20 import java.util.List; +21 import java.util.Map; +22 import java.util.Map.Entry; +23 import java.util.Properties; +24 import java.util.Set; +25 import java.util.regex.Matcher; +26 import java.util.regex.Pattern; +27 import javax.persistence.Embeddable; +28 import javax.persistence.Entity; +29 import javax.persistence.MappedSuperclass; +30 import javax.persistence.spi.PersistenceUnitTransactionType; +31 import org.apache.maven.artifact.Artifact; +32 import org.apache.maven.model.Resource; +33 import org.apache.maven.plugin.AbstractMojo; +34 import org.apache.maven.plugin.MojoExecutionException; +35 import org.apache.maven.plugin.MojoFailureException; +36 import org.apache.maven.project.MavenProject; +37 import org.hibernate.boot.MetadataBuilder; +38 import org.hibernate.boot.MetadataSources; +39 import org.hibernate.boot.cfgxml.internal.ConfigLoader; +40 import org.hibernate.boot.cfgxml.spi.LoadedConfig; +41 import org.hibernate.boot.cfgxml.spi.MappingReference; +42 import org.hibernate.boot.model.naming.ImplicitNamingStrategy; +43 import org.hibernate.boot.model.naming.PhysicalNamingStrategy; +44 import org.hibernate.boot.registry.BootstrapServiceRegistry; +45 import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; +46 import org.hibernate.boot.registry.StandardServiceRegistry; +47 import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +48 import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +49 import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +50 import org.hibernate.boot.registry.selector.spi.StrategySelector; +51 import org.hibernate.boot.spi.MetadataImplementor; +52 import org.hibernate.cfg.AvailableSettings; +53 import static org.hibernate.cfg.AvailableSettings.DIALECT; +54 import static org.hibernate.cfg.AvailableSettings.DRIVER; +55 import static org.hibernate.cfg.AvailableSettings.FORMAT_SQL; +56 import static org.hibernate.cfg.AvailableSettings.HBM2DDL_DELIMITER; +57 import static org.hibernate.cfg.AvailableSettings.HBM2DLL_CREATE_NAMESPACES; +58 import static org.hibernate.cfg.AvailableSettings.IMPLICIT_NAMING_STRATEGY; +59 import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_DRIVER; +60 import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_PASSWORD; +61 import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_URL; +62 import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_USER; +63 import static org.hibernate.cfg.AvailableSettings.PASS; +64 import static org.hibernate.cfg.AvailableSettings.PHYSICAL_NAMING_STRATEGY; +65 import static org.hibernate.cfg.AvailableSettings.SHOW_SQL; +66 import static org.hibernate.cfg.AvailableSettings.USER; +67 import static org.hibernate.cfg.AvailableSettings.URL; +68 import org.hibernate.engine.config.spi.ConfigurationService; +69 import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +70 import org.hibernate.internal.util.config.ConfigurationException; +71 import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor; +72 import org.hibernate.jpa.boot.internal.PersistenceXmlParser; +73 import org.hibernate.tool.schema.TargetType; +74 import org.hibernate.tool.schema.internal.ExceptionHandlerCollectingImpl; +75 import org.hibernate.tool.schema.internal.exec.ScriptTargetOutputToFile; +76 import org.hibernate.tool.schema.spi.ExecutionOptions; +77 import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator; +78 import org.hibernate.tool.schema.spi.ScriptTargetOutput; +79 import org.hibernate.tool.schema.spi.TargetDescriptor; +80 import org.scannotation.AnnotationDB; +81 +82 +83 /** +84 * Baseclass with common attributes and methods. +85 * +86 * @phase process-classes +87 * @threadSafe +88 * @requiresDependencyResolution runtime +89 */ +90 public abstract class AbstractSchemaMojo extends AbstractMojo +91 { +92 public final static String EXECUTE = "hibernate.schema.execute"; +93 public final static String OUTPUTDIRECTORY = "project.build.outputDirectory"; +94 public final static String SCAN_CLASSES = "hibernate.schema.scan.classes"; +95 public final static String SCAN_DEPENDENCIES = "hibernate.schema.scan.dependencies"; +96 public final static String SCAN_TESTCLASSES = "hibernate.schema.scan.test_classes"; +97 public final static String TEST_OUTPUTDIRECTORY = "project.build.testOutputDirectory"; +98 public final static String SKIPPED = "hibernate.schema.skipped"; +99 public final static String SCRIPT = "hibernate.schema.script"; +100 +101 private final static Pattern SPLIT = Pattern.compile("[^,\\s]+"); +102 +103 private final Set<String> packages = new HashSet<String>(); +104 +105 +106 /** +107 * The maven project. +108 * <p> +109 * Only needed internally. +110 * +111 * @parameter property="project" +112 * @required +113 * @readonly +114 */ +115 private MavenProject project; +116 +117 /** +118 * Build-directory. +119 * <p> +120 * Only needed internally. +121 * +122 * @parameter property="project.build.directory" +123 * @required +124 * @readonly +125 */ +126 private String buildDirectory; +127 +128 +129 /** Parameters to configure the genaration of the SQL *********************/ +130 +131 /** +132 * Excecute the generated SQL. +133 * If set to <code>false</code>, only the SQL-script is created and the +134 * database is not touched. +135 * <p> +136 * <strong>Important:</strong> +137 * This configuration value can only be configured through the +138 * <code>pom.xml</code>, or by the definition of a system-property, because +139 * it is not known by Hibernate nor JPA and, hence, not picked up from +140 * their configuration! +141 * +142 * @parameter property="hibernate.schema.execute" default-value="true" +143 * @since 2.0 +144 */ +145 private Boolean execute; +146 +147 /** +148 * Skip execution +149 * <p> +150 * If set to <code>true</code>, the execution is skipped. +151 * <p> +152 * A skipped execution is signaled via the maven-property +153 * <code>${hibernate.schema.skipped}</code>. +154 * <p> +155 * The execution is skipped automatically, if no modified or newly added +156 * annotated classes are found and the dialect was not changed. +157 * <p> +158 * <strong>Important:</strong> +159 * This configuration value can only be configured through the +160 * <code>pom.xml</code>, or by the definition of a system-property, because +161 * it is not known by Hibernate nor JPA and, hence, not picked up from +162 * their configuration! +163 * +164 * @parameter property="hibernate.schema.skip" default-value="${maven.test.skip}" +165 * @since 1.0 +166 */ +167 private boolean skip; +168 +169 /** +170 * Force generation/execution +171 * <p> +172 * Force the generation and (if configured) the execution of the SQL, even if +173 * no modified or newly added annotated classes where found and the +174 * configuration was not changed. +175 * <p> +176 * <code>skip</code> takes precedence over <code>force</code>. +177 * <p> +178 * <strong>Important:</strong> +179 * This configuration value can only be configured through the +180 * <code>pom.xml</code>, or by the definition of a system-property, because +181 * it is not known by Hibernate nor JPA and, hence, not picked up from +182 * their configuration! +183 * +184 * @parameter property="hibernate.schema.force" default-value="false" +185 * @since 1.0 +186 */ +187 private boolean force; +188 +189 /** +190 * Hibernate dialect. +191 * +192 * @parameter property="hibernate.dialect" +193 * @since 1.0 +194 */ +195 private String dialect; +196 +197 /** +198 * Delimiter in output-file. +199 * <p> +200 * <strong>Important:</strong> +201 * This configuration value can only be configured through the +202 * <code>pom.xml</code>, or by the definition of a system-property, because +203 * it is not known by Hibernate nor JPA and, hence, not picked up from +204 * their configuration! +205 * +206 * @parameter property="hibernate.hbm2ddl.delimiter" default-value=";" +207 * @since 1.0 +208 */ +209 private String delimiter; +210 +211 /** +212 * Show the generated SQL in the command-line output. +213 * +214 * @parameter property="hibernate.show_sql" +215 * @since 1.0 +216 */ +217 private Boolean show; +218 +219 /** +220 * Format output-file. +221 * +222 * @parameter property="hibernate.format_sql" +223 * @since 1.0 +224 */ +225 private Boolean format; +226 +227 /** +228 * Specifies whether to automatically create also the database schema/catalog. +229 * +230 * @parameter property="hibernate.hbm2dll.create_namespaces" default-value="false" +231 * @since 2.0 +232 */ +233 private Boolean createNamespaces; +234 +235 /** +236 * Implicit naming strategy +237 * +238 * @parameter property="hibernate.implicit_naming_strategy" +239 * @since 2.0 +240 */ +241 private String implicitNamingStrategy; +242 +243 /** +244 * Physical naming strategy +245 * +246 * @parameter property="hibernate.physical_naming_strategy" +247 * @since 2.0 +248 */ +249 private String physicalNamingStrategy; +250 +251 /** +252 * Wether the project should be scanned for annotated-classes, or not +253 * <p> +254 * This parameter is intended to allow overwriting of the parameter +255 * <code>exclude-unlisted-classes</code> of a <code>persistence-unit</code>. +256 * If not specified, it defaults to <code>true</code> +257 * +258 * @parameter property="hibernate.schema.scan.classes" +259 * @since 2.0 +260 */ +261 private Boolean scanClasses; +262 +263 /** +264 * Classes-Directory to scan. +265 * <p> +266 * This parameter defaults to the maven build-output-directory for classes. +267 * Additionally, all dependencies are scanned for annotated classes. +268 * <p> +269 * <strong>Important:</strong> +270 * This configuration value can only be configured through the +271 * <code>pom.xml</code>, or by the definition of a system-property, because +272 * it is not known by Hibernate nor JPA and, hence, not picked up from +273 * their configuration! +274 * +275 * @parameter property="project.build.outputDirectory" +276 * @since 1.0 +277 */ +278 private String outputDirectory; +279 +280 /** +281 * Dependency-Scopes, that should be scanned for annotated classes. +282 * <p> +283 * By default, only dependencies in the scope <code>compile</code> are +284 * scanned for annotated classes. Multiple scopes can be seperated by +285 * white space or commas. +286 * <p> +287 * If you do not want any dependencies to be scanned for annotated +288 * classes, set this parameter to <code>none</code>. +289 * <p> +290 * The plugin does not scan for annotated classes in transitive +291 * dependencies. If some of your annotated classes are hidden in a +292 * transitive dependency, you can simply add that dependency explicitly. +293 * +294 * @parameter property="hibernate.schema.scan.dependencies" default-value="compile" +295 * @since 1.0.3 +296 */ +297 private String scanDependencies; +298 +299 /** +300 * Whether to scan the test-branch of the project for annotated classes, or +301 * not. +302 * <p> +303 * If this parameter is set to <code>true</code> the test-classes of the +304 * artifact will be scanned for hibernate-annotated classes additionally. +305 * <p> +306 * <strong>Important:</strong> +307 * This configuration value can only be configured through the +308 * <code>pom.xml</code>, or by the definition of a system-property, because +309 * it is not known by Hibernate nor JPA and, hence, not picked up from +310 * their configuration! +311 * +312 * @parameter property="hibernate.schema.scan.test_classes" default-value="false" +313 * @since 1.0.1 +314 */ +315 private Boolean scanTestClasses; +316 +317 /** +318 * Test-Classes-Directory to scan. +319 * <p> +320 * This parameter defaults to the maven build-output-directory for +321 * test-classes. +322 * <p> +323 * This parameter is only used, when <code>scanTestClasses</code> is set +324 * to <code>true</code>! +325 * <p> +326 * <strong>Important:</strong> +327 * This configuration value can only be configured through the +328 * <code>pom.xml</code>, or by the definition of a system-property, because +329 * it is not known by Hibernate nor JPA and, hence, not picked up from +330 * their configuration! +331 * +332 * @parameter property="project.build.testOutputDirectory" +333 * @since 1.0.2 +334 */ +335 private String testOutputDirectory; +336 +337 +338 /** Conection parameters *************************************************/ +339 +340 /** +341 * SQL-Driver name. +342 * +343 * @parameter property="hibernate.connection.driver_class" +344 * @since 1.0 +345 */ +346 private String driver; +347 +348 /** +349 * Database URL. +350 * +351 * @parameter property="hibernate.connection.url" +352 * @since 1.0 +353 */ +354 private String url; +355 +356 /** +357 * Database username +358 * +359 * @parameter property="hibernate.connection.username" +360 * @since 1.0 +361 */ +362 private String username; +363 +364 /** +365 * Database password +366 * +367 * @parameter property="hibernate.connection.password" +368 * @since 1.0 +369 */ +370 private String password; +371 +372 +373 /** Parameters to locate configuration sources ****************************/ +374 +375 /** +376 * Path to a file or name of a ressource with hibernate properties. +377 * If this parameter is specified, the plugin will try to load configuration +378 * values from a file with the given path or a ressource on the classpath with +379 * the given name. If both fails, the execution of the plugin will fail. +380 * <p> +381 * If this parameter is not set the plugin will load configuration values +382 * from a ressource named <code>hibernate.properties</code> on the classpath, +383 * if it is present, but will not fail if there is no such ressource. +384 * <p> +385 * During ressource-lookup, the test-classpath takes precedence. +386 * +387 * @parameter +388 * @since 1.0 +389 */ +390 private String hibernateProperties; +391 +392 /** +393 * Path to Hibernate configuration file (.cfg.xml). +394 * If this parameter is specified, the plugin will try to load configuration +395 * values from a file with the given path or a ressource on the classpath with +396 * the given name. If both fails, the execution of the plugin will fail. +397 * <p> +398 * If this parameter is not set the plugin will load configuration values +399 * from a ressource named <code>hibernate.cfg.xml</code> on the classpath, +400 * if it is present, but will not fail if there is no such ressource. +401 * <p> +402 * During ressource-lookup, the test-classpath takes precedence. +403 * <p> +404 * Settings in this file will overwrite settings in the properties file. +405 * +406 * @parameter +407 * @since 1.1.0 +408 */ +409 private String hibernateConfig; +410 +411 /** +412 * Name of the persistence-unit. +413 * If this parameter is specified, the plugin will try to load configuration +414 * values from a persistence-unit with the specified name. If no such +415 * persistence-unit can be found, the plugin will throw an exception. +416 * <p> +417 * If this parameter is not set and there is only one persistence-unit +418 * available, that unit will be used automatically. But if this parameter is +419 * not set and there are multiple persistence-units available on, +420 * the class-path, the execution of the plugin will fail. +421 * <p> +422 * Settings in this file will overwrite settings in the properties or the +423 * configuration file. +424 * +425 * @parameter +426 * @since 1.1.0 +427 */ +428 private String persistenceUnit; +429 +430 /** +431 * List of Hibernate-Mapping-Files (XML). +432 * Multiple files can be separated with white-spaces and/or commas. +433 * +434 * @parameter property="hibernate.mapping" +435 * @since 1.0.2 +436 */ +437 private String mappings; +438 +439 +440 +441 public final void execute(String filename) +442 throws +443 MojoFailureException, +444 MojoExecutionException +445 { +446 if (skip) +447 { +448 getLog().info("Execution of hibernate-maven-plugin was skipped!"); +449 project.getProperties().setProperty(SKIPPED, "true"); +450 return; +451 } +452 +453 ModificationTracker tracker; +454 try +455 { +456 tracker = new ModificationTracker(buildDirectory, filename, getLog()); +457 } +458 catch (NoSuchAlgorithmException e) +459 { +460 throw new MojoFailureException("Digest-Algorithm MD5 is missing!", e); +461 } +462 +463 final SimpleConnectionProvider connectionProvider = +464 new SimpleConnectionProvider(getLog()); +465 +466 try +467 { +468 /** Start extended logging */ +469 MavenLogAppender.startPluginLog(this); +470 +471 /** Load checksums for old mapping and configuration */ +472 tracker.load(); +473 +474 /** Create the ClassLoader */ +475 MutableClassLoader classLoader = createClassLoader(); +476 +477 /** Create a BootstrapServiceRegistry with the created ClassLoader */ +478 BootstrapServiceRegistry bootstrapServiceRegitry = +479 new BootstrapServiceRegistryBuilder() +480 .applyClassLoader(classLoader) +481 .build(); +482 ClassLoaderService classLoaderService = +483 bootstrapServiceRegitry.getService(ClassLoaderService.class); +484 +485 Properties properties = new Properties(); +486 ConfigLoader configLoader = new ConfigLoader(bootstrapServiceRegitry); +487 +488 /** Loading and merging configuration */ +489 properties.putAll(loadProperties(configLoader)); +490 LoadedConfig config = loadConfig(configLoader); +491 if (config != null) +492 properties.putAll(config.getConfigurationValues()); +493 ParsedPersistenceXmlDescriptor unit = +494 loadPersistenceUnit(classLoaderService, properties); +495 if (unit != null) +496 properties.putAll(unit.getProperties()); +497 +498 /** Overwriting/Completing configuration */ +499 configure(properties, tracker); +500 +501 /** Check configuration for modifications */ +502 if(tracker.track(properties)) +503 getLog().debug("Configuration has changed."); +504 else +505 getLog().debug("Configuration unchanged."); +506 +507 /** Check, that the outputfile is writable */ +508 final File output = getOutputFile(filename); +509 /** Check, if the outputfile is missing or was changed */ +510 checkOutputFile(output, tracker); +511 +512 /** Configure Hibernate */ +513 final StandardServiceRegistry serviceRegistry = +514 new StandardServiceRegistryBuilder(bootstrapServiceRegitry) +515 .applySettings(properties) +516 .addService(ConnectionProvider.class, connectionProvider) +517 .build(); +518 final MetadataSources sources = new MetadataSources(serviceRegistry); +519 +520 /** Add the remaining class-path-elements */ +521 completeClassPath(classLoader); +522 +523 /** Apply mappings from hibernate-configuration, if present */ +524 if (config != null) +525 { +526 for (MappingReference mapping : config.getMappingReferences()) +527 mapping.apply(sources); +528 } +529 +530 Set<String> classes; +531 if (unit == null) +532 { +533 /** No persistent unit: default behaviour */ +534 if (scanClasses == null) +535 scanClasses = true; +536 Set<URL> urls = new HashSet<URL>(); +537 if (scanClasses) +538 addRoot(urls, outputDirectory); +539 if (scanTestClasses) +540 addRoot(urls, testOutputDirectory); +541 addDependencies(urls); +542 classes = scanUrls(urls); +543 } +544 else +545 { +546 /** Follow configuration in persisten unit */ +547 if (scanClasses == null) +548 scanClasses = !unit.isExcludeUnlistedClasses(); +549 Set<URL> urls = new HashSet<URL>(); +550 if (scanClasses) +551 { +552 /** +553 * Scan the root of the persiten unit and configured jars for +554 * annotated classes +555 */ +556 urls.add(unit.getPersistenceUnitRootUrl()); +557 for (URL url : unit.getJarFileUrls()) +558 urls.add(url); +559 } +560 if (scanTestClasses) +561 addRoot(urls, testOutputDirectory); +562 classes = scanUrls(urls); +563 for (String className : unit.getManagedClassNames()) +564 classes.add(className); +565 /** +566 * Add mappings from the default mapping-file +567 * <code>META-INF/orm.xml</code>, if present +568 */ +569 boolean error = false; +570 InputStream is; +571 is = classLoader.getResourceAsStream("META-INF/orm.xml"); +572 if (is != null) +573 { +574 getLog().info("Adding default JPA-XML-mapping from META-INF/orm.xml"); +575 try +576 { +577 tracker.track("META-INF/orm.xml", is); +578 sources.addResource("META-INF/orm.xml"); +579 } +580 catch (IOException e) +581 { +582 getLog().error("cannot read META-INF/orm.xml: " + e); +583 error = true; +584 } +585 } +586 else +587 { +588 getLog().debug("no META-INF/orm.xml found"); +589 } +590 /** +591 * Add mappings from files, that are explicitly configured in the +592 * persistence unit +593 */ +594 for (String mapping : unit.getMappingFileNames()) +595 { +596 getLog().info("Adding explicitly configured mapping from " + mapping); +597 is = classLoader.getResourceAsStream(mapping); +598 if (is != null) +599 { +600 try +601 { +602 tracker.track(mapping, is); +603 sources.addResource(mapping); +604 } +605 catch (IOException e) +606 { +607 getLog().info("cannot read mapping-file " + mapping + ": " + e); +608 error = true; +609 } +610 } +611 else +612 { +613 getLog().error("cannot find mapping-file " + mapping); +614 error = true; +615 } +616 } +617 if (error) +618 throw new MojoFailureException( +619 "error, while reading mappings configured in persistence-unit \"" + +620 unit.getName() + +621 "\"" +622 ); +623 } +624 +625 /** Add the configured/collected annotated classes */ +626 for (String className : classes) +627 addAnnotated(className, sources, classLoaderService, tracker); +628 +629 /** Add explicitly configured classes */ +630 addMappings(sources, tracker); +631 +632 /** Skip execution, if mapping and configuration is unchanged */ +633 if (!tracker.modified()) +634 { +635 getLog().info("Mapping and configuration unchanged."); +636 if (force) +637 getLog().info("Generation/execution is forced!"); +638 else +639 { +640 getLog().info("Skipping schema generation!"); +641 project.getProperties().setProperty(SKIPPED, "true"); +642 return; +643 } +644 } +645 +646 +647 /** Truncate output file */ +648 try +649 { +650 new FileOutputStream(output).getChannel().truncate(0).close(); +651 } +652 catch (IOException e) +653 { +654 String error = +655 "Error while truncating " + output.getAbsolutePath() + ": " +656 + e.getMessage(); +657 getLog().warn(error); +658 throw new MojoExecutionException(error); +659 } +660 +661 /** Create a connection, if sufficient configuration infromation is available */ +662 connectionProvider.open(classLoaderService, properties); +663 +664 MetadataBuilder metadataBuilder = sources.getMetadataBuilder(); +665 +666 StrategySelector strategySelector = +667 serviceRegistry.getService(StrategySelector.class); +668 +669 if (properties.containsKey(IMPLICIT_NAMING_STRATEGY)) +670 { +671 metadataBuilder.applyImplicitNamingStrategy( +672 strategySelector.resolveStrategy( +673 ImplicitNamingStrategy.class, +674 properties.getProperty(IMPLICIT_NAMING_STRATEGY) +675 ) +676 ); +677 } +678 +679 if (properties.containsKey(PHYSICAL_NAMING_STRATEGY)) +680 { +681 metadataBuilder.applyPhysicalNamingStrategy( +682 strategySelector.resolveStrategy( +683 PhysicalNamingStrategy.class, +684 properties.getProperty(PHYSICAL_NAMING_STRATEGY) +685 ) +686 ); +687 } +688 +689 /** Prepare the generation of the SQL */ +690 Map settings = new HashMap(); +691 settings.putAll( +692 serviceRegistry +693 .getService(ConfigurationService.class) +694 .getSettings() +695 ); +696 ExceptionHandlerCollectingImpl handler = +697 new ExceptionHandlerCollectingImpl(); +698 ExecutionOptions options = +699 SchemaManagementToolCoordinator +700 .buildExecutionOptions(settings, handler); +701 final EnumSet<TargetType> targetTypes = EnumSet.of(TargetType.SCRIPT); +702 if (execute) +703 targetTypes.add(TargetType.DATABASE); +704 TargetDescriptor target = new TargetDescriptor() +705 { +706 @Override +707 public EnumSet<TargetType> getTargetTypes() +708 { +709 return targetTypes; +710 } +711 +712 @Override +713 public ScriptTargetOutput getScriptTargetOutput() +714 { +715 String charset = +716 (String) +717 serviceRegistry +718 .getService(ConfigurationService.class) +719 .getSettings() +720 .get(AvailableSettings.HBM2DDL_CHARSET_NAME); +721 return new ScriptTargetOutputToFile(output, charset); +722 } +723 }; +724 +725 /** +726 * Change class-loader of current thread. +727 * This is necessary, because still not all parts of Hibernate 5 use +728 * the newly introduced ClassLoaderService and will fail otherwise! +729 */ +730 Thread thread = Thread.currentThread(); +731 ClassLoader contextClassLoader = thread.getContextClassLoader(); +732 try +733 { +734 thread.setContextClassLoader(classLoader); +735 build((MetadataImplementor)metadataBuilder.build(), options, target); +736 if (handler.getExceptions().size() > 0) +737 { +738 StringBuilder builder = new StringBuilder(); +739 builder.append("Hibernate failed:"); +740 for (Exception e : handler.getExceptions()) +741 { +742 builder.append("\n * "); +743 builder.append(e.getMessage()); +744 AbstractSchemaMojo.printStrackTrace(builder, e); +745 builder.append("\n"); +746 } +747 String error = builder.toString(); +748 getLog().error(error); +749 throw new MojoFailureException(error); +750 } +751 } +752 finally +753 { +754 thread.setContextClassLoader(contextClassLoader); +755 /** Track, the content of the generated script */ +756 checkOutputFile(output, tracker); +757 } +758 } +759 catch (MojoExecutionException e) +760 { +761 tracker.failed(); +762 throw e; +763 } +764 catch (MojoFailureException e) +765 { +766 tracker.failed(); +767 throw e; +768 } +769 catch (RuntimeException e) +770 { +771 tracker.failed(); +772 throw e; +773 } +774 finally +775 { +776 /** Remember mappings and configuration */ +777 tracker.save(); +778 +779 /** Close the connection - if one was opened */ +780 connectionProvider.close(); +781 +782 /** Stop Log-Capturing */ +783 MavenLogAppender.endPluginLog(this); +784 } +785 } +786 +787 +788 abstract void build( +789 MetadataImplementor metadata, +790 ExecutionOptions options, +791 TargetDescriptor target +792 ) +793 throws +794 MojoFailureException, +795 MojoExecutionException; +796 +797 +798 private MutableClassLoader createClassLoader() throws MojoExecutionException +799 { +800 try +801 { +802 getLog().debug("Creating ClassLoader for project-dependencies..."); +803 LinkedHashSet<URL> urls = new LinkedHashSet<URL>(); +804 File file; +805 +806 file = new File(testOutputDirectory); +807 if (!file.exists()) +808 { +809 getLog().info("Creating test-output-directory: " + testOutputDirectory); +810 file.mkdirs(); +811 } +812 urls.add(file.toURI().toURL()); +813 +814 file = new File(outputDirectory); +815 if (!file.exists()) +816 { +817 getLog().info("Creating output-directory: " + outputDirectory); +818 file.mkdirs(); +819 } +820 urls.add(file.toURI().toURL()); +821 +822 return new MutableClassLoader(urls, getLog()); +823 } +824 catch (Exception e) +825 { +826 getLog().error("Error while creating ClassLoader!", e); +827 throw new MojoExecutionException(e.getMessage()); +828 } +829 } +830 +831 private void completeClassPath(MutableClassLoader classLoader) +832 throws +833 MojoExecutionException +834 { +835 try +836 { +837 getLog().debug("Completing class-paths of the ClassLoader for project-dependencies..."); +838 List<String> classpathFiles = project.getCompileClasspathElements(); +839 if (scanTestClasses) +840 classpathFiles.addAll(project.getTestClasspathElements()); +841 LinkedHashSet<URL> urls = new LinkedHashSet<URL>(); +842 for (String pathElement : classpathFiles) +843 { +844 getLog().debug("Dependency: " + pathElement); +845 urls.add(new File(pathElement).toURI().toURL()); +846 } +847 classLoader.add(urls); +848 } +849 catch (Exception e) +850 { +851 getLog().error("Error while creating ClassLoader!", e); +852 throw new MojoExecutionException(e.getMessage()); +853 } +854 } +855 +856 private Map loadProperties(ConfigLoader configLoader) +857 throws +858 MojoExecutionException +859 { +860 /** Try to read configuration from properties-file */ +861 if (hibernateProperties == null) +862 { +863 try +864 { +865 return configLoader.loadProperties("hibernate.properties"); +866 } +867 catch (ConfigurationException e) +868 { +869 getLog().debug(e.getMessage()); +870 return Collections.EMPTY_MAP; +871 } +872 } +873 else +874 { +875 try +876 { +877 File file = new File(hibernateProperties); +878 if (file.exists()) +879 { +880 getLog().info("Reading settings from file " + hibernateProperties + "..."); +881 return configLoader.loadProperties(file); +882 } +883 else +884 return configLoader.loadProperties(hibernateProperties); +885 } +886 catch (ConfigurationException e) +887 { +888 getLog().error("Error while reading properties!", e); +889 throw new MojoExecutionException(e.getMessage()); +890 } +891 } +892 } +893 +894 private LoadedConfig loadConfig(ConfigLoader configLoader) +895 throws MojoExecutionException +896 { +897 /** Try to read configuration from configuration-file */ +898 if (hibernateConfig == null) +899 { +900 try +901 { +902 return configLoader.loadConfigXmlResource("hibernate.cfg.xml"); +903 } +904 catch (ConfigurationException e) +905 { +906 getLog().debug(e.getMessage()); +907 return null; +908 } +909 } +910 else +911 { +912 try +913 { +914 File file = new File(hibernateConfig); +915 if (file.exists()) +916 { +917 getLog().info("Reading configuration from file " + hibernateConfig + "..."); +918 return configLoader.loadConfigXmlFile(file); +919 } +920 else +921 { +922 return configLoader.loadConfigXmlResource(hibernateConfig); +923 } +924 } +925 catch (ConfigurationException e) +926 { +927 getLog().error("Error while reading configuration!", e); +928 throw new MojoExecutionException(e.getMessage()); +929 } +930 } +931 } +932 +933 private void configure(Properties properties, ModificationTracker tracker) +934 throws MojoFailureException +935 { +936 /** +937 * Special treatment for the configuration-value "execute": if it is +938 * switched to "true", the genearation fo the schema should be forced! +939 */ +940 if (tracker.check(EXECUTE, execute.toString()) && execute) +941 { +942 getLog().info( +943 "hibernate.schema.execute was switched on: " + +944 "forcing generation/execution of SQL" +945 ); +946 tracker.touch(); +947 } +948 configure(properties, execute, EXECUTE); +949 +950 /** +951 * Configure the generation of the SQL. +952 * Overwrite values from properties-file if the configuration parameter is +953 * known to Hibernate. +954 */ +955 configure(properties, dialect, DIALECT); +956 configure(properties, delimiter, HBM2DDL_DELIMITER); +957 configure(properties, format, FORMAT_SQL); +958 configure(properties, createNamespaces, HBM2DLL_CREATE_NAMESPACES); +959 configure(properties, implicitNamingStrategy, IMPLICIT_NAMING_STRATEGY); +960 configure(properties, physicalNamingStrategy, PHYSICAL_NAMING_STRATEGY); +961 configure(properties, outputDirectory, OUTPUTDIRECTORY); +962 configure(properties, scanDependencies, SCAN_DEPENDENCIES); +963 configure(properties, scanTestClasses, SCAN_TESTCLASSES); +964 configure(properties, testOutputDirectory, TEST_OUTPUTDIRECTORY); +965 +966 /** +967 * Special treatment for the configuration-value "show": a change of its +968 * configured value should not lead to a regeneration of the database +969 * schama! +970 */ +971 if (show == null) +972 show = Boolean.valueOf(properties.getProperty(SHOW_SQL)); +973 else +974 properties.setProperty(SHOW_SQL, show.toString()); +975 +976 /** +977 * Configure the connection parameters. +978 * Overwrite values from properties-file. +979 */ +980 configure(properties, driver, DRIVER, JPA_JDBC_DRIVER); +981 configure(properties, url, URL, JPA_JDBC_URL); +982 configure(properties, username, USER, JPA_JDBC_USER); +983 configure(properties, password, PASS, JPA_JDBC_PASSWORD); +984 +985 if (properties.isEmpty()) +986 { +987 getLog().error("No properties set!"); +988 throw new MojoFailureException("Hibernate configuration is missing!"); +989 } +990 +991 getLog().info("Gathered configuration:"); +992 for (Entry<Object,Object> entry : properties.entrySet()) +993 getLog().info(" " + entry.getKey() + " = " + entry.getValue()); +994 } +995 +996 private void configure( +997 Properties properties, +998 String value, +999 String key, +1000 String alternativeKey +1001 ) +1002 { +1003 configure(properties, value, key); +1004 +1005 if (properties.containsKey(alternativeKey)) +1006 { +1007 if (properties.containsKey(key)) +1008 { +1009 getLog().warn( +1010 "Ignoring property " + alternativeKey + "=\"" + +1011 properties.getProperty(alternativeKey) + +1012 "\" in favour for property " + key + "=\"" + +1013 properties.getProperty(key) + "\"" +1014 ); +1015 properties.remove(alternativeKey); +1016 } +1017 else +1018 { +1019 value = properties.getProperty(alternativeKey); +1020 properties.remove(alternativeKey); +1021 getLog().info( +1022 "Using value \"" + value + "\" from property " + alternativeKey + +1023 " for property " + key +1024 ); +1025 properties.setProperty(key, value); +1026 } +1027 } +1028 } +1029 +1030 private void configure(Properties properties, String value, String key) +1031 { +1032 if (value != null) +1033 { +1034 if (properties.containsKey(key)) +1035 { +1036 if (!properties.getProperty(key).equals(value)) +1037 { +1038 getLog().info( +1039 "Overwriting property " + key + "=\"" + +1040 properties.getProperty(key) + +1041 "\" with value \"" + value + "\"" +1042 ); +1043 properties.setProperty(key, value); +1044 } +1045 } +1046 else +1047 { +1048 getLog().debug("Using value \"" + value + "\" for property " + key); +1049 properties.setProperty(key, value); +1050 } +1051 } +1052 } +1053 +1054 private void configure(Properties properties, Boolean value, String key) +1055 { +1056 configure(properties, value == null ? null : value.toString(), key); +1057 } +1058 +1059 private File getOutputFile(String filename) +1060 throws +1061 MojoExecutionException +1062 { +1063 File output = new File(filename); +1064 +1065 if (!output.isAbsolute()) +1066 { +1067 // Interpret relative file path relative to build directory +1068 output = new File(buildDirectory, filename); +1069 } +1070 getLog().debug("Output file: " + output.getPath()); +1071 +1072 // Ensure that directory path for specified file exists +1073 File outFileParentDir = output.getParentFile(); +1074 if (null != outFileParentDir && !outFileParentDir.exists()) +1075 { +1076 try +1077 { +1078 getLog().info( +1079 "Creating directory path for output file:" + +1080 outFileParentDir.getPath() +1081 ); +1082 outFileParentDir.mkdirs(); +1083 } +1084 catch (Exception e) +1085 { +1086 String error = +1087 "Error creating directory path for output file: " + e.getMessage(); +1088 getLog().error(error); +1089 throw new MojoExecutionException(error); +1090 } +1091 } +1092 +1093 try +1094 { +1095 output.createNewFile(); +1096 } +1097 catch (IOException e) +1098 { +1099 String error = "Error creating output file: " + e.getMessage(); +1100 getLog().error(error); +1101 throw new MojoExecutionException(error); +1102 } +1103 +1104 if (!output.canWrite()) +1105 { +1106 String error = +1107 "Output file " + output.getAbsolutePath() + " is not writable!"; +1108 getLog().error(error); +1109 throw new MojoExecutionException(error); +1110 } +1111 +1112 return output; +1113 } +1114 +1115 private void checkOutputFile(File output, ModificationTracker tracker) +1116 throws +1117 MojoExecutionException +1118 { +1119 try +1120 { +1121 if (output.exists()) +1122 tracker.track(SCRIPT, new FileInputStream(output)); +1123 else +1124 tracker.track(SCRIPT, ZonedDateTime.now().toString()); +1125 } +1126 catch (IOException e) +1127 { +1128 String error = +1129 "Error while checking the generated script: " + e.getMessage(); +1130 getLog().error(error); +1131 throw new MojoExecutionException(error); +1132 } +1133 } +1134 +1135 private void addMappings(MetadataSources sources, ModificationTracker tracker) +1136 throws MojoFailureException +1137 { +1138 getLog().debug("Adding explicitly configured mappings..."); +1139 if (mappings != null) +1140 { +1141 try +1142 { +1143 for (String filename : mappings.split("[\\s,]+")) +1144 { +1145 // First try the filename as absolute/relative path +1146 File file = new File(filename); +1147 if (!file.exists()) +1148 { +1149 // If the file was not found, search for it in the resource-directories +1150 for (Resource resource : project.getResources()) +1151 { +1152 file = new File(resource.getDirectory() + File.separator + filename); +1153 if (file.exists()) +1154 break; +1155 } +1156 } +1157 if (file.exists()) +1158 { +1159 if (file.isDirectory()) +1160 // TODO: add support to read all mappings under a directory +1161 throw new MojoFailureException(file.getAbsolutePath() + " is a directory"); +1162 if (tracker.track(filename, new FileInputStream(file))) +1163 getLog().debug("Found new or modified mapping-file: " + filename); +1164 else +1165 getLog().debug("Mapping-file unchanged: " + filename); +1166 +1167 sources.addFile(file); +1168 } +1169 else +1170 throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!"); +1171 } +1172 } +1173 catch (IOException e) +1174 { +1175 throw new MojoFailureException("Cannot calculate MD5 sums!", e); +1176 } +1177 } +1178 } +1179 +1180 private void addRoot(Set<URL> urls, String path) throws MojoFailureException +1181 { +1182 try +1183 { +1184 File dir = new File(path); +1185 if (dir.exists()) +1186 { +1187 getLog().info("Adding " + dir.getAbsolutePath() + " to the list of roots to scan..."); +1188 urls.add(dir.toURI().toURL()); +1189 } +1190 else +1191 getLog().warn( +1192 "the directory cannot be scanned for annotated classes, " + +1193 "because it does not exist: " + +1194 dir.getAbsolutePath() +1195 ); +1196 } +1197 catch (MalformedURLException e) +1198 { +1199 getLog().error("error while adding the project-root to the list of roots to scan!", e); +1200 throw new MojoFailureException(e.getMessage()); +1201 } +1202 } +1203 +1204 private void addDependencies(Set<URL> urls) throws MojoFailureException +1205 { +1206 try +1207 { +1208 if (scanDependencies != null) +1209 { +1210 Matcher matcher = SPLIT.matcher(scanDependencies); +1211 while (matcher.find()) +1212 { +1213 getLog().info("Adding dependencies from scope " + matcher.group() + " to the list of roots to scan"); +1214 for (Artifact artifact : project.getDependencyArtifacts()) +1215 { +1216 if (!artifact.getScope().equalsIgnoreCase(matcher.group())) +1217 continue; +1218 if (artifact.getFile() == null) +1219 { +1220 getLog().warn("Cannot add dependency " + artifact.getId() + ": no JAR-file available!"); +1221 continue; +1222 } +1223 getLog().info("Adding dependencies from scope " + artifact.getId() + " to the list of roots to scan"); +1224 urls.add(artifact.getFile().toURI().toURL()); +1225 } +1226 } +1227 } +1228 } +1229 catch (MalformedURLException e) +1230 { +1231 getLog().error("Error while adding dependencies to the list of roots to scan!", e); +1232 throw new MojoFailureException(e.getMessage()); +1233 } +1234 } +1235 +1236 private Set<String> scanUrls(Set<URL> scanRoots) +1237 throws +1238 MojoFailureException +1239 { +1240 try +1241 { +1242 AnnotationDB db = new AnnotationDB(); +1243 for (URL root : scanRoots) +1244 db.scanArchives(root); +1245 +1246 Set<String> classes = new HashSet<String>(); +1247 if (db.getAnnotationIndex().containsKey(Entity.class.getName())) +1248 classes.addAll(db.getAnnotationIndex().get(Entity.class.getName())); +1249 if (db.getAnnotationIndex().containsKey(MappedSuperclass.class.getName())) +1250 classes.addAll(db.getAnnotationIndex().get(MappedSuperclass.class.getName())); +1251 if (db.getAnnotationIndex().containsKey(Embeddable.class.getName())) +1252 classes.addAll(db.getAnnotationIndex().get(Embeddable.class.getName())); +1253 +1254 return classes; +1255 } +1256 catch (Exception e) +1257 { +1258 getLog().error("Error while scanning!", e); +1259 throw new MojoFailureException(e.getMessage()); +1260 } +1261 } +1262 +1263 private void addAnnotated( +1264 String name, +1265 MetadataSources sources, +1266 ClassLoaderService classLoaderService, +1267 ModificationTracker tracker +1268 ) +1269 throws +1270 MojoFailureException, +1271 MojoExecutionException +1272 { +1273 try +1274 { +1275 getLog().info("Adding annotated resource: " + name); +1276 String packageName = null; +1277 +1278 boolean error = false; +1279 try +1280 { +1281 Class<?> annotatedClass = classLoaderService.classForName(name); +1282 String resourceName = annotatedClass.getName(); +1283 resourceName = +1284 resourceName.substring( +1285 resourceName.lastIndexOf(".") + 1, +1286 resourceName.length() +1287 ) + ".class"; +1288 InputStream is = annotatedClass.getResourceAsStream(resourceName); +1289 if (is != null) +1290 { +1291 if (tracker.track(name, is)) +1292 getLog().debug("New or modified class: " + name); +1293 else +1294 getLog().debug("Unchanged class: " + name); +1295 sources.addAnnotatedClass(annotatedClass); +1296 packageName = annotatedClass.getPackage().getName(); +1297 } +1298 else +1299 { +1300 getLog().error("cannot find ressource " + resourceName + " for class " + name); +1301 error = true; +1302 } +1303 } +1304 catch(ClassLoadingException e) +1305 { +1306 packageName = name; +1307 } +1308 if (error) +1309 { +1310 throw new MojoExecutionException("error while inspecting annotated class " + name); +1311 } +1312 +1313 while (packageName != null) +1314 { +1315 if (packages.contains(packageName)) +1316 return; +1317 String resource = packageName.replace('.', '/') + "/package-info.class"; +1318 InputStream is = classLoaderService.locateResourceStream(resource); +1319 if (is == null) +1320 { +1321 // No compiled package-info available: no package-level annotations! +1322 getLog().debug("Package " + packageName + " is not annotated."); +1323 } +1324 else +1325 { +1326 if (tracker.track(packageName, is)) +1327 getLog().debug("New or modified package: " + packageName); +1328 else +1329 getLog().debug("Unchanged package: " + packageName); +1330 getLog().info("Adding annotations from package " + packageName); +1331 sources.addPackage(packageName); +1332 } +1333 packages.add(packageName); +1334 int i = packageName.lastIndexOf('.'); +1335 if (i < 0) +1336 packageName = null; +1337 else +1338 packageName = packageName.substring(0,i); +1339 } +1340 } +1341 catch (Exception e) +1342 { +1343 getLog().error("Error while adding the annotated class " + name, e); +1344 throw new MojoFailureException(e.getMessage()); +1345 } +1346 } +1347 +1348 private ParsedPersistenceXmlDescriptor loadPersistenceUnit( +1349 ClassLoaderService classLoaderService, +1350 Properties properties +1351 ) +1352 throws +1353 MojoFailureException +1354 { +1355 PersistenceXmlParser parser = +1356 new PersistenceXmlParser( +1357 classLoaderService, +1358 PersistenceUnitTransactionType.RESOURCE_LOCAL +1359 ); +1360 +1361 Map<String, ParsedPersistenceXmlDescriptor> units = +1362 parser.doResolve(properties); +1363 +1364 if (persistenceUnit == null) +1365 { +1366 Iterator<String> names = units.keySet().iterator(); +1367 if (!names.hasNext()) +1368 { +1369 getLog().info("Found no META-INF/persistence.xml."); +1370 return null; +1371 } +1372 +1373 String name = names.next(); +1374 if (!names.hasNext()) +1375 { +1376 getLog().info("Using persistence-unit " + name); +1377 return units.get(name); +1378 } +1379 +1380 StringBuilder builder = new StringBuilder(); +1381 builder.append("No name provided and multiple persistence units found: "); +1382 builder.append(name); +1383 while(names.hasNext()) +1384 { +1385 builder.append(", "); +1386 builder.append(names.next()); +1387 } +1388 builder.append('.'); +1389 throw new MojoFailureException(builder.toString()); +1390 } +1391 +1392 if (units.containsKey(persistenceUnit)) +1393 { +1394 getLog().info("Using configured persistence-unit " + persistenceUnit); +1395 return units.get(persistenceUnit); +1396 } +1397 +1398 throw new MojoFailureException("Could not find persistence-unit " + persistenceUnit); +1399 } +1400 +1401 +1402 public static void printStrackTrace(StringBuilder builder, Throwable t) +1403 { +1404 while (t != null) +1405 { +1406 builder.append("\n\tCause: "); +1407 builder.append(t.getMessage() == null ? "" : t.getMessage().replaceAll("\\s+", " ")); +1408 for (StackTraceElement trace : t.getStackTrace()) +1409 { +1410 builder.append("\n\t"); +1411 builder.append(trace.getClassName()); +1412 builder.append("."); +1413 builder.append(trace.getMethodName()); +1414 builder.append("():"); +1415 builder.append(trace.getLineNumber()); +1416 } +1417 t = t.getCause(); +1418 } +1419 } +1420 } ++