X-Git-Url: https://juplo.de/gitweb/?p=website;a=blobdiff_plain;f=dist%2Fhibernate4-maven-plugin-1.0.3%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate4%2FHbm2DdlMojo.html;fp=dist%2Fhibernate4-maven-plugin-1.0.3%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate4%2FHbm2DdlMojo.html;h=fe3ef3fb2e619121628c858bfa7d63d4d9ce7ecc;hp=0000000000000000000000000000000000000000;hb=a53595184bd6e57bdc45292cc92c393c4e2dfe6e;hpb=c48c9ee0e9faa89a4c0a5323b367b9f5a6abe602 diff --git a/dist/hibernate4-maven-plugin-1.0.3/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html b/dist/hibernate4-maven-plugin-1.0.3/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html new file mode 100644 index 00000000..fe3ef3fb --- /dev/null +++ b/dist/hibernate4-maven-plugin-1.0.3/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html @@ -0,0 +1,1033 @@ + + +
+ ++ +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.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 = "schema.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 * Additonally, 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 * Wether 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 excecution is signaled via the maven-property +176 * <code>${hibernate.export.skipped}</code>. +177 * <p> +178 * The excecution is skipped automatically, if no modified or newly added +179 * annotated classes are found and the dialect was not changed. +180 * +181 * @parameter property="maven.test.skip" default-value="false" +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 excecution, signals skip)</li> +268 * <li><strong>EXPORT</strong> create database (<strong>DEFAULT!</strong>). forces excecution, 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 databaseconnection is only needed for EXPORT and BOTH, but a +274 * Hibernate-Dialect must always be choosen. +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("Exectuion 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.exists()) +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 propertie-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 Configuration config = new Configuration(); +674 config.setProperties(properties); +675 +676 if ( properties.containsKey(NAMING_STRATEGY)) +677 { +678 String namingStrategy = properties.getProperty(NAMING_STRATEGY); +679 getLog().debug("Explicitly set NamingStrategy: " + namingStrategy); +680 try +681 { +682 @SuppressWarnings("unchecked") +683 Class<NamingStrategy> namingStrategyClass = (Class<NamingStrategy>) Class.forName(namingStrategy); +684 config.setNamingStrategy(namingStrategyClass.newInstance()); +685 } +686 catch (Exception e) +687 { +688 getLog().error("Error setting NamingStrategy", e); +689 throw new MojoExecutionException(e.getMessage()); +690 } +691 } +692 +693 getLog().debug("Adding annotated classes to hibernate-mapping-configuration..."); +694 for (Class<?> annotatedClass : classes) +695 { +696 getLog().debug("Class " + annotatedClass); +697 config.addAnnotatedClass(annotatedClass); +698 } +699 +700 if (hibernateMapping != null) +701 { +702 try +703 { +704 MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); +705 for (String filename : hibernateMapping.split("[\\s,]+")) +706 { +707 // First try the filename as absolute/relative path +708 File file = new File(filename); +709 if (!file.exists()) +710 { +711 // If the file was not found, search for it in the resource-directories +712 for (Resource resource : project.getResources()) +713 { +714 file = new File(resource.getDirectory() + File.separator + filename); +715 if (file.exists()) +716 break; +717 } +718 } +719 if (file != null && file.exists()) +720 { +721 InputStream is = new FileInputStream(file); +722 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks +723 int i; +724 while((i = is.read(buffer)) > -1) +725 digest.update(buffer, 0, i); +726 is.close(); +727 byte[] bytes = digest.digest(); +728 BigInteger bi = new BigInteger(1, bytes); +729 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi); +730 String oldMd5 = !md5s.containsKey(filename) ? "" : md5s.get(filename); +731 if (!newMd5.equals(oldMd5)) +732 { +733 getLog().debug("Found new or modified mapping-file: " + filename); +734 modified = true; +735 md5s.put(filename, newMd5); +736 } +737 else +738 { +739 getLog().debug(oldMd5 + " -> mapping-file unchanged: " + filename); +740 } +741 getLog().debug("Adding mappings from XML-configurationfile: " + file); +742 config.addFile(file); +743 } +744 else +745 throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!"); +746 } +747 } +748 catch (NoSuchAlgorithmException e) +749 { +750 throw new MojoFailureException("Cannot calculate MD5-summs!", e); +751 } +752 catch (FileNotFoundException e) +753 { +754 throw new MojoFailureException("Cannot calculate MD5-summs!", e); +755 } +756 catch (IOException e) +757 { +758 throw new MojoFailureException("Cannot calculate MD5-summs!", e); +759 } +760 } +761 +762 Target target = null; +763 try +764 { +765 target = Target.valueOf(this.target.toUpperCase()); +766 } +767 catch (IllegalArgumentException e) +768 { +769 getLog().error("Invalid value for configuration-option \"target\": " + this.target); +770 getLog().error("Valid values are: NONE, SCRIPT, EXPORT, BOTH"); +771 throw new MojoExecutionException("Invalid value for configuration-option \"target\""); +772 } +773 Type type = null; +774 try +775 { +776 type = Type.valueOf(this.type.toUpperCase()); +777 } +778 catch (IllegalArgumentException e) +779 { +780 getLog().error("Invalid value for configuration-option \"type\": " + this.type); +781 getLog().error("Valid values are: NONE, CREATE, DROP, BOTH"); +782 throw new MojoExecutionException("Invalid value for configuration-option \"type\""); +783 } +784 +785 if (target.equals(Target.SCRIPT) || target.equals(Target.NONE)) +786 { +787 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true"); +788 } +789 if ( +790 !modified +791 && !target.equals(Target.SCRIPT) +792 && !target.equals(Target.NONE) +793 && !force +794 ) +795 { +796 getLog().info("No modified annotated classes or mapping-files found and dialect unchanged."); +797 getLog().info("Skipping schema generation!"); +798 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true"); +799 return; +800 } +801 +802 getLog().info("Gathered hibernate-configuration (turn on debugging for details):"); +803 for (Entry<Object,Object> entry : properties.entrySet()) +804 getLog().info(" " + entry.getKey() + " = " + entry.getValue()); +805 +806 Connection connection = null; +807 try +808 { +809 /** +810 * The connection must be established outside of hibernate, because +811 * hibernate does not use the context-classloader of the current +812 * thread and, hence, would not be able to resolve the driver-class! +813 */ +814 getLog().debug("Target: " + target + ", Type: " + type); +815 switch (target) +816 { +817 case EXPORT: +818 case BOTH: +819 switch (type) +820 { +821 case CREATE: +822 case DROP: +823 case BOTH: +824 Class driverClass = classLoader.loadClass(properties.getProperty(DRIVER_CLASS)); +825 getLog().debug("Registering JDBC-driver " + driverClass.getName()); +826 DriverManager.registerDriver(new DriverProxy((Driver)driverClass.newInstance())); +827 getLog().debug( +828 "Opening JDBC-connection to " +829 + properties.getProperty(URL) +830 + " as " +831 + properties.getProperty(USERNAME) +832 + " with password " +833 + properties.getProperty(PASSWORD) +834 ); +835 connection = DriverManager.getConnection( +836 properties.getProperty(URL), +837 properties.getProperty(USERNAME), +838 properties.getProperty(PASSWORD) +839 ); +840 } +841 } +842 } +843 catch (ClassNotFoundException e) +844 { +845 getLog().error("Dependency for driver-class " + properties.getProperty(DRIVER_CLASS) + " is missing!"); +846 throw new MojoExecutionException(e.getMessage()); +847 } +848 catch (Exception e) +849 { +850 getLog().error("Cannot establish connection to database!"); +851 Enumeration<Driver> drivers = DriverManager.getDrivers(); +852 if (!drivers.hasMoreElements()) +853 getLog().error("No drivers registered!"); +854 while (drivers.hasMoreElements()) +855 getLog().debug("Driver: " + drivers.nextElement()); +856 throw new MojoExecutionException(e.getMessage()); +857 } +858 +859 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); +860 MavenLogAppender.startPluginLog(this); +861 try +862 { +863 /** +864 * Change class-loader of current thread, so that hibernate can +865 * see all dependencies! +866 */ +867 Thread.currentThread().setContextClassLoader(classLoader); +868 +869 config.buildMappings(); +870 +871 if (envers) +872 { +873 getLog().info("Automatic auditing via hibernate-envers enabled!"); +874 AuditConfiguration.getFor(config); +875 } +876 +877 SchemaExport export = new SchemaExport(config, connection); +878 export.setOutputFile(outputFile); +879 export.setDelimiter(delimiter); +880 export.setFormat(format); +881 export.execute(target, type); +882 +883 for (Object exception : export.getExceptions()) +884 getLog().debug(exception.toString()); +885 } +886 finally +887 { +888 /** Stop Log-Capturing */ +889 MavenLogAppender.endPluginLog(this); +890 +891 /** Restore the old class-loader (TODO: is this really necessary?) */ +892 Thread.currentThread().setContextClassLoader(contextClassLoader); +893 +894 /** Close the connection */ +895 try +896 { +897 if (connection != null) +898 connection.close(); +899 } +900 catch (SQLException e) +901 { +902 getLog().error("Error while closing connection: " + e.getMessage()); +903 } +904 } +905 +906 /** Write md5-sums for annotated classes to file */ +907 try +908 { +909 FileOutputStream fos = new FileOutputStream(saved); +910 ObjectOutputStream oos = new ObjectOutputStream(fos); +911 oos.writeObject(md5s); +912 oos.close(); +913 fos.close(); +914 } +915 catch (Exception e) +916 { +917 getLog().error("Cannot write md5-sums to file: " + e); +918 } +919 } +920 +921 /** +922 * Needed, because DriverManager won't pick up drivers, that were not +923 * loaded by the system-classloader! +924 * See: +925 * http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-fromodifiedm-an-arbitrary-location +926 */ +927 static final class DriverProxy implements Driver +928 { +929 private final Driver target; +930 +931 DriverProxy(Driver target) +932 { +933 if (target == null) +934 throw new NullPointerException(); +935 this.target = target; +936 } +937 +938 public java.sql.Driver getTarget() +939 { +940 return target; +941 } +942 +943 @Override +944 public boolean acceptsURL(String url) throws SQLException +945 { +946 return target.acceptsURL(url); +947 } +948 +949 @Override +950 public java.sql.Connection connect( +951 String url, +952 java.util.Properties info +953 ) +954 throws +955 SQLException +956 { +957 return target.connect(url, info); +958 } +959 +960 @Override +961 public int getMajorVersion() +962 { +963 return target.getMajorVersion(); +964 } +965 +966 @Override +967 public int getMinorVersion() +968 { +969 return target.getMinorVersion(); +970 } +971 +972 @Override +973 public DriverPropertyInfo[] getPropertyInfo( +974 String url, +975 Properties info +976 ) +977 throws +978 SQLException +979 { +980 return target.getPropertyInfo(url, info); +981 } +982 +983 @Override +984 public boolean jdbcCompliant() +985 { +986 return target.jdbcCompliant(); +987 } +988 +989 /** +990 * This Method cannot be annotated with @Override, becaus the plugin +991 * will not compile then under Java 1.6! +992 */ +993 public Logger getParentLogger() throws SQLFeatureNotSupportedException +994 { +995 throw new SQLFeatureNotSupportedException("Not supported, for backward-compatibility with Java 1.6"); +996 } +997 +998 @Override +999 public String toString() +1000 { +1001 return "Proxy: " + target; +1002 } +1003 +1004 @Override +1005 public int hashCode() +1006 { +1007 return target.hashCode(); +1008 } +1009 +1010 @Override +1011 public boolean equals(Object obj) +1012 { +1013 if (!(obj instanceof DriverProxy)) +1014 return false; +1015 DriverProxy other = (DriverProxy) obj; +1016 return this.target.equals(other.target); +1017 } +1018 } +1019 } ++