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.List;
44 import java.util.Map.Entry;
45 import java.util.Properties;
47 import java.util.TreeSet;
48 import java.util.logging.Logger;
49 import java.util.regex.Matcher;
50 import java.util.regex.Pattern;
51 import javax.persistence.Embeddable;
52 import javax.persistence.Entity;
53 import javax.persistence.MappedSuperclass;
54 import javax.persistence.spi.PersistenceUnitTransactionType;
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.boot.registry.StandardServiceRegistryBuilder;
62 import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
63 import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
64 import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl;
65 import org.hibernate.cfg.Environment;
66 import org.hibernate.cfg.NamingStrategy;
67 import org.hibernate.envers.configuration.spi.AuditConfiguration;
68 import org.hibernate.internal.util.config.ConfigurationHelper;
69 import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
70 import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
71 import org.hibernate.jpa.boot.spi.ProviderChecker;
72 import org.hibernate.tool.hbm2ddl.SchemaExport;
73 import org.hibernate.tool.hbm2ddl.SchemaExport.Type;
74 import org.hibernate.tool.hbm2ddl.Target;
75 import org.scannotation.AnnotationDB;
79 * Goal which extracts the hibernate-mapping-configuration and
80 * exports an according SQL-database-schema.
83 * @phase process-classes
85 * @requiresDependencyResolution runtime
87 public class Hbm2DdlMojo extends AbstractMojo
89 public final static String EXPORT_SKIPPED_PROPERTY = "hibernate.export.skipped";
91 public final static String DRIVER_CLASS = "hibernate.connection.driver_class";
92 public final static String URL = "hibernate.connection.url";
93 public final static String USERNAME = "hibernate.connection.username";
94 public final static String PASSWORD = "hibernate.connection.password";
95 public final static String DIALECT = "hibernate.dialect";
96 public final static String NAMING_STRATEGY="hibernate.ejb.naming_strategy";
97 public final static String ENVERS = "hibernate.export.envers";
99 public final static String MD5S = "hibernate4-generatedschema.md5s";
101 private final static Pattern split = Pattern.compile("[^,\\s]+");
107 * Only needed internally.
109 * @parameter property="project"
113 private MavenProject project;
118 * Only needed internally.
120 * @parameter property="project.build.directory"
124 private String buildDirectory;
127 * Classes-Directory to scan.
129 * This parameter defaults to the maven build-output-directory for classes.
130 * Additionally, all dependencies are scanned for annotated classes.
132 * @parameter property="project.build.outputDirectory"
135 private String outputDirectory;
138 * Whether to scan test-classes too, or not.
140 * If this parameter is set to <code>true</code> the test-classes of the
141 * artifact will be scanned for hibernate-annotated classes additionally.
143 * @parameter property="hibernate.export.scan_testclasses" default-value="false"
146 private boolean scanTestClasses;
149 * Dependency-Scopes, that should be scanned for annotated classes.
151 * By default, only dependencies in the scope <code>compile</code> are
152 * scanned for annotated classes. Multiple scopes can be seperated by
153 * white space or commas.
155 * If you do not want any dependencies to be scanned for annotated
156 * classes, set this parameter to <code>none</code>.
158 * The plugin does not scan for annotated classes in transitive
159 * dependencies. If some of your annotated classes are hidden in a
160 * transitive dependency, you can simply add that dependency explicitly.
162 * @parameter property="hibernate.export.scan_dependencies" default-value="compile"
165 private String scanDependencies;
168 * Test-Classes-Directory to scan.
170 * This parameter defaults to the maven build-output-directory for
173 * This parameter is only used, when <code>scanTestClasses</code> is set
174 * to <code>true</code>!
176 * @parameter property="project.build.testOutputDirectory"
179 private String testOutputDirectory;
184 * If set to <code>true</code>, the execution is skipped.
186 * A skipped execution is signaled via the maven-property
187 * <code>${hibernate.export.skipped}</code>.
189 * The execution is skipped automatically, if no modified or newly added
190 * annotated classes are found and the dialect was not changed.
192 * @parameter property="hibernate.skip" default-value="${maven.test.skip}"
195 private boolean skip;
200 * Force execution, even if no modified or newly added annotated classes
201 * where found and the dialect was not changed.
203 * <code>skip</code> takes precedence over <code>force</code>.
205 * @parameter property="hibernate.export.force" default-value="false"
208 private boolean force;
213 * @parameter property="hibernate.connection.driver_class"
216 private String driverClassName;
221 * @parameter property="hibernate.connection.url"
229 * @parameter property="hibernate.connection.username"
232 private String username;
237 * @parameter property="hibernate.connection.password"
240 private String password;
245 * @parameter property="hibernate.dialect"
248 private String hibernateDialect;
251 * Hibernate Naming Strategy
253 * @parameter property="hibernate.ejb.naming_strategy"
256 private String hibernateNamingStrategy;
259 * Path to Hibernate configuration file.
261 * @parameter default-value="${project.build.outputDirectory}/hibernate.properties"
264 private String hibernateProperties;
267 * Name of the persistence-unit.
268 * If there is only one persistence-unit available, that unit will be used
273 private String persistenceUnit;
276 * List of Hibernate-Mapping-Files (XML).
277 * Multiple files can be separated with white-spaces and/or commas.
279 * @parameter property="hibernate.mapping"
282 private String hibernateMapping;
285 * Target of execution:
287 * <li><strong>NONE</strong> only export schema to SQL-script (forces execution, signals skip)</li>
288 * <li><strong>EXPORT</strong> create database (<strong>DEFAULT!</strong>). forces execution, signals skip)</li>
289 * <li><strong>SCRIPT</strong> export schema to SQL-script and print it to STDOUT</li>
290 * <li><strong>BOTH</strong></li>
293 * A database connection is only needed for EXPORT and BOTH, but a
294 * Hibernate-Dialect must always be chosen.
296 * @parameter property="hibernate.export.target" default-value="EXPORT"
299 private String target;
304 * <li><strong>NONE</strong> do nothing - just validate the configuration</li>
305 * <li><strong>CREATE</strong> create database-schema</li>
306 * <li><strong>DROP</strong> drop database-schema</li>
307 * <li><strong>BOTH</strong> (<strong>DEFAULT!</strong>)</li>
310 * If NONE is choosen, no databaseconnection is needed.
312 * @parameter property="hibernate.export.type" default-value="BOTH"
320 * @parameter property="hibernate.export.schema.filename" default-value="${project.build.directory}/schema.sql"
323 private String outputFile;
326 * Delimiter in output-file.
328 * @parameter property="hibernate.export.schema.delimiter" default-value=";"
331 private String delimiter;
334 * Format output-file.
336 * @parameter property="hibernate.export.schema.format" default-value="true"
339 private boolean format;
342 * Generate envers schema for auditing tables.
344 * @parameter property="hibernate.export.envers" default-value="true"
347 private boolean envers;
351 public void execute()
353 MojoFailureException,
354 MojoExecutionException
358 getLog().info("Execution of hibernate4-maven-plugin:export was skipped!");
359 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
363 Map<String,String> md5s;
364 boolean modified = false;
365 File saved = new File(buildDirectory + File.separator + MD5S);
367 if (saved.isFile() && saved.length() > 0)
371 FileInputStream fis = new FileInputStream(saved);
372 ObjectInputStream ois = new ObjectInputStream(fis);
373 md5s = (HashMap<String,String>)ois.readObject();
378 md5s = new HashMap<String,String>();
379 getLog().warn("Cannot read timestamps from saved: " + e);
384 md5s = new HashMap<String,String>();
387 saved.createNewFile();
389 catch (IOException e)
391 getLog().debug("Cannot create file \"" + saved.getPath() + "\" for timestamps: " + e);
395 ClassLoader classLoader = null;
398 getLog().debug("Creating ClassLoader for project-dependencies...");
399 List<String> classpathFiles = project.getCompileClasspathElements();
401 classpathFiles.addAll(project.getTestClasspathElements());
402 URL[] urls = new URL[classpathFiles.size()];
403 for (int i = 0; i < classpathFiles.size(); ++i)
405 getLog().debug("Dependency: " + classpathFiles.get(i));
406 urls[i] = new File(classpathFiles.get(i)).toURI().toURL();
408 classLoader = new URLClassLoader(urls, getClass().getClassLoader());
412 getLog().error("Error while creating ClassLoader!", e);
413 throw new MojoExecutionException(e.getMessage());
416 Set<Class<?>> classes =
417 new TreeSet<Class<?>>(
418 new Comparator<Class<?>>() {
420 public int compare(Class<?> a, Class<?> b)
422 return a.getName().compareTo(b.getName());
429 AnnotationDB db = new AnnotationDB();
430 File dir = new File(outputDirectory);
433 getLog().info("Scanning directory " + outputDirectory + " for annotated classes...");
434 URL dirUrl = dir.toURI().toURL();
435 db.scanArchives(dirUrl);
439 dir = new File(testOutputDirectory);
442 getLog().info("Scanning directory " + testOutputDirectory + " for annotated classes...");
443 URL dirUrl = dir.toURI().toURL();
444 db.scanArchives(dirUrl);
447 if (scanDependencies != null)
449 Matcher matcher = split.matcher(scanDependencies);
450 while (matcher.find())
452 getLog().info("Scanning dependencies for scope " + matcher.group());
453 for (Artifact artifact : project.getDependencyArtifacts())
455 if (!artifact.getScope().equalsIgnoreCase(matcher.group()))
457 if (artifact.getFile() == null)
460 "Cannot scan dependency " +
462 ": no JAR-file available!"
467 "Scanning dependency " +
469 " for annotated classes..."
471 db.scanArchives(artifact.getFile().toURI().toURL());
476 Set<String> classNames = new HashSet<String>();
477 if (db.getAnnotationIndex().containsKey(Entity.class.getName()))
478 classNames.addAll(db.getAnnotationIndex().get(Entity.class.getName()));
479 if (db.getAnnotationIndex().containsKey(MappedSuperclass.class.getName()))
480 classNames.addAll(db.getAnnotationIndex().get(MappedSuperclass.class.getName()));
481 if (db.getAnnotationIndex().containsKey(Embeddable.class.getName()))
482 classNames.addAll(db.getAnnotationIndex().get(Embeddable.class.getName()));
484 MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
485 for (String name : classNames)
487 Class<?> annotatedClass = classLoader.loadClass(name);
488 classes.add(annotatedClass);
489 String resourceName = annotatedClass.getName();
490 resourceName = resourceName.substring(resourceName.lastIndexOf(".") + 1, resourceName.length()) + ".class";
493 .getResourceAsStream(resourceName);
494 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
496 while((i = is.read(buffer)) > -1)
497 digest.update(buffer, 0, i);
499 byte[] bytes = digest.digest();
500 BigInteger bi = new BigInteger(1, bytes);
501 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
502 String oldMd5 = !md5s.containsKey(name) ? "" : md5s.get(name);
503 if (!newMd5.equals(oldMd5))
505 getLog().debug("Found new or modified annotated class: " + name);
507 md5s.put(name, newMd5);
511 getLog().debug(oldMd5 + " -> class unchanged: " + name);
515 catch (ClassNotFoundException e)
517 getLog().error("Error while adding annotated classes!", e);
518 throw new MojoExecutionException(e.getMessage());
522 getLog().error("Error while scanning!", e);
523 throw new MojoFailureException(e.getMessage());
526 if (classes.isEmpty())
528 if (hibernateMapping == null || hibernateMapping.isEmpty())
529 throw new MojoFailureException("No annotated classes found in directory " + outputDirectory);
533 getLog().debug("Detected classes with mapping-annotations:");
534 for (Class<?> annotatedClass : classes)
535 getLog().debug(" " + annotatedClass.getName());
539 Properties properties = new Properties();
541 /** Try to read configuration from properties-file */
544 File file = new File(hibernateProperties);
547 getLog().info("Reading properties from file " + hibernateProperties + "...");
548 properties.load(new FileInputStream(file));
551 getLog().info("No hibernate-properties-file found! (Checked path: " + hibernateProperties + ")");
553 catch (IOException e)
555 getLog().error("Error while reading properties!", e);
556 throw new MojoExecutionException(e.getMessage());
559 ParsedPersistenceXmlDescriptor persistenceUnitDescriptor =
560 getPersistenceUnitDescriptor(
563 new MavenProjectClassLoaderService(classLoader)
565 if (persistenceUnitDescriptor != null)
566 properties = persistenceUnitDescriptor.getProperties();
568 /** Overwrite values from properties-file or set, if given */
569 if (driverClassName != null)
571 if (properties.containsKey(DRIVER_CLASS))
573 "Overwriting property " +
574 DRIVER_CLASS + "=" + properties.getProperty(DRIVER_CLASS) +
575 " with the value " + driverClassName
578 getLog().debug("Using the value " + driverClassName);
579 properties.setProperty(DRIVER_CLASS, driverClassName);
583 if (properties.containsKey(URL))
585 "Overwriting property " +
586 URL + "=" + properties.getProperty(URL) +
587 " with the value " + url
590 getLog().debug("Using the value " + url);
591 properties.setProperty(URL, url);
593 if (username != null)
595 if (properties.containsKey(USERNAME))
597 "Overwriting property " +
598 USERNAME + "=" + properties.getProperty(USERNAME) +
599 " with the value " + username
602 getLog().debug("Using the value " + username);
603 properties.setProperty(USERNAME, username);
605 if (password != null)
607 if (properties.containsKey(PASSWORD))
609 "Overwriting property " +
610 PASSWORD + "=" + properties.getProperty(PASSWORD) +
611 " with value " + password
614 getLog().debug("Using value " + password + " for property " + PASSWORD);
615 properties.setProperty(PASSWORD, password);
617 if (hibernateDialect != null)
619 if (properties.containsKey(DIALECT))
621 "Overwriting property " +
622 DIALECT + "=" + properties.getProperty(DIALECT) +
623 " with value " + hibernateDialect
627 "Using value " + hibernateDialect + " for property " + DIALECT
629 properties.setProperty(DIALECT, hibernateDialect);
633 hibernateDialect = properties.getProperty(DIALECT);
635 if ( hibernateNamingStrategy != null )
637 if ( properties.contains(NAMING_STRATEGY))
639 "Overwriting property " +
640 NAMING_STRATEGY + "=" + properties.getProperty(NAMING_STRATEGY) +
641 " with value " + hibernateNamingStrategy
645 "Using value " + hibernateNamingStrategy + " for property " +
648 properties.setProperty(NAMING_STRATEGY, hibernateNamingStrategy);
651 /** The generated SQL varies with the dialect! */
652 if (md5s.containsKey(DIALECT))
654 String dialect = properties.getProperty(DIALECT);
655 if (md5s.get(DIALECT).equals(dialect))
656 getLog().debug("SQL-dialect unchanged.");
662 getLog().debug("SQL-dialect was unset.");
663 md5s.remove(DIALECT);
667 getLog().debug("SQL-dialect changed: " + dialect);
668 md5s.put(DIALECT, dialect);
674 String dialect = properties.getProperty(DIALECT);
678 md5s.put(DIALECT, properties.getProperty(DIALECT));
682 /** The generated SQL varies with the envers-configuration */
683 if (md5s.get(ENVERS) != null)
685 if (md5s.get(ENVERS).equals(Boolean.toString(envers)))
686 getLog().debug("Envers-Configuration unchanged. Enabled: " + envers);
689 getLog().debug("Envers-Configuration changed. Enabled: " + envers);
691 md5s.put(ENVERS, Boolean.toString(envers));
697 md5s.put(ENVERS, Boolean.toString(envers));
700 if (properties.isEmpty())
702 getLog().error("No properties set!");
703 throw new MojoFailureException("Hibernate configuration is missing!");
706 getLog().info("Gathered hibernate-configuration (turn on debugging for details):");
707 for (Entry<Object,Object> entry : properties.entrySet())
708 getLog().info(" " + entry.getKey() + " = " + entry.getValue());
710 if (hibernateDialect == null)
711 throw new MojoFailureException("hibernate-dialect must be set!");
713 final ValidationConfiguration config = new ValidationConfiguration(hibernateDialect);
715 config.setProperties(properties);
717 if ( properties.containsKey(NAMING_STRATEGY))
719 String namingStrategy = properties.getProperty(NAMING_STRATEGY);
720 getLog().debug("Explicitly set NamingStrategy: " + namingStrategy);
723 @SuppressWarnings("unchecked")
724 Class<NamingStrategy> namingStrategyClass = (Class<NamingStrategy>) Class.forName(namingStrategy);
725 config.setNamingStrategy(namingStrategyClass.newInstance());
729 getLog().error("Error setting NamingStrategy", e);
730 throw new MojoExecutionException(e.getMessage());
734 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
735 MavenLogAppender.startPluginLog(this);
739 * Change class-loader of current thread, so that hibernate can
740 * see all dependencies!
742 Thread.currentThread().setContextClassLoader(classLoader);
744 getLog().debug("Adding annotated classes to hibernate-mapping-configuration...");
745 // build annotated packages
746 Set<String> packages = new HashSet<String>();
747 for (Class<?> annotatedClass : classes)
749 String packageName = annotatedClass.getPackage().getName();
750 if (!packages.contains(packageName))
752 getLog().debug("Add package " + packageName);
753 packages.add(packageName);
754 config.addPackage(packageName);
755 getLog().debug("type definintions" + config.getTypeDefs());
757 getLog().debug("Class " + annotatedClass);
758 config.addAnnotatedClass(annotatedClass);
761 if (hibernateMapping != null)
765 MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
766 for (String filename : hibernateMapping.split("[\\s,]+"))
768 // First try the filename as absolute/relative path
769 File file = new File(filename);
772 // If the file was not found, search for it in the resource-directories
773 for (Resource resource : project.getResources())
775 file = new File(resource.getDirectory() + File.separator + filename);
780 if (file != null && file.exists())
782 InputStream is = new FileInputStream(file);
783 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
785 while((i = is.read(buffer)) > -1)
786 digest.update(buffer, 0, i);
788 byte[] bytes = digest.digest();
789 BigInteger bi = new BigInteger(1, bytes);
790 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
791 String oldMd5 = !md5s.containsKey(filename) ? "" : md5s.get(filename);
792 if (!newMd5.equals(oldMd5))
794 getLog().debug("Found new or modified mapping-file: " + filename);
796 md5s.put(filename, newMd5);
800 getLog().debug(oldMd5 + " -> mapping-file unchanged: " + filename);
802 getLog().debug("Adding mappings from XML-configurationfile: " + file);
803 config.addFile(file);
806 throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!");
809 catch (NoSuchAlgorithmException e)
811 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
813 catch (FileNotFoundException e)
815 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
817 catch (IOException e)
819 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
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\"");
846 if (target.equals(Target.SCRIPT) || target.equals(Target.NONE))
848 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
852 && !target.equals(Target.SCRIPT)
853 && !target.equals(Target.NONE)
857 getLog().info("No modified annotated classes or mapping-files found and dialect unchanged.");
858 getLog().info("Skipping schema generation!");
859 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
863 Environment.verifyProperties( properties );
864 ConfigurationHelper.resolvePlaceHolders( properties );
865 StandardServiceRegistryImpl registry =
866 (StandardServiceRegistryImpl)
867 new StandardServiceRegistryBuilder().applySettings(properties).build();
869 config.buildMappings();
873 getLog().info("Automatic auditing via hibernate-envers enabled!");
874 AuditConfiguration.getFor(config);
877 SchemaExport export = new SchemaExport(registry, config);
878 export.setDelimiter(delimiter);
879 export.setFormat(format);
881 File outF = new File(outputFile);
883 if (!outF.isAbsolute())
885 // Interpret relative file path relative to build directory
886 outF = new File(buildDirectory, outputFile);
887 getLog().info("Adjusted relative path, resulting path is " + outF.getPath());
890 // Ensure that directory path for specified file exists
891 File outFileParentDir = outF.getParentFile();
892 if (null != outFileParentDir && !outFileParentDir.exists())
896 getLog().info("Creating directory path for output file:" + outFileParentDir.getPath());
897 outFileParentDir.mkdirs();
901 getLog().error("Error creating directory path for output file: " + e.getLocalizedMessage());
905 export.setOutputFile(outF.getPath());
906 export.execute(target, type);
908 for (Object exception : export.getExceptions())
909 getLog().debug(exception.toString());
913 /** Stop Log-Capturing */
914 MavenLogAppender.endPluginLog(this);
916 /** Restore the old class-loader (TODO: is this really necessary?) */
917 Thread.currentThread().setContextClassLoader(contextClassLoader);
920 /** Write md5-sums for annotated classes to file */
923 FileOutputStream fos = new FileOutputStream(saved);
924 ObjectOutputStream oos = new ObjectOutputStream(fos);
925 oos.writeObject(md5s);
931 getLog().error("Cannot write md5-sums to file: " + e);
935 private ParsedPersistenceXmlDescriptor getPersistenceUnitDescriptor(
937 Properties properties,
938 ClassLoaderService loader
943 PersistenceXmlParser parser =
944 new PersistenceXmlParser(
946 PersistenceUnitTransactionType.RESOURCE_LOCAL
949 List<ParsedPersistenceXmlDescriptor> units = parser.doResolve(properties);
953 switch (units.size())
956 getLog().info("Found no META-INF/persistence.xml.");
959 getLog().info("Using persistence-unit " + units.get(0).getName());
962 getLog().warn("No name provided and multiple persistence units found:");
963 for (ParsedPersistenceXmlDescriptor unit : units)
964 getLog().warn(" - " + unit.getName());
970 for (ParsedPersistenceXmlDescriptor unit : units)
972 getLog().debug("Found persistence-unit " + unit.getName());
973 if (!unit.getName().equals(name))
976 // See if we (Hibernate) are the persistence provider
977 if (!ProviderChecker.isProvider(unit, properties))
979 getLog().debug("Wrong provider: " + unit.getProviderClassName());
983 getLog().info("Using persistence-unit " + unit.getName());
987 throw new MojoFailureException("Could not find persistence-unit " + name);
991 static final class MavenProjectClassLoaderService implements ClassLoaderService
993 final private ClassLoader loader;
996 public MavenProjectClassLoaderService(ClassLoader loader)
998 this.loader = loader;
1003 public <T> Class<T> classForName(String name)
1007 return (Class<T>)loader.loadClass(name);
1009 catch (ClassNotFoundException e)
1011 throw new ClassLoadingException( "Unable to load class [" + name + "]", e );
1016 public URL locateResource(String name)
1018 return loader.getResource(name);
1022 public InputStream locateResourceStream(String name)
1024 return loader.getResourceAsStream(name);
1028 public List<URL> locateResources(String name)
1032 return Collections.list(loader.getResources(name));
1034 catch (IOException e)
1036 return Collections.EMPTY_LIST;
1041 public <S> LinkedHashSet<S> loadJavaServices(Class<S> serviceContract)
1043 throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1047 public void stop() { }
1053 * Needed, because DriverManager won't pick up drivers, that were not
1054 * loaded by the system-classloader!
1056 * http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-fromodifiedm-an-arbitrary-location
1058 static final class DriverProxy implements Driver
1060 private final Driver target;
1062 DriverProxy(Driver target)
1065 throw new NullPointerException();
1066 this.target = target;
1069 public java.sql.Driver getTarget()
1075 public boolean acceptsURL(String url) throws SQLException
1077 return target.acceptsURL(url);
1081 public java.sql.Connection connect(
1083 java.util.Properties info
1088 return target.connect(url, info);
1092 public int getMajorVersion()
1094 return target.getMajorVersion();
1098 public int getMinorVersion()
1100 return target.getMinorVersion();
1104 public DriverPropertyInfo[] getPropertyInfo(
1111 return target.getPropertyInfo(url, info);
1115 public boolean jdbcCompliant()
1117 return target.jdbcCompliant();
1121 * This Method cannot be annotated with @Override, becaus the plugin
1122 * will not compile then under Java 1.6!
1124 public Logger getParentLogger() throws SQLFeatureNotSupportedException
1126 throw new SQLFeatureNotSupportedException("Not supported, for backward-compatibility with Java 1.6");
1130 public String toString()
1132 return "Proxy: " + target;
1136 public int hashCode()
1138 return target.hashCode();
1142 public boolean equals(Object obj)
1144 if (!(obj instanceof DriverProxy))
1146 DriverProxy other = (DriverProxy) obj;
1147 return this.target.equals(other.target);