1 package de.juplo.plugins.hibernate;
4 import com.pyx4j.log4j.MavenLogAppender;
6 import java.io.FileInputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.net.MalformedURLException;
11 import java.security.NoSuchAlgorithmException;
12 import java.util.Collections;
13 import java.util.HashSet;
14 import java.util.Iterator;
15 import java.util.LinkedHashSet;
16 import java.util.List;
18 import java.util.Map.Entry;
19 import java.util.Properties;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23 import javax.persistence.Embeddable;
24 import javax.persistence.Entity;
25 import javax.persistence.MappedSuperclass;
26 import javax.persistence.spi.PersistenceUnitTransactionType;
27 import org.apache.maven.artifact.Artifact;
28 import org.apache.maven.model.Resource;
29 import org.apache.maven.plugin.AbstractMojo;
30 import org.apache.maven.plugin.MojoExecutionException;
31 import org.apache.maven.plugin.MojoFailureException;
32 import org.apache.maven.project.MavenProject;
33 import org.hibernate.boot.MetadataBuilder;
34 import org.hibernate.boot.MetadataSources;
35 import org.hibernate.boot.cfgxml.internal.ConfigLoader;
36 import org.hibernate.boot.cfgxml.spi.LoadedConfig;
37 import org.hibernate.boot.cfgxml.spi.MappingReference;
38 import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
39 import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
40 import org.hibernate.boot.registry.BootstrapServiceRegistry;
41 import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
42 import org.hibernate.boot.registry.StandardServiceRegistry;
43 import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
44 import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
45 import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
46 import org.hibernate.boot.registry.selector.spi.StrategySelector;
47 import org.hibernate.boot.spi.MetadataImplementor;
48 import static org.hibernate.cfg.AvailableSettings.DIALECT;
49 import static org.hibernate.cfg.AvailableSettings.DRIVER;
50 import static org.hibernate.cfg.AvailableSettings.FORMAT_SQL;
51 import static org.hibernate.cfg.AvailableSettings.HBM2DLL_CREATE_NAMESPACES;
52 import static org.hibernate.cfg.AvailableSettings.IMPLICIT_NAMING_STRATEGY;
53 import static org.hibernate.cfg.AvailableSettings.PASS;
54 import static org.hibernate.cfg.AvailableSettings.PHYSICAL_NAMING_STRATEGY;
55 import static org.hibernate.cfg.AvailableSettings.SHOW_SQL;
56 import static org.hibernate.cfg.AvailableSettings.USER;
57 import static org.hibernate.cfg.AvailableSettings.URL;
58 import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
59 import org.hibernate.internal.util.config.ConfigurationException;
60 import static org.hibernate.jpa.AvailableSettings.JDBC_DRIVER;
61 import static org.hibernate.jpa.AvailableSettings.JDBC_PASSWORD;
62 import static org.hibernate.jpa.AvailableSettings.JDBC_URL;
63 import static org.hibernate.jpa.AvailableSettings.JDBC_USER;
64 import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
65 import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
66 import org.hibernate.jpa.boot.spi.ProviderChecker;
67 import org.scannotation.AnnotationDB;
71 * Baseclass with common attributes and methods.
73 * @phase process-classes
75 * @requiresDependencyResolution runtime
77 public abstract class AbstractSchemaMojo extends AbstractMojo
79 public final static String EXPORT = "hibernate.schema.export";
80 public final static String DELIMITER = "hibernate.schema.delimiter";
81 public final static String OUTPUTDIRECTORY = "project.build.outputDirectory";
82 public final static String SCAN_CLASSES = "hibernate.schema.scan.classes";
83 public final static String SCAN_DEPENDENCIES = "hibernate.schema.scan.dependencies";
84 public final static String SCAN_TESTCLASSES = "hibernate.schema.scan.test_classes";
85 public final static String TEST_OUTPUTDIRECTORY = "project.build.testOutputDirectory";
86 public final static String SKIPPED = "hibernate.schema.skipped";
88 private final static Pattern SPLIT = Pattern.compile("[^,\\s]+");
90 private final Set<String> packages = new HashSet<String>();
95 * Only needed internally.
97 * @parameter property="project"
101 private MavenProject project;
106 * Only needed internally.
108 * @parameter property="project.build.directory"
112 String buildDirectory;
115 /** Parameters to configure the genaration of the SQL *********************/
118 * Export the database-schma to the database.
119 * If set to <code>false</code>, only the SQL-script is created and the
120 * database is not touched.
122 * <strong>Important:</strong>
123 * This configuration value can only be configured through the
124 * <code>pom.xml</code>, or by the definition of a system-property, because
125 * it is not known by Hibernate nor JPA and, hence, not picked up from
126 * their configuration!
128 * @parameter property="hibernate.schema.export" default-value="true"
136 * If set to <code>true</code>, the execution is skipped.
138 * A skipped execution is signaled via the maven-property
139 * <code>${hibernate.schema.skipped}</code>.
141 * The execution is skipped automatically, if no modified or newly added
142 * annotated classes are found and the dialect was not changed.
144 * <strong>Important:</strong>
145 * This configuration value can only be configured through the
146 * <code>pom.xml</code>, or by the definition of a system-property, because
147 * it is not known by Hibernate nor JPA and, hence, not picked up from
148 * their configuration!
150 * @parameter property="hibernate.schema.skip" default-value="${maven.test.skip}"
153 private boolean skip;
158 * Force execution, even if no modified or newly added annotated classes
159 * where found and the dialect was not changed.
161 * <code>skip</code> takes precedence over <code>force</code>.
163 * <strong>Important:</strong>
164 * This configuration value can only be configured through the
165 * <code>pom.xml</code>, or by the definition of a system-property, because
166 * it is not known by Hibernate nor JPA and, hence, not picked up from
167 * their configuration!
169 * @parameter property="hibernate.schema.force" default-value="false"
172 private boolean force;
177 * @parameter property="hibernate.dialect"
180 private String dialect;
183 * Delimiter in output-file.
185 * <strong>Important:</strong>
186 * This configuration value can only be configured through the
187 * <code>pom.xml</code>, or by the definition of a system-property, because
188 * it is not known by Hibernate nor JPA and, hence, not picked up from
189 * their configuration!
191 * @parameter property="hibernate.schema.delimiter" default-value=";"
197 * Show the generated SQL in the command-line output.
199 * @parameter property="hibernate.show_sql"
205 * Format output-file.
207 * @parameter property="hibernate.format_sql"
213 * Specifies whether to automatically create also the database schema/catalog.
215 * @parameter property="hibernate.hbm2dll.create_namespaces" default-value="false"
218 Boolean createNamespaces;
221 * Implicit naming strategy
223 * @parameter property="hibernate.implicit_naming_strategy"
226 private String implicitNamingStrategy;
229 * Physical naming strategy
231 * @parameter property="hibernate.physical_naming_strategy"
234 private String physicalNamingStrategy;
237 * Wether the project should be scanned for annotated-classes, or not
239 * This parameter is intended to allow overwriting of the parameter
240 * <code>exclude-unlisted-classes</code> of a <code>persistence-unit</code>.
241 * If not specified, it defaults to <code>true</code>
243 * @parameter property="hibernate.schema.scan.classes"
246 private Boolean scanClasses;
249 * Classes-Directory to scan.
251 * This parameter defaults to the maven build-output-directory for classes.
252 * Additionally, all dependencies are scanned for annotated classes.
254 * <strong>Important:</strong>
255 * This configuration value can only be configured through the
256 * <code>pom.xml</code>, or by the definition of a system-property, because
257 * it is not known by Hibernate nor JPA and, hence, not picked up from
258 * their configuration!
260 * @parameter property="project.build.outputDirectory"
263 private String outputDirectory;
266 * Dependency-Scopes, that should be scanned for annotated classes.
268 * By default, only dependencies in the scope <code>compile</code> are
269 * scanned for annotated classes. Multiple scopes can be seperated by
270 * white space or commas.
272 * If you do not want any dependencies to be scanned for annotated
273 * classes, set this parameter to <code>none</code>.
275 * The plugin does not scan for annotated classes in transitive
276 * dependencies. If some of your annotated classes are hidden in a
277 * transitive dependency, you can simply add that dependency explicitly.
279 * @parameter property="hibernate.schema.scan.dependencies" default-value="compile"
282 private String scanDependencies;
285 * Whether to scan the test-branch of the project for annotated classes, or
288 * If this parameter is set to <code>true</code> the test-classes of the
289 * artifact will be scanned for hibernate-annotated classes additionally.
291 * <strong>Important:</strong>
292 * This configuration value can only be configured through the
293 * <code>pom.xml</code>, or by the definition of a system-property, because
294 * it is not known by Hibernate nor JPA and, hence, not picked up from
295 * their configuration!
297 * @parameter property="hibernate.schema.scan.test_classes" default-value="false"
300 private Boolean scanTestClasses;
303 * Test-Classes-Directory to scan.
305 * This parameter defaults to the maven build-output-directory for
308 * This parameter is only used, when <code>scanTestClasses</code> is set
309 * to <code>true</code>!
311 * <strong>Important:</strong>
312 * This configuration value can only be configured through the
313 * <code>pom.xml</code>, or by the definition of a system-property, because
314 * it is not known by Hibernate nor JPA and, hence, not picked up from
315 * their configuration!
317 * @parameter property="project.build.testOutputDirectory"
320 private String testOutputDirectory;
323 /** Conection parameters *************************************************/
328 * @parameter property="hibernate.connection.driver_class"
331 private String driver;
336 * @parameter property="hibernate.connection.url"
344 * @parameter property="hibernate.connection.username"
347 private String username;
352 * @parameter property="hibernate.connection.password"
355 private String password;
358 /** Parameters to locate configuration sources ****************************/
361 * Path to a file or name of a ressource with hibernate properties.
362 * If this parameter is specified, the plugin will try to load configuration
363 * values from a file with the given path or a ressource on the classpath with
364 * the given name. If both fails, the execution of the plugin will fail.
366 * If this parameter is not set the plugin will load configuration values
367 * from a ressource named <code>hibernate.properties</code> on the classpath,
368 * if it is present, but will not fail if there is no such ressource.
370 * During ressource-lookup, the test-classpath takes precedence.
375 private String hibernateProperties;
378 * Path to Hibernate configuration file (.cfg.xml).
379 * If this parameter is specified, the plugin will try to load configuration
380 * values from a file with the given path or a ressource on the classpath with
381 * the given name. If both fails, the execution of the plugin will fail.
383 * If this parameter is not set the plugin will load configuration values
384 * from a ressource named <code>hibernate.cfg.xml</code> on the classpath,
385 * if it is present, but will not fail if there is no such ressource.
387 * During ressource-lookup, the test-classpath takes precedence.
389 * Settings in this file will overwrite settings in the properties file.
394 private String hibernateConfig;
397 * Name of the persistence-unit.
398 * If this parameter is specified, the plugin will try to load configuration
399 * values from a persistence-unit with the specified name. If no such
400 * persistence-unit can be found, the plugin will throw an exception.
402 * If this parameter is not set and there is only one persistence-unit
403 * available, that unit will be used automatically. But if this parameter is
404 * not set and there are multiple persistence-units available on,
405 * the class-path, the execution of the plugin will fail.
407 * Settings in this file will overwrite settings in the properties or the
408 * configuration file.
413 private String persistenceUnit;
416 * List of Hibernate-Mapping-Files (XML).
417 * Multiple files can be separated with white-spaces and/or commas.
419 * @parameter property="hibernate.mapping"
422 private String mappings;
426 public final void execute(String filename)
428 MojoFailureException,
429 MojoExecutionException
433 getLog().info("Execution of hibernate-maven-plugin was skipped!");
434 project.getProperties().setProperty(SKIPPED, "true");
438 ModificationTracker tracker;
441 tracker = new ModificationTracker(buildDirectory, filename, getLog());
443 catch (NoSuchAlgorithmException e)
445 throw new MojoFailureException("Digest-Algorithm MD5 is missing!", e);
448 SimpleConnectionProvider connectionProvider =
449 new SimpleConnectionProvider(getLog());
453 /** Start extended logging */
454 MavenLogAppender.startPluginLog(this);
456 /** Load checksums for old mapping and configuration */
459 /** Create the ClassLoader */
460 MutableClassLoader classLoader = createClassLoader();
462 /** Create a BootstrapServiceRegistry with the created ClassLoader */
463 BootstrapServiceRegistry bootstrapServiceRegitry =
464 new BootstrapServiceRegistryBuilder()
465 .applyClassLoader(classLoader)
467 ClassLoaderService classLoaderService =
468 bootstrapServiceRegitry.getService(ClassLoaderService.class);
470 Properties properties = new Properties();
471 ConfigLoader configLoader = new ConfigLoader(bootstrapServiceRegitry);
473 /** Loading and merging configuration */
474 properties.putAll(loadProperties(configLoader));
475 LoadedConfig config = loadConfig(configLoader);
477 properties.putAll(config.getConfigurationValues());
478 ParsedPersistenceXmlDescriptor unit =
479 loadPersistenceUnit(classLoaderService, properties);
481 properties.putAll(unit.getProperties());
483 /** Overwriting/Completing configuration */
484 configure(properties, tracker);
486 /** Check configuration for modifications */
487 if(tracker.track(properties))
488 getLog().debug("Configuration has changed.");
490 getLog().debug("Configuration unchanged.");
492 /** Configure Hibernate */
493 StandardServiceRegistry serviceRegistry =
494 new StandardServiceRegistryBuilder(bootstrapServiceRegitry)
495 .applySettings(properties)
496 .addService(ConnectionProvider.class, connectionProvider)
498 MetadataSources sources = new MetadataSources(serviceRegistry);
500 /** Add the remaining class-path-elements */
501 completeClassPath(classLoader);
503 /** Apply mappings from hibernate-configuration, if present */
506 for (MappingReference mapping : config.getMappingReferences())
507 mapping.apply(sources);
513 /** No persistent unit: default behaviour */
514 if (scanClasses == null)
516 Set<URL> urls = new HashSet<URL>();
518 addRoot(urls, outputDirectory);
520 addRoot(urls, testOutputDirectory);
521 addDependencies(urls);
522 classes = scanUrls(urls);
526 /** Follow configuration in persisten unit */
527 if (scanClasses == null)
528 scanClasses = !unit.isExcludeUnlistedClasses();
529 Set<URL> urls = new HashSet<URL>();
533 * Scan the root of the persiten unit and configured jars for
536 urls.add(unit.getPersistenceUnitRootUrl());
537 for (URL url : unit.getJarFileUrls())
541 addRoot(urls, testOutputDirectory);
542 classes = scanUrls(urls);
543 for (String className : unit.getManagedClassNames())
544 classes.add(className);
546 * Add mappings from the default mapping-file
547 * <code>META-INF/orm.xml</code>, if present
549 boolean error = false;
551 is = classLoader.getResourceAsStream("META-INF/orm.xml");
554 getLog().info("Adding default JPA-XML-mapping from META-INF/orm.xml");
557 tracker.track("META-INF/orm.xml", is);
558 sources.addResource("META-INF/orm.xml");
560 catch (IOException e)
562 getLog().error("cannot read META-INF/orm.xml: " + e);
568 getLog().debug("no META-INF/orm.xml found");
571 * Add mappings from files, that are explicitly configured in the
574 for (String mapping : unit.getMappingFileNames())
576 getLog().info("Adding explicitly configured mapping from " + mapping);
577 is = classLoader.getResourceAsStream(mapping);
582 tracker.track(mapping, is);
583 sources.addResource(mapping);
585 catch (IOException e)
587 getLog().info("cannot read mapping-file " + mapping + ": " + e);
593 getLog().error("cannot find mapping-file " + mapping);
598 throw new MojoFailureException(
599 "error, while reading mappings configured in persistence-unit \"" +
605 /** Add the configured/collected annotated classes */
606 for (String className : classes)
607 addAnnotated(className, sources, classLoaderService, tracker);
609 /** Add explicitly configured classes */
610 addMappings(sources, tracker);
612 /** Skip execution, if mapping and configuration is unchanged */
613 if (!tracker.modified())
616 "Mapping and configuration unchanged."
619 getLog().info("Schema generation is forced!");
622 getLog().info("Skipping schema generation!");
623 project.getProperties().setProperty(SKIPPED, "true");
629 /** Create a connection, if sufficient configuration infromation is available */
630 connectionProvider.open(classLoaderService, properties);
632 MetadataBuilder metadataBuilder = sources.getMetadataBuilder();
634 StrategySelector strategySelector =
635 serviceRegistry.getService(StrategySelector.class);
637 if (properties.containsKey(IMPLICIT_NAMING_STRATEGY))
639 metadataBuilder.applyImplicitNamingStrategy(
640 strategySelector.resolveStrategy(
641 ImplicitNamingStrategy.class,
642 properties.getProperty(IMPLICIT_NAMING_STRATEGY)
647 if (properties.containsKey(PHYSICAL_NAMING_STRATEGY))
649 metadataBuilder.applyPhysicalNamingStrategy(
650 strategySelector.resolveStrategy(
651 PhysicalNamingStrategy.class,
652 properties.getProperty(PHYSICAL_NAMING_STRATEGY)
658 * Change class-loader of current thread.
659 * This is necessary, because still not all parts of Hibernate 5 use
660 * the newly introduced ClassLoaderService and will fail otherwise!
662 Thread thread = Thread.currentThread();
663 ClassLoader contextClassLoader = thread.getContextClassLoader();
666 thread.setContextClassLoader(classLoader);
667 build((MetadataImplementor)metadataBuilder.build());
671 thread.setContextClassLoader(contextClassLoader);
674 catch (MojoExecutionException e)
679 catch (MojoFailureException e)
684 catch (RuntimeException e)
691 /** Remember mappings and configuration */
694 /** Close the connection - if one was opened */
695 connectionProvider.close();
697 /** Stop Log-Capturing */
698 MavenLogAppender.endPluginLog(this);
703 abstract void build(MetadataImplementor metadata)
705 MojoFailureException,
706 MojoExecutionException;
709 private MutableClassLoader createClassLoader() throws MojoExecutionException
713 getLog().debug("Creating ClassLoader for project-dependencies...");
714 LinkedHashSet<URL> urls = new LinkedHashSet<URL>();
717 file = new File(testOutputDirectory);
720 getLog().info("Creating test-output-directory: " + testOutputDirectory);
723 urls.add(file.toURI().toURL());
725 file = new File(outputDirectory);
728 getLog().info("Creating output-directory: " + outputDirectory);
731 urls.add(file.toURI().toURL());
733 return new MutableClassLoader(urls, getLog());
737 getLog().error("Error while creating ClassLoader!", e);
738 throw new MojoExecutionException(e.getMessage());
742 private void completeClassPath(MutableClassLoader classLoader)
744 MojoExecutionException
748 getLog().debug("Completing class-paths of the ClassLoader for project-dependencies...");
749 List<String> classpathFiles = project.getCompileClasspathElements();
751 classpathFiles.addAll(project.getTestClasspathElements());
752 LinkedHashSet<URL> urls = new LinkedHashSet<URL>();
753 for (String pathElement : classpathFiles)
755 getLog().debug("Dependency: " + pathElement);
756 urls.add(new File(pathElement).toURI().toURL());
758 classLoader.add(urls);
762 getLog().error("Error while creating ClassLoader!", e);
763 throw new MojoExecutionException(e.getMessage());
767 private Map loadProperties(ConfigLoader configLoader)
769 MojoExecutionException
771 /** Try to read configuration from properties-file */
772 if (hibernateProperties == null)
776 return configLoader.loadProperties("hibernate.properties");
778 catch (ConfigurationException e)
780 getLog().debug(e.getMessage());
781 return Collections.EMPTY_MAP;
788 File file = new File(hibernateProperties);
791 getLog().info("Reading settings from file " + hibernateProperties + "...");
792 return configLoader.loadProperties(file);
795 return configLoader.loadProperties(hibernateProperties);
797 catch (ConfigurationException e)
799 getLog().error("Error while reading properties!", e);
800 throw new MojoExecutionException(e.getMessage());
805 private LoadedConfig loadConfig(ConfigLoader configLoader)
806 throws MojoExecutionException
808 /** Try to read configuration from configuration-file */
809 if (hibernateConfig == null)
813 return configLoader.loadConfigXmlResource("hibernate.cfg.xml");
815 catch (ConfigurationException e)
817 getLog().debug(e.getMessage());
825 File file = new File(hibernateConfig);
828 getLog().info("Reading configuration from file " + hibernateConfig + "...");
829 return configLoader.loadConfigXmlFile(file);
833 return configLoader.loadConfigXmlResource(hibernateConfig);
836 catch (ConfigurationException e)
838 getLog().error("Error while reading configuration!", e);
839 throw new MojoExecutionException(e.getMessage());
844 private void configure(Properties properties, ModificationTracker tracker)
845 throws MojoFailureException
848 * Special treatment for the configuration-value "export": if it is
849 * switched to "true", the genearation fo the schema should be forced!
851 if (tracker.check(EXPORT, export.toString()) && export)
855 * Configure the generation of the SQL.
856 * Overwrite values from properties-file if the configuration parameter is
857 * known to Hibernate.
859 dialect = configure(properties, dialect, DIALECT);
860 tracker.track(DELIMITER, delimiter); // << not reflected in hibernate configuration!
861 format = configure(properties, format, FORMAT_SQL);
862 createNamespaces = configure(properties, createNamespaces, HBM2DLL_CREATE_NAMESPACES);
863 implicitNamingStrategy = configure(properties, implicitNamingStrategy, IMPLICIT_NAMING_STRATEGY);
864 physicalNamingStrategy = configure(properties, physicalNamingStrategy, PHYSICAL_NAMING_STRATEGY);
865 tracker.track(OUTPUTDIRECTORY, outputDirectory); // << not reflected in hibernate configuration!
866 tracker.track(SCAN_DEPENDENCIES, scanDependencies); // << not reflected in hibernate configuration!
867 tracker.track(SCAN_TESTCLASSES, scanTestClasses.toString()); // << not reflected in hibernate configuration!
868 tracker.track(TEST_OUTPUTDIRECTORY, testOutputDirectory); // << not reflected in hibernate configuration!
871 * Special treatment for the configuration-value "show": a change of its
872 * configured value should not lead to a regeneration of the database
876 show = Boolean.valueOf(properties.getProperty(SHOW_SQL));
878 properties.setProperty(SHOW_SQL, show.toString());
881 * Configure the connection parameters.
882 * Overwrite values from properties-file.
884 driver = configure(properties, driver, DRIVER, JDBC_DRIVER);
885 url = configure(properties, url, URL, JDBC_URL);
886 username = configure(properties, username, USER, JDBC_USER);
887 password = configure(properties, password, PASS, JDBC_PASSWORD);
889 if (properties.isEmpty())
891 getLog().error("No properties set!");
892 throw new MojoFailureException("Hibernate configuration is missing!");
895 getLog().info("Gathered hibernate-configuration (turn on debugging for details):");
896 for (Entry<Object,Object> entry : properties.entrySet())
897 getLog().info(" " + entry.getKey() + " = " + entry.getValue());
900 private String configure(
901 Properties properties,
904 String alternativeKey
907 value = configure(properties, value, key);
909 return properties.getProperty(alternativeKey);
911 if (properties.containsKey(alternativeKey))
914 "Ignoring property " + alternativeKey + "=" +
915 properties.getProperty(alternativeKey) + " in favour for property " +
916 key + "=" + properties.getProperty(key)
918 properties.remove(alternativeKey);
920 return properties.getProperty(alternativeKey);
923 private String configure(Properties properties, String value, String key)
927 if (properties.containsKey(key))
929 "Overwriting property " + key + "=" + properties.getProperty(key) +
930 " with the value " + value
933 getLog().debug("Using the value " + value + " for property " + key);
934 properties.setProperty(key, value);
936 return properties.getProperty(key);
939 private boolean configure(Properties properties, Boolean value, String key)
943 if (properties.containsKey(key))
945 "Overwriting property " + key + "=" + properties.getProperty(key) +
946 " with the value " + value
949 getLog().debug("Using the value " + value + " for property " + key);
950 properties.setProperty(key, value.toString());
952 return Boolean.valueOf(properties.getProperty(key));
955 private void addMappings(MetadataSources sources, ModificationTracker tracker)
956 throws MojoFailureException
958 getLog().debug("Adding explicitly configured mappings...");
959 if (mappings != null)
963 for (String filename : mappings.split("[\\s,]+"))
965 // First try the filename as absolute/relative path
966 File file = new File(filename);
969 // If the file was not found, search for it in the resource-directories
970 for (Resource resource : project.getResources())
972 file = new File(resource.getDirectory() + File.separator + filename);
979 if (file.isDirectory())
980 // TODO: add support to read all mappings under a directory
981 throw new MojoFailureException(file.getAbsolutePath() + " is a directory");
982 if (tracker.track(filename, new FileInputStream(file)))
983 getLog().debug("Found new or modified mapping-file: " + filename);
985 getLog().debug("Mapping-file unchanged: " + filename);
987 sources.addFile(file);
990 throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!");
993 catch (IOException e)
995 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
1000 private void addRoot(Set<URL> urls, String path) throws MojoFailureException
1004 File dir = new File(outputDirectory);
1007 getLog().info("Adding " + dir.getAbsolutePath() + " to the list of roots to scan...");
1008 urls.add(dir.toURI().toURL());
1011 catch (MalformedURLException e)
1013 getLog().error("error while adding the project-root to the list of roots to scan!", e);
1014 throw new MojoFailureException(e.getMessage());
1018 private void addDependencies(Set<URL> urls) throws MojoFailureException
1022 if (scanDependencies != null)
1024 Matcher matcher = SPLIT.matcher(scanDependencies);
1025 while (matcher.find())
1027 getLog().info("Adding dependencies from scope " + matcher.group() + " to the list of roots to scan");
1028 for (Artifact artifact : project.getDependencyArtifacts())
1030 if (!artifact.getScope().equalsIgnoreCase(matcher.group()))
1032 if (artifact.getFile() == null)
1034 getLog().warn("Cannot add dependency " + artifact.getId() + ": no JAR-file available!");
1037 getLog().info("Adding dependencies from scope " + artifact.getId() + " to the list of roots to scan");
1038 urls.add(artifact.getFile().toURI().toURL());
1043 catch (MalformedURLException e)
1045 getLog().error("Error while adding dependencies to the list of roots to scan!", e);
1046 throw new MojoFailureException(e.getMessage());
1050 private Set<String> scanUrls(Set<URL> scanRoots)
1052 MojoFailureException
1056 AnnotationDB db = new AnnotationDB();
1057 for (URL root : scanRoots)
1058 db.scanArchives(root);
1060 Set<String> classes = new HashSet<String>();
1061 if (db.getAnnotationIndex().containsKey(Entity.class.getName()))
1062 classes.addAll(db.getAnnotationIndex().get(Entity.class.getName()));
1063 if (db.getAnnotationIndex().containsKey(MappedSuperclass.class.getName()))
1064 classes.addAll(db.getAnnotationIndex().get(MappedSuperclass.class.getName()));
1065 if (db.getAnnotationIndex().containsKey(Embeddable.class.getName()))
1066 classes.addAll(db.getAnnotationIndex().get(Embeddable.class.getName()));
1072 getLog().error("Error while scanning!", e);
1073 throw new MojoFailureException(e.getMessage());
1077 private void addAnnotated(
1079 MetadataSources sources,
1080 ClassLoaderService classLoaderService,
1081 ModificationTracker tracker
1084 MojoFailureException,
1085 MojoExecutionException
1089 getLog().info("Adding annotated resource: " + name);
1090 String packageName = null;
1092 boolean error = false;
1095 Class<?> annotatedClass = classLoaderService.classForName(name);
1096 String resourceName = annotatedClass.getName();
1098 resourceName.substring(
1099 resourceName.lastIndexOf(".") + 1,
1100 resourceName.length()
1102 InputStream is = annotatedClass.getResourceAsStream(resourceName);
1105 if (tracker.track(name, is))
1106 getLog().debug("New or modified class: " + name);
1108 getLog().debug("Unchanged class: " + name);
1109 sources.addAnnotatedClass(annotatedClass);
1110 packageName = annotatedClass.getPackage().getName();
1114 getLog().error("cannot find ressource " + resourceName + " for class " + name);
1118 catch(ClassLoadingException e)
1124 throw new MojoExecutionException("error while inspecting annotated class " + name);
1127 while (packageName != null)
1129 if (packages.contains(packageName))
1131 String resource = packageName.replace('.', '/') + "/package-info.class";
1132 InputStream is = classLoaderService.locateResourceStream(resource);
1135 // No compiled package-info available: no package-level annotations!
1136 getLog().debug("Package " + packageName + " is not annotated.");
1140 if (tracker.track(packageName, is))
1141 getLog().debug("New or modified package: " + packageName);
1143 getLog().debug("Unchanged package: " + packageName);
1144 getLog().info("Adding annotations from package " + packageName);
1145 sources.addPackage(packageName);
1147 packages.add(packageName);
1148 int i = packageName.lastIndexOf('.');
1152 packageName = packageName.substring(0,i);
1157 getLog().error("Error while adding the annotated class " + name, e);
1158 throw new MojoFailureException(e.getMessage());
1162 private ParsedPersistenceXmlDescriptor loadPersistenceUnit(
1163 ClassLoaderService classLoaderService,
1164 Properties properties
1167 MojoFailureException
1169 PersistenceXmlParser parser =
1170 new PersistenceXmlParser(
1172 PersistenceUnitTransactionType.RESOURCE_LOCAL
1175 List<ParsedPersistenceXmlDescriptor> units = parser.doResolve(properties);
1177 if (persistenceUnit == null)
1179 switch (units.size())
1182 getLog().info("Found no META-INF/persistence.xml.");
1185 getLog().info("Using persistence-unit " + units.get(0).getName());
1186 return units.get(0);
1188 StringBuilder builder = new StringBuilder();
1189 builder.append("No name provided and multiple persistence units found: ");
1190 Iterator<ParsedPersistenceXmlDescriptor> it = units.iterator();
1191 builder.append(it.next().getName());
1192 while (it.hasNext())
1194 builder.append(", ");
1195 builder.append(it.next().getName());
1197 builder.append('.');
1198 throw new MojoFailureException(builder.toString());
1202 for (ParsedPersistenceXmlDescriptor unit : units)
1204 getLog().debug("Found persistence-unit " + unit.getName());
1205 if (!unit.getName().equals(persistenceUnit))
1208 // See if we (Hibernate) are the persistence provider
1209 if (!ProviderChecker.isProvider(unit, properties))
1211 getLog().debug("Wrong provider: " + unit.getProviderClassName());
1215 getLog().info("Using persistence-unit " + unit.getName());
1219 throw new MojoFailureException("Could not find persistence-unit " + persistenceUnit);