1 package de.juplo.plugins.hibernate4;
4 * Copyright 2001-2005 The Apache Software Foundation.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 import com.pyx4j.log4j.MavenLogAppender;
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;
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;
45 import java.util.Map.Entry;
46 import java.util.Properties;
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;
80 * Goal which extracts the hibernate-mapping-configuration and
81 * exports an according SQL-database-schema.
84 * @phase process-classes
86 * @requiresDependencyResolution runtime
88 public class Hbm2DdlMojo extends AbstractMojo
90 public final static String EXPORT_SKIPPED_PROPERTY = "hibernate.export.skipped";
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";
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";
105 public final static String MD5S = "hibernate4-generatedschema.md5s";
107 private final static Pattern split = Pattern.compile("[^,\\s]+");
113 * Only needed internally.
115 * @parameter property="project"
119 private MavenProject project;
124 * Only needed internally.
126 * @parameter property="project.build.directory"
130 private String buildDirectory;
133 * Classes-Directory to scan.
135 * This parameter defaults to the maven build-output-directory for classes.
136 * Additionally, all dependencies are scanned for annotated classes.
138 * @parameter property="project.build.outputDirectory"
141 private String outputDirectory;
144 * Whether to scan test-classes too, or not.
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.
149 * @parameter property="hibernate.export.scan_testclasses" default-value="false"
152 private boolean scanTestClasses;
155 * Dependency-Scopes, that should be scanned for annotated classes.
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.
161 * If you do not want any dependencies to be scanned for annotated
162 * classes, set this parameter to <code>none</code>.
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.
168 * @parameter property="hibernate.export.scan_dependencies" default-value="compile"
171 private String scanDependencies;
174 * Test-Classes-Directory to scan.
176 * This parameter defaults to the maven build-output-directory for
179 * This parameter is only used, when <code>scanTestClasses</code> is set
180 * to <code>true</code>!
182 * @parameter property="project.build.testOutputDirectory"
185 private String testOutputDirectory;
190 * If set to <code>true</code>, the execution is skipped.
192 * A skipped execution is signaled via the maven-property
193 * <code>${hibernate.export.skipped}</code>.
195 * The execution is skipped automatically, if no modified or newly added
196 * annotated classes are found and the dialect was not changed.
198 * @parameter property="hibernate.skip" default-value="${maven.test.skip}"
201 private boolean skip;
206 * Force execution, even if no modified or newly added annotated classes
207 * where found and the dialect was not changed.
209 * <code>skip</code> takes precedence over <code>force</code>.
211 * @parameter property="hibernate.export.force" default-value="false"
214 private boolean force;
219 * @parameter property="hibernate.connection.driver_class"
222 private String driverClassName;
227 * @parameter property="hibernate.connection.url"
235 * @parameter property="hibernate.connection.username"
238 private String username;
243 * @parameter property="hibernate.connection.password"
246 private String password;
251 * @parameter property="hibernate.dialect"
254 private String hibernateDialect;
257 * Hibernate Naming Strategy
259 * @parameter property="hibernate.ejb.naming_strategy"
262 private String hibernateNamingStrategy;
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.
273 private String hibernateProperties;
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.
285 private String hibernateConfig;
288 * Name of the persistence-unit.
289 * If there is only one persistence-unit available, that unit will be used
291 * Settings in this file will overwrite settings in the properties or the
292 * configuration file.
297 private String persistenceUnit;
300 * List of Hibernate-Mapping-Files (XML).
301 * Multiple files can be separated with white-spaces and/or commas.
303 * @parameter property="hibernate.mapping"
306 private String hibernateMapping;
309 * Target of execution:
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>
317 * A database connection is only needed for EXPORT and BOTH, but a
318 * Hibernate-Dialect must always be chosen.
320 * @parameter property="hibernate.export.target" default-value="EXPORT"
323 private String target;
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>
334 * If NONE is choosen, no databaseconnection is needed.
336 * @parameter property="hibernate.export.type" default-value="BOTH"
344 * @parameter property="hibernate.export.schema.filename" default-value="${project.build.directory}/schema.sql"
347 private String outputFile;
350 * Delimiter in output-file.
352 * @parameter property="hibernate.export.schema.delimiter" default-value=";"
355 private String delimiter;
358 * Format output-file.
360 * @parameter property="hibernate.export.schema.format" default-value="true"
363 private boolean format;
366 * Generate envers schema for auditing tables.
368 * @parameter property="hibernate.export.envers" default-value="true"
371 private boolean envers;
375 public void execute()
377 MojoFailureException,
378 MojoExecutionException
382 getLog().info("Execution of hibernate4-maven-plugin:export was skipped!");
383 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
387 Map<String,String> md5s;
388 boolean modified = false;
389 File saved = new File(buildDirectory + File.separator + MD5S);
391 if (saved.isFile() && saved.length() > 0)
395 FileInputStream fis = new FileInputStream(saved);
396 ObjectInputStream ois = new ObjectInputStream(fis);
397 md5s = (HashMap<String,String>)ois.readObject();
402 md5s = new HashMap<String,String>();
403 getLog().warn("Cannot read timestamps from saved: " + e);
408 md5s = new HashMap<String,String>();
411 saved.createNewFile();
413 catch (IOException e)
415 getLog().debug("Cannot create file \"" + saved.getPath() + "\" for timestamps: " + e);
419 URLClassLoader classLoader = null;
422 getLog().debug("Creating ClassLoader for project-dependencies...");
423 List<String> classpathFiles = project.getCompileClasspathElements();
425 classpathFiles.addAll(project.getTestClasspathElements());
426 List<URL> urls = new LinkedList<URL>();
428 file = new File(testOutputDirectory);
431 getLog().info("creating test-output-directory: " + testOutputDirectory);
434 urls.add(file.toURI().toURL());
435 file = new File(outputDirectory);
438 getLog().info("creating output-directory: " + outputDirectory);
441 urls.add(file.toURI().toURL());
442 for (String pathElement : classpathFiles)
444 getLog().debug("Dependency: " + pathElement);
445 urls.add(new File(pathElement).toURI().toURL());
449 urls.toArray(new URL[urls.size()]),
450 getClass().getClassLoader()
455 getLog().error("Error while creating ClassLoader!", e);
456 throw new MojoExecutionException(e.getMessage());
459 Set<Class<?>> classes =
460 new TreeSet<Class<?>>(
461 new Comparator<Class<?>>() {
463 public int compare(Class<?> a, Class<?> b)
465 return a.getName().compareTo(b.getName());
472 AnnotationDB db = new AnnotationDB();
473 File dir = new File(outputDirectory);
476 getLog().info("Scanning directory " + outputDirectory + " for annotated classes...");
477 URL dirUrl = dir.toURI().toURL();
478 db.scanArchives(dirUrl);
482 dir = new File(testOutputDirectory);
485 getLog().info("Scanning directory " + testOutputDirectory + " for annotated classes...");
486 URL dirUrl = dir.toURI().toURL();
487 db.scanArchives(dirUrl);
490 if (scanDependencies != null)
492 Matcher matcher = split.matcher(scanDependencies);
493 while (matcher.find())
495 getLog().info("Scanning dependencies for scope " + matcher.group());
496 for (Artifact artifact : project.getDependencyArtifacts())
498 if (!artifact.getScope().equalsIgnoreCase(matcher.group()))
500 if (artifact.getFile() == null)
503 "Cannot scan dependency " +
505 ": no JAR-file available!"
510 "Scanning dependency " +
512 " for annotated classes..."
514 db.scanArchives(artifact.getFile().toURI().toURL());
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()));
527 MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
528 for (String name : classNames)
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";
536 .getResourceAsStream(resourceName);
537 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
539 while((i = is.read(buffer)) > -1)
540 digest.update(buffer, 0, i);
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))
548 getLog().debug("Found new or modified annotated class: " + name);
550 md5s.put(name, newMd5);
554 getLog().debug(oldMd5 + " -> class unchanged: " + name);
558 catch (ClassNotFoundException e)
560 getLog().error("Error while adding annotated classes!", e);
561 throw new MojoExecutionException(e.getMessage());
565 getLog().error("Error while scanning!", e);
566 throw new MojoFailureException(e.getMessage());
570 ValidationConfiguration config = new ValidationConfiguration();
571 // Clear unused system-properties
572 config.setProperties(new Properties());
575 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
576 StandardServiceRegistryImpl registry = null;
577 MavenLogAppender.startPluginLog(this);
582 * Change class-loader of current thread, so that hibernate can
583 * see all dependencies!
585 Thread.currentThread().setContextClassLoader(classLoader);
588 /** Try to read configuration from properties-file */
591 if (hibernateProperties == null)
593 URL url = classLoader.findResource("hibernate.properties");
596 getLog().info("No hibernate.properties on the classpath!");
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);
608 File file = new File(hibernateProperties);
611 getLog().info("Reading settings from file " + hibernateProperties + "...");
612 Properties properties = new Properties();
613 properties.load(new FileInputStream(file));
614 config.setProperties(properties);
617 getLog().info("No hibernate-properties-file found! (Checked path: " + hibernateProperties + ")");
620 catch (IOException e)
622 getLog().error("Error while reading properties!", e);
623 throw new MojoExecutionException(e.getMessage());
626 /** Try to read configuration from configuration-file */
629 if (hibernateConfig == null)
631 URL url = classLoader.findResource("hibernate.cfg.xml");
634 getLog().info("No hibernate.cfg.xml on the classpath!");
638 getLog().info("Reading settings from hibernate.cfg.xml on the classpath.");
639 config.configure(url);
644 File file = new File(hibernateConfig);
647 getLog().info("Reading configuration from file " + hibernateConfig + "...");
648 config.configure(file);
651 getLog().info("No hibernate-configuration-file found! (Checked path: " + hibernateConfig + ")");
656 getLog().error("Error while reading configuration!", e);
657 throw new MojoExecutionException(e.getMessage());
660 ParsedPersistenceXmlDescriptor persistenceUnitDescriptor =
661 getPersistenceUnitDescriptor(
663 config.getProperties(),
664 new MavenProjectClassLoaderService(classLoader)
666 if (persistenceUnitDescriptor != null)
667 config.setProperties(persistenceUnitDescriptor.getProperties());
670 /** Overwrite values from properties-file or set, if given */
672 if (driverClassName != null)
674 if (config.getProperties().containsKey(DRIVER_CLASS))
676 "Overwriting property " +
677 DRIVER_CLASS + "=" + config.getProperty(DRIVER_CLASS) +
678 " with the value " + driverClassName
681 getLog().debug("Using the value " + driverClassName);
682 config.setProperty(DRIVER_CLASS, driverClassName);
684 if (config.getProperty(DRIVER_CLASS) == null)
686 String driver = config.getProperty(JPA_DRIVER);
691 " is not set. Borrow setting from " +
695 config.setProperty(DRIVER_CLASS, driver);
701 if (config.getProperties().containsKey(URL))
703 "Overwriting property " +
704 URL + "=" + config.getProperty(URL) +
705 " with the value " + url
708 getLog().debug("Using the value " + url);
709 config.setProperty(URL, url);
711 if (config.getProperty(URL) == null)
713 String url = config.getProperty(JPA_URL);
718 " is not set. Borrow setting from " +
722 config.setProperty(URL, url);
726 if (username != null)
728 if (config.getProperties().containsKey(USERNAME))
730 "Overwriting property " +
731 USERNAME + "=" + config.getProperty(USERNAME) +
732 " with the value " + username
735 getLog().debug("Using the value " + username);
736 config.setProperty(USERNAME, username);
738 if (config.getProperty(USERNAME) == null)
740 String username = config.getProperty(JPA_USERNAME);
741 if (username != null)
745 " is not set. Borrow setting from " +
749 config.setProperty(USERNAME, username);
753 if (password != null)
755 if (config.getProperties().containsKey(PASSWORD))
757 "Overwriting property " +
758 PASSWORD + "=" + config.getProperty(PASSWORD) +
759 " with value " + password
762 getLog().debug("Using value " + password + " for property " + PASSWORD);
763 config.setProperty(PASSWORD, password);
765 if (config.getProperty(PASSWORD) == null)
767 String password = config.getProperty(JPA_PASSWORD);
768 if (password != null)
772 " is not set. Borrow setting from " +
776 config.setProperty(PASSWORD, password);
780 if (hibernateDialect != null)
782 if (config.getProperties().containsKey(DIALECT))
784 "Overwriting property " +
785 DIALECT + "=" + config.getProperty(DIALECT) +
786 " with value " + hibernateDialect
790 "Using value " + hibernateDialect + " for property " + DIALECT
792 config.setProperty(DIALECT, hibernateDialect);
795 if ( hibernateNamingStrategy != null )
797 if ( config.getProperties().contains(NAMING_STRATEGY))
799 "Overwriting property " +
800 NAMING_STRATEGY + "=" + config.getProperty(NAMING_STRATEGY) +
801 " with value " + hibernateNamingStrategy
805 "Using value " + hibernateNamingStrategy + " for property " +
808 config.setProperty(NAMING_STRATEGY, hibernateNamingStrategy);
811 /** The generated SQL varies with the dialect! */
812 if (md5s.containsKey(DIALECT))
814 String dialect = config.getProperty(DIALECT);
815 if (md5s.get(DIALECT).equals(dialect))
816 getLog().debug("SQL-dialect unchanged.");
822 getLog().debug("SQL-dialect was unset.");
823 md5s.remove(DIALECT);
827 getLog().debug("SQL-dialect changed: " + dialect);
828 md5s.put(DIALECT, dialect);
834 String dialect = config.getProperty(DIALECT);
838 md5s.put(DIALECT, config.getProperty(DIALECT));
842 /** The generated SQL varies with the envers-configuration */
843 if (md5s.get(ENVERS) != null)
845 if (md5s.get(ENVERS).equals(Boolean.toString(envers)))
846 getLog().debug("Envers-Configuration unchanged. Enabled: " + envers);
849 getLog().debug("Envers-Configuration changed. Enabled: " + envers);
851 md5s.put(ENVERS, Boolean.toString(envers));
857 md5s.put(ENVERS, Boolean.toString(envers));
860 if (config.getProperties().isEmpty())
862 getLog().error("No properties set!");
863 throw new MojoFailureException("Hibernate configuration is missing!");
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());
871 getLog().debug("Adding explicitly configured mappings...");
872 if (hibernateMapping != null)
876 MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
877 for (String filename : hibernateMapping.split("[\\s,]+"))
879 // First try the filename as absolute/relative path
880 File file = new File(filename);
883 // If the file was not found, search for it in the resource-directories
884 for (Resource resource : project.getResources())
886 file = new File(resource.getDirectory() + File.separator + filename);
891 if (file != null && file.exists())
893 InputStream is = new FileInputStream(file);
894 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
896 while((i = is.read(buffer)) > -1)
897 digest.update(buffer, 0, i);
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))
905 getLog().debug("Found new or modified mapping-file: " + filename);
907 md5s.put(filename, newMd5);
911 getLog().debug(oldMd5 + " -> mapping-file unchanged: " + filename);
913 getLog().debug("Adding mappings from XML-configurationfile: " + file);
914 config.addFile(file);
917 throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!");
920 catch (NoSuchAlgorithmException e)
922 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
924 catch (FileNotFoundException e)
926 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
928 catch (IOException e)
930 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
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)
939 String packageName = annotatedClass.getPackage().getName();
940 if (!packages.contains(packageName))
942 getLog().debug("Add package " + packageName);
943 packages.add(packageName);
944 config.addPackage(packageName);
945 getLog().debug("type definintions" + config.getTypeDefs());
947 getLog().debug("Class " + annotatedClass);
948 config.addAnnotatedClass(annotatedClass);
951 Target target = null;
954 target = Target.valueOf(this.target.toUpperCase());
956 catch (IllegalArgumentException e)
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\"");
965 type = Type.valueOf(this.type.toUpperCase());
967 catch (IllegalArgumentException e)
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\"");
975 if (config.getProperty(DIALECT) == null)
976 throw new MojoFailureException("hibernate-dialect must be set!");
979 if (target.equals(Target.SCRIPT) || target.equals(Target.NONE))
981 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
985 && !target.equals(Target.SCRIPT)
986 && !target.equals(Target.NONE)
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");
997 if ( config.getProperties().containsKey(NAMING_STRATEGY))
999 String namingStrategy = config.getProperty(NAMING_STRATEGY);
1000 getLog().debug("Explicitly set NamingStrategy: " + namingStrategy);
1003 @SuppressWarnings("unchecked")
1004 Class<NamingStrategy> namingStrategyClass = (Class<NamingStrategy>) Class.forName(namingStrategy);
1005 config.setNamingStrategy(namingStrategyClass.newInstance());
1009 getLog().error("Error setting NamingStrategy", e);
1010 throw new MojoExecutionException(e.getMessage());
1015 Environment.verifyProperties(config.getProperties());
1016 ConfigurationHelper.resolvePlaceHolders(config.getProperties());
1018 (StandardServiceRegistryImpl)
1019 new StandardServiceRegistryBuilder()
1020 .applySettings(config.getProperties())
1023 config.buildMappings();
1027 getLog().info("Automatic auditing via hibernate-envers enabled!");
1028 AuditConfiguration.getFor(config);
1031 SchemaExport export = new SchemaExport(registry, config);
1032 export.setDelimiter(delimiter);
1033 export.setFormat(format);
1035 File outF = new File(outputFile);
1037 if (!outF.isAbsolute())
1039 // Interpret relative file path relative to build directory
1040 outF = new File(buildDirectory, outputFile);
1041 getLog().info("Adjusted relative path, resulting path is " + outF.getPath());
1044 // Ensure that directory path for specified file exists
1045 File outFileParentDir = outF.getParentFile();
1046 if (null != outFileParentDir && !outFileParentDir.exists())
1050 getLog().info("Creating directory path for output file:" + outFileParentDir.getPath());
1051 outFileParentDir.mkdirs();
1055 getLog().error("Error creating directory path for output file: " + e.getLocalizedMessage());
1059 export.setOutputFile(outF.getPath());
1060 export.execute(target, type);
1062 for (Object exception : export.getExceptions())
1063 getLog().debug(exception.toString());
1067 /** Stop Log-Capturing */
1068 MavenLogAppender.endPluginLog(this);
1070 /** Restore the old class-loader (TODO: is this really necessary?) */
1071 Thread.currentThread().setContextClassLoader(contextClassLoader);
1073 if (registry != null)
1077 /** Write md5-sums for annotated classes to file */
1080 FileOutputStream fos = new FileOutputStream(saved);
1081 ObjectOutputStream oos = new ObjectOutputStream(fos);
1082 oos.writeObject(md5s);
1088 getLog().error("Cannot write md5-sums to file: " + e);
1092 private ParsedPersistenceXmlDescriptor getPersistenceUnitDescriptor(
1094 Properties properties,
1095 ClassLoaderService loader
1098 MojoFailureException
1100 PersistenceXmlParser parser =
1101 new PersistenceXmlParser(
1103 PersistenceUnitTransactionType.RESOURCE_LOCAL
1106 List<ParsedPersistenceXmlDescriptor> units = parser.doResolve(properties);
1110 switch (units.size())
1113 getLog().info("Found no META-INF/persistence.xml.");
1116 getLog().info("Using persistence-unit " + units.get(0).getName());
1117 return units.get(0);
1119 getLog().warn("No name provided and multiple persistence units found:");
1120 for (ParsedPersistenceXmlDescriptor unit : units)
1121 getLog().warn(" - " + unit.getName());
1127 for (ParsedPersistenceXmlDescriptor unit : units)
1129 getLog().debug("Found persistence-unit " + unit.getName());
1130 if (!unit.getName().equals(name))
1133 // See if we (Hibernate) are the persistence provider
1134 if (!ProviderChecker.isProvider(unit, properties))
1136 getLog().debug("Wrong provider: " + unit.getProviderClassName());
1140 getLog().info("Using persistence-unit " + unit.getName());
1144 throw new MojoFailureException("Could not find persistence-unit " + name);
1148 static final class MavenProjectClassLoaderService implements ClassLoaderService
1150 final private ClassLoader loader;
1153 public MavenProjectClassLoaderService(ClassLoader loader)
1155 this.loader = loader;
1160 public <T> Class<T> classForName(String name)
1164 return (Class<T>)loader.loadClass(name);
1166 catch (ClassNotFoundException e)
1168 throw new ClassLoadingException( "Unable to load class [" + name + "]", e );
1173 public URL locateResource(String name)
1175 return loader.getResource(name);
1179 public InputStream locateResourceStream(String name)
1181 return loader.getResourceAsStream(name);
1185 public List<URL> locateResources(String name)
1189 return Collections.list(loader.getResources(name));
1191 catch (IOException e)
1193 return Collections.EMPTY_LIST;
1198 public <S> LinkedHashSet<S> loadJavaServices(Class<S> serviceContract)
1200 throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1204 public void stop() { }
1210 * Needed, because DriverManager won't pick up drivers, that were not
1211 * loaded by the system-classloader!
1213 * http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-fromodifiedm-an-arbitrary-location
1215 static final class DriverProxy implements Driver
1217 private final Driver target;
1219 DriverProxy(Driver target)
1222 throw new NullPointerException();
1223 this.target = target;
1226 public java.sql.Driver getTarget()
1232 public boolean acceptsURL(String url) throws SQLException
1234 return target.acceptsURL(url);
1238 public java.sql.Connection connect(
1240 java.util.Properties info
1245 return target.connect(url, info);
1249 public int getMajorVersion()
1251 return target.getMajorVersion();
1255 public int getMinorVersion()
1257 return target.getMinorVersion();
1261 public DriverPropertyInfo[] getPropertyInfo(
1268 return target.getPropertyInfo(url, info);
1272 public boolean jdbcCompliant()
1274 return target.jdbcCompliant();
1278 * This Method cannot be annotated with @Override, becaus the plugin
1279 * will not compile then under Java 1.6!
1281 public Logger getParentLogger() throws SQLFeatureNotSupportedException
1283 throw new SQLFeatureNotSupportedException("Not supported, for backward-compatibility with Java 1.6");
1287 public String toString()
1289 return "Proxy: " + target;
1293 public int hashCode()
1295 return target.hashCode();
1299 public boolean equals(Object obj)
1301 if (!(obj instanceof DriverProxy))
1303 DriverProxy other = (DriverProxy) obj;
1304 return this.target.equals(other.target);