X-Git-Url: https://juplo.de/gitweb/?p=website;a=blobdiff_plain;f=dist%2Fhibernate4-maven-plugin-1.1.0%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate4%2FHbm2DdlMojo.html;fp=dist%2Fhibernate4-maven-plugin-1.1.0%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate4%2FHbm2DdlMojo.html;h=7f39b0f0b3e4e2aa9fcd28cbb8812cc6565d6a4f;hp=0000000000000000000000000000000000000000;hb=a53595184bd6e57bdc45292cc92c393c4e2dfe6e;hpb=c48c9ee0e9faa89a4c0a5323b367b9f5a6abe602 diff --git a/dist/hibernate4-maven-plugin-1.1.0/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html b/dist/hibernate4-maven-plugin-1.1.0/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html new file mode 100644 index 00000000..7f39b0f0 --- /dev/null +++ b/dist/hibernate4-maven-plugin-1.1.0/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html @@ -0,0 +1,1320 @@ + + +
++1 package de.juplo.plugins.hibernate4; +2 +3 /* +4 * Copyright 2001-2005 The Apache Software Foundation. +5 * +6 * Licensed under the Apache License, Version 2.0 (the "License"); +7 * you may not use this file except in compliance with the License. +8 * You may obtain a copy of the License at +9 * +10 * http://www.apache.org/licenses/LICENSE-2.0 +11 * +12 * Unless required by applicable law or agreed to in writing, software +13 * distributed under the License is distributed on an "AS IS" BASIS, +14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +15 * See the License for the specific language governing permissions and +16 * limitations under the License. +17 */ +18 +19 import com.pyx4j.log4j.MavenLogAppender; +20 import java.io.File; +21 import java.io.FileInputStream; +22 import java.io.FileNotFoundException; +23 import java.io.FileOutputStream; +24 import java.io.IOException; +25 import java.io.InputStream; +26 import java.io.ObjectInputStream; +27 import java.io.ObjectOutputStream; +28 import java.math.BigInteger; +29 import java.net.URL; +30 import java.net.URLClassLoader; +31 import java.security.MessageDigest; +32 import java.security.NoSuchAlgorithmException; +33 import java.sql.Driver; +34 import java.sql.DriverPropertyInfo; +35 import java.sql.SQLException; +36 import java.sql.SQLFeatureNotSupportedException; +37 import java.util.Collections; +38 import java.util.Comparator; +39 import java.util.HashMap; +40 import java.util.HashSet; +41 import java.util.LinkedHashSet; +42 import java.util.LinkedList; +43 import java.util.List; +44 import java.util.Map; +45 import java.util.Map.Entry; +46 import java.util.Properties; +47 import java.util.Set; +48 import java.util.TreeSet; +49 import java.util.logging.Logger; +50 import java.util.regex.Matcher; +51 import java.util.regex.Pattern; +52 import javax.persistence.Embeddable; +53 import javax.persistence.Entity; +54 import javax.persistence.MappedSuperclass; +55 import javax.persistence.spi.PersistenceUnitTransactionType; +56 import org.apache.maven.artifact.Artifact; +57 import org.apache.maven.model.Resource; +58 import org.apache.maven.plugin.AbstractMojo; +59 import org.apache.maven.plugin.MojoExecutionException; +60 import org.apache.maven.plugin.MojoFailureException; +61 import org.apache.maven.project.MavenProject; +62 import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +63 import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +64 import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +65 import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl; +66 import org.hibernate.cfg.Environment; +67 import org.hibernate.cfg.NamingStrategy; +68 import org.hibernate.envers.configuration.spi.AuditConfiguration; +69 import org.hibernate.internal.util.config.ConfigurationHelper; +70 import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor; +71 import org.hibernate.jpa.boot.internal.PersistenceXmlParser; +72 import org.hibernate.jpa.boot.spi.ProviderChecker; +73 import org.hibernate.tool.hbm2ddl.SchemaExport; +74 import org.hibernate.tool.hbm2ddl.SchemaExport.Type; +75 import org.hibernate.tool.hbm2ddl.Target; +76 import org.scannotation.AnnotationDB; +77 +78 +79 /** +80 * Goal which extracts the hibernate-mapping-configuration and +81 * exports an according SQL-database-schema. +82 * +83 * @goal export +84 * @phase process-classes +85 * @threadSafe +86 * @requiresDependencyResolution runtime +87 */ +88 public class Hbm2DdlMojo extends AbstractMojo +89 { +90 public final static String EXPORT_SKIPPED_PROPERTY = "hibernate.export.skipped"; +91 +92 public final static String DRIVER_CLASS = "hibernate.connection.driver_class"; +93 public final static String URL = "hibernate.connection.url"; +94 public final static String USERNAME = "hibernate.connection.username"; +95 public final static String PASSWORD = "hibernate.connection.password"; +96 public final static String DIALECT = "hibernate.dialect"; +97 public final static String NAMING_STRATEGY="hibernate.ejb.naming_strategy"; +98 public final static String ENVERS = "hibernate.export.envers"; +99 +100 public final static String JPA_DRIVER = "javax.persistence.jdbc.driver"; +101 public final static String JPA_URL = "javax.persistence.jdbc.url"; +102 public final static String JPA_USERNAME = "javax.persistence.jdbc.user"; +103 public final static String JPA_PASSWORD = "javax.persistence.jdbc.password"; +104 +105 public final static String MD5S = "hibernate4-generatedschema.md5s"; +106 +107 private final static Pattern split = Pattern.compile("[^,\\s]+"); +108 +109 +110 /** +111 * The maven project. +112 * <p> +113 * Only needed internally. +114 * +115 * @parameter property="project" +116 * @required +117 * @readonly +118 */ +119 private MavenProject project; +120 +121 /** +122 * Build-directory. +123 * <p> +124 * Only needed internally. +125 * +126 * @parameter property="project.build.directory" +127 * @required +128 * @readonly +129 */ +130 private String buildDirectory; +131 +132 /** +133 * Classes-Directory to scan. +134 * <p> +135 * This parameter defaults to the maven build-output-directory for classes. +136 * Additionally, all dependencies are scanned for annotated classes. +137 * +138 * @parameter property="project.build.outputDirectory" +139 * @since 1.0 +140 */ +141 private String outputDirectory; +142 +143 /** +144 * Whether to scan test-classes too, or not. +145 * <p> +146 * If this parameter is set to <code>true</code> the test-classes of the +147 * artifact will be scanned for hibernate-annotated classes additionally. +148 * +149 * @parameter property="hibernate.export.scan_testclasses" default-value="false" +150 * @since 1.0.1 +151 */ +152 private boolean scanTestClasses; +153 +154 /** +155 * Dependency-Scopes, that should be scanned for annotated classes. +156 * <p> +157 * By default, only dependencies in the scope <code>compile</code> are +158 * scanned for annotated classes. Multiple scopes can be seperated by +159 * white space or commas. +160 * <p> +161 * If you do not want any dependencies to be scanned for annotated +162 * classes, set this parameter to <code>none</code>. +163 * <p> +164 * The plugin does not scan for annotated classes in transitive +165 * dependencies. If some of your annotated classes are hidden in a +166 * transitive dependency, you can simply add that dependency explicitly. +167 * +168 * @parameter property="hibernate.export.scan_dependencies" default-value="compile" +169 * @since 1.0.3 +170 */ +171 private String scanDependencies; +172 +173 /** +174 * Test-Classes-Directory to scan. +175 * <p> +176 * This parameter defaults to the maven build-output-directory for +177 * test-classes. +178 * <p> +179 * This parameter is only used, when <code>scanTestClasses</code> is set +180 * to <code>true</code>! +181 * +182 * @parameter property="project.build.testOutputDirectory" +183 * @since 1.0.2 +184 */ +185 private String testOutputDirectory; +186 +187 /** +188 * Skip execution +189 * <p> +190 * If set to <code>true</code>, the execution is skipped. +191 * <p> +192 * A skipped execution is signaled via the maven-property +193 * <code>${hibernate.export.skipped}</code>. +194 * <p> +195 * The execution is skipped automatically, if no modified or newly added +196 * annotated classes are found and the dialect was not changed. +197 * +198 * @parameter property="hibernate.skip" default-value="${maven.test.skip}" +199 * @since 1.0 +200 */ +201 private boolean skip; +202 +203 /** +204 * Force execution +205 * <p> +206 * Force execution, even if no modified or newly added annotated classes +207 * where found and the dialect was not changed. +208 * <p> +209 * <code>skip</code> takes precedence over <code>force</code>. +210 * +211 * @parameter property="hibernate.export.force" default-value="false" +212 * @since 1.0 +213 */ +214 private boolean force; +215 +216 /** +217 * SQL-Driver name. +218 * +219 * @parameter property="hibernate.connection.driver_class" +220 * @since 1.0 +221 */ +222 private String driverClassName; +223 +224 /** +225 * Database URL. +226 * +227 * @parameter property="hibernate.connection.url" +228 * @since 1.0 +229 */ +230 private String url; +231 +232 /** +233 * Database username +234 * +235 * @parameter property="hibernate.connection.username" +236 * @since 1.0 +237 */ +238 private String username; +239 +240 /** +241 * Database password +242 * +243 * @parameter property="hibernate.connection.password" +244 * @since 1.0 +245 */ +246 private String password; +247 +248 /** +249 * Hibernate dialect. +250 * +251 * @parameter property="hibernate.dialect" +252 * @since 1.0 +253 */ +254 private String hibernateDialect; +255 +256 /** +257 * Hibernate Naming Strategy +258 * +259 * @parameter property="hibernate.ejb.naming_strategy" +260 * @since 1.0.2 +261 */ +262 private String hibernateNamingStrategy; +263 +264 /** +265 * Path to Hibernate properties file. +266 * If this parameter is not set the plugin will try to load the configuration +267 * from a file <code>hibernate.properties</code> on the classpath. The +268 * test-classpath takes precedence. +269 * +270 * @parameter +271 * @since 1.0 +272 */ +273 private String hibernateProperties; +274 +275 /** +276 * Path to Hibernate configuration file (.cfg.xml). +277 * Settings in this file will overwrite settings in the properties file. +278 * If this parameter is not set the plugin will try to load the configuration +279 * from a file <code>hibernate.cfg.xml</code> on the classpath. The +280 * test-classpath takes precedence. +281 * +282 * @parameter +283 * @since 1.1.0 +284 */ +285 private String hibernateConfig; +286 +287 /** +288 * Name of the persistence-unit. +289 * If there is only one persistence-unit available, that unit will be used +290 * automatically. +291 * Settings in this file will overwrite settings in the properties or the +292 * configuration file. +293 * +294 * @parameter +295 * @since 1.1.0 +296 */ +297 private String persistenceUnit; +298 +299 /** +300 * List of Hibernate-Mapping-Files (XML). +301 * Multiple files can be separated with white-spaces and/or commas. +302 * +303 * @parameter property="hibernate.mapping" +304 * @since 1.0.2 +305 */ +306 private String hibernateMapping; +307 +308 /** +309 * Target of execution: +310 * <ul> +311 * <li><strong>NONE</strong> only export schema to SQL-script (forces execution, signals skip)</li> +312 * <li><strong>EXPORT</strong> create database (<strong>DEFAULT!</strong>). forces execution, signals skip)</li> +313 * <li><strong>SCRIPT</strong> export schema to SQL-script and print it to STDOUT</li> +314 * <li><strong>BOTH</strong></li> +315 * </ul> +316 * +317 * A database connection is only needed for EXPORT and BOTH, but a +318 * Hibernate-Dialect must always be chosen. +319 * +320 * @parameter property="hibernate.export.target" default-value="EXPORT" +321 * @since 1.0 +322 */ +323 private String target; +324 +325 /** +326 * Type of execution. +327 * <ul> +328 * <li><strong>NONE</strong> do nothing - just validate the configuration</li> +329 * <li><strong>CREATE</strong> create database-schema</li> +330 * <li><strong>DROP</strong> drop database-schema</li> +331 * <li><strong>BOTH</strong> (<strong>DEFAULT!</strong>)</li> +332 * </ul> +333 * +334 * If NONE is choosen, no databaseconnection is needed. +335 * +336 * @parameter property="hibernate.export.type" default-value="BOTH" +337 * @since 1.0 +338 */ +339 private String type; +340 +341 /** +342 * Output file. +343 * +344 * @parameter property="hibernate.export.schema.filename" default-value="${project.build.directory}/schema.sql" +345 * @since 1.0 +346 */ +347 private String outputFile; +348 +349 /** +350 * Delimiter in output-file. +351 * +352 * @parameter property="hibernate.export.schema.delimiter" default-value=";" +353 * @since 1.0 +354 */ +355 private String delimiter; +356 +357 /** +358 * Format output-file. +359 * +360 * @parameter property="hibernate.export.schema.format" default-value="true" +361 * @since 1.0 +362 */ +363 private boolean format; +364 +365 /** +366 * Generate envers schema for auditing tables. +367 * +368 * @parameter property="hibernate.export.envers" default-value="true" +369 * @since 1.0.3 +370 */ +371 private boolean envers; +372 +373 +374 @Override +375 public void execute() +376 throws +377 MojoFailureException, +378 MojoExecutionException +379 { +380 if (skip) +381 { +382 getLog().info("Execution of hibernate4-maven-plugin:export was skipped!"); +383 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true"); +384 return; +385 } +386 +387 Map<String,String> md5s; +388 boolean modified = false; +389 File saved = new File(buildDirectory + File.separator + MD5S); +390 +391 if (saved.isFile() && saved.length() > 0) +392 { +393 try +394 { +395 FileInputStream fis = new FileInputStream(saved); +396 ObjectInputStream ois = new ObjectInputStream(fis); +397 md5s = (HashMap<String,String>)ois.readObject(); +398 ois.close(); +399 } +400 catch (Exception e) +401 { +402 md5s = new HashMap<String,String>(); +403 getLog().warn("Cannot read timestamps from saved: " + e); +404 } +405 } +406 else +407 { +408 md5s = new HashMap<String,String>(); +409 try +410 { +411 saved.createNewFile(); +412 } +413 catch (IOException e) +414 { +415 getLog().debug("Cannot create file \"" + saved.getPath() + "\" for timestamps: " + e); +416 } +417 } +418 +419 URLClassLoader classLoader = null; +420 try +421 { +422 getLog().debug("Creating ClassLoader for project-dependencies..."); +423 List<String> classpathFiles = project.getCompileClasspathElements(); +424 if (scanTestClasses) +425 classpathFiles.addAll(project.getTestClasspathElements()); +426 List<URL> urls = new LinkedList<URL>(); +427 File file; +428 file = new File(testOutputDirectory); +429 if (!file.exists()) +430 { +431 getLog().info("creating test-output-directory: " + testOutputDirectory); +432 file.mkdirs(); +433 } +434 urls.add(file.toURI().toURL()); +435 file = new File(outputDirectory); +436 if (!file.exists()) +437 { +438 getLog().info("creating output-directory: " + outputDirectory); +439 file.mkdirs(); +440 } +441 urls.add(file.toURI().toURL()); +442 for (String pathElement : classpathFiles) +443 { +444 getLog().debug("Dependency: " + pathElement); +445 urls.add(new File(pathElement).toURI().toURL()); +446 } +447 classLoader = +448 new URLClassLoader( +449 urls.toArray(new URL[urls.size()]), +450 getClass().getClassLoader() +451 ); +452 } +453 catch (Exception e) +454 { +455 getLog().error("Error while creating ClassLoader!", e); +456 throw new MojoExecutionException(e.getMessage()); +457 } +458 +459 Set<Class<?>> classes = +460 new TreeSet<Class<?>>( +461 new Comparator<Class<?>>() { +462 @Override +463 public int compare(Class<?> a, Class<?> b) +464 { +465 return a.getName().compareTo(b.getName()); +466 } +467 } +468 ); +469 +470 try +471 { +472 AnnotationDB db = new AnnotationDB(); +473 File dir = new File(outputDirectory); +474 if (dir.exists()) +475 { +476 getLog().info("Scanning directory " + outputDirectory + " for annotated classes..."); +477 URL dirUrl = dir.toURI().toURL(); +478 db.scanArchives(dirUrl); +479 } +480 if (scanTestClasses) +481 { +482 dir = new File(testOutputDirectory); +483 if (dir.exists()) +484 { +485 getLog().info("Scanning directory " + testOutputDirectory + " for annotated classes..."); +486 URL dirUrl = dir.toURI().toURL(); +487 db.scanArchives(dirUrl); +488 } +489 } +490 if (scanDependencies != null) +491 { +492 Matcher matcher = split.matcher(scanDependencies); +493 while (matcher.find()) +494 { +495 getLog().info("Scanning dependencies for scope " + matcher.group()); +496 for (Artifact artifact : project.getDependencyArtifacts()) +497 { +498 if (!artifact.getScope().equalsIgnoreCase(matcher.group())) +499 continue; +500 if (artifact.getFile() == null) +501 { +502 getLog().warn( +503 "Cannot scan dependency " + +504 artifact.getId() + +505 ": no JAR-file available!" +506 ); +507 continue; +508 } +509 getLog().info( +510 "Scanning dependency " + +511 artifact.getId() + +512 " for annotated classes..." +513 ); +514 db.scanArchives(artifact.getFile().toURI().toURL()); +515 } +516 } +517 } +518 +519 Set<String> classNames = new HashSet<String>(); +520 if (db.getAnnotationIndex().containsKey(Entity.class.getName())) +521 classNames.addAll(db.getAnnotationIndex().get(Entity.class.getName())); +522 if (db.getAnnotationIndex().containsKey(MappedSuperclass.class.getName())) +523 classNames.addAll(db.getAnnotationIndex().get(MappedSuperclass.class.getName())); +524 if (db.getAnnotationIndex().containsKey(Embeddable.class.getName())) +525 classNames.addAll(db.getAnnotationIndex().get(Embeddable.class.getName())); +526 +527 MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); +528 for (String name : classNames) +529 { +530 Class<?> annotatedClass = classLoader.loadClass(name); +531 classes.add(annotatedClass); +532 String resourceName = annotatedClass.getName(); +533 resourceName = resourceName.substring(resourceName.lastIndexOf(".") + 1, resourceName.length()) + ".class"; +534 InputStream is = +535 annotatedClass +536 .getResourceAsStream(resourceName); +537 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks +538 int i; +539 while((i = is.read(buffer)) > -1) +540 digest.update(buffer, 0, i); +541 is.close(); +542 byte[] bytes = digest.digest(); +543 BigInteger bi = new BigInteger(1, bytes); +544 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi); +545 String oldMd5 = !md5s.containsKey(name) ? "" : md5s.get(name); +546 if (!newMd5.equals(oldMd5)) +547 { +548 getLog().debug("Found new or modified annotated class: " + name); +549 modified = true; +550 md5s.put(name, newMd5); +551 } +552 else +553 { +554 getLog().debug(oldMd5 + " -> class unchanged: " + name); +555 } +556 } +557 } +558 catch (ClassNotFoundException e) +559 { +560 getLog().error("Error while adding annotated classes!", e); +561 throw new MojoExecutionException(e.getMessage()); +562 } +563 catch (Exception e) +564 { +565 getLog().error("Error while scanning!", e); +566 throw new MojoFailureException(e.getMessage()); +567 } +568 +569 +570 ValidationConfiguration config = new ValidationConfiguration(); +571 // Clear unused system-properties +572 config.setProperties(new Properties()); +573 +574 +575 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); +576 StandardServiceRegistryImpl registry = null; +577 MavenLogAppender.startPluginLog(this); +578 +579 try +580 { +581 /** +582 * Change class-loader of current thread, so that hibernate can +583 * see all dependencies! +584 */ +585 Thread.currentThread().setContextClassLoader(classLoader); +586 +587 +588 /** Try to read configuration from properties-file */ +589 try +590 { +591 if (hibernateProperties == null) +592 { +593 URL url = classLoader.findResource("hibernate.properties"); +594 if (url == null) +595 { +596 getLog().info("No hibernate.properties on the classpath!"); +597 } +598 else +599 { +600 getLog().info("Reading settings from hibernate.properties on the classpath."); +601 Properties properties = new Properties(); +602 properties.load(url.openStream()); +603 config.setProperties(properties); +604 } +605 } +606 else +607 { +608 File file = new File(hibernateProperties); +609 if (file.exists()) +610 { +611 getLog().info("Reading settings from file " + hibernateProperties + "..."); +612 Properties properties = new Properties(); +613 properties.load(new FileInputStream(file)); +614 config.setProperties(properties); +615 } +616 else +617 getLog().info("No hibernate-properties-file found! (Checked path: " + hibernateProperties + ")"); +618 } +619 } +620 catch (IOException e) +621 { +622 getLog().error("Error while reading properties!", e); +623 throw new MojoExecutionException(e.getMessage()); +624 } +625 +626 /** Try to read configuration from configuration-file */ +627 try +628 { +629 if (hibernateConfig == null) +630 { +631 URL url = classLoader.findResource("hibernate.cfg.xml"); +632 if (url == null) +633 { +634 getLog().info("No hibernate.cfg.xml on the classpath!"); +635 } +636 else +637 { +638 getLog().info("Reading settings from hibernate.cfg.xml on the classpath."); +639 config.configure(url); +640 } +641 } +642 else +643 { +644 File file = new File(hibernateConfig); +645 if (file.exists()) +646 { +647 getLog().info("Reading configuration from file " + hibernateConfig + "..."); +648 config.configure(file); +649 } +650 else +651 getLog().info("No hibernate-configuration-file found! (Checked path: " + hibernateConfig + ")"); +652 } +653 } +654 catch (Exception e) +655 { +656 getLog().error("Error while reading configuration!", e); +657 throw new MojoExecutionException(e.getMessage()); +658 } +659 +660 ParsedPersistenceXmlDescriptor persistenceUnitDescriptor = +661 getPersistenceUnitDescriptor( +662 persistenceUnit, +663 config.getProperties(), +664 new MavenProjectClassLoaderService(classLoader) +665 ); +666 if (persistenceUnitDescriptor != null) +667 config.setProperties(persistenceUnitDescriptor.getProperties()); +668 +669 +670 /** Overwrite values from properties-file or set, if given */ +671 +672 if (driverClassName != null) +673 { +674 if (config.getProperties().containsKey(DRIVER_CLASS)) +675 getLog().debug( +676 "Overwriting property " + +677 DRIVER_CLASS + "=" + config.getProperty(DRIVER_CLASS) + +678 " with the value " + driverClassName +679 ); +680 else +681 getLog().debug("Using the value " + driverClassName); +682 config.setProperty(DRIVER_CLASS, driverClassName); +683 } +684 if (config.getProperty(DRIVER_CLASS) == null) +685 { +686 String driver = config.getProperty(JPA_DRIVER); +687 if (driver != null) +688 { +689 getLog().info( +690 DRIVER_CLASS + +691 " is not set. Borrow setting from " + +692 JPA_DRIVER + +693 ": " + +694 driver); +695 config.setProperty(DRIVER_CLASS, driver); +696 } +697 } +698 +699 if (url != null) +700 { +701 if (config.getProperties().containsKey(URL)) +702 getLog().debug( +703 "Overwriting property " + +704 URL + "=" + config.getProperty(URL) + +705 " with the value " + url +706 ); +707 else +708 getLog().debug("Using the value " + url); +709 config.setProperty(URL, url); +710 } +711 if (config.getProperty(URL) == null) +712 { +713 String url = config.getProperty(JPA_URL); +714 if (url != null) +715 { +716 getLog().info( +717 URL + +718 " is not set. Borrow setting from " + +719 JPA_URL + +720 ": " + +721 url); +722 config.setProperty(URL, url); +723 } +724 } +725 +726 if (username != null) +727 { +728 if (config.getProperties().containsKey(USERNAME)) +729 getLog().debug( +730 "Overwriting property " + +731 USERNAME + "=" + config.getProperty(USERNAME) + +732 " with the value " + username +733 ); +734 else +735 getLog().debug("Using the value " + username); +736 config.setProperty(USERNAME, username); +737 } +738 if (config.getProperty(USERNAME) == null) +739 { +740 String username = config.getProperty(JPA_USERNAME); +741 if (username != null) +742 { +743 getLog().info( +744 USERNAME + +745 " is not set. Borrow setting from " + +746 JPA_USERNAME + +747 ": " + +748 username); +749 config.setProperty(USERNAME, username); +750 } +751 } +752 +753 if (password != null) +754 { +755 if (config.getProperties().containsKey(PASSWORD)) +756 getLog().debug( +757 "Overwriting property " + +758 PASSWORD + "=" + config.getProperty(PASSWORD) + +759 " with value " + password +760 ); +761 else +762 getLog().debug("Using value " + password + " for property " + PASSWORD); +763 config.setProperty(PASSWORD, password); +764 } +765 if (config.getProperty(PASSWORD) == null) +766 { +767 String password = config.getProperty(JPA_PASSWORD); +768 if (password != null) +769 { +770 getLog().info( +771 PASSWORD + +772 " is not set. Borrow setting from " + +773 JPA_PASSWORD + +774 ": " + +775 password); +776 config.setProperty(PASSWORD, password); +777 } +778 } +779 +780 if (hibernateDialect != null) +781 { +782 if (config.getProperties().containsKey(DIALECT)) +783 getLog().debug( +784 "Overwriting property " + +785 DIALECT + "=" + config.getProperty(DIALECT) + +786 " with value " + hibernateDialect +787 ); +788 else +789 getLog().debug( +790 "Using value " + hibernateDialect + " for property " + DIALECT +791 ); +792 config.setProperty(DIALECT, hibernateDialect); +793 } +794 +795 if ( hibernateNamingStrategy != null ) +796 { +797 if ( config.getProperties().contains(NAMING_STRATEGY)) +798 getLog().debug( +799 "Overwriting property " + +800 NAMING_STRATEGY + "=" + config.getProperty(NAMING_STRATEGY) + +801 " with value " + hibernateNamingStrategy +802 ); +803 else +804 getLog().debug( +805 "Using value " + hibernateNamingStrategy + " for property " + +806 NAMING_STRATEGY +807 ); +808 config.setProperty(NAMING_STRATEGY, hibernateNamingStrategy); +809 } +810 +811 /** The generated SQL varies with the dialect! */ +812 if (md5s.containsKey(DIALECT)) +813 { +814 String dialect = config.getProperty(DIALECT); +815 if (md5s.get(DIALECT).equals(dialect)) +816 getLog().debug("SQL-dialect unchanged."); +817 else +818 { +819 modified = true; +820 if (dialect == null) +821 { +822 getLog().debug("SQL-dialect was unset."); +823 md5s.remove(DIALECT); +824 } +825 else +826 { +827 getLog().debug("SQL-dialect changed: " + dialect); +828 md5s.put(DIALECT, dialect); +829 } +830 } +831 } +832 else +833 { +834 String dialect = config.getProperty(DIALECT); +835 if (dialect != null) +836 { +837 modified = true; +838 md5s.put(DIALECT, config.getProperty(DIALECT)); +839 } +840 } +841 +842 /** The generated SQL varies with the envers-configuration */ +843 if (md5s.get(ENVERS) != null) +844 { +845 if (md5s.get(ENVERS).equals(Boolean.toString(envers))) +846 getLog().debug("Envers-Configuration unchanged. Enabled: " + envers); +847 else +848 { +849 getLog().debug("Envers-Configuration changed. Enabled: " + envers); +850 modified = true; +851 md5s.put(ENVERS, Boolean.toString(envers)); +852 } +853 } +854 else +855 { +856 modified = true; +857 md5s.put(ENVERS, Boolean.toString(envers)); +858 } +859 +860 if (config.getProperties().isEmpty()) +861 { +862 getLog().error("No properties set!"); +863 throw new MojoFailureException("Hibernate configuration is missing!"); +864 } +865 +866 getLog().info("Gathered hibernate-configuration (turn on debugging for details):"); +867 for (Entry<Object,Object> entry : config.getProperties().entrySet()) +868 getLog().info(" " + entry.getKey() + " = " + entry.getValue()); +869 +870 +871 getLog().debug("Adding explicitly configured mappings..."); +872 if (hibernateMapping != null) +873 { +874 try +875 { +876 MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); +877 for (String filename : hibernateMapping.split("[\\s,]+")) +878 { +879 // First try the filename as absolute/relative path +880 File file = new File(filename); +881 if (!file.exists()) +882 { +883 // If the file was not found, search for it in the resource-directories +884 for (Resource resource : project.getResources()) +885 { +886 file = new File(resource.getDirectory() + File.separator + filename); +887 if (file.exists()) +888 break; +889 } +890 } +891 if (file != null && file.exists()) +892 { +893 InputStream is = new FileInputStream(file); +894 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks +895 int i; +896 while((i = is.read(buffer)) > -1) +897 digest.update(buffer, 0, i); +898 is.close(); +899 byte[] bytes = digest.digest(); +900 BigInteger bi = new BigInteger(1, bytes); +901 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi); +902 String oldMd5 = !md5s.containsKey(filename) ? "" : md5s.get(filename); +903 if (!newMd5.equals(oldMd5)) +904 { +905 getLog().debug("Found new or modified mapping-file: " + filename); +906 modified = true; +907 md5s.put(filename, newMd5); +908 } +909 else +910 { +911 getLog().debug(oldMd5 + " -> mapping-file unchanged: " + filename); +912 } +913 getLog().debug("Adding mappings from XML-configurationfile: " + file); +914 config.addFile(file); +915 } +916 else +917 throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!"); +918 } +919 } +920 catch (NoSuchAlgorithmException e) +921 { +922 throw new MojoFailureException("Cannot calculate MD5 sums!", e); +923 } +924 catch (FileNotFoundException e) +925 { +926 throw new MojoFailureException("Cannot calculate MD5 sums!", e); +927 } +928 catch (IOException e) +929 { +930 throw new MojoFailureException("Cannot calculate MD5 sums!", e); +931 } +932 } +933 +934 getLog().debug("Adding annotated classes to hibernate-mapping-configuration..."); +935 // build annotated packages +936 Set<String> packages = new HashSet<String>(); +937 for (Class<?> annotatedClass : classes) +938 { +939 String packageName = annotatedClass.getPackage().getName(); +940 if (!packages.contains(packageName)) +941 { +942 getLog().debug("Add package " + packageName); +943 packages.add(packageName); +944 config.addPackage(packageName); +945 getLog().debug("type definintions" + config.getTypeDefs()); +946 } +947 getLog().debug("Class " + annotatedClass); +948 config.addAnnotatedClass(annotatedClass); +949 } +950 +951 Target target = null; +952 try +953 { +954 target = Target.valueOf(this.target.toUpperCase()); +955 } +956 catch (IllegalArgumentException e) +957 { +958 getLog().error("Invalid value for configuration-option \"target\": " + this.target); +959 getLog().error("Valid values are: NONE, SCRIPT, EXPORT, BOTH"); +960 throw new MojoExecutionException("Invalid value for configuration-option \"target\""); +961 } +962 Type type = null; +963 try +964 { +965 type = Type.valueOf(this.type.toUpperCase()); +966 } +967 catch (IllegalArgumentException e) +968 { +969 getLog().error("Invalid value for configuration-option \"type\": " + this.type); +970 getLog().error("Valid values are: NONE, CREATE, DROP, BOTH"); +971 throw new MojoExecutionException("Invalid value for configuration-option \"type\""); +972 } +973 +974 +975 if (config.getProperty(DIALECT) == null) +976 throw new MojoFailureException("hibernate-dialect must be set!"); +977 +978 +979 if (target.equals(Target.SCRIPT) || target.equals(Target.NONE)) +980 { +981 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true"); +982 } +983 if ( +984 !modified +985 && !target.equals(Target.SCRIPT) +986 && !target.equals(Target.NONE) +987 && !force +988 ) +989 { +990 getLog().info("No modified annotated classes or mapping-files found and dialect unchanged."); +991 getLog().info("Skipping schema generation!"); +992 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true"); +993 return; +994 } +995 +996 +997 if ( config.getProperties().containsKey(NAMING_STRATEGY)) +998 { +999 String namingStrategy = config.getProperty(NAMING_STRATEGY); +1000 getLog().debug("Explicitly set NamingStrategy: " + namingStrategy); +1001 try +1002 { +1003 @SuppressWarnings("unchecked") +1004 Class<NamingStrategy> namingStrategyClass = (Class<NamingStrategy>) Class.forName(namingStrategy); +1005 config.setNamingStrategy(namingStrategyClass.newInstance()); +1006 } +1007 catch (Exception e) +1008 { +1009 getLog().error("Error setting NamingStrategy", e); +1010 throw new MojoExecutionException(e.getMessage()); +1011 } +1012 } +1013 +1014 +1015 Environment.verifyProperties(config.getProperties()); +1016 ConfigurationHelper.resolvePlaceHolders(config.getProperties()); +1017 registry = +1018 (StandardServiceRegistryImpl) +1019 new StandardServiceRegistryBuilder() +1020 .applySettings(config.getProperties()) +1021 .build(); +1022 +1023 config.buildMappings(); +1024 +1025 if (envers) +1026 { +1027 getLog().info("Automatic auditing via hibernate-envers enabled!"); +1028 AuditConfiguration.getFor(config); +1029 } +1030 +1031 SchemaExport export = new SchemaExport(registry, config); +1032 export.setDelimiter(delimiter); +1033 export.setFormat(format); +1034 +1035 File outF = new File(outputFile); +1036 +1037 if (!outF.isAbsolute()) +1038 { +1039 // Interpret relative file path relative to build directory +1040 outF = new File(buildDirectory, outputFile); +1041 getLog().info("Adjusted relative path, resulting path is " + outF.getPath()); +1042 } +1043 +1044 // Ensure that directory path for specified file exists +1045 File outFileParentDir = outF.getParentFile(); +1046 if (null != outFileParentDir && !outFileParentDir.exists()) +1047 { +1048 try +1049 { +1050 getLog().info("Creating directory path for output file:" + outFileParentDir.getPath()); +1051 outFileParentDir.mkdirs(); +1052 } +1053 catch (Exception e) +1054 { +1055 getLog().error("Error creating directory path for output file: " + e.getLocalizedMessage()); +1056 } +1057 } +1058 +1059 export.setOutputFile(outF.getPath()); +1060 export.execute(target, type); +1061 +1062 for (Object exception : export.getExceptions()) +1063 getLog().debug(exception.toString()); +1064 } +1065 finally +1066 { +1067 /** Stop Log-Capturing */ +1068 MavenLogAppender.endPluginLog(this); +1069 +1070 /** Restore the old class-loader (TODO: is this really necessary?) */ +1071 Thread.currentThread().setContextClassLoader(contextClassLoader); +1072 +1073 if (registry != null) +1074 registry.destroy(); +1075 } +1076 +1077 /** Write md5-sums for annotated classes to file */ +1078 try +1079 { +1080 FileOutputStream fos = new FileOutputStream(saved); +1081 ObjectOutputStream oos = new ObjectOutputStream(fos); +1082 oos.writeObject(md5s); +1083 oos.close(); +1084 fos.close(); +1085 } +1086 catch (Exception e) +1087 { +1088 getLog().error("Cannot write md5-sums to file: " + e); +1089 } +1090 } +1091 +1092 private ParsedPersistenceXmlDescriptor getPersistenceUnitDescriptor( +1093 String name, +1094 Properties properties, +1095 ClassLoaderService loader +1096 ) +1097 throws +1098 MojoFailureException +1099 { +1100 PersistenceXmlParser parser = +1101 new PersistenceXmlParser( +1102 loader, +1103 PersistenceUnitTransactionType.RESOURCE_LOCAL +1104 ); +1105 +1106 List<ParsedPersistenceXmlDescriptor> units = parser.doResolve(properties); +1107 +1108 if (name == null) +1109 { +1110 switch (units.size()) +1111 { +1112 case 0: +1113 getLog().info("Found no META-INF/persistence.xml."); +1114 return null; +1115 case 1: +1116 getLog().info("Using persistence-unit " + units.get(0).getName()); +1117 return units.get(0); +1118 default: +1119 getLog().warn("No name provided and multiple persistence units found:"); +1120 for (ParsedPersistenceXmlDescriptor unit : units) +1121 getLog().warn(" - " + unit.getName()); +1122 return null; +1123 } +1124 +1125 } +1126 +1127 for (ParsedPersistenceXmlDescriptor unit : units) +1128 { +1129 getLog().debug("Found persistence-unit " + unit.getName()); +1130 if (!unit.getName().equals(name)) +1131 continue; +1132 +1133 // See if we (Hibernate) are the persistence provider +1134 if (!ProviderChecker.isProvider(unit, properties)) +1135 { +1136 getLog().debug("Wrong provider: " + unit.getProviderClassName()); +1137 continue; +1138 } +1139 +1140 getLog().info("Using persistence-unit " + unit.getName()); +1141 return unit; +1142 } +1143 +1144 throw new MojoFailureException("Could not find persistence-unit " + name); +1145 } +1146 +1147 +1148 static final class MavenProjectClassLoaderService implements ClassLoaderService +1149 { +1150 final private ClassLoader loader; +1151 +1152 +1153 public MavenProjectClassLoaderService(ClassLoader loader) +1154 { +1155 this.loader = loader; +1156 } +1157 +1158 +1159 @Override +1160 public <T> Class<T> classForName(String name) +1161 { +1162 try +1163 { +1164 return (Class<T>)loader.loadClass(name); +1165 } +1166 catch (ClassNotFoundException e) +1167 { +1168 throw new ClassLoadingException( "Unable to load class [" + name + "]", e ); +1169 } +1170 } +1171 +1172 @Override +1173 public URL locateResource(String name) +1174 { +1175 return loader.getResource(name); +1176 } +1177 +1178 @Override +1179 public InputStream locateResourceStream(String name) +1180 { +1181 return loader.getResourceAsStream(name); +1182 } +1183 +1184 @Override +1185 public List<URL> locateResources(String name) +1186 { +1187 try +1188 { +1189 return Collections.list(loader.getResources(name)); +1190 } +1191 catch (IOException e) +1192 { +1193 return Collections.EMPTY_LIST; +1194 } +1195 } +1196 +1197 @Override +1198 public <S> LinkedHashSet<S> loadJavaServices(Class<S> serviceContract) +1199 { +1200 throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. +1201 } +1202 +1203 @Override +1204 public void stop() { } +1205 +1206 } +1207 +1208 +1209 /** +1210 * Needed, because DriverManager won't pick up drivers, that were not +1211 * loaded by the system-classloader! +1212 * See: +1213 * http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-fromodifiedm-an-arbitrary-location +1214 */ +1215 static final class DriverProxy implements Driver +1216 { +1217 private final Driver target; +1218 +1219 DriverProxy(Driver target) +1220 { +1221 if (target == null) +1222 throw new NullPointerException(); +1223 this.target = target; +1224 } +1225 +1226 public java.sql.Driver getTarget() +1227 { +1228 return target; +1229 } +1230 +1231 @Override +1232 public boolean acceptsURL(String url) throws SQLException +1233 { +1234 return target.acceptsURL(url); +1235 } +1236 +1237 @Override +1238 public java.sql.Connection connect( +1239 String url, +1240 java.util.Properties info +1241 ) +1242 throws +1243 SQLException +1244 { +1245 return target.connect(url, info); +1246 } +1247 +1248 @Override +1249 public int getMajorVersion() +1250 { +1251 return target.getMajorVersion(); +1252 } +1253 +1254 @Override +1255 public int getMinorVersion() +1256 { +1257 return target.getMinorVersion(); +1258 } +1259 +1260 @Override +1261 public DriverPropertyInfo[] getPropertyInfo( +1262 String url, +1263 Properties info +1264 ) +1265 throws +1266 SQLException +1267 { +1268 return target.getPropertyInfo(url, info); +1269 } +1270 +1271 @Override +1272 public boolean jdbcCompliant() +1273 { +1274 return target.jdbcCompliant(); +1275 } +1276 +1277 /** +1278 * This Method cannot be annotated with @Override, becaus the plugin +1279 * will not compile then under Java 1.6! +1280 */ +1281 public Logger getParentLogger() throws SQLFeatureNotSupportedException +1282 { +1283 throw new SQLFeatureNotSupportedException("Not supported, for backward-compatibility with Java 1.6"); +1284 } +1285 +1286 @Override +1287 public String toString() +1288 { +1289 return "Proxy: " + target; +1290 } +1291 +1292 @Override +1293 public int hashCode() +1294 { +1295 return target.hashCode(); +1296 } +1297 +1298 @Override +1299 public boolean equals(Object obj) +1300 { +1301 if (!(obj instanceof DriverProxy)) +1302 return false; +1303 DriverProxy other = (DriverProxy) obj; +1304 return this.target.equals(other.target); +1305 } +1306 } +1307 } ++