import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.net.MalformedURLException;
import java.net.URL;
-import java.net.URLClassLoader;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.cfgxml.internal.ConfigLoader;
+import org.hibernate.boot.cfgxml.spi.LoadedConfig;
+import org.hibernate.boot.cfgxml.spi.MappingReference;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
+import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.boot.spi.MetadataImplementor;
import static org.hibernate.cfg.AvailableSettings.DIALECT;
import static org.hibernate.cfg.AvailableSettings.DRIVER;
+import static org.hibernate.cfg.AvailableSettings.FORMAT_SQL;
+import static org.hibernate.cfg.AvailableSettings.HBM2DLL_CREATE_NAMESPACES;
import static org.hibernate.cfg.AvailableSettings.IMPLICIT_NAMING_STRATEGY;
import static org.hibernate.cfg.AvailableSettings.PASS;
import static org.hibernate.cfg.AvailableSettings.PHYSICAL_NAMING_STRATEGY;
+import static org.hibernate.cfg.AvailableSettings.SHOW_SQL;
import static org.hibernate.cfg.AvailableSettings.USER;
import static org.hibernate.cfg.AvailableSettings.URL;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
*/
public abstract class AbstractSchemaMojo extends AbstractMojo
{
- public final static String EXPORT_SKIPPED_PROPERTY = "hibernate.export.skipped";
+ public final static String EXPORT = "hibernate.schema.export";
+ public final static String DELIMITER = "hibernate.schema.delimiter";
+ public final static String OUTPUTDIRECTORY = "project.build.outputDirectory";
+ public final static String SCAN_CLASSES = "hibernate.schema.scan.classes";
+ public final static String SCAN_DEPENDENCIES = "hibernate.schema.scan.dependencies";
+ public final static String SCAN_TESTCLASSES = "hibernate.schema.scan.test_classes";
+ public final static String TEST_OUTPUTDIRECTORY = "project.build.testOutputDirectory";
+ public final static String SKIPPED = "hibernate.schema.skipped";
private final static Pattern SPLIT = Pattern.compile("[^,\\s]+");
+ private final Set<String> packages = new HashSet<String>();
/**
* The maven project.
*/
String buildDirectory;
+
+ /** Parameters to configure the genaration of the SQL *********************/
+
/**
- * Classes-Directory to scan.
+ * Export the database-schma to the database.
+ * If set to <code>false</code>, only the SQL-script is created and the
+ * database is not touched.
* <p>
- * This parameter defaults to the maven build-output-directory for classes.
- * Additionally, all dependencies are scanned for annotated classes.
+ * <strong>Important:</strong>
+ * This configuration value can only be configured through the
+ * <code>pom.xml</code>, or by the definition of a system-property, because
+ * it is not known by Hibernate nor JPA and, hence, not picked up from
+ * their configuration!
*
- * @parameter property="project.build.outputDirectory"
+ * @parameter property="hibernate.schema.export" default-value="true"
+ * @since 2.0
+ */
+ Boolean export;
+
+ /**
+ * Skip execution
+ * <p>
+ * If set to <code>true</code>, the execution is skipped.
+ * <p>
+ * A skipped execution is signaled via the maven-property
+ * <code>${hibernate.export.skipped}</code>.
+ * <p>
+ * The execution is skipped automatically, if no modified or newly added
+ * annotated classes are found and the dialect was not changed.
+ * <p>
+ * <strong>Important:</strong>
+ * This configuration value can only be configured through the
+ * <code>pom.xml</code>, or by the definition of a system-property, because
+ * it is not known by Hibernate nor JPA and, hence, not picked up from
+ * their configuration!
+ *
+ * @parameter property="hibernate.schema.skip" default-value="${maven.test.skip}"
* @since 1.0
*/
- private String outputDirectory;
+ private boolean skip;
/**
- * Whether to scan test-classes too, or not.
+ * Force execution
* <p>
- * If this parameter is set to <code>true</code> the test-classes of the
- * artifact will be scanned for hibernate-annotated classes additionally.
+ * Force execution, even if no modified or newly added annotated classes
+ * where found and the dialect was not changed.
+ * <p>
+ * <code>skip</code> takes precedence over <code>force</code>.
+ * <p>
+ * <strong>Important:</strong>
+ * This configuration value can only be configured through the
+ * <code>pom.xml</code>, or by the definition of a system-property, because
+ * it is not known by Hibernate nor JPA and, hence, not picked up from
+ * their configuration!
*
- * @parameter property="hibernate.export.scan_testclasses" default-value="false"
- * @since 1.0.1
+ * @parameter property="hibernate.schema.force" default-value="false"
+ * @since 1.0
+ */
+ private boolean force;
+
+ /**
+ * Hibernate dialect.
+ *
+ * @parameter property="hibernate.dialect"
+ * @since 1.0
+ */
+ private String dialect;
+
+ /**
+ * Delimiter in output-file.
+ * <p>
+ * <strong>Important:</strong>
+ * This configuration value can only be configured through the
+ * <code>pom.xml</code>, or by the definition of a system-property, because
+ * it is not known by Hibernate nor JPA and, hence, not picked up from
+ * their configuration!
+ *
+ * @parameter property="hibernate.schema.delimiter" default-value=";"
+ * @since 1.0
+ */
+ String delimiter;
+
+ /**
+ * Show the generated SQL in the command-line output.
+ *
+ * @parameter property="hibernate.show_sql"
+ * @since 1.0
+ */
+ Boolean show;
+
+ /**
+ * Format output-file.
+ *
+ * @parameter property="hibernate.format_sql"
+ * @since 1.0
+ */
+ Boolean format;
+
+ /**
+ * Specifies whether to automatically create also the database schema/catalog.
+ *
+ * @parameter property="hibernate.hbm2dll.create_namespaces" default-value="false"
+ * @since 2.0
+ */
+ Boolean createNamespaces;
+
+ /**
+ * Implicit naming strategy
+ *
+ * @parameter property="hibernate.implicit_naming_strategy"
+ * @since 2.0
+ */
+ private String implicitNamingStrategy;
+
+ /**
+ * Physical naming strategy
+ *
+ * @parameter property="hibernate.physical_naming_strategy"
+ * @since 2.0
+ */
+ private String physicalNamingStrategy;
+
+ /**
+ * Wether the project should be scanned for annotated-classes, or not
+ * <p>
+ * This parameter is intended to allow overwriting of the parameter
+ * <code>exclude-unlisted-classes</code> of a <code>persistence-unit</code>.
+ * If not specified, it defaults to <code>true</code>
+ *
+ * @parameter property="hibernate.schema.scan.classes"
+ * @since 2.0
+ */
+ private Boolean scanClasses;
+
+ /**
+ * Classes-Directory to scan.
+ * <p>
+ * This parameter defaults to the maven build-output-directory for classes.
+ * Additionally, all dependencies are scanned for annotated classes.
+ * <p>
+ * <strong>Important:</strong>
+ * This configuration value can only be configured through the
+ * <code>pom.xml</code>, or by the definition of a system-property, because
+ * it is not known by Hibernate nor JPA and, hence, not picked up from
+ * their configuration!
+ *
+ * @parameter property="project.build.outputDirectory"
+ * @since 1.0
*/
- private boolean scanTestClasses;
+ private String outputDirectory;
/**
* Dependency-Scopes, that should be scanned for annotated classes.
* By default, only dependencies in the scope <code>compile</code> are
* scanned for annotated classes. Multiple scopes can be seperated by
* white space or commas.
- * <p>md5s
+ * <p>
* If you do not want any dependencies to be scanned for annotated
* classes, set this parameter to <code>none</code>.
* <p>
* dependencies. If some of your annotated classes are hidden in a
* transitive dependency, you can simply add that dependency explicitly.
*
- * @parameter property="hibernate.export.scan_dependencies" default-value="compile"
+ * @parameter property="hibernate.schema.scan.dependencies" default-value="compile"
* @since 1.0.3
*/
private String scanDependencies;
+ /**
+ * Whether to scan the test-branch of the project for annotated classes, or
+ * not.
+ * <p>
+ * If this parameter is set to <code>true</code> the test-classes of the
+ * artifact will be scanned for hibernate-annotated classes additionally.
+ * <p>
+ * <strong>Important:</strong>
+ * This configuration value can only be configured through the
+ * <code>pom.xml</code>, or by the definition of a system-property, because
+ * it is not known by Hibernate nor JPA and, hence, not picked up from
+ * their configuration!
+ *
+ * @parameter property="hibernate.schema.scan.test_classes" default-value="false"
+ * @since 1.0.1
+ */
+ private Boolean scanTestClasses;
+
/**
* Test-Classes-Directory to scan.
* <p>
* <p>
* This parameter is only used, when <code>scanTestClasses</code> is set
* to <code>true</code>!
+ * <p>
+ * <strong>Important:</strong>
+ * This configuration value can only be configured through the
+ * <code>pom.xml</code>, or by the definition of a system-property, because
+ * it is not known by Hibernate nor JPA and, hence, not picked up from
+ * their configuration!
*
* @parameter property="project.build.testOutputDirectory"
* @since 1.0.2
*/
private String testOutputDirectory;
- /**
- * Skip execution
- * <p>
- * If set to <code>true</code>, the execution is skipped.
- * <p>
- * A skipped execution is signaled via the maven-property
- * <code>${hibernate.export.skipped}</code>.
- * <p>
- * The execution is skipped automatically, if no modified or newly added
- * annotated classes are found and the dialect was not changed.
- *
- * @parameter property="hibernate.skip" default-value="${maven.test.skip}"
- * @since 1.0
- */
- private boolean skip;
- /**
- * Force execution
- * <p>
- * Force execution, even if no modified or newly added annotated classes
- * where found and the dialect was not changed.
- * <p>
- * <code>skip</code> takes precedence over <code>force</code>.
- *
- * @parameter property="hibernate.export.force" default-value="false"
- * @since 1.0
- */
- private boolean force;
+ /** Conection parameters *************************************************/
/**
* SQL-Driver name.
*/
private String password;
- /**
- * Hibernate dialect.
- *
- * @parameter property="hibernate.dialect"
- * @since 1.0
- */
- private String dialect;
-
- /**
- * Implicit naming strategy
- *
- * @parameter property=IMPLICIT_NAMING_STRATEGY
- * @since 2.0
- */
- private String implicitNamingStrategy;
- /**
- * Physical naming strategy
- *
- * @parameter property=PHYSICAL_NAMING_STRATEGY
- * @since 2.0
- */
- private String physicalNamingStrategy;
+ /** Parameters to locate configuration sources ****************************/
/**
* Path to a file or name of a ressource with hibernate properties.
private String mappings;
- @Override
- public final void execute()
+
+ public final void execute(String filename)
throws
MojoFailureException,
MojoExecutionException
if (skip)
{
getLog().info("Execution of hibernate-maven-plugin was skipped!");
- project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
+ project.getProperties().setProperty(SKIPPED, "true");
return;
}
ModificationTracker tracker;
try
{
- tracker = new ModificationTracker(buildDirectory, getLog());
+ tracker = new ModificationTracker(buildDirectory, filename, getLog());
}
catch (NoSuchAlgorithmException e)
{
/** Load checksums for old mapping and configuration */
tracker.load();
- /** Create a BootstrapServiceRegistry with special ClassLoader */
+ /** Create the ClassLoader */
+ MutableClassLoader classLoader = createClassLoader();
+
+ /** Create a BootstrapServiceRegistry with the created ClassLoader */
BootstrapServiceRegistry bootstrapServiceRegitry =
new BootstrapServiceRegistryBuilder()
- .applyClassLoader(createClassLoader())
+ .applyClassLoader(classLoader)
.build();
ClassLoaderService classLoaderService =
bootstrapServiceRegitry.getService(ClassLoaderService.class);
/** Loading and merging configuration */
properties.putAll(loadProperties(configLoader));
- properties.putAll(loadConfig(configLoader));
- properties.putAll(loadPersistenceUnit(classLoaderService, properties));
+ LoadedConfig config = loadConfig(configLoader);
+ if (config != null)
+ properties.putAll(config.getConfigurationValues());
+ ParsedPersistenceXmlDescriptor unit =
+ loadPersistenceUnit(classLoaderService, properties);
+ if (unit != null)
+ properties.putAll(unit.getProperties());
/** Overwriting/Completing configuration */
- configure(properties);
+ configure(properties, tracker);
/** Check configuration for modifications */
- if(tracker.check(properties))
+ if(tracker.track(properties))
getLog().debug("Configuration has changed.");
else
getLog().debug("Configuration unchanged.");
.applySettings(properties)
.addService(ConnectionProvider.class, connectionProvider)
.build();
-
- /** Load Mappings */
MetadataSources sources = new MetadataSources(serviceRegistry);
- addAnnotatedClasses(sources, classLoaderService, tracker);
+
+ /** Add the remaining class-path-elements */
+ completeClassPath(classLoader);
+
+ /** Apply mappings from hibernate-configuration, if present */
+ if (config != null)
+ {
+ for (MappingReference mapping : config.getMappingReferences())
+ mapping.apply(sources);
+ }
+
+ Set<String> classes;
+ if (unit == null)
+ {
+ /** No persistent unit: default behaviour */
+ if (scanClasses == null)
+ scanClasses = true;
+ Set<URL> urls = new HashSet<URL>();
+ if (scanClasses)
+ addRoot(urls, outputDirectory);
+ if (scanTestClasses)
+ addRoot(urls, testOutputDirectory);
+ addDependencies(urls);
+ classes = scanUrls(urls);
+ }
+ else
+ {
+ /** Follow configuration in persisten unit */
+ if (scanClasses == null)
+ scanClasses = !unit.isExcludeUnlistedClasses();
+ Set<URL> urls = new HashSet<URL>();
+ if (scanClasses)
+ {
+ /**
+ * Scan the root of the persiten unit and configured jars for
+ * annotated classes
+ */
+ urls.add(unit.getPersistenceUnitRootUrl());
+ for (URL url : unit.getJarFileUrls())
+ urls.add(url);
+ }
+ if (scanTestClasses)
+ addRoot(urls, testOutputDirectory);
+ classes = scanUrls(urls);
+ for (String className : unit.getManagedClassNames())
+ classes.add(className);
+ /**
+ * Add mappings from the default mapping-file
+ * <code>META-INF/orm.xml</code>, if present
+ */
+ try
+ {
+ InputStream is = classLoader.getResourceAsStream("META-INF/orm.xml");
+ if (is != null)
+ {
+ getLog().info("Adding default JPA-XML-mapping from META-INF/orm.xml");
+ tracker.track("META-INF/orm.xml", is);
+ sources.addResource("META-INF/orm.xml");
+ }
+ /**
+ * Add mappings from files, that are explicitly configured in the
+ * persistence unit
+ */
+ for (String mapping : unit.getMappingFileNames())
+ {
+ getLog().info("Adding explicitly configured mapping from " + mapping);
+ tracker.track(mapping, classLoader.getResourceAsStream(mapping));
+ sources.addResource(mapping);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new MojoFailureException("Error reading XML-mappings", e);
+ }
+ }
+
+ /** Add the configured/collected annotated classes */
+ for (String className : classes)
+ addAnnotated(className, sources, classLoaderService, tracker);
+
+ /** Add explicitly configured classes */
addMappings(sources, tracker);
/** Skip execution, if mapping and configuration is unchanged */
else
{
getLog().info("Skipping schema generation!");
- project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
+ project.getProperties().setProperty(SKIPPED, "true");
return;
}
}
);
}
- build((MetadataImplementor)metadataBuilder.build());
+ /**
+ * Change class-loader of current thread.
+ * This is necessary, because still not all parts of Hibernate 5 use
+ * the newly introduced ClassLoaderService and will fail otherwise!
+ */
+ Thread thread = Thread.currentThread();
+ ClassLoader contextClassLoader = thread.getContextClassLoader();
+ try
+ {
+ thread.setContextClassLoader(classLoader);
+ build((MetadataImplementor)metadataBuilder.build());
+ }
+ finally
+ {
+ thread.setContextClassLoader(contextClassLoader);
+ }
+ }
+ catch (MojoExecutionException e)
+ {
+ tracker.failed();
+ throw e;
+ }
+ catch (MojoFailureException e)
+ {
+ tracker.failed();
+ throw e;
+ }
+ catch (RuntimeException e)
+ {
+ tracker.failed();
+ throw e;
}
finally
{
MojoExecutionException;
- private URLClassLoader createClassLoader() throws MojoExecutionException
+ private MutableClassLoader createClassLoader() throws MojoExecutionException
{
try
{
getLog().debug("Creating ClassLoader for project-dependencies...");
- List<String> classpathFiles = project.getCompileClasspathElements();
- if (scanTestClasses)
- classpathFiles.addAll(project.getTestClasspathElements());
- List<URL> urls = new LinkedList<URL>();
+ LinkedHashSet<URL> urls = new LinkedHashSet<URL>();
File file;
+
file = new File(testOutputDirectory);
if (!file.exists())
{
- getLog().info("creating test-output-directory: " + testOutputDirectory);
+ getLog().info("Creating test-output-directory: " + testOutputDirectory);
file.mkdirs();
}
urls.add(file.toURI().toURL());
+
file = new File(outputDirectory);
if (!file.exists())
{
- getLog().info("creating output-directory: " + outputDirectory);
+ getLog().info("Creating output-directory: " + outputDirectory);
file.mkdirs();
}
urls.add(file.toURI().toURL());
+
+ return new MutableClassLoader(urls, getLog());
+ }
+ catch (Exception e)
+ {
+ getLog().error("Error while creating ClassLoader!", e);
+ throw new MojoExecutionException(e.getMessage());
+ }
+ }
+
+ private void completeClassPath(MutableClassLoader classLoader)
+ throws
+ MojoExecutionException
+ {
+ try
+ {
+ getLog().debug("Completing class-paths of the ClassLoader for project-dependencies...");
+ List<String> classpathFiles = project.getCompileClasspathElements();
+ if (scanTestClasses)
+ classpathFiles.addAll(project.getTestClasspathElements());
+ LinkedHashSet<URL> urls = new LinkedHashSet<URL>();
for (String pathElement : classpathFiles)
{
getLog().debug("Dependency: " + pathElement);
urls.add(new File(pathElement).toURI().toURL());
}
- return
- new URLClassLoader(
- urls.toArray(new URL[urls.size()]),
- getClass().getClassLoader()
- );
+ classLoader.add(urls);
}
catch (Exception e)
{
}
}
- private Map loadConfig(ConfigLoader configLoader)
+ private LoadedConfig loadConfig(ConfigLoader configLoader)
throws MojoExecutionException
{
/** Try to read configuration from configuration-file */
{
try
{
- return
- configLoader
- .loadConfigXmlResource("hibernate.cfg.xml")
- .getConfigurationValues();
+ return configLoader.loadConfigXmlResource("hibernate.cfg.xml");
}
catch (ConfigurationException e)
{
getLog().debug(e.getMessage());
- return Collections.EMPTY_MAP;
+ return null;
}
}
else
if (file.exists())
{
getLog().info("Reading configuration from file " + hibernateConfig + "...");
- return configLoader.loadConfigXmlFile(file).getConfigurationValues();
+ return configLoader.loadConfigXmlFile(file);
}
else
- return
- configLoader
- .loadConfigXmlResource(hibernateConfig)
- .getConfigurationValues();
+ {
+ return configLoader.loadConfigXmlResource(hibernateConfig);
+ }
}
catch (ConfigurationException e)
{
}
}
- private void configure(Properties properties)
+ private void configure(Properties properties, ModificationTracker tracker)
throws MojoFailureException
{
- /** Overwrite values from properties-file or set, if given */
+ /**
+ * Special treatment for the configuration-value "export": if it is
+ * switched to "true", the genearation fo the schema should be forced!
+ */
+ if (tracker.check(EXPORT, export.toString()) && export)
+ tracker.touch();
+
+ /**
+ * Configure the generation of the SQL.
+ * Overwrite values from properties-file if the configuration parameter is
+ * known to Hibernate.
+ */
+ dialect = configure(properties, dialect, DIALECT);
+ tracker.track(DELIMITER, delimiter); // << not reflected in hibernate configuration!
+ format = configure(properties, format, FORMAT_SQL);
+ createNamespaces = configure(properties, createNamespaces, HBM2DLL_CREATE_NAMESPACES);
+ implicitNamingStrategy = configure(properties, implicitNamingStrategy, IMPLICIT_NAMING_STRATEGY);
+ physicalNamingStrategy = configure(properties, physicalNamingStrategy, PHYSICAL_NAMING_STRATEGY);
+ tracker.track(OUTPUTDIRECTORY, outputDirectory); // << not reflected in hibernate configuration!
+ tracker.track(SCAN_DEPENDENCIES, scanDependencies); // << not reflected in hibernate configuration!
+ tracker.track(SCAN_TESTCLASSES, scanTestClasses.toString()); // << not reflected in hibernate configuration!
+ tracker.track(TEST_OUTPUTDIRECTORY, testOutputDirectory); // << not reflected in hibernate configuration!
+
+ /**
+ * Special treatment for the configuration-value "show": a change of its
+ * configured value should not lead to a regeneration of the database
+ * schama!
+ */
+ if (show == null)
+ show = Boolean.valueOf(properties.getProperty(SHOW_SQL));
+ else
+ properties.setProperty(SHOW_SQL, show.toString());
- if (driver != null)
- {
- if (properties.containsKey(DRIVER))
- getLog().debug("Overwriting property " +
- DRIVER + "=" + properties.getProperty(DRIVER) +
- " with the value " + driver
- );
- else
- getLog().debug("Using the value " + driver);
- properties.setProperty(DRIVER, driver);
- }
- if (properties.getProperty(DRIVER) == null)
- {
- String driver = properties.getProperty(JDBC_DRIVER);
- if (driver != null)
- {
- getLog().info(DRIVER +
- " is not set. Borrow setting from " +
- JDBC_DRIVER +
- ": " +
- driver);
- properties.setProperty(DRIVER, driver);
- }
- }
+ /**
+ * Configure the connection parameters.
+ * Overwrite values from properties-file.
+ */
+ driver = configure(properties, driver, DRIVER, JDBC_DRIVER);
+ url = configure(properties, url, URL, JDBC_URL);
+ username = configure(properties, username, USER, JDBC_USER);
+ password = configure(properties, password, PASS, JDBC_PASSWORD);
- if (url != null)
- {
- if (properties.containsKey(URL))
- getLog().debug(
- "Overwriting property " +
- URL + "=" + properties.getProperty(URL) +
- " with the value " + url
- );
- else
- getLog().debug("Using the value " + url);
- properties.setProperty(URL, url);
- }
- if (properties.getProperty(URL) == null)
+ if (properties.isEmpty())
{
- String url = properties.getProperty(JDBC_URL);
- if (url != null)
- {
- getLog().info(URL +
- " is not set. Borrow setting from " +
- JDBC_URL +
- ": " +
- url);
- properties.setProperty(URL, url);
- }
+ getLog().error("No properties set!");
+ throw new MojoFailureException("Hibernate configuration is missing!");
}
- if (username != null)
- {
- if (properties.containsKey(USER))
- getLog().debug("Overwriting property " +
- USER + "=" + properties.getProperty(USER) +
- " with the value " + username
- );
- else
- getLog().debug("Using the value " + username);
- properties.setProperty(USER, username);
- }
- if (properties.getProperty(USER) == null)
- {
- username = properties.getProperty(JDBC_USER);
- if (username != null)
- {
- getLog().info(USER +
- " is not set. Borrow setting from " +
- JDBC_USER +
- ": " +
- username);
- properties.setProperty(USER, username);
- }
- }
+ getLog().info("Gathered hibernate-configuration (turn on debugging for details):");
+ for (Entry<Object,Object> entry : properties.entrySet())
+ getLog().info(" " + entry.getKey() + " = " + entry.getValue());
+ }
- if (password != null)
- {
- if (properties.containsKey(PASS))
- getLog().debug("Overwriting property " +
- PASS + "=" + properties.getProperty(PASS) +
- " with value " + password
- );
- else
- getLog().debug("Using value " + password + " for property " + PASS);
- properties.setProperty(PASS, password);
- }
- if (properties.getProperty(PASS) == null)
- {
- password = properties.getProperty(JDBC_PASSWORD);
- if (password != null)
- {
- getLog().info(PASS +
- " is not set. Borrow setting from " +
- JDBC_PASSWORD +
- ": " +
- password);
- properties.setProperty(PASS, password);
- }
- }
+ private String configure(
+ Properties properties,
+ String value,
+ String key,
+ String alternativeKey
+ )
+ {
+ value = configure(properties, value, key);
+ if (value == null)
+ return properties.getProperty(alternativeKey);
- if (dialect != null)
+ if (properties.containsKey(alternativeKey))
{
- if (properties.containsKey(DIALECT))
- getLog().debug(
- "Overwriting property " +
- DIALECT + "=" + properties.getProperty(DIALECT) +
- " with value " + dialect
+ getLog().warn(
+ "Ignoring property " + alternativeKey + "=" +
+ properties.getProperty(alternativeKey) + " in favour for property " +
+ key + "=" + properties.getProperty(key)
);
- else
- getLog().debug(
- "Using value " + dialect + " for property " + DIALECT
- );
- properties.setProperty(DIALECT, dialect);
+ properties.remove(alternativeKey);
}
+ return properties.getProperty(alternativeKey);
+ }
- if (implicitNamingStrategy != null )
+ private String configure(Properties properties, String value, String key)
+ {
+ if (value != null)
{
- if ( properties.contains(IMPLICIT_NAMING_STRATEGY))
+ if (properties.containsKey(key))
getLog().debug(
- "Overwriting property " +
- IMPLICIT_NAMING_STRATEGY + "=" + properties.getProperty(IMPLICIT_NAMING_STRATEGY) +
- " with value " + implicitNamingStrategy
- );
- else
- getLog().debug(
- "Using value " + implicitNamingStrategy + " for property " +
- IMPLICIT_NAMING_STRATEGY +
- "Using value " + dialect + " for property " + DIALECT
+ "Overwriting property " + key + "=" + properties.getProperty(key) +
+ " with the value " + value
);
- properties.setProperty(IMPLICIT_NAMING_STRATEGY, implicitNamingStrategy);
+ else
+ getLog().debug("Using the value " + value + " for property " + key);
+ properties.setProperty(key, value);
}
+ return properties.getProperty(key);
+ }
- if (physicalNamingStrategy != null )
+ private boolean configure(Properties properties, Boolean value, String key)
+ {
+ if (value != null)
{
- if ( properties.contains(PHYSICAL_NAMING_STRATEGY))
+ if (properties.containsKey(key))
getLog().debug(
- "Overwriting property " +
- PHYSICAL_NAMING_STRATEGY + "=" + properties.getProperty(PHYSICAL_NAMING_STRATEGY) +
- " with value " + physicalNamingStrategy
- );
- else
- getLog().debug(
- "Using value " + physicalNamingStrategy + " for property " +
- PHYSICAL_NAMING_STRATEGY +
- "Using value " + dialect + " for property " + DIALECT
+ "Overwriting property " + key + "=" + properties.getProperty(key) +
+ " with the value " + value
);
- properties.setProperty(PHYSICAL_NAMING_STRATEGY, physicalNamingStrategy);
- }
-
- if (properties.isEmpty())
- {
- getLog().error("No properties set!");
- throw new MojoFailureException("Hibernate configuration is missing!");
+ else
+ getLog().debug("Using the value " + value + " for property " + key);
+ properties.setProperty(key, value.toString());
}
-
- getLog().info("Gathered hibernate-configuration (turn on debugging for details):");
- for (Entry<Object,Object> entry : properties.entrySet())
- getLog().info(" " + entry.getKey() + " = " + entry.getValue());
+ return Boolean.valueOf(properties.getProperty(key));
}
private void addMappings(MetadataSources sources, ModificationTracker tracker)
if (file.isDirectory())
// TODO: add support to read all mappings under a directory
throw new MojoFailureException(file.getAbsolutePath() + " is a directory");
- if (tracker.check(filename, new FileInputStream(file)))
+ if (tracker.track(filename, new FileInputStream(file)))
getLog().debug("Found new or modified mapping-file: " + filename);
else
- getLog().debug("mapping-file unchanged: " + filename);
+ getLog().debug("Mapping-file unchanged: " + filename);
sources.addFile(file);
}
}
}
- private void addAnnotatedClasses(
- MetadataSources sources,
- ClassLoaderService classLoaderService,
- ModificationTracker tracker
- )
- throws
- MojoFailureException,
- MojoExecutionException
-
+ private void addRoot(Set<URL> urls, String path) throws MojoFailureException
{
try
{
- AnnotationDB db = new AnnotationDB();
- File dir;
-
- dir = new File(outputDirectory);
+ File dir = new File(outputDirectory);
if (dir.exists())
{
- getLog().info("Scanning directory " + dir.getAbsolutePath() + " for annotated classes...");
- URL dirUrl = dir.toURI().toURL();
- db.scanArchives(dirUrl);
- }
-
- if (scanTestClasses)
- {
- dir = new File(testOutputDirectory);
- if (dir.exists())
- {
- getLog().info("Scanning directory " + dir.getAbsolutePath() + " for annotated classes...");
- URL dirUrl = dir.toURI().toURL();
- db.scanArchives(dirUrl);
- }
+ getLog().info("Adding " + dir.getAbsolutePath() + " to the list of roots to scan...");
+ urls.add(dir.toURI().toURL());
}
+ }
+ catch (MalformedURLException e)
+ {
+ getLog().error("error while adding the project-root to the list of roots to scan!", e);
+ throw new MojoFailureException(e.getMessage());
+ }
+ }
+ private void addDependencies(Set<URL> urls) throws MojoFailureException
+ {
+ try
+ {
if (scanDependencies != null)
{
Matcher matcher = SPLIT.matcher(scanDependencies);
while (matcher.find())
{
- getLog().info("Scanning dependencies for scope " + matcher.group());
+ getLog().info("Adding dependencies from scope " + matcher.group() + " to the list of roots to scan");
for (Artifact artifact : project.getDependencyArtifacts())
{
if (!artifact.getScope().equalsIgnoreCase(matcher.group()))
continue;
if (artifact.getFile() == null)
{
- getLog().warn("Cannot scan dependency " + artifact.getId() + ": no JAR-file available!");
+ getLog().warn("Cannot add dependency " + artifact.getId() + ": no JAR-file available!");
continue;
}
- getLog().info("Scanning dependency " + artifact.getId() + " for annotated classes...");
- db.scanArchives(artifact.getFile().toURI().toURL());
+ getLog().info("Adding dependencies from scope " + artifact.getId() + " to the list of roots to scan");
+ urls.add(artifact.getFile().toURI().toURL());
}
}
}
+ }
+ catch (MalformedURLException e)
+ {
+ getLog().error("Error while adding dependencies to the list of roots to scan!", e);
+ throw new MojoFailureException(e.getMessage());
+ }
+ }
+
+ private Set<String> scanUrls(Set<URL> scanRoots)
+ throws
+ MojoFailureException
+ {
+ try
+ {
+ AnnotationDB db = new AnnotationDB();
+ for (URL root : scanRoots)
+ db.scanArchives(root);
Set<String> classes = new HashSet<String>();
if (db.getAnnotationIndex().containsKey(Entity.class.getName()))
if (db.getAnnotationIndex().containsKey(Embeddable.class.getName()))
classes.addAll(db.getAnnotationIndex().get(Embeddable.class.getName()));
- Set<String> packages = new HashSet<String>();
+ return classes;
+ }
+ catch (Exception e)
+ {
+ getLog().error("Error while scanning!", e);
+ throw new MojoFailureException(e.getMessage());
+ }
+ }
+
+ private void addAnnotated(
+ String name,
+ MetadataSources sources,
+ ClassLoaderService classLoaderService,
+ ModificationTracker tracker
+ )
+ throws
+ MojoFailureException,
+ MojoExecutionException
+ {
+ try
+ {
+ getLog().info("Adding annotated resource: " + name);
+ String packageName;
- for (String name : classes)
+ try
{
Class<?> annotatedClass = classLoaderService.classForName(name);
- String packageName = annotatedClass.getPackage().getName();
- if (!packages.contains(packageName))
- {
- InputStream is =
- annotatedClass.getResourceAsStream("package-info.class");
- if (is == null)
- {
- // No compiled package-info available: no package-level annotations!
- getLog().debug("Package " + packageName + " is not annotated.");
- }
- else
- {
- if (tracker.check(packageName, is))
- getLog().debug("New or modified package: " + packageName);
- else
- getLog().debug("Unchanged package: " + packageName);
- getLog().info("Adding annotated package " + packageName);
- sources.addPackage(packageName);
- }
- packages.add(packageName);
- }
String resourceName = annotatedClass.getName();
resourceName =
resourceName.substring(
resourceName.lastIndexOf(".") + 1,
resourceName.length()
) + ".class";
- InputStream is =
- annotatedClass
- .getResourceAsStream(resourceName);
- if (tracker.check(name, is))
+ InputStream is = annotatedClass.getResourceAsStream(resourceName);
+ if (tracker.track(name, is))
getLog().debug("New or modified class: " + name);
else
getLog().debug("Unchanged class: " + name);
- getLog().info("Adding annotated class " + annotatedClass);
sources.addAnnotatedClass(annotatedClass);
+ packageName = annotatedClass.getPackage().getName();
+ }
+ catch(ClassLoadingException e)
+ {
+ packageName = name;
+ }
+
+ if (!packages.contains(packageName))
+ {
+ String resource = packageName.replace('.', '/') + "/package-info.class";
+ InputStream is = classLoaderService.locateResourceStream(resource);
+ if (is == null)
+ {
+ // No compiled package-info available: no package-level annotations!
+ getLog().debug("Package " + packageName + " is not annotated.");
+ }
+ else
+ {
+ if (tracker.track(packageName, is))
+ getLog().debug("New or modified package: " + packageName);
+ else
+ getLog().debug("Unchanged package: " + packageName);
+ getLog().info("Adding annotations from package " + packageName);
+ sources.addPackage(packageName);
+ }
+ packages.add(packageName);
}
}
catch (Exception e)
{
- getLog().error("Error while scanning!", e);
+ getLog().error("Error while adding the annotated class " + name, e);
throw new MojoFailureException(e.getMessage());
}
}
- private Properties loadPersistenceUnit(
+ private ParsedPersistenceXmlDescriptor loadPersistenceUnit(
ClassLoaderService classLoaderService,
Properties properties
)
{
case 0:
getLog().info("Found no META-INF/persistence.xml.");
- return new Properties();
+ return null;
case 1:
getLog().info("Using persistence-unit " + units.get(0).getName());
- return units.get(0).getProperties();
+ return units.get(0);
default:
StringBuilder builder = new StringBuilder();
builder.append("No name provided and multiple persistence units found: ");
}
getLog().info("Using persistence-unit " + unit.getName());
- return unit.getProperties();
+ return unit;
}
throw new MojoFailureException("Could not find persistence-unit " + persistenceUnit);