X-Git-Url: https://juplo.de/gitweb/?p=website;a=blobdiff_plain;f=dist%2Fhibernate4-maven-plugin-1.0.4%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate4%2FHbm2DdlMojo.html;fp=dist%2Fhibernate4-maven-plugin-1.0.4%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate4%2FHbm2DdlMojo.html;h=3266e2177e3845b2fe8c0cecf6c2ee1b8f749381;hp=0000000000000000000000000000000000000000;hb=a53595184bd6e57bdc45292cc92c393c4e2dfe6e;hpb=c48c9ee0e9faa89a4c0a5323b367b9f5a6abe602 diff --git a/dist/hibernate4-maven-plugin-1.0.4/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html b/dist/hibernate4-maven-plugin-1.0.4/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html new file mode 100644 index 00000000..3266e217 --- /dev/null +++ b/dist/hibernate4-maven-plugin-1.0.4/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html @@ -0,0 +1,1059 @@ + + +
+ ++ +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.Connection; +34 import java.sql.Driver; +35 import java.sql.DriverManager; +36 import java.sql.DriverPropertyInfo; +37 import java.sql.SQLException; +38 import java.sql.SQLFeatureNotSupportedException; +39 import java.util.Comparator; +40 import java.util.Enumeration; +41 import java.util.HashMap; +42 import java.util.HashSet; +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 org.apache.maven.artifact.Artifact; +56 import org.apache.maven.model.Resource; +57 import org.apache.maven.plugin.AbstractMojo; +58 import org.apache.maven.plugin.MojoExecutionException; +59 import org.apache.maven.plugin.MojoFailureException; +60 import org.apache.maven.project.MavenProject; +61 import org.hibernate.cfg.Configuration; +62 import org.hibernate.cfg.NamingStrategy; +63 import org.hibernate.envers.configuration.spi.AuditConfiguration; +64 import org.hibernate.tool.hbm2ddl.SchemaExport; +65 import org.hibernate.tool.hbm2ddl.SchemaExport.Type; +66 import org.hibernate.tool.hbm2ddl.Target; +67 import org.scannotation.AnnotationDB; +68 +69 +70 /** +71 * Goal which extracts the hibernate-mapping-configuration and +72 * exports an according SQL-database-schema. +73 * +74 * @goal export +75 * @phase process-classes +76 * @threadSafe +77 * @requiresDependencyResolution runtime +78 */ +79 public class Hbm2DdlMojo extends AbstractMojo +80 { +81 public final static String EXPORT_SKIPPED_PROPERTY = "hibernate.export.skipped"; +82 +83 public final static String DRIVER_CLASS = "hibernate.connection.driver_class"; +84 public final static String URL = "hibernate.connection.url"; +85 public final static String USERNAME = "hibernate.connection.username"; +86 public final static String PASSWORD = "hibernate.connection.password"; +87 public final static String DIALECT = "hibernate.dialect"; +88 public final static String NAMING_STRATEGY="hibernate.ejb.naming_strategy"; +89 public final static String ENVERS = "hibernate.export.envers"; +90 +91 public final static String MD5S = "hibernate4-generatedschema.md5s"; +92 +93 private final static Pattern split = Pattern.compile("[^,\\s]+"); +94 +95 +96 /** +97 * The maven project. +98 * <p> +99 * Only needed internally. +100 * +101 * @parameter property="project" +102 * @required +103 * @readonly +104 */ +105 private MavenProject project; +106 +107 /** +108 * Build-directory. +109 * <p> +110 * Only needed internally. +111 * +112 * @parameter property="project.build.directory" +113 * @required +114 * @readonly +115 */ +116 private String buildDirectory; +117 +118 /** +119 * Classes-Directory to scan. +120 * <p> +121 * This parameter defaults to the maven build-output-directory for classes. +122 * Additionally, all dependencies are scanned for annotated classes. +123 * +124 * @parameter property="project.build.outputDirectory" +125 * @since 1.0 +126 */ +127 private String outputDirectory; +128 +129 /** +130 * Whether to scan test-classes too, or not. +131 * <p> +132 * If this parameter is set to <code>true</code> the test-classes of the +133 * artifact will be scanned for hibernate-annotated classes additionally. +134 * +135 * @parameter property="hibernate.export.scan_testclasses" default-value="false" +136 * @since 1.0.1 +137 */ +138 private boolean scanTestClasses; +139 +140 /** +141 * Dependency-Scopes, that should be scanned for annotated classes. +142 * <p> +143 * By default, only dependencies in the scope <code>compile</code> are +144 * scanned for annotated classes. Multiple scopes can be seperated by +145 * white space or commas. +146 * <p> +147 * The plugin does not scan for annotated classes in transitive +148 * dependencies. If some of your annotated classes are hidden in a +149 * transitive dependency, you can simply add that dependency explicitly. +150 * +151 * @parameter property="hibernate.export.scan_dependencies" default-value="compile" +152 * @since 1.0.3 +153 */ +154 private String scanDependencies; +155 +156 /** +157 * Test-Classes-Directory to scan. +158 * <p> +159 * This parameter defaults to the maven build-output-directory for +160 * test-classes. +161 * <p> +162 * This parameter is only used, when <code>scanTestClasses</code> is set +163 * to <code>true</code>! +164 * +165 * @parameter property="project.build.testOutputDirectory" +166 * @since 1.0.2 +167 */ +168 private String testOutputDirectory; +169 +170 /** +171 * Skip execution +172 * <p> +173 * If set to <code>true</code>, the execution is skipped. +174 * <p> +175 * A skipped execution is signaled via the maven-property +176 * <code>${hibernate.export.skipped}</code>. +177 * <p> +178 * The execution is skipped automatically, if no modified or newly added +179 * annotated classes are found and the dialect was not changed. +180 * +181 * @parameter property="hibernate.skip" default-value="${maven.test.skip}" +182 * @since 1.0 +183 */ +184 private boolean skip; +185 +186 /** +187 * Force execution +188 * <p> +189 * Force execution, even if no modified or newly added annotated classes +190 * where found and the dialect was not changed. +191 * <p> +192 * <code>skip</code> takes precedence over <code>force</code>. +193 * +194 * @parameter property="hibernate.export.force" default-value="false" +195 * @since 1.0 +196 */ +197 private boolean force; +198 +199 /** +200 * SQL-Driver name. +201 * +202 * @parameter property="hibernate.connection.driver_class" +203 * @since 1.0 +204 */ +205 private String driverClassName; +206 +207 /** +208 * Database URL. +209 * +210 * @parameter property="hibernate.connection.url" +211 * @since 1.0 +212 */ +213 private String url; +214 +215 /** +216 * Database username +217 * +218 * @parameter property="hibernate.connection.username" +219 * @since 1.0 +220 */ +221 private String username; +222 +223 /** +224 * Database password +225 * +226 * @parameter property="hibernate.connection.password" +227 * @since 1.0 +228 */ +229 private String password; +230 +231 /** +232 * Hibernate dialect. +233 * +234 * @parameter property="hibernate.dialect" +235 * @since 1.0 +236 */ +237 private String hibernateDialect; +238 +239 /** +240 * Hibernate Naming Strategy +241 * +242 * @parameter property="hibernate.ejb.naming_strategy" +243 * @since 1.0.2 +244 */ +245 private String hibernateNamingStrategy; +246 +247 /** +248 * Path to Hibernate configuration file. +249 * +250 * @parameter default-value="${project.build.outputDirectory}/hibernate.properties" +251 * @since 1.0 +252 */ +253 private String hibernateProperties; +254 +255 /** +256 * List of Hibernate-Mapping-Files (XML). +257 * Multiple files can be separated with white-spaces and/or commas. +258 * +259 * @parameter property="hibernate.mapping" +260 * @since 1.0.2 +261 */ +262 private String hibernateMapping; +263 +264 /** +265 * Target of execution: +266 * <ul> +267 * <li><strong>NONE</strong> only export schema to SQL-script (forces execution, signals skip)</li> +268 * <li><strong>EXPORT</strong> create database (<strong>DEFAULT!</strong>). forces execution, signals skip)</li> +269 * <li><strong>SCRIPT</strong> export schema to SQL-script and print it to STDOUT</li> +270 * <li><strong>BOTH</strong></li> +271 * </ul> +272 * +273 * A database connection is only needed for EXPORT and BOTH, but a +274 * Hibernate-Dialect must always be chosen. +275 * +276 * @parameter property="hibernate.export.target" default-value="EXPORT" +277 * @since 1.0 +278 */ +279 private String target; +280 +281 /** +282 * Type of execution. +283 * <ul> +284 * <li><strong>NONE</strong> do nothing - just validate the configuration</li> +285 * <li><strong>CREATE</strong> create database-schema</li> +286 * <li><strong>DROP</strong> drop database-schema</li> +287 * <li><strong>BOTH</strong> (<strong>DEFAULT!</strong>)</li> +288 * </ul> +289 * +290 * If NONE is choosen, no databaseconnection is needed. +291 * +292 * @parameter property="hibernate.export.type" default-value="BOTH" +293 * @since 1.0 +294 */ +295 private String type; +296 +297 /** +298 * Output file. +299 * +300 * @parameter property="hibernate.export.schema.filename" default-value="${project.build.directory}/schema.sql" +301 * @since 1.0 +302 */ +303 private String outputFile; +304 +305 /** +306 * Delimiter in output-file. +307 * +308 * @parameter property="hibernate.export.schema.delimiter" default-value=";" +309 * @since 1.0 +310 */ +311 private String delimiter; +312 +313 /** +314 * Format output-file. +315 * +316 * @parameter property="hibernate.export.schema.format" default-value="true" +317 * @since 1.0 +318 */ +319 private boolean format; +320 +321 /** +322 * Generate envers schema for auditing tables. +323 * +324 * @parameter property="hibernate.export.envers" default-value="false" +325 * @since 1.0.3 +326 */ +327 private boolean envers; +328 +329 +330 @Override +331 public void execute() +332 throws +333 MojoFailureException, +334 MojoExecutionException +335 { +336 if (skip) +337 { +338 getLog().info("Execution of hibernate4-maven-plugin:export was skipped!"); +339 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true"); +340 return; +341 } +342 +343 Map<String,String> md5s; +344 boolean modified = false; +345 File saved = new File(buildDirectory + File.separator + MD5S); +346 +347 if (saved.isFile() && saved.length() > 0) +348 { +349 try +350 { +351 FileInputStream fis = new FileInputStream(saved); +352 ObjectInputStream ois = new ObjectInputStream(fis); +353 md5s = (HashMap<String,String>)ois.readObject(); +354 ois.close(); +355 } +356 catch (Exception e) +357 { +358 md5s = new HashMap<String,String>(); +359 getLog().warn("Cannot read timestamps from saved: " + e); +360 } +361 } +362 else +363 { +364 md5s = new HashMap<String,String>(); +365 try +366 { +367 saved.createNewFile(); +368 } +369 catch (IOException e) +370 { +371 getLog().debug("Cannot create file \"" + saved.getPath() + "\" for timestamps: " + e); +372 } +373 } +374 +375 ClassLoader classLoader = null; +376 try +377 { +378 getLog().debug("Creating ClassLoader for project-dependencies..."); +379 List<String> classpathFiles = project.getCompileClasspathElements(); +380 if (scanTestClasses) +381 classpathFiles.addAll(project.getTestClasspathElements()); +382 URL[] urls = new URL[classpathFiles.size()]; +383 for (int i = 0; i < classpathFiles.size(); ++i) +384 { +385 getLog().debug("Dependency: " + classpathFiles.get(i)); +386 urls[i] = new File(classpathFiles.get(i)).toURI().toURL(); +387 } +388 classLoader = new URLClassLoader(urls, getClass().getClassLoader()); +389 } +390 catch (Exception e) +391 { +392 getLog().error("Error while creating ClassLoader!", e); +393 throw new MojoExecutionException(e.getMessage()); +394 } +395 +396 Set<Class<?>> classes = +397 new TreeSet<Class<?>>( +398 new Comparator<Class<?>>() { +399 @Override +400 public int compare(Class<?> a, Class<?> b) +401 { +402 return a.getName().compareTo(b.getName()); +403 } +404 } +405 ); +406 +407 try +408 { +409 AnnotationDB db = new AnnotationDB(); +410 File dir = new File(outputDirectory); +411 if (dir.exists()) +412 { +413 getLog().info("Scanning directory " + outputDirectory + " for annotated classes..."); +414 URL dirUrl = dir.toURI().toURL(); +415 db.scanArchives(dirUrl); +416 } +417 if (scanTestClasses) +418 { +419 dir = new File(testOutputDirectory); +420 if (dir.exists()) +421 { +422 getLog().info("Scanning directory " + testOutputDirectory + " for annotated classes..."); +423 URL dirUrl = dir.toURI().toURL(); +424 db.scanArchives(dirUrl); +425 } +426 } +427 if (scanDependencies != null) +428 { +429 Matcher matcher = split.matcher(scanDependencies); +430 while (matcher.find()) +431 { +432 getLog().info("Scanning dependencies for scope " + matcher.group()); +433 for (Artifact artifact : project.getDependencyArtifacts()) +434 { +435 if (!artifact.getScope().equalsIgnoreCase(matcher.group())) +436 continue; +437 if (artifact.getFile() == null) +438 { +439 getLog().warn( +440 "Cannot scan dependency " + +441 artifact.getId() + +442 ": no JAR-file available!" +443 ); +444 continue; +445 } +446 getLog().info( +447 "Scanning dependency " + +448 artifact.getId() + +449 " for annotated classes..." +450 ); +451 db.scanArchives(artifact.getFile().toURI().toURL()); +452 } +453 } +454 } +455 +456 Set<String> classNames = new HashSet<String>(); +457 if (db.getAnnotationIndex().containsKey(Entity.class.getName())) +458 classNames.addAll(db.getAnnotationIndex().get(Entity.class.getName())); +459 if (db.getAnnotationIndex().containsKey(MappedSuperclass.class.getName())) +460 classNames.addAll(db.getAnnotationIndex().get(MappedSuperclass.class.getName())); +461 if (db.getAnnotationIndex().containsKey(Embeddable.class.getName())) +462 classNames.addAll(db.getAnnotationIndex().get(Embeddable.class.getName())); +463 +464 MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); +465 for (String name : classNames) +466 { +467 Class<?> annotatedClass = classLoader.loadClass(name); +468 classes.add(annotatedClass); +469 String resourceName = annotatedClass.getName(); +470 resourceName = resourceName.substring(resourceName.lastIndexOf(".") + 1, resourceName.length()) + ".class"; +471 InputStream is = +472 annotatedClass +473 .getResourceAsStream(resourceName); +474 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks +475 int i; +476 while((i = is.read(buffer)) > -1) +477 digest.update(buffer, 0, i); +478 is.close(); +479 byte[] bytes = digest.digest(); +480 BigInteger bi = new BigInteger(1, bytes); +481 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi); +482 String oldMd5 = !md5s.containsKey(name) ? "" : md5s.get(name); +483 if (!newMd5.equals(oldMd5)) +484 { +485 getLog().debug("Found new or modified annotated class: " + name); +486 modified = true; +487 md5s.put(name, newMd5); +488 } +489 else +490 { +491 getLog().debug(oldMd5 + " -> class unchanged: " + name); +492 } +493 } +494 } +495 catch (ClassNotFoundException e) +496 { +497 getLog().error("Error while adding annotated classes!", e); +498 throw new MojoExecutionException(e.getMessage()); +499 } +500 catch (Exception e) +501 { +502 getLog().error("Error while scanning!", e); +503 throw new MojoFailureException(e.getMessage()); +504 } +505 +506 if (classes.isEmpty()) +507 { +508 if (hibernateMapping == null || hibernateMapping.isEmpty()) +509 throw new MojoFailureException("No annotated classes found in directory " + outputDirectory); +510 } +511 else +512 { +513 getLog().debug("Detected classes with mapping-annotations:"); +514 for (Class<?> annotatedClass : classes) +515 getLog().debug(" " + annotatedClass.getName()); +516 } +517 +518 +519 Properties properties = new Properties(); +520 +521 /** Try to read configuration from properties-file */ +522 try +523 { +524 File file = new File(hibernateProperties); +525 if (file.exists()) +526 { +527 getLog().info("Reading properties from file " + hibernateProperties + "..."); +528 properties.load(new FileInputStream(file)); +529 } +530 else +531 getLog().info("No hibernate-properties-file found! (Checked path: " + hibernateProperties + ")"); +532 } +533 catch (IOException e) +534 { +535 getLog().error("Error while reading properties!", e); +536 throw new MojoExecutionException(e.getMessage()); +537 } +538 +539 /** Overwrite values from properties-file or set, if given */ +540 if (driverClassName != null) +541 { +542 if (properties.containsKey(DRIVER_CLASS)) +543 getLog().debug( +544 "Overwriting property " + +545 DRIVER_CLASS + "=" + properties.getProperty(DRIVER_CLASS) + +546 " with the value " + driverClassName +547 ); +548 else +549 getLog().debug("Using the value " + driverClassName); +550 properties.setProperty(DRIVER_CLASS, driverClassName); +551 } +552 if (url != null) +553 { +554 if (properties.containsKey(URL)) +555 getLog().debug( +556 "Overwriting property " + +557 URL + "=" + properties.getProperty(URL) + +558 " with the value " + url +559 ); +560 else +561 getLog().debug("Using the value " + url); +562 properties.setProperty(URL, url); +563 } +564 if (username != null) +565 { +566 if (properties.containsKey(USERNAME)) +567 getLog().debug( +568 "Overwriting property " + +569 USERNAME + "=" + properties.getProperty(USERNAME) + +570 " with the value " + username +571 ); +572 else +573 getLog().debug("Using the value " + username); +574 properties.setProperty(USERNAME, username); +575 } +576 if (password != null) +577 { +578 if (properties.containsKey(PASSWORD)) +579 getLog().debug( +580 "Overwriting property " + +581 PASSWORD + "=" + properties.getProperty(PASSWORD) + +582 " with value " + password +583 ); +584 else +585 getLog().debug("Using value " + password + " for property " + PASSWORD); +586 properties.setProperty(PASSWORD, password); +587 } +588 if (hibernateDialect != null) +589 { +590 if (properties.containsKey(DIALECT)) +591 getLog().debug( +592 "Overwriting property " + +593 DIALECT + "=" + properties.getProperty(DIALECT) + +594 " with value " + hibernateDialect +595 ); +596 else +597 getLog().debug( +598 "Using value " + hibernateDialect + " for property " + DIALECT +599 ); +600 properties.setProperty(DIALECT, hibernateDialect); +601 } +602 if ( hibernateNamingStrategy != null ) +603 { +604 if ( properties.contains(NAMING_STRATEGY)) +605 getLog().debug( +606 "Overwriting property " + +607 NAMING_STRATEGY + "=" + properties.getProperty(NAMING_STRATEGY) + +608 " with value " + hibernateNamingStrategy +609 ); +610 else +611 getLog().debug( +612 "Using value " + hibernateNamingStrategy + " for property " + +613 NAMING_STRATEGY +614 ); +615 properties.setProperty(NAMING_STRATEGY, hibernateNamingStrategy); +616 } +617 +618 /** The generated SQL varies with the dialect! */ +619 if (md5s.containsKey(DIALECT)) +620 { +621 String dialect = properties.getProperty(DIALECT); +622 if (md5s.get(DIALECT).equals(dialect)) +623 getLog().debug("SQL-dialect unchanged."); +624 else +625 { +626 modified = true; +627 if (dialect == null) +628 { +629 getLog().debug("SQL-dialect was unset."); +630 md5s.remove(DIALECT); +631 } +632 else +633 { +634 getLog().debug("SQL-dialect changed: " + dialect); +635 md5s.put(DIALECT, dialect); +636 } +637 } +638 } +639 else +640 { +641 String dialect = properties.getProperty(DIALECT); +642 if (dialect != null) +643 { +644 modified = true; +645 md5s.put(DIALECT, properties.getProperty(DIALECT)); +646 } +647 } +648 +649 /** The generated SQL varies with the envers-configuration */ +650 if (md5s.get(ENVERS) != null) +651 { +652 if (md5s.get(ENVERS).equals(Boolean.toString(envers))) +653 getLog().debug("Envers-Configuration unchanged. Enabled: " + envers); +654 else +655 { +656 getLog().debug("Envers-Configuration changed. Enabled: " + envers); +657 modified = true; +658 md5s.put(ENVERS, Boolean.toString(envers)); +659 } +660 } +661 else +662 { +663 modified = true; +664 md5s.put(ENVERS, Boolean.toString(envers)); +665 } +666 +667 if (properties.isEmpty()) +668 { +669 getLog().error("No properties set!"); +670 throw new MojoFailureException("Hibernate configuration is missing!"); +671 } +672 +673 final Configuration config = new ValidationConfiguration(hibernateDialect); +674 +675 config.setProperties(properties); +676 +677 if ( properties.containsKey(NAMING_STRATEGY)) +678 { +679 String namingStrategy = properties.getProperty(NAMING_STRATEGY); +680 getLog().debug("Explicitly set NamingStrategy: " + namingStrategy); +681 try +682 { +683 @SuppressWarnings("unchecked") +684 Class<NamingStrategy> namingStrategyClass = (Class<NamingStrategy>) Class.forName(namingStrategy); +685 config.setNamingStrategy(namingStrategyClass.newInstance()); +686 } +687 catch (Exception e) +688 { +689 getLog().error("Error setting NamingStrategy", e); +690 throw new MojoExecutionException(e.getMessage()); +691 } +692 } +693 +694 getLog().debug("Adding annotated classes to hibernate-mapping-configuration..."); +695 for (Class<?> annotatedClass : classes) +696 { +697 getLog().debug("Class " + annotatedClass); +698 config.addAnnotatedClass(annotatedClass); +699 } +700 +701 if (hibernateMapping != null) +702 { +703 try +704 { +705 MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); +706 for (String filename : hibernateMapping.split("[\\s,]+")) +707 { +708 // First try the filename as absolute/relative path +709 File file = new File(filename); +710 if (!file.exists()) +711 { +712 // If the file was not found, search for it in the resource-directories +713 for (Resource resource : project.getResources()) +714 { +715 file = new File(resource.getDirectory() + File.separator + filename); +716 if (file.exists()) +717 break; +718 } +719 } +720 if (file != null && file.exists()) +721 { +722 InputStream is = new FileInputStream(file); +723 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks +724 int i; +725 while((i = is.read(buffer)) > -1) +726 digest.update(buffer, 0, i); +727 is.close(); +728 byte[] bytes = digest.digest(); +729 BigInteger bi = new BigInteger(1, bytes); +730 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi); +731 String oldMd5 = !md5s.containsKey(filename) ? "" : md5s.get(filename); +732 if (!newMd5.equals(oldMd5)) +733 { +734 getLog().debug("Found new or modified mapping-file: " + filename); +735 modified = true; +736 md5s.put(filename, newMd5); +737 } +738 else +739 { +740 getLog().debug(oldMd5 + " -> mapping-file unchanged: " + filename); +741 } +742 getLog().debug("Adding mappings from XML-configurationfile: " + file); +743 config.addFile(file); +744 } +745 else +746 throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!"); +747 } +748 } +749 catch (NoSuchAlgorithmException e) +750 { +751 throw new MojoFailureException("Cannot calculate MD5 sums!", e); +752 } +753 catch (FileNotFoundException e) +754 { +755 throw new MojoFailureException("Cannot calculate MD5 sums!", e); +756 } +757 catch (IOException e) +758 { +759 throw new MojoFailureException("Cannot calculate MD5 sums!", e); +760 } +761 } +762 +763 Target target = null; +764 try +765 { +766 target = Target.valueOf(this.target.toUpperCase()); +767 } +768 catch (IllegalArgumentException e) +769 { +770 getLog().error("Invalid value for configuration-option \"target\": " + this.target); +771 getLog().error("Valid values are: NONE, SCRIPT, EXPORT, BOTH"); +772 throw new MojoExecutionException("Invalid value for configuration-option \"target\""); +773 } +774 Type type = null; +775 try +776 { +777 type = Type.valueOf(this.type.toUpperCase()); +778 } +779 catch (IllegalArgumentException e) +780 { +781 getLog().error("Invalid value for configuration-option \"type\": " + this.type); +782 getLog().error("Valid values are: NONE, CREATE, DROP, BOTH"); +783 throw new MojoExecutionException("Invalid value for configuration-option \"type\""); +784 } +785 +786 if (target.equals(Target.SCRIPT) || target.equals(Target.NONE)) +787 { +788 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true"); +789 } +790 if ( +791 !modified +792 && !target.equals(Target.SCRIPT) +793 && !target.equals(Target.NONE) +794 && !force +795 ) +796 { +797 getLog().info("No modified annotated classes or mapping-files found and dialect unchanged."); +798 getLog().info("Skipping schema generation!"); +799 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true"); +800 return; +801 } +802 +803 getLog().info("Gathered hibernate-configuration (turn on debugging for details):"); +804 for (Entry<Object,Object> entry : properties.entrySet()) +805 getLog().info(" " + entry.getKey() + " = " + entry.getValue()); +806 +807 Connection connection = null; +808 try +809 { +810 /** +811 * The connection must be established outside of hibernate, because +812 * hibernate does not use the context-classloader of the current +813 * thread and, hence, would not be able to resolve the driver-class! +814 */ +815 getLog().debug("Target: " + target + ", Type: " + type); +816 switch (target) +817 { +818 case EXPORT: +819 case BOTH: +820 switch (type) +821 { +822 case CREATE: +823 case DROP: +824 case BOTH: +825 Class driverClass = classLoader.loadClass(properties.getProperty(DRIVER_CLASS)); +826 getLog().debug("Registering JDBC-driver " + driverClass.getName()); +827 DriverManager.registerDriver(new DriverProxy((Driver)driverClass.newInstance())); +828 getLog().debug( +829 "Opening JDBC-connection to " +830 + properties.getProperty(URL) +831 + " as " +832 + properties.getProperty(USERNAME) +833 + " with password " +834 + properties.getProperty(PASSWORD) +835 ); +836 connection = DriverManager.getConnection( +837 properties.getProperty(URL), +838 properties.getProperty(USERNAME), +839 properties.getProperty(PASSWORD) +840 ); +841 } +842 } +843 } +844 catch (ClassNotFoundException e) +845 { +846 getLog().error("Dependency for driver-class " + properties.getProperty(DRIVER_CLASS) + " is missing!"); +847 throw new MojoExecutionException(e.getMessage()); +848 } +849 catch (Exception e) +850 { +851 getLog().error("Cannot establish connection to database!"); +852 Enumeration<Driver> drivers = DriverManager.getDrivers(); +853 if (!drivers.hasMoreElements()) +854 getLog().error("No drivers registered!"); +855 while (drivers.hasMoreElements()) +856 getLog().debug("Driver: " + drivers.nextElement()); +857 throw new MojoExecutionException(e.getMessage()); +858 } +859 +860 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); +861 MavenLogAppender.startPluginLog(this); +862 try +863 { +864 /** +865 * Change class-loader of current thread, so that hibernate can +866 * see all dependencies! +867 */ +868 Thread.currentThread().setContextClassLoader(classLoader); +869 +870 config.buildMappings(); +871 +872 if (envers) +873 { +874 getLog().info("Automatic auditing via hibernate-envers enabled!"); +875 AuditConfiguration.getFor(config); +876 } +877 +878 SchemaExport export = new SchemaExport(config, connection); +879 export.setDelimiter(delimiter); +880 export.setFormat(format); +881 +882 File outF = new File(outputFile); +883 +884 if (!outF.isAbsolute()) +885 { +886 // Interpret relative file path relative to build directory +887 outF = new File(buildDirectory, outputFile); +888 getLog().info("Adjusted relative path, resulting path is " + outF.getPath()); +889 } +890 +891 // Ensure that directory path for specified file exists +892 File outFileParentDir = outF.getParentFile(); +893 if (null != outFileParentDir && !outFileParentDir.exists()) +894 { +895 try +896 { +897 getLog().info("Creating directory path for output file:" + outFileParentDir.getPath()); +898 outFileParentDir.mkdirs(); +899 } +900 catch (Exception e) +901 { +902 getLog().error("Error creating directory path for output file: " + e.getLocalizedMessage()); +903 } +904 } +905 +906 export.setOutputFile(outF.getPath()); +907 export.execute(target, type); +908 +909 for (Object exception : export.getExceptions()) +910 getLog().debug(exception.toString()); +911 } +912 finally +913 { +914 /** Stop Log-Capturing */ +915 MavenLogAppender.endPluginLog(this); +916 +917 /** Restore the old class-loader (TODO: is this really necessary?) */ +918 Thread.currentThread().setContextClassLoader(contextClassLoader); +919 +920 /** Close the connection */ +921 try +922 { +923 if (connection != null) +924 connection.close(); +925 } +926 catch (SQLException e) +927 { +928 getLog().error("Error while closing connection: " + e.getMessage()); +929 } +930 } +931 +932 /** Write md5-sums for annotated classes to file */ +933 try +934 { +935 FileOutputStream fos = new FileOutputStream(saved); +936 ObjectOutputStream oos = new ObjectOutputStream(fos); +937 oos.writeObject(md5s); +938 oos.close(); +939 fos.close(); +940 } +941 catch (Exception e) +942 { +943 getLog().error("Cannot write md5-sums to file: " + e); +944 } +945 } +946 +947 /** +948 * Needed, because DriverManager won't pick up drivers, that were not +949 * loaded by the system-classloader! +950 * See: +951 * http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-fromodifiedm-an-arbitrary-location +952 */ +953 static final class DriverProxy implements Driver +954 { +955 private final Driver target; +956 +957 DriverProxy(Driver target) +958 { +959 if (target == null) +960 throw new NullPointerException(); +961 this.target = target; +962 } +963 +964 public java.sql.Driver getTarget() +965 { +966 return target; +967 } +968 +969 @Override +970 public boolean acceptsURL(String url) throws SQLException +971 { +972 return target.acceptsURL(url); +973 } +974 +975 @Override +976 public java.sql.Connection connect( +977 String url, +978 java.util.Properties info +979 ) +980 throws +981 SQLException +982 { +983 return target.connect(url, info); +984 } +985 +986 @Override +987 public int getMajorVersion() +988 { +989 return target.getMajorVersion(); +990 } +991 +992 @Override +993 public int getMinorVersion() +994 { +995 return target.getMinorVersion(); +996 } +997 +998 @Override +999 public DriverPropertyInfo[] getPropertyInfo( +1000 String url, +1001 Properties info +1002 ) +1003 throws +1004 SQLException +1005 { +1006 return target.getPropertyInfo(url, info); +1007 } +1008 +1009 @Override +1010 public boolean jdbcCompliant() +1011 { +1012 return target.jdbcCompliant(); +1013 } +1014 +1015 /** +1016 * This Method cannot be annotated with @Override, becaus the plugin +1017 * will not compile then under Java 1.6! +1018 */ +1019 public Logger getParentLogger() throws SQLFeatureNotSupportedException +1020 { +1021 throw new SQLFeatureNotSupportedException("Not supported, for backward-compatibility with Java 1.6"); +1022 } +1023 +1024 @Override +1025 public String toString() +1026 { +1027 return "Proxy: " + target; +1028 } +1029 +1030 @Override +1031 public int hashCode() +1032 { +1033 return target.hashCode(); +1034 } +1035 +1036 @Override +1037 public boolean equals(Object obj) +1038 { +1039 if (!(obj instanceof DriverProxy)) +1040 return false; +1041 DriverProxy other = (DriverProxy) obj; +1042 return this.target.equals(other.target); +1043 } +1044 } +1045 } ++