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.Iterator;
42 import java.util.LinkedHashSet;
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.mapping.PersistentClass;
74 import org.hibernate.tool.hbm2ddl.SchemaExport;
75 import org.hibernate.tool.hbm2ddl.SchemaExport.Type;
76 import org.hibernate.tool.hbm2ddl.Target;
77 import org.scannotation.AnnotationDB;
81 * Goal which extracts the hibernate-mapping-configuration and
82 * exports an according SQL-database-schema.
85 * @phase process-classes
87 * @requiresDependencyResolution runtime
89 public class Hbm2DdlMojo extends AbstractMojo
91 public final static String EXPORT_SKIPPED_PROPERTY = "hibernate.export.skipped";
93 public final static String DRIVER_CLASS = "hibernate.connection.driver_class";
94 public final static String URL = "hibernate.connection.url";
95 public final static String USERNAME = "hibernate.connection.username";
96 public final static String PASSWORD = "hibernate.connection.password";
97 public final static String DIALECT = "hibernate.dialect";
98 public final static String NAMING_STRATEGY="hibernate.ejb.naming_strategy";
99 public final static String ENVERS = "hibernate.export.envers";
101 public final static String MD5S = "hibernate4-generatedschema.md5s";
103 private final static Pattern split = Pattern.compile("[^,\\s]+");
109 * Only needed internally.
111 * @parameter property="project"
115 private MavenProject project;
120 * Only needed internally.
122 * @parameter property="project.build.directory"
126 private String buildDirectory;
129 * Classes-Directory to scan.
131 * This parameter defaults to the maven build-output-directory for classes.
132 * Additionally, all dependencies are scanned for annotated classes.
134 * @parameter property="project.build.outputDirectory"
137 private String outputDirectory;
140 * Whether to scan test-classes too, or not.
142 * If this parameter is set to <code>true</code> the test-classes of the
143 * artifact will be scanned for hibernate-annotated classes additionally.
145 * @parameter property="hibernate.export.scan_testclasses" default-value="false"
148 private boolean scanTestClasses;
151 * Dependency-Scopes, that should be scanned for annotated classes.
153 * By default, only dependencies in the scope <code>compile</code> are
154 * scanned for annotated classes. Multiple scopes can be seperated by
155 * white space or commas.
157 * If you do not want any dependencies to be scanned for annotated
158 * classes, set this parameter to <code>none</code>.
160 * The plugin does not scan for annotated classes in transitive
161 * dependencies. If some of your annotated classes are hidden in a
162 * transitive dependency, you can simply add that dependency explicitly.
164 * @parameter property="hibernate.export.scan_dependencies" default-value="compile"
167 private String scanDependencies;
170 * Test-Classes-Directory to scan.
172 * This parameter defaults to the maven build-output-directory for
175 * This parameter is only used, when <code>scanTestClasses</code> is set
176 * to <code>true</code>!
178 * @parameter property="project.build.testOutputDirectory"
181 private String testOutputDirectory;
186 * If set to <code>true</code>, the execution is skipped.
188 * A skipped execution is signaled via the maven-property
189 * <code>${hibernate.export.skipped}</code>.
191 * The execution is skipped automatically, if no modified or newly added
192 * annotated classes are found and the dialect was not changed.
194 * @parameter property="hibernate.skip" default-value="${maven.test.skip}"
197 private boolean skip;
202 * Force execution, even if no modified or newly added annotated classes
203 * where found and the dialect was not changed.
205 * <code>skip</code> takes precedence over <code>force</code>.
207 * @parameter property="hibernate.export.force" default-value="false"
210 private boolean force;
215 * @parameter property="hibernate.connection.driver_class"
218 private String driverClassName;
223 * @parameter property="hibernate.connection.url"
231 * @parameter property="hibernate.connection.username"
234 private String username;
239 * @parameter property="hibernate.connection.password"
242 private String password;
247 * @parameter property="hibernate.dialect"
250 private String hibernateDialect;
253 * Hibernate Naming Strategy
255 * @parameter property="hibernate.ejb.naming_strategy"
258 private String hibernateNamingStrategy;
261 * Path to Hibernate properties file.
263 * @parameter default-value="${project.build.outputDirectory}/hibernate.properties"
266 private String hibernateProperties;
269 * Path to Hibernate configuration file (.cfg.xml).
270 * Settings in this file will overwrite settings in the properties file.
272 * @parameter default-value="${project.build.outputDirectory}/hibernate.cfg.xml"
275 private String hibernateConfig;
278 * Name of the persistence-unit.
279 * If there is only one persistence-unit available, that unit will be used
281 * Settings in this file will overwrite settings in the properties or the
282 * configuration file.
286 private String persistenceUnit;
289 * List of Hibernate-Mapping-Files (XML).
290 * Multiple files can be separated with white-spaces and/or commas.
292 * @parameter property="hibernate.mapping"
295 private String hibernateMapping;
298 * Target of execution:
300 * <li><strong>NONE</strong> only export schema to SQL-script (forces execution, signals skip)</li>
301 * <li><strong>EXPORT</strong> create database (<strong>DEFAULT!</strong>). forces execution, signals skip)</li>
302 * <li><strong>SCRIPT</strong> export schema to SQL-script and print it to STDOUT</li>
303 * <li><strong>BOTH</strong></li>
306 * A database connection is only needed for EXPORT and BOTH, but a
307 * Hibernate-Dialect must always be chosen.
309 * @parameter property="hibernate.export.target" default-value="EXPORT"
312 private String target;
317 * <li><strong>NONE</strong> do nothing - just validate the configuration</li>
318 * <li><strong>CREATE</strong> create database-schema</li>
319 * <li><strong>DROP</strong> drop database-schema</li>
320 * <li><strong>BOTH</strong> (<strong>DEFAULT!</strong>)</li>
323 * If NONE is choosen, no databaseconnection is needed.
325 * @parameter property="hibernate.export.type" default-value="BOTH"
333 * @parameter property="hibernate.export.schema.filename" default-value="${project.build.directory}/schema.sql"
336 private String outputFile;
339 * Delimiter in output-file.
341 * @parameter property="hibernate.export.schema.delimiter" default-value=";"
344 private String delimiter;
347 * Format output-file.
349 * @parameter property="hibernate.export.schema.format" default-value="true"
352 private boolean format;
355 * Generate envers schema for auditing tables.
357 * @parameter property="hibernate.export.envers" default-value="true"
360 private boolean envers;
364 public void execute()
366 MojoFailureException,
367 MojoExecutionException
371 getLog().info("Execution of hibernate4-maven-plugin:export was skipped!");
372 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
376 Map<String,String> md5s;
377 boolean modified = false;
378 File saved = new File(buildDirectory + File.separator + MD5S);
380 if (saved.isFile() && saved.length() > 0)
384 FileInputStream fis = new FileInputStream(saved);
385 ObjectInputStream ois = new ObjectInputStream(fis);
386 md5s = (HashMap<String,String>)ois.readObject();
391 md5s = new HashMap<String,String>();
392 getLog().warn("Cannot read timestamps from saved: " + e);
397 md5s = new HashMap<String,String>();
400 saved.createNewFile();
402 catch (IOException e)
404 getLog().debug("Cannot create file \"" + saved.getPath() + "\" for timestamps: " + e);
408 ClassLoader classLoader = null;
411 getLog().debug("Creating ClassLoader for project-dependencies...");
412 List<String> classpathFiles = project.getCompileClasspathElements();
414 classpathFiles.addAll(project.getTestClasspathElements());
415 URL[] urls = new URL[classpathFiles.size()];
416 for (int i = 0; i < classpathFiles.size(); ++i)
418 getLog().debug("Dependency: " + classpathFiles.get(i));
419 urls[i] = new File(classpathFiles.get(i)).toURI().toURL();
421 classLoader = new URLClassLoader(urls, getClass().getClassLoader());
425 getLog().error("Error while creating ClassLoader!", e);
426 throw new MojoExecutionException(e.getMessage());
429 Set<Class<?>> classes =
430 new TreeSet<Class<?>>(
431 new Comparator<Class<?>>() {
433 public int compare(Class<?> a, Class<?> b)
435 return a.getName().compareTo(b.getName());
442 AnnotationDB db = new AnnotationDB();
443 File dir = new File(outputDirectory);
446 getLog().info("Scanning directory " + outputDirectory + " for annotated classes...");
447 URL dirUrl = dir.toURI().toURL();
448 db.scanArchives(dirUrl);
452 dir = new File(testOutputDirectory);
455 getLog().info("Scanning directory " + testOutputDirectory + " for annotated classes...");
456 URL dirUrl = dir.toURI().toURL();
457 db.scanArchives(dirUrl);
460 if (scanDependencies != null)
462 Matcher matcher = split.matcher(scanDependencies);
463 while (matcher.find())
465 getLog().info("Scanning dependencies for scope " + matcher.group());
466 for (Artifact artifact : project.getDependencyArtifacts())
468 if (!artifact.getScope().equalsIgnoreCase(matcher.group()))
470 if (artifact.getFile() == null)
473 "Cannot scan dependency " +
475 ": no JAR-file available!"
480 "Scanning dependency " +
482 " for annotated classes..."
484 db.scanArchives(artifact.getFile().toURI().toURL());
489 Set<String> classNames = new HashSet<String>();
490 if (db.getAnnotationIndex().containsKey(Entity.class.getName()))
491 classNames.addAll(db.getAnnotationIndex().get(Entity.class.getName()));
492 if (db.getAnnotationIndex().containsKey(MappedSuperclass.class.getName()))
493 classNames.addAll(db.getAnnotationIndex().get(MappedSuperclass.class.getName()));
494 if (db.getAnnotationIndex().containsKey(Embeddable.class.getName()))
495 classNames.addAll(db.getAnnotationIndex().get(Embeddable.class.getName()));
497 MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
498 for (String name : classNames)
500 Class<?> annotatedClass = classLoader.loadClass(name);
501 classes.add(annotatedClass);
502 String resourceName = annotatedClass.getName();
503 resourceName = resourceName.substring(resourceName.lastIndexOf(".") + 1, resourceName.length()) + ".class";
506 .getResourceAsStream(resourceName);
507 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
509 while((i = is.read(buffer)) > -1)
510 digest.update(buffer, 0, i);
512 byte[] bytes = digest.digest();
513 BigInteger bi = new BigInteger(1, bytes);
514 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
515 String oldMd5 = !md5s.containsKey(name) ? "" : md5s.get(name);
516 if (!newMd5.equals(oldMd5))
518 getLog().debug("Found new or modified annotated class: " + name);
520 md5s.put(name, newMd5);
524 getLog().debug(oldMd5 + " -> class unchanged: " + name);
528 catch (ClassNotFoundException e)
530 getLog().error("Error while adding annotated classes!", e);
531 throw new MojoExecutionException(e.getMessage());
535 getLog().error("Error while scanning!", e);
536 throw new MojoFailureException(e.getMessage());
540 ValidationConfiguration config = new ValidationConfiguration();
541 // Clear unused system-properties
542 config.setProperties(new Properties());
545 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
546 StandardServiceRegistryImpl registry = null;
547 MavenLogAppender.startPluginLog(this);
551 /** Try to read configuration from properties-file */
554 File file = new File(hibernateProperties);
557 getLog().info("Reading properties from file " + hibernateProperties + "...");
558 Properties properties = new Properties();
559 properties.load(new FileInputStream(file));
560 config.setProperties(properties);
563 getLog().info("No hibernate-properties-file found! (Checked path: " + hibernateProperties + ")");
565 catch (IOException e)
567 getLog().error("Error while reading properties!", e);
568 throw new MojoExecutionException(e.getMessage());
572 * Change class-loader of current thread, so that hibernate can
573 * see all dependencies!
575 Thread.currentThread().setContextClassLoader(classLoader);
577 /** Try to read configuration from configuration-file */
580 File file = new File(hibernateConfig);
583 getLog().info("Reading configuration from file " + hibernateConfig + "...");
584 config.configure(file);
587 getLog().info("No hibernate-configuration-file found! (Checked path: " + hibernateConfig + ")");
591 getLog().error("Error while reading configuration!", e);
592 throw new MojoExecutionException(e.getMessage());
595 ParsedPersistenceXmlDescriptor persistenceUnitDescriptor =
596 getPersistenceUnitDescriptor(
598 config.getProperties(),
599 new MavenProjectClassLoaderService(classLoader)
601 if (persistenceUnitDescriptor != null)
602 config.setProperties(persistenceUnitDescriptor.getProperties());
604 /** Overwrite values from properties-file or set, if given */
605 if (driverClassName != null)
607 if (config.getProperties().containsKey(DRIVER_CLASS))
609 "Overwriting property " +
610 DRIVER_CLASS + "=" + config.getProperty(DRIVER_CLASS) +
611 " with the value " + driverClassName
614 getLog().debug("Using the value " + driverClassName);
615 config.setProperty(DRIVER_CLASS, driverClassName);
619 if (config.getProperties().containsKey(URL))
621 "Overwriting property " +
622 URL + "=" + config.getProperty(URL) +
623 " with the value " + url
626 getLog().debug("Using the value " + url);
627 config.setProperty(URL, url);
629 if (username != null)
631 if (config.getProperties().containsKey(USERNAME))
633 "Overwriting property " +
634 USERNAME + "=" + config.getProperty(USERNAME) +
635 " with the value " + username
638 getLog().debug("Using the value " + username);
639 config.setProperty(USERNAME, username);
641 if (password != null)
643 if (config.getProperties().containsKey(PASSWORD))
645 "Overwriting property " +
646 PASSWORD + "=" + config.getProperty(PASSWORD) +
647 " with value " + password
650 getLog().debug("Using value " + password + " for property " + PASSWORD);
651 config.setProperty(PASSWORD, password);
653 if (hibernateDialect != null)
655 if (config.getProperties().containsKey(DIALECT))
657 "Overwriting property " +
658 DIALECT + "=" + config.getProperty(DIALECT) +
659 " with value " + hibernateDialect
663 "Using value " + hibernateDialect + " for property " + DIALECT
665 config.setProperty(DIALECT, hibernateDialect);
667 if ( hibernateNamingStrategy != null )
669 if ( config.getProperties().contains(NAMING_STRATEGY))
671 "Overwriting property " +
672 NAMING_STRATEGY + "=" + config.getProperty(NAMING_STRATEGY) +
673 " with value " + hibernateNamingStrategy
677 "Using value " + hibernateNamingStrategy + " for property " +
680 config.setProperty(NAMING_STRATEGY, hibernateNamingStrategy);
683 /** The generated SQL varies with the dialect! */
684 if (md5s.containsKey(DIALECT))
686 String dialect = config.getProperty(DIALECT);
687 if (md5s.get(DIALECT).equals(dialect))
688 getLog().debug("SQL-dialect unchanged.");
694 getLog().debug("SQL-dialect was unset.");
695 md5s.remove(DIALECT);
699 getLog().debug("SQL-dialect changed: " + dialect);
700 md5s.put(DIALECT, dialect);
706 String dialect = config.getProperty(DIALECT);
710 md5s.put(DIALECT, config.getProperty(DIALECT));
714 /** The generated SQL varies with the envers-configuration */
715 if (md5s.get(ENVERS) != null)
717 if (md5s.get(ENVERS).equals(Boolean.toString(envers)))
718 getLog().debug("Envers-Configuration unchanged. Enabled: " + envers);
721 getLog().debug("Envers-Configuration changed. Enabled: " + envers);
723 md5s.put(ENVERS, Boolean.toString(envers));
729 md5s.put(ENVERS, Boolean.toString(envers));
732 if (config.getProperties().isEmpty())
734 getLog().error("No properties set!");
735 throw new MojoFailureException("Hibernate configuration is missing!");
738 getLog().info("Gathered hibernate-configuration (turn on debugging for details):");
739 for (Entry<Object,Object> entry : config.getProperties().entrySet())
740 getLog().info(" " + entry.getKey() + " = " + entry.getValue());
743 getLog().debug("Adding explicitly configured mappings...");
744 if (hibernateMapping != null)
748 MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
749 for (String filename : hibernateMapping.split("[\\s,]+"))
751 // First try the filename as absolute/relative path
752 File file = new File(filename);
755 // If the file was not found, search for it in the resource-directories
756 for (Resource resource : project.getResources())
758 file = new File(resource.getDirectory() + File.separator + filename);
763 if (file != null && file.exists())
765 InputStream is = new FileInputStream(file);
766 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
768 while((i = is.read(buffer)) > -1)
769 digest.update(buffer, 0, i);
771 byte[] bytes = digest.digest();
772 BigInteger bi = new BigInteger(1, bytes);
773 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
774 String oldMd5 = !md5s.containsKey(filename) ? "" : md5s.get(filename);
775 if (!newMd5.equals(oldMd5))
777 getLog().debug("Found new or modified mapping-file: " + filename);
779 md5s.put(filename, newMd5);
783 getLog().debug(oldMd5 + " -> mapping-file unchanged: " + filename);
785 getLog().debug("Adding mappings from XML-configurationfile: " + file);
786 config.addFile(file);
789 throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!");
792 catch (NoSuchAlgorithmException e)
794 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
796 catch (FileNotFoundException e)
798 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
800 catch (IOException e)
802 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
806 getLog().debug("Adding annotated classes to hibernate-mapping-configuration...");
807 // build annotated packages
808 Set<String> packages = new HashSet<String>();
809 for (Class<?> annotatedClass : classes)
811 String packageName = annotatedClass.getPackage().getName();
812 if (!packages.contains(packageName))
814 getLog().debug("Add package " + packageName);
815 packages.add(packageName);
816 config.addPackage(packageName);
817 getLog().debug("type definintions" + config.getTypeDefs());
819 getLog().debug("Class " + annotatedClass);
820 config.addAnnotatedClass(annotatedClass);
823 Target target = null;
826 target = Target.valueOf(this.target.toUpperCase());
828 catch (IllegalArgumentException e)
830 getLog().error("Invalid value for configuration-option \"target\": " + this.target);
831 getLog().error("Valid values are: NONE, SCRIPT, EXPORT, BOTH");
832 throw new MojoExecutionException("Invalid value for configuration-option \"target\"");
837 type = Type.valueOf(this.type.toUpperCase());
839 catch (IllegalArgumentException e)
841 getLog().error("Invalid value for configuration-option \"type\": " + this.type);
842 getLog().error("Valid values are: NONE, CREATE, DROP, BOTH");
843 throw new MojoExecutionException("Invalid value for configuration-option \"type\"");
847 Iterator<PersistentClass> it = config.getClassMappings();
850 throw new MojoFailureException("No mapped classes found!");
854 getLog().info("Mapped classes:");
857 getLog().debug(" " + it.next().getClassName());
861 if (config.getProperty(DIALECT) == null)
862 throw new MojoFailureException("hibernate-dialect must be set!");
865 if (target.equals(Target.SCRIPT) || target.equals(Target.NONE))
867 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
871 && !target.equals(Target.SCRIPT)
872 && !target.equals(Target.NONE)
876 getLog().info("No modified annotated classes or mapping-files found and dialect unchanged.");
877 getLog().info("Skipping schema generation!");
878 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
883 if ( config.getProperties().containsKey(NAMING_STRATEGY))
885 String namingStrategy = config.getProperty(NAMING_STRATEGY);
886 getLog().debug("Explicitly set NamingStrategy: " + namingStrategy);
889 @SuppressWarnings("unchecked")
890 Class<NamingStrategy> namingStrategyClass = (Class<NamingStrategy>) Class.forName(namingStrategy);
891 config.setNamingStrategy(namingStrategyClass.newInstance());
895 getLog().error("Error setting NamingStrategy", e);
896 throw new MojoExecutionException(e.getMessage());
901 Environment.verifyProperties(config.getProperties());
902 ConfigurationHelper.resolvePlaceHolders(config.getProperties());
904 (StandardServiceRegistryImpl)
905 new StandardServiceRegistryBuilder()
906 .applySettings(config.getProperties())
909 config.buildMappings();
913 getLog().info("Automatic auditing via hibernate-envers enabled!");
914 AuditConfiguration.getFor(config);
917 SchemaExport export = new SchemaExport(registry, config);
918 export.setDelimiter(delimiter);
919 export.setFormat(format);
921 File outF = new File(outputFile);
923 if (!outF.isAbsolute())
925 // Interpret relative file path relative to build directory
926 outF = new File(buildDirectory, outputFile);
927 getLog().info("Adjusted relative path, resulting path is " + outF.getPath());
930 // Ensure that directory path for specified file exists
931 File outFileParentDir = outF.getParentFile();
932 if (null != outFileParentDir && !outFileParentDir.exists())
936 getLog().info("Creating directory path for output file:" + outFileParentDir.getPath());
937 outFileParentDir.mkdirs();
941 getLog().error("Error creating directory path for output file: " + e.getLocalizedMessage());
945 export.setOutputFile(outF.getPath());
946 export.execute(target, type);
948 for (Object exception : export.getExceptions())
949 getLog().debug(exception.toString());
953 /** Stop Log-Capturing */
954 MavenLogAppender.endPluginLog(this);
956 /** Restore the old class-loader (TODO: is this really necessary?) */
957 Thread.currentThread().setContextClassLoader(contextClassLoader);
959 if (registry != null)
963 /** Write md5-sums for annotated classes to file */
966 FileOutputStream fos = new FileOutputStream(saved);
967 ObjectOutputStream oos = new ObjectOutputStream(fos);
968 oos.writeObject(md5s);
974 getLog().error("Cannot write md5-sums to file: " + e);
978 private ParsedPersistenceXmlDescriptor getPersistenceUnitDescriptor(
980 Properties properties,
981 ClassLoaderService loader
986 PersistenceXmlParser parser =
987 new PersistenceXmlParser(
989 PersistenceUnitTransactionType.RESOURCE_LOCAL
992 List<ParsedPersistenceXmlDescriptor> units = parser.doResolve(properties);
996 switch (units.size())
999 getLog().info("Found no META-INF/persistence.xml.");
1002 getLog().info("Using persistence-unit " + units.get(0).getName());
1003 return units.get(0);
1005 getLog().warn("No name provided and multiple persistence units found:");
1006 for (ParsedPersistenceXmlDescriptor unit : units)
1007 getLog().warn(" - " + unit.getName());
1013 for (ParsedPersistenceXmlDescriptor unit : units)
1015 getLog().debug("Found persistence-unit " + unit.getName());
1016 if (!unit.getName().equals(name))
1019 // See if we (Hibernate) are the persistence provider
1020 if (!ProviderChecker.isProvider(unit, properties))
1022 getLog().debug("Wrong provider: " + unit.getProviderClassName());
1026 getLog().info("Using persistence-unit " + unit.getName());
1030 throw new MojoFailureException("Could not find persistence-unit " + name);
1034 static final class MavenProjectClassLoaderService implements ClassLoaderService
1036 final private ClassLoader loader;
1039 public MavenProjectClassLoaderService(ClassLoader loader)
1041 this.loader = loader;
1046 public <T> Class<T> classForName(String name)
1050 return (Class<T>)loader.loadClass(name);
1052 catch (ClassNotFoundException e)
1054 throw new ClassLoadingException( "Unable to load class [" + name + "]", e );
1059 public URL locateResource(String name)
1061 return loader.getResource(name);
1065 public InputStream locateResourceStream(String name)
1067 return loader.getResourceAsStream(name);
1071 public List<URL> locateResources(String name)
1075 return Collections.list(loader.getResources(name));
1077 catch (IOException e)
1079 return Collections.EMPTY_LIST;
1084 public <S> LinkedHashSet<S> loadJavaServices(Class<S> serviceContract)
1086 throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1090 public void stop() { }
1096 * Needed, because DriverManager won't pick up drivers, that were not
1097 * loaded by the system-classloader!
1099 * http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-fromodifiedm-an-arbitrary-location
1101 static final class DriverProxy implements Driver
1103 private final Driver target;
1105 DriverProxy(Driver target)
1108 throw new NullPointerException();
1109 this.target = target;
1112 public java.sql.Driver getTarget()
1118 public boolean acceptsURL(String url) throws SQLException
1120 return target.acceptsURL(url);
1124 public java.sql.Connection connect(
1126 java.util.Properties info
1131 return target.connect(url, info);
1135 public int getMajorVersion()
1137 return target.getMajorVersion();
1141 public int getMinorVersion()
1143 return target.getMinorVersion();
1147 public DriverPropertyInfo[] getPropertyInfo(
1154 return target.getPropertyInfo(url, info);
1158 public boolean jdbcCompliant()
1160 return target.jdbcCompliant();
1164 * This Method cannot be annotated with @Override, becaus the plugin
1165 * will not compile then under Java 1.6!
1167 public Logger getParentLogger() throws SQLFeatureNotSupportedException
1169 throw new SQLFeatureNotSupportedException("Not supported, for backward-compatibility with Java 1.6");
1173 public String toString()
1175 return "Proxy: " + target;
1179 public int hashCode()
1181 return target.hashCode();
1185 public boolean equals(Object obj)
1187 if (!(obj instanceof DriverProxy))
1189 DriverProxy other = (DriverProxy) obj;
1190 return this.target.equals(other.target);