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 MD5S = "hibernate4-generatedschema.md5s";
102 private final static Pattern split = Pattern.compile("[^,\\s]+");
108 * Only needed internally.
110 * @parameter property="project"
114 private MavenProject project;
119 * Only needed internally.
121 * @parameter property="project.build.directory"
125 private String buildDirectory;
128 * Classes-Directory to scan.
130 * This parameter defaults to the maven build-output-directory for classes.
131 * Additionally, all dependencies are scanned for annotated classes.
133 * @parameter property="project.build.outputDirectory"
136 private String outputDirectory;
139 * Whether to scan test-classes too, or not.
141 * If this parameter is set to <code>true</code> the test-classes of the
142 * artifact will be scanned for hibernate-annotated classes additionally.
144 * @parameter property="hibernate.export.scan_testclasses" default-value="false"
147 private boolean scanTestClasses;
150 * Dependency-Scopes, that should be scanned for annotated classes.
152 * By default, only dependencies in the scope <code>compile</code> are
153 * scanned for annotated classes. Multiple scopes can be seperated by
154 * white space or commas.
156 * If you do not want any dependencies to be scanned for annotated
157 * classes, set this parameter to <code>none</code>.
159 * The plugin does not scan for annotated classes in transitive
160 * dependencies. If some of your annotated classes are hidden in a
161 * transitive dependency, you can simply add that dependency explicitly.
163 * @parameter property="hibernate.export.scan_dependencies" default-value="compile"
166 private String scanDependencies;
169 * Test-Classes-Directory to scan.
171 * This parameter defaults to the maven build-output-directory for
174 * This parameter is only used, when <code>scanTestClasses</code> is set
175 * to <code>true</code>!
177 * @parameter property="project.build.testOutputDirectory"
180 private String testOutputDirectory;
185 * If set to <code>true</code>, the execution is skipped.
187 * A skipped execution is signaled via the maven-property
188 * <code>${hibernate.export.skipped}</code>.
190 * The execution is skipped automatically, if no modified or newly added
191 * annotated classes are found and the dialect was not changed.
193 * @parameter property="hibernate.skip" default-value="${maven.test.skip}"
196 private boolean skip;
201 * Force execution, even if no modified or newly added annotated classes
202 * where found and the dialect was not changed.
204 * <code>skip</code> takes precedence over <code>force</code>.
206 * @parameter property="hibernate.export.force" default-value="false"
209 private boolean force;
214 * @parameter property="hibernate.connection.driver_class"
217 private String driverClassName;
222 * @parameter property="hibernate.connection.url"
230 * @parameter property="hibernate.connection.username"
233 private String username;
238 * @parameter property="hibernate.connection.password"
241 private String password;
246 * @parameter property="hibernate.dialect"
249 private String hibernateDialect;
252 * Hibernate Naming Strategy
254 * @parameter property="hibernate.ejb.naming_strategy"
257 private String hibernateNamingStrategy;
260 * Path to Hibernate properties file.
261 * If this parameter is not set the plugin will try to load the configuration
262 * from a file <code>hibernate.properties</code> on the classpath. The
263 * test-classpath takes precedence.
268 private String hibernateProperties;
271 * Path to Hibernate configuration file (.cfg.xml).
272 * Settings in this file will overwrite settings in the properties file.
273 * If this parameter is not set the plugin will try to load the configuration
274 * from a file <code>hibernate.cfg.xml</code> on the classpath. The
275 * test-classpath takes precedence.
280 private String hibernateConfig;
283 * Name of the persistence-unit.
284 * If there is only one persistence-unit available, that unit will be used
286 * Settings in this file will overwrite settings in the properties or the
287 * configuration file.
292 private String persistenceUnit;
295 * List of Hibernate-Mapping-Files (XML).
296 * Multiple files can be separated with white-spaces and/or commas.
298 * @parameter property="hibernate.mapping"
301 private String hibernateMapping;
304 * Target of execution:
306 * <li><strong>NONE</strong> only export schema to SQL-script (forces execution, signals skip)</li>
307 * <li><strong>EXPORT</strong> create database (<strong>DEFAULT!</strong>). forces execution, signals skip)</li>
308 * <li><strong>SCRIPT</strong> export schema to SQL-script and print it to STDOUT</li>
309 * <li><strong>BOTH</strong></li>
312 * A database connection is only needed for EXPORT and BOTH, but a
313 * Hibernate-Dialect must always be chosen.
315 * @parameter property="hibernate.export.target" default-value="EXPORT"
318 private String target;
323 * <li><strong>NONE</strong> do nothing - just validate the configuration</li>
324 * <li><strong>CREATE</strong> create database-schema</li>
325 * <li><strong>DROP</strong> drop database-schema</li>
326 * <li><strong>BOTH</strong> (<strong>DEFAULT!</strong>)</li>
329 * If NONE is choosen, no databaseconnection is needed.
331 * @parameter property="hibernate.export.type" default-value="BOTH"
339 * @parameter property="hibernate.export.schema.filename" default-value="${project.build.directory}/schema.sql"
342 private String outputFile;
345 * Delimiter in output-file.
347 * @parameter property="hibernate.export.schema.delimiter" default-value=";"
350 private String delimiter;
353 * Format output-file.
355 * @parameter property="hibernate.export.schema.format" default-value="true"
358 private boolean format;
361 * Generate envers schema for auditing tables.
363 * @parameter property="hibernate.export.envers" default-value="true"
366 private boolean envers;
370 public void execute()
372 MojoFailureException,
373 MojoExecutionException
377 getLog().info("Execution of hibernate4-maven-plugin:export was skipped!");
378 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
382 Map<String,String> md5s;
383 boolean modified = false;
384 File saved = new File(buildDirectory + File.separator + MD5S);
386 if (saved.isFile() && saved.length() > 0)
390 FileInputStream fis = new FileInputStream(saved);
391 ObjectInputStream ois = new ObjectInputStream(fis);
392 md5s = (HashMap<String,String>)ois.readObject();
397 md5s = new HashMap<String,String>();
398 getLog().warn("Cannot read timestamps from saved: " + e);
403 md5s = new HashMap<String,String>();
406 saved.createNewFile();
408 catch (IOException e)
410 getLog().debug("Cannot create file \"" + saved.getPath() + "\" for timestamps: " + e);
414 URLClassLoader classLoader = null;
417 getLog().debug("Creating ClassLoader for project-dependencies...");
418 List<String> classpathFiles = project.getCompileClasspathElements();
420 classpathFiles.addAll(project.getTestClasspathElements());
421 List<URL> urls = new LinkedList<URL>();
423 file = new File(testOutputDirectory);
426 getLog().info("creating test-output-directory: " + testOutputDirectory);
429 urls.add(file.toURI().toURL());
430 file = new File(outputDirectory);
433 getLog().info("creating output-directory: " + outputDirectory);
436 urls.add(file.toURI().toURL());
437 for (String pathElement : classpathFiles)
439 getLog().debug("Dependency: " + pathElement);
440 urls.add(new File(pathElement).toURI().toURL());
444 urls.toArray(new URL[urls.size()]),
445 getClass().getClassLoader()
450 getLog().error("Error while creating ClassLoader!", e);
451 throw new MojoExecutionException(e.getMessage());
454 Set<Class<?>> classes =
455 new TreeSet<Class<?>>(
456 new Comparator<Class<?>>() {
458 public int compare(Class<?> a, Class<?> b)
460 return a.getName().compareTo(b.getName());
467 AnnotationDB db = new AnnotationDB();
468 File dir = new File(outputDirectory);
471 getLog().info("Scanning directory " + outputDirectory + " for annotated classes...");
472 URL dirUrl = dir.toURI().toURL();
473 db.scanArchives(dirUrl);
477 dir = new File(testOutputDirectory);
480 getLog().info("Scanning directory " + testOutputDirectory + " for annotated classes...");
481 URL dirUrl = dir.toURI().toURL();
482 db.scanArchives(dirUrl);
485 if (scanDependencies != null)
487 Matcher matcher = split.matcher(scanDependencies);
488 while (matcher.find())
490 getLog().info("Scanning dependencies for scope " + matcher.group());
491 for (Artifact artifact : project.getDependencyArtifacts())
493 if (!artifact.getScope().equalsIgnoreCase(matcher.group()))
495 if (artifact.getFile() == null)
498 "Cannot scan dependency " +
500 ": no JAR-file available!"
505 "Scanning dependency " +
507 " for annotated classes..."
509 db.scanArchives(artifact.getFile().toURI().toURL());
514 Set<String> classNames = new HashSet<String>();
515 if (db.getAnnotationIndex().containsKey(Entity.class.getName()))
516 classNames.addAll(db.getAnnotationIndex().get(Entity.class.getName()));
517 if (db.getAnnotationIndex().containsKey(MappedSuperclass.class.getName()))
518 classNames.addAll(db.getAnnotationIndex().get(MappedSuperclass.class.getName()));
519 if (db.getAnnotationIndex().containsKey(Embeddable.class.getName()))
520 classNames.addAll(db.getAnnotationIndex().get(Embeddable.class.getName()));
522 MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
523 for (String name : classNames)
525 Class<?> annotatedClass = classLoader.loadClass(name);
526 classes.add(annotatedClass);
527 String resourceName = annotatedClass.getName();
528 resourceName = resourceName.substring(resourceName.lastIndexOf(".") + 1, resourceName.length()) + ".class";
531 .getResourceAsStream(resourceName);
532 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
534 while((i = is.read(buffer)) > -1)
535 digest.update(buffer, 0, i);
537 byte[] bytes = digest.digest();
538 BigInteger bi = new BigInteger(1, bytes);
539 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
540 String oldMd5 = !md5s.containsKey(name) ? "" : md5s.get(name);
541 if (!newMd5.equals(oldMd5))
543 getLog().debug("Found new or modified annotated class: " + name);
545 md5s.put(name, newMd5);
549 getLog().debug(oldMd5 + " -> class unchanged: " + name);
553 catch (ClassNotFoundException e)
555 getLog().error("Error while adding annotated classes!", e);
556 throw new MojoExecutionException(e.getMessage());
560 getLog().error("Error while scanning!", e);
561 throw new MojoFailureException(e.getMessage());
565 ValidationConfiguration config = new ValidationConfiguration();
566 // Clear unused system-properties
567 config.setProperties(new Properties());
570 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
571 StandardServiceRegistryImpl registry = null;
572 MavenLogAppender.startPluginLog(this);
577 * Change class-loader of current thread, so that hibernate can
578 * see all dependencies!
580 Thread.currentThread().setContextClassLoader(classLoader);
583 /** Try to read configuration from properties-file */
586 if (hibernateProperties == null)
588 URL url = classLoader.findResource("hibernate.properties");
591 getLog().info("No hibernate.properties on the classpath!");
595 getLog().info("Reading settings from hibernate.properties on the classpath.");
596 Properties properties = new Properties();
597 properties.load(url.openStream());
598 config.setProperties(properties);
603 File file = new File(hibernateProperties);
606 getLog().info("Reading settings from file " + hibernateProperties + "...");
607 Properties properties = new Properties();
608 properties.load(new FileInputStream(file));
609 config.setProperties(properties);
612 getLog().info("No hibernate-properties-file found! (Checked path: " + hibernateProperties + ")");
615 catch (IOException e)
617 getLog().error("Error while reading properties!", e);
618 throw new MojoExecutionException(e.getMessage());
621 /** Try to read configuration from configuration-file */
624 if (hibernateConfig == null)
626 URL url = classLoader.findResource("hibernate.cfg.xml");
629 getLog().info("No hibernate.cfg.xml on the classpath!");
633 getLog().info("Reading settings from hibernate.cfg.xml on the classpath.");
634 config.configure(url);
639 File file = new File(hibernateConfig);
642 getLog().info("Reading configuration from file " + hibernateConfig + "...");
643 config.configure(file);
646 getLog().info("No hibernate-configuration-file found! (Checked path: " + hibernateConfig + ")");
651 getLog().error("Error while reading configuration!", e);
652 throw new MojoExecutionException(e.getMessage());
655 ParsedPersistenceXmlDescriptor persistenceUnitDescriptor =
656 getPersistenceUnitDescriptor(
658 config.getProperties(),
659 new MavenProjectClassLoaderService(classLoader)
661 if (persistenceUnitDescriptor != null)
662 config.setProperties(persistenceUnitDescriptor.getProperties());
664 /** Overwrite values from properties-file or set, if given */
665 if (driverClassName != null)
667 if (config.getProperties().containsKey(DRIVER_CLASS))
669 "Overwriting property " +
670 DRIVER_CLASS + "=" + config.getProperty(DRIVER_CLASS) +
671 " with the value " + driverClassName
674 getLog().debug("Using the value " + driverClassName);
675 config.setProperty(DRIVER_CLASS, driverClassName);
679 if (config.getProperties().containsKey(URL))
681 "Overwriting property " +
682 URL + "=" + config.getProperty(URL) +
683 " with the value " + url
686 getLog().debug("Using the value " + url);
687 config.setProperty(URL, url);
689 if (username != null)
691 if (config.getProperties().containsKey(USERNAME))
693 "Overwriting property " +
694 USERNAME + "=" + config.getProperty(USERNAME) +
695 " with the value " + username
698 getLog().debug("Using the value " + username);
699 config.setProperty(USERNAME, username);
701 if (password != null)
703 if (config.getProperties().containsKey(PASSWORD))
705 "Overwriting property " +
706 PASSWORD + "=" + config.getProperty(PASSWORD) +
707 " with value " + password
710 getLog().debug("Using value " + password + " for property " + PASSWORD);
711 config.setProperty(PASSWORD, password);
713 if (hibernateDialect != null)
715 if (config.getProperties().containsKey(DIALECT))
717 "Overwriting property " +
718 DIALECT + "=" + config.getProperty(DIALECT) +
719 " with value " + hibernateDialect
723 "Using value " + hibernateDialect + " for property " + DIALECT
725 config.setProperty(DIALECT, hibernateDialect);
727 if ( hibernateNamingStrategy != null )
729 if ( config.getProperties().contains(NAMING_STRATEGY))
731 "Overwriting property " +
732 NAMING_STRATEGY + "=" + config.getProperty(NAMING_STRATEGY) +
733 " with value " + hibernateNamingStrategy
737 "Using value " + hibernateNamingStrategy + " for property " +
740 config.setProperty(NAMING_STRATEGY, hibernateNamingStrategy);
743 /** The generated SQL varies with the dialect! */
744 if (md5s.containsKey(DIALECT))
746 String dialect = config.getProperty(DIALECT);
747 if (md5s.get(DIALECT).equals(dialect))
748 getLog().debug("SQL-dialect unchanged.");
754 getLog().debug("SQL-dialect was unset.");
755 md5s.remove(DIALECT);
759 getLog().debug("SQL-dialect changed: " + dialect);
760 md5s.put(DIALECT, dialect);
766 String dialect = config.getProperty(DIALECT);
770 md5s.put(DIALECT, config.getProperty(DIALECT));
774 /** The generated SQL varies with the envers-configuration */
775 if (md5s.get(ENVERS) != null)
777 if (md5s.get(ENVERS).equals(Boolean.toString(envers)))
778 getLog().debug("Envers-Configuration unchanged. Enabled: " + envers);
781 getLog().debug("Envers-Configuration changed. Enabled: " + envers);
783 md5s.put(ENVERS, Boolean.toString(envers));
789 md5s.put(ENVERS, Boolean.toString(envers));
792 if (config.getProperties().isEmpty())
794 getLog().error("No properties set!");
795 throw new MojoFailureException("Hibernate configuration is missing!");
798 getLog().info("Gathered hibernate-configuration (turn on debugging for details):");
799 for (Entry<Object,Object> entry : config.getProperties().entrySet())
800 getLog().info(" " + entry.getKey() + " = " + entry.getValue());
803 getLog().debug("Adding explicitly configured mappings...");
804 if (hibernateMapping != null)
808 MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
809 for (String filename : hibernateMapping.split("[\\s,]+"))
811 // First try the filename as absolute/relative path
812 File file = new File(filename);
815 // If the file was not found, search for it in the resource-directories
816 for (Resource resource : project.getResources())
818 file = new File(resource.getDirectory() + File.separator + filename);
823 if (file != null && file.exists())
825 InputStream is = new FileInputStream(file);
826 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
828 while((i = is.read(buffer)) > -1)
829 digest.update(buffer, 0, i);
831 byte[] bytes = digest.digest();
832 BigInteger bi = new BigInteger(1, bytes);
833 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
834 String oldMd5 = !md5s.containsKey(filename) ? "" : md5s.get(filename);
835 if (!newMd5.equals(oldMd5))
837 getLog().debug("Found new or modified mapping-file: " + filename);
839 md5s.put(filename, newMd5);
843 getLog().debug(oldMd5 + " -> mapping-file unchanged: " + filename);
845 getLog().debug("Adding mappings from XML-configurationfile: " + file);
846 config.addFile(file);
849 throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!");
852 catch (NoSuchAlgorithmException e)
854 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
856 catch (FileNotFoundException e)
858 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
860 catch (IOException e)
862 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
866 getLog().debug("Adding annotated classes to hibernate-mapping-configuration...");
867 // build annotated packages
868 Set<String> packages = new HashSet<String>();
869 for (Class<?> annotatedClass : classes)
871 String packageName = annotatedClass.getPackage().getName();
872 if (!packages.contains(packageName))
874 getLog().debug("Add package " + packageName);
875 packages.add(packageName);
876 config.addPackage(packageName);
877 getLog().debug("type definintions" + config.getTypeDefs());
879 getLog().debug("Class " + annotatedClass);
880 config.addAnnotatedClass(annotatedClass);
883 Target target = null;
886 target = Target.valueOf(this.target.toUpperCase());
888 catch (IllegalArgumentException e)
890 getLog().error("Invalid value for configuration-option \"target\": " + this.target);
891 getLog().error("Valid values are: NONE, SCRIPT, EXPORT, BOTH");
892 throw new MojoExecutionException("Invalid value for configuration-option \"target\"");
897 type = Type.valueOf(this.type.toUpperCase());
899 catch (IllegalArgumentException e)
901 getLog().error("Invalid value for configuration-option \"type\": " + this.type);
902 getLog().error("Valid values are: NONE, CREATE, DROP, BOTH");
903 throw new MojoExecutionException("Invalid value for configuration-option \"type\"");
907 if (config.getProperty(DIALECT) == null)
908 throw new MojoFailureException("hibernate-dialect must be set!");
911 if (target.equals(Target.SCRIPT) || target.equals(Target.NONE))
913 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
917 && !target.equals(Target.SCRIPT)
918 && !target.equals(Target.NONE)
922 getLog().info("No modified annotated classes or mapping-files found and dialect unchanged.");
923 getLog().info("Skipping schema generation!");
924 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
929 if ( config.getProperties().containsKey(NAMING_STRATEGY))
931 String namingStrategy = config.getProperty(NAMING_STRATEGY);
932 getLog().debug("Explicitly set NamingStrategy: " + namingStrategy);
935 @SuppressWarnings("unchecked")
936 Class<NamingStrategy> namingStrategyClass = (Class<NamingStrategy>) Class.forName(namingStrategy);
937 config.setNamingStrategy(namingStrategyClass.newInstance());
941 getLog().error("Error setting NamingStrategy", e);
942 throw new MojoExecutionException(e.getMessage());
947 Environment.verifyProperties(config.getProperties());
948 ConfigurationHelper.resolvePlaceHolders(config.getProperties());
950 (StandardServiceRegistryImpl)
951 new StandardServiceRegistryBuilder()
952 .applySettings(config.getProperties())
955 config.buildMappings();
959 getLog().info("Automatic auditing via hibernate-envers enabled!");
960 AuditConfiguration.getFor(config);
963 SchemaExport export = new SchemaExport(registry, config);
964 export.setDelimiter(delimiter);
965 export.setFormat(format);
967 File outF = new File(outputFile);
969 if (!outF.isAbsolute())
971 // Interpret relative file path relative to build directory
972 outF = new File(buildDirectory, outputFile);
973 getLog().info("Adjusted relative path, resulting path is " + outF.getPath());
976 // Ensure that directory path for specified file exists
977 File outFileParentDir = outF.getParentFile();
978 if (null != outFileParentDir && !outFileParentDir.exists())
982 getLog().info("Creating directory path for output file:" + outFileParentDir.getPath());
983 outFileParentDir.mkdirs();
987 getLog().error("Error creating directory path for output file: " + e.getLocalizedMessage());
991 export.setOutputFile(outF.getPath());
992 export.execute(target, type);
994 for (Object exception : export.getExceptions())
995 getLog().debug(exception.toString());
999 /** Stop Log-Capturing */
1000 MavenLogAppender.endPluginLog(this);
1002 /** Restore the old class-loader (TODO: is this really necessary?) */
1003 Thread.currentThread().setContextClassLoader(contextClassLoader);
1005 if (registry != null)
1009 /** Write md5-sums for annotated classes to file */
1012 FileOutputStream fos = new FileOutputStream(saved);
1013 ObjectOutputStream oos = new ObjectOutputStream(fos);
1014 oos.writeObject(md5s);
1020 getLog().error("Cannot write md5-sums to file: " + e);
1024 private ParsedPersistenceXmlDescriptor getPersistenceUnitDescriptor(
1026 Properties properties,
1027 ClassLoaderService loader
1030 MojoFailureException
1032 PersistenceXmlParser parser =
1033 new PersistenceXmlParser(
1035 PersistenceUnitTransactionType.RESOURCE_LOCAL
1038 List<ParsedPersistenceXmlDescriptor> units = parser.doResolve(properties);
1042 switch (units.size())
1045 getLog().info("Found no META-INF/persistence.xml.");
1048 getLog().info("Using persistence-unit " + units.get(0).getName());
1049 return units.get(0);
1051 getLog().warn("No name provided and multiple persistence units found:");
1052 for (ParsedPersistenceXmlDescriptor unit : units)
1053 getLog().warn(" - " + unit.getName());
1059 for (ParsedPersistenceXmlDescriptor unit : units)
1061 getLog().debug("Found persistence-unit " + unit.getName());
1062 if (!unit.getName().equals(name))
1065 // See if we (Hibernate) are the persistence provider
1066 if (!ProviderChecker.isProvider(unit, properties))
1068 getLog().debug("Wrong provider: " + unit.getProviderClassName());
1072 getLog().info("Using persistence-unit " + unit.getName());
1076 throw new MojoFailureException("Could not find persistence-unit " + name);
1080 static final class MavenProjectClassLoaderService implements ClassLoaderService
1082 final private ClassLoader loader;
1085 public MavenProjectClassLoaderService(ClassLoader loader)
1087 this.loader = loader;
1092 public <T> Class<T> classForName(String name)
1096 return (Class<T>)loader.loadClass(name);
1098 catch (ClassNotFoundException e)
1100 throw new ClassLoadingException( "Unable to load class [" + name + "]", e );
1105 public URL locateResource(String name)
1107 return loader.getResource(name);
1111 public InputStream locateResourceStream(String name)
1113 return loader.getResourceAsStream(name);
1117 public List<URL> locateResources(String name)
1121 return Collections.list(loader.getResources(name));
1123 catch (IOException e)
1125 return Collections.EMPTY_LIST;
1130 public <S> LinkedHashSet<S> loadJavaServices(Class<S> serviceContract)
1132 throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1136 public void stop() { }
1142 * Needed, because DriverManager won't pick up drivers, that were not
1143 * loaded by the system-classloader!
1145 * http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-fromodifiedm-an-arbitrary-location
1147 static final class DriverProxy implements Driver
1149 private final Driver target;
1151 DriverProxy(Driver target)
1154 throw new NullPointerException();
1155 this.target = target;
1158 public java.sql.Driver getTarget()
1164 public boolean acceptsURL(String url) throws SQLException
1166 return target.acceptsURL(url);
1170 public java.sql.Connection connect(
1172 java.util.Properties info
1177 return target.connect(url, info);
1181 public int getMajorVersion()
1183 return target.getMajorVersion();
1187 public int getMinorVersion()
1189 return target.getMinorVersion();
1193 public DriverPropertyInfo[] getPropertyInfo(
1200 return target.getPropertyInfo(url, info);
1204 public boolean jdbcCompliant()
1206 return target.jdbcCompliant();
1210 * This Method cannot be annotated with @Override, becaus the plugin
1211 * will not compile then under Java 1.6!
1213 public Logger getParentLogger() throws SQLFeatureNotSupportedException
1215 throw new SQLFeatureNotSupportedException("Not supported, for backward-compatibility with Java 1.6");
1219 public String toString()
1221 return "Proxy: " + target;
1225 public int hashCode()
1227 return target.hashCode();
1231 public boolean equals(Object obj)
1233 if (!(obj instanceof DriverProxy))
1235 DriverProxy other = (DriverProxy) obj;
1236 return this.target.equals(other.target);