X-Git-Url: https://juplo.de/gitweb/?p=website;a=blobdiff_plain;f=dist%2Fhibernate4-maven-plugin-1.1.1%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate4%2FHbm2DdlMojo.html;fp=dist%2Fhibernate4-maven-plugin-1.1.1%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate4%2FHbm2DdlMojo.html;h=0b1c2db828666f3fa408f15f299a5861cf7c9eaa;hp=0000000000000000000000000000000000000000;hb=a53595184bd6e57bdc45292cc92c393c4e2dfe6e;hpb=c48c9ee0e9faa89a4c0a5323b367b9f5a6abe602 diff --git a/dist/hibernate4-maven-plugin-1.1.1/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html b/dist/hibernate4-maven-plugin-1.1.1/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html new file mode 100644 index 00000000..0b1c2db8 --- /dev/null +++ b/dist/hibernate4-maven-plugin-1.1.1/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html @@ -0,0 +1,1332 @@ + + +
++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 List runtimeClasspathElements = project.getRuntimeClasspathElements(); +1004 URL[] runtimeUrls = new URL[runtimeClasspathElements.size()]; +1005 for (int i = 0; i < runtimeClasspathElements.size(); i++) +1006 { +1007 String element = (String) runtimeClasspathElements.get(i); +1008 runtimeUrls[i] = new File(element).toURI().toURL(); +1009 } +1010 URLClassLoader newLoader = new URLClassLoader( +1011 runtimeUrls, +1012 Thread.currentThread().getContextClassLoader() +1013 ); +1014 @SuppressWarnings("unchecked") +1015 Class<NamingStrategy> namingStrategyClass = +1016 (Class<NamingStrategy>) newLoader.loadClass(namingStrategy); +1017 config.setNamingStrategy(namingStrategyClass.newInstance()); +1018 } +1019 catch (Exception e) +1020 { +1021 getLog().error("Error setting NamingStrategy", e); +1022 throw new MojoExecutionException(e.getMessage()); +1023 } +1024 } +1025 +1026 +1027 Environment.verifyProperties(config.getProperties()); +1028 ConfigurationHelper.resolvePlaceHolders(config.getProperties()); +1029 registry = +1030 (StandardServiceRegistryImpl) +1031 new StandardServiceRegistryBuilder() +1032 .applySettings(config.getProperties()) +1033 .build(); +1034 +1035 config.buildMappings(); +1036 +1037 if (envers) +1038 { +1039 getLog().info("Automatic auditing via hibernate-envers enabled!"); +1040 AuditConfiguration.getFor(config); +1041 } +1042 +1043 SchemaExport export = new SchemaExport(registry, config); +1044 export.setDelimiter(delimiter); +1045 export.setFormat(format); +1046 +1047 File outF = new File(outputFile); +1048 +1049 if (!outF.isAbsolute()) +1050 { +1051 // Interpret relative file path relative to build directory +1052 outF = new File(buildDirectory, outputFile); +1053 getLog().info("Adjusted relative path, resulting path is " + outF.getPath()); +1054 } +1055 +1056 // Ensure that directory path for specified file exists +1057 File outFileParentDir = outF.getParentFile(); +1058 if (null != outFileParentDir && !outFileParentDir.exists()) +1059 { +1060 try +1061 { +1062 getLog().info("Creating directory path for output file:" + outFileParentDir.getPath()); +1063 outFileParentDir.mkdirs(); +1064 } +1065 catch (Exception e) +1066 { +1067 getLog().error("Error creating directory path for output file: " + e.getLocalizedMessage()); +1068 } +1069 } +1070 +1071 export.setOutputFile(outF.getPath()); +1072 export.execute(target, type); +1073 +1074 for (Object exception : export.getExceptions()) +1075 getLog().debug(exception.toString()); +1076 } +1077 finally +1078 { +1079 /** Stop Log-Capturing */ +1080 MavenLogAppender.endPluginLog(this); +1081 +1082 /** Restore the old class-loader (TODO: is this really necessary?) */ +1083 Thread.currentThread().setContextClassLoader(contextClassLoader); +1084 +1085 if (registry != null) +1086 registry.destroy(); +1087 } +1088 +1089 /** Write md5-sums for annotated classes to file */ +1090 try +1091 { +1092 FileOutputStream fos = new FileOutputStream(saved); +1093 ObjectOutputStream oos = new ObjectOutputStream(fos); +1094 oos.writeObject(md5s); +1095 oos.close(); +1096 fos.close(); +1097 } +1098 catch (Exception e) +1099 { +1100 getLog().error("Cannot write md5-sums to file: " + e); +1101 } +1102 } +1103 +1104 private ParsedPersistenceXmlDescriptor getPersistenceUnitDescriptor( +1105 String name, +1106 Properties properties, +1107 ClassLoaderService loader +1108 ) +1109 throws +1110 MojoFailureException +1111 { +1112 PersistenceXmlParser parser = +1113 new PersistenceXmlParser( +1114 loader, +1115 PersistenceUnitTransactionType.RESOURCE_LOCAL +1116 ); +1117 +1118 List<ParsedPersistenceXmlDescriptor> units = parser.doResolve(properties); +1119 +1120 if (name == null) +1121 { +1122 switch (units.size()) +1123 { +1124 case 0: +1125 getLog().info("Found no META-INF/persistence.xml."); +1126 return null; +1127 case 1: +1128 getLog().info("Using persistence-unit " + units.get(0).getName()); +1129 return units.get(0); +1130 default: +1131 getLog().warn("No name provided and multiple persistence units found:"); +1132 for (ParsedPersistenceXmlDescriptor unit : units) +1133 getLog().warn(" - " + unit.getName()); +1134 return null; +1135 } +1136 +1137 } +1138 +1139 for (ParsedPersistenceXmlDescriptor unit : units) +1140 { +1141 getLog().debug("Found persistence-unit " + unit.getName()); +1142 if (!unit.getName().equals(name)) +1143 continue; +1144 +1145 // See if we (Hibernate) are the persistence provider +1146 if (!ProviderChecker.isProvider(unit, properties)) +1147 { +1148 getLog().debug("Wrong provider: " + unit.getProviderClassName()); +1149 continue; +1150 } +1151 +1152 getLog().info("Using persistence-unit " + unit.getName()); +1153 return unit; +1154 } +1155 +1156 throw new MojoFailureException("Could not find persistence-unit " + name); +1157 } +1158 +1159 +1160 static final class MavenProjectClassLoaderService implements ClassLoaderService +1161 { +1162 final private ClassLoader loader; +1163 +1164 +1165 public MavenProjectClassLoaderService(ClassLoader loader) +1166 { +1167 this.loader = loader; +1168 } +1169 +1170 +1171 @Override +1172 public <T> Class<T> classForName(String name) +1173 { +1174 try +1175 { +1176 return (Class<T>)loader.loadClass(name); +1177 } +1178 catch (ClassNotFoundException e) +1179 { +1180 throw new ClassLoadingException( "Unable to load class [" + name + "]", e ); +1181 } +1182 } +1183 +1184 @Override +1185 public URL locateResource(String name) +1186 { +1187 return loader.getResource(name); +1188 } +1189 +1190 @Override +1191 public InputStream locateResourceStream(String name) +1192 { +1193 return loader.getResourceAsStream(name); +1194 } +1195 +1196 @Override +1197 public List<URL> locateResources(String name) +1198 { +1199 try +1200 { +1201 return Collections.list(loader.getResources(name)); +1202 } +1203 catch (IOException e) +1204 { +1205 return Collections.EMPTY_LIST; +1206 } +1207 } +1208 +1209 @Override +1210 public <S> LinkedHashSet<S> loadJavaServices(Class<S> serviceContract) +1211 { +1212 throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. +1213 } +1214 +1215 @Override +1216 public void stop() { } +1217 +1218 } +1219 +1220 +1221 /** +1222 * Needed, because DriverManager won't pick up drivers, that were not +1223 * loaded by the system-classloader! +1224 * See: +1225 * http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-fromodifiedm-an-arbitrary-location +1226 */ +1227 static final class DriverProxy implements Driver +1228 { +1229 private final Driver target; +1230 +1231 DriverProxy(Driver target) +1232 { +1233 if (target == null) +1234 throw new NullPointerException(); +1235 this.target = target; +1236 } +1237 +1238 public java.sql.Driver getTarget() +1239 { +1240 return target; +1241 } +1242 +1243 @Override +1244 public boolean acceptsURL(String url) throws SQLException +1245 { +1246 return target.acceptsURL(url); +1247 } +1248 +1249 @Override +1250 public java.sql.Connection connect( +1251 String url, +1252 java.util.Properties info +1253 ) +1254 throws +1255 SQLException +1256 { +1257 return target.connect(url, info); +1258 } +1259 +1260 @Override +1261 public int getMajorVersion() +1262 { +1263 return target.getMajorVersion(); +1264 } +1265 +1266 @Override +1267 public int getMinorVersion() +1268 { +1269 return target.getMinorVersion(); +1270 } +1271 +1272 @Override +1273 public DriverPropertyInfo[] getPropertyInfo( +1274 String url, +1275 Properties info +1276 ) +1277 throws +1278 SQLException +1279 { +1280 return target.getPropertyInfo(url, info); +1281 } +1282 +1283 @Override +1284 public boolean jdbcCompliant() +1285 { +1286 return target.jdbcCompliant(); +1287 } +1288 +1289 /** +1290 * This Method cannot be annotated with @Override, becaus the plugin +1291 * will not compile then under Java 1.6! +1292 */ +1293 public Logger getParentLogger() throws SQLFeatureNotSupportedException +1294 { +1295 throw new SQLFeatureNotSupportedException("Not supported, for backward-compatibility with Java 1.6"); +1296 } +1297 +1298 @Override +1299 public String toString() +1300 { +1301 return "Proxy: " + target; +1302 } +1303 +1304 @Override +1305 public int hashCode() +1306 { +1307 return target.hashCode(); +1308 } +1309 +1310 @Override +1311 public boolean equals(Object obj) +1312 { +1313 if (!(obj instanceof DriverProxy)) +1314 return false; +1315 DriverProxy other = (DriverProxy) obj; +1316 return this.target.equals(other.target); +1317 } +1318 } +1319 } ++