X-Git-Url: https://juplo.de/gitweb/?p=website;a=blobdiff_plain;f=dist%2Fhibernate-maven-plugin-2.1.0%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate%2FAbstractSchemaMojo.html;fp=dist%2Fhibernate-maven-plugin-2.1.0%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate%2FAbstractSchemaMojo.html;h=8522d9a69900b9de3fcaffb2e67ad95f4f673913;hp=0000000000000000000000000000000000000000;hb=a53595184bd6e57bdc45292cc92c393c4e2dfe6e;hpb=c48c9ee0e9faa89a4c0a5323b367b9f5a6abe602 diff --git a/dist/hibernate-maven-plugin-2.1.0/xref/de/juplo/plugins/hibernate/AbstractSchemaMojo.html b/dist/hibernate-maven-plugin-2.1.0/xref/de/juplo/plugins/hibernate/AbstractSchemaMojo.html new file mode 100644 index 00000000..8522d9a6 --- /dev/null +++ b/dist/hibernate-maven-plugin-2.1.0/xref/de/juplo/plugins/hibernate/AbstractSchemaMojo.html @@ -0,0 +1,1433 @@ + + + +AbstractSchemaMojo xref + + + +
View Javadoc
+1   package de.juplo.plugins.hibernate;
+2   
+3   
+4   import com.pyx4j.log4j.MavenLogAppender;
+5   import java.io.File;
+6   import java.io.FileInputStream;
+7   import java.io.FileOutputStream;
+8   import java.io.IOException;
+9   import java.io.InputStream;
+10  import java.net.MalformedURLException;
+11  import java.net.URL;
+12  import java.security.NoSuchAlgorithmException;
+13  import java.time.ZonedDateTime;
+14  import java.util.Collections;
+15  import java.util.EnumSet;
+16  import java.util.HashMap;
+17  import java.util.HashSet;
+18  import java.util.Iterator;
+19  import java.util.LinkedHashSet;
+20  import java.util.List;
+21  import java.util.Map;
+22  import java.util.Map.Entry;
+23  import java.util.Properties;
+24  import java.util.Set;
+25  import java.util.regex.Matcher;
+26  import java.util.regex.Pattern;
+27  import javax.persistence.Embeddable;
+28  import javax.persistence.Entity;
+29  import javax.persistence.MappedSuperclass;
+30  import javax.persistence.spi.PersistenceUnitTransactionType;
+31  import org.apache.maven.artifact.Artifact;
+32  import org.apache.maven.model.Resource;
+33  import org.apache.maven.plugin.AbstractMojo;
+34  import org.apache.maven.plugin.MojoExecutionException;
+35  import org.apache.maven.plugin.MojoFailureException;
+36  import org.apache.maven.project.MavenProject;
+37  import org.hibernate.boot.MetadataBuilder;
+38  import org.hibernate.boot.MetadataSources;
+39  import org.hibernate.boot.cfgxml.internal.ConfigLoader;
+40  import org.hibernate.boot.cfgxml.spi.LoadedConfig;
+41  import org.hibernate.boot.cfgxml.spi.MappingReference;
+42  import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
+43  import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
+44  import org.hibernate.boot.registry.BootstrapServiceRegistry;
+45  import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
+46  import org.hibernate.boot.registry.StandardServiceRegistry;
+47  import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+48  import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
+49  import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
+50  import org.hibernate.boot.registry.selector.spi.StrategySelector;
+51  import org.hibernate.boot.spi.MetadataImplementor;
+52  import org.hibernate.cfg.AvailableSettings;
+53  import static org.hibernate.cfg.AvailableSettings.DIALECT;
+54  import static org.hibernate.cfg.AvailableSettings.DRIVER;
+55  import static org.hibernate.cfg.AvailableSettings.FORMAT_SQL;
+56  import static org.hibernate.cfg.AvailableSettings.HBM2DDL_DELIMITER;
+57  import static org.hibernate.cfg.AvailableSettings.HBM2DLL_CREATE_NAMESPACES;
+58  import static org.hibernate.cfg.AvailableSettings.IMPLICIT_NAMING_STRATEGY;
+59  import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_DRIVER;
+60  import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_PASSWORD;
+61  import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_URL;
+62  import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_USER;
+63  import static org.hibernate.cfg.AvailableSettings.PASS;
+64  import static org.hibernate.cfg.AvailableSettings.PHYSICAL_NAMING_STRATEGY;
+65  import static org.hibernate.cfg.AvailableSettings.SHOW_SQL;
+66  import static org.hibernate.cfg.AvailableSettings.USER;
+67  import static org.hibernate.cfg.AvailableSettings.URL;
+68  import org.hibernate.engine.config.spi.ConfigurationService;
+69  import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
+70  import org.hibernate.internal.util.config.ConfigurationException;
+71  import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
+72  import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
+73  import org.hibernate.tool.schema.TargetType;
+74  import org.hibernate.tool.schema.internal.ExceptionHandlerCollectingImpl;
+75  import org.hibernate.tool.schema.internal.exec.ScriptTargetOutputToFile;
+76  import org.hibernate.tool.schema.spi.ExecutionOptions;
+77  import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator;
+78  import org.hibernate.tool.schema.spi.ScriptTargetOutput;
+79  import org.hibernate.tool.schema.spi.TargetDescriptor;
+80  import org.scannotation.AnnotationDB;
+81  
+82  
+83  /**
+84   * Baseclass with common attributes and methods.
+85   *
+86   * @phase process-classes
+87   * @threadSafe
+88   * @requiresDependencyResolution runtime
+89   */
+90  public abstract class AbstractSchemaMojo extends AbstractMojo
+91  {
+92    public final static String EXECUTE = "hibernate.schema.execute";
+93    public final static String OUTPUTDIRECTORY = "project.build.outputDirectory";
+94    public final static String SCAN_CLASSES = "hibernate.schema.scan.classes";
+95    public final static String SCAN_DEPENDENCIES = "hibernate.schema.scan.dependencies";
+96    public final static String SCAN_TESTCLASSES = "hibernate.schema.scan.test_classes";
+97    public final static String TEST_OUTPUTDIRECTORY = "project.build.testOutputDirectory";
+98    public final static String SKIPPED = "hibernate.schema.skipped";
+99    public final static String SCRIPT = "hibernate.schema.script";
+100 
+101   private final static Pattern SPLIT = Pattern.compile("[^,\\s]+");
+102 
+103   private final Set<String> packages = new HashSet<String>();
+104 
+105 
+106   /**
+107    * The maven project.
+108    * <p>
+109    * Only needed internally.
+110    *
+111    * @parameter property="project"
+112    * @required
+113    * @readonly
+114    */
+115   private MavenProject project;
+116 
+117   /**
+118    * Build-directory.
+119    * <p>
+120    * Only needed internally.
+121    *
+122    * @parameter property="project.build.directory"
+123    * @required
+124    * @readonly
+125    */
+126   private String buildDirectory;
+127 
+128 
+129   /** Parameters to configure the genaration of the SQL *********************/
+130 
+131   /**
+132    * Excecute the generated SQL.
+133    * If set to <code>false</code>, only the SQL-script is created and the
+134    * database is not touched.
+135    * <p>
+136    * <strong>Important:</strong>
+137    * This configuration value can only be configured through the
+138    * <code>pom.xml</code>, or by the definition of a system-property, because
+139    * it is not known by Hibernate nor JPA and, hence, not picked up from
+140    * their configuration!
+141    *
+142    * @parameter property="hibernate.schema.execute" default-value="true"
+143    * @since 2.0
+144    */
+145   private Boolean execute;
+146 
+147   /**
+148    * Skip execution
+149    * <p>
+150    * If set to <code>true</code>, the execution is skipped.
+151    * <p>
+152    * A skipped execution is signaled via the maven-property
+153    * <code>${hibernate.schema.skipped}</code>.
+154    * <p>
+155    * The execution is skipped automatically, if no modified or newly added
+156    * annotated classes are found and the dialect was not changed.
+157    * <p>
+158    * <strong>Important:</strong>
+159    * This configuration value can only be configured through the
+160    * <code>pom.xml</code>, or by the definition of a system-property, because
+161    * it is not known by Hibernate nor JPA and, hence, not picked up from
+162    * their configuration!
+163    *
+164    * @parameter property="hibernate.schema.skip" default-value="${maven.test.skip}"
+165    * @since 1.0
+166    */
+167   private boolean skip;
+168 
+169   /**
+170    * Force generation/execution
+171    * <p>
+172    * Force the generation and (if configured) the execution of the SQL, even if
+173    * no modified or newly added annotated classes where found and the
+174    * configuration was not changed.
+175    * <p>
+176    * <code>skip</code> takes precedence over <code>force</code>.
+177    * <p>
+178    * <strong>Important:</strong>
+179    * This configuration value can only be configured through the
+180    * <code>pom.xml</code>, or by the definition of a system-property, because
+181    * it is not known by Hibernate nor JPA and, hence, not picked up from
+182    * their configuration!
+183    *
+184    * @parameter property="hibernate.schema.force" default-value="false"
+185    * @since 1.0
+186    */
+187   private boolean force;
+188 
+189   /**
+190    * Hibernate dialect.
+191    *
+192    * @parameter property="hibernate.dialect"
+193    * @since 1.0
+194    */
+195   private String dialect;
+196 
+197   /**
+198    * Delimiter in output-file.
+199    * <p>
+200    * <strong>Important:</strong>
+201    * This configuration value can only be configured through the
+202    * <code>pom.xml</code>, or by the definition of a system-property, because
+203    * it is not known by Hibernate nor JPA and, hence, not picked up from
+204    * their configuration!
+205    *
+206    * @parameter property="hibernate.hbm2ddl.delimiter" default-value=";"
+207    * @since 1.0
+208    */
+209   private String delimiter;
+210 
+211   /**
+212    * Show the generated SQL in the command-line output.
+213    *
+214    * @parameter property="hibernate.show_sql"
+215    * @since 1.0
+216    */
+217   private Boolean show;
+218 
+219   /**
+220    * Format output-file.
+221    *
+222    * @parameter property="hibernate.format_sql"
+223    * @since 1.0
+224    */
+225   private Boolean format;
+226 
+227   /**
+228    * Specifies whether to automatically create also the database schema/catalog.
+229    *
+230    * @parameter property="hibernate.hbm2dll.create_namespaces" default-value="false"
+231    * @since 2.0
+232    */
+233   private Boolean createNamespaces;
+234 
+235   /**
+236    * Implicit naming strategy
+237    *
+238    * @parameter property="hibernate.implicit_naming_strategy"
+239    * @since 2.0
+240    */
+241   private String implicitNamingStrategy;
+242 
+243   /**
+244    * Physical naming strategy
+245    *
+246    * @parameter property="hibernate.physical_naming_strategy"
+247    * @since 2.0
+248    */
+249   private String physicalNamingStrategy;
+250 
+251   /**
+252    * Wether the project should be scanned for annotated-classes, or not
+253    * <p>
+254    * This parameter is intended to allow overwriting of the parameter
+255    * <code>exclude-unlisted-classes</code> of a <code>persistence-unit</code>.
+256    * If not specified, it defaults to <code>true</code>
+257    *
+258    * @parameter property="hibernate.schema.scan.classes"
+259    * @since 2.0
+260    */
+261   private Boolean scanClasses;
+262 
+263   /**
+264    * Classes-Directory to scan.
+265    * <p>
+266    * This parameter defaults to the maven build-output-directory for classes.
+267    * Additionally, all dependencies are scanned for annotated classes.
+268    * <p>
+269    * <strong>Important:</strong>
+270    * This configuration value can only be configured through the
+271    * <code>pom.xml</code>, or by the definition of a system-property, because
+272    * it is not known by Hibernate nor JPA and, hence, not picked up from
+273    * their configuration!
+274    *
+275    * @parameter property="project.build.outputDirectory"
+276    * @since 1.0
+277    */
+278   private String outputDirectory;
+279 
+280   /**
+281    * Dependency-Scopes, that should be scanned for annotated classes.
+282    * <p>
+283    * By default, only dependencies in the scope <code>compile</code> are
+284    * scanned for annotated classes. Multiple scopes can be seperated by
+285    * white space or commas.
+286    * <p>
+287    * If you do not want any dependencies to be scanned for annotated
+288    * classes, set this parameter to <code>none</code>.
+289    * <p>
+290    * The plugin does not scan for annotated classes in transitive
+291    * dependencies. If some of your annotated classes are hidden in a
+292    * transitive dependency, you can simply add that dependency explicitly.
+293    *
+294    * @parameter property="hibernate.schema.scan.dependencies" default-value="compile"
+295    * @since 1.0.3
+296    */
+297   private String scanDependencies;
+298 
+299   /**
+300    * Whether to scan the test-branch of the project for annotated classes, or
+301    * not.
+302    * <p>
+303    * If this parameter is set to <code>true</code> the test-classes of the
+304    * artifact will be scanned for hibernate-annotated classes additionally.
+305    * <p>
+306    * <strong>Important:</strong>
+307    * This configuration value can only be configured through the
+308    * <code>pom.xml</code>, or by the definition of a system-property, because
+309    * it is not known by Hibernate nor JPA and, hence, not picked up from
+310    * their configuration!
+311    *
+312    * @parameter property="hibernate.schema.scan.test_classes" default-value="false"
+313    * @since 1.0.1
+314    */
+315   private Boolean scanTestClasses;
+316 
+317   /**
+318    * Test-Classes-Directory to scan.
+319    * <p>
+320    * This parameter defaults to the maven build-output-directory for
+321    * test-classes.
+322    * <p>
+323    * This parameter is only used, when <code>scanTestClasses</code> is set
+324    * to <code>true</code>!
+325    * <p>
+326    * <strong>Important:</strong>
+327    * This configuration value can only be configured through the
+328    * <code>pom.xml</code>, or by the definition of a system-property, because
+329    * it is not known by Hibernate nor JPA and, hence, not picked up from
+330    * their configuration!
+331    *
+332    * @parameter property="project.build.testOutputDirectory"
+333    * @since 1.0.2
+334    */
+335   private String testOutputDirectory;
+336 
+337 
+338   /** Conection parameters *************************************************/
+339 
+340   /**
+341    * SQL-Driver name.
+342    *
+343    * @parameter property="hibernate.connection.driver_class"
+344    * @since 1.0
+345    */
+346   private String driver;
+347 
+348   /**
+349    * Database URL.
+350    *
+351    * @parameter property="hibernate.connection.url"
+352    * @since 1.0
+353    */
+354   private String url;
+355 
+356   /**
+357    * Database username
+358    *
+359    * @parameter property="hibernate.connection.username"
+360    * @since 1.0
+361    */
+362   private String username;
+363 
+364   /**
+365    * Database password
+366    *
+367    * @parameter property="hibernate.connection.password"
+368    * @since 1.0
+369    */
+370   private String password;
+371 
+372 
+373   /** Parameters to locate configuration sources ****************************/
+374 
+375   /**
+376    * Path to a file or name of a ressource with hibernate properties.
+377    * If this parameter is specified, the plugin will try to load configuration
+378    * values from a file with the given path or a ressource on the classpath with
+379    * the given name. If both fails, the execution of the plugin will fail.
+380    * <p>
+381    * If this parameter is not set the plugin will load configuration values
+382    * from a ressource named <code>hibernate.properties</code> on the classpath,
+383    * if it is present, but will not fail if there is no such ressource.
+384    * <p>
+385    * During ressource-lookup, the test-classpath takes precedence.
+386    *
+387    * @parameter
+388    * @since 1.0
+389    */
+390   private String hibernateProperties;
+391 
+392   /**
+393    * Path to Hibernate configuration file (.cfg.xml).
+394    * If this parameter is specified, the plugin will try to load configuration
+395    * values from a file with the given path or a ressource on the classpath with
+396    * the given name. If both fails, the execution of the plugin will fail.
+397    * <p>
+398    * If this parameter is not set the plugin will load configuration values
+399    * from a ressource named <code>hibernate.cfg.xml</code> on the classpath,
+400    * if it is present, but will not fail if there is no such ressource.
+401    * <p>
+402    * During ressource-lookup, the test-classpath takes precedence.
+403    * <p>
+404    * Settings in this file will overwrite settings in the properties file.
+405    *
+406    * @parameter
+407    * @since 1.1.0
+408    */
+409   private String hibernateConfig;
+410 
+411   /**
+412    * Name of the persistence-unit.
+413    * If this parameter is specified, the plugin will try to load configuration
+414    * values from a persistence-unit with the specified name. If no such
+415    * persistence-unit can be found, the plugin will throw an exception.
+416    * <p>
+417    * If this parameter is not set and there is only one persistence-unit
+418    * available, that unit will be used automatically. But if this parameter is
+419    * not set and there are multiple persistence-units available on,
+420    * the class-path, the execution of the plugin will fail.
+421    * <p>
+422    * Settings in this file will overwrite settings in the properties or the
+423    * configuration file.
+424    *
+425    * @parameter
+426    * @since 1.1.0
+427    */
+428   private String persistenceUnit;
+429 
+430   /**
+431    * List of Hibernate-Mapping-Files (XML).
+432    * Multiple files can be separated with white-spaces and/or commas.
+433    *
+434    * @parameter property="hibernate.mapping"
+435    * @since 1.0.2
+436    */
+437   private String mappings;
+438 
+439 
+440 
+441   public final void execute(String filename)
+442     throws
+443       MojoFailureException,
+444       MojoExecutionException
+445   {
+446     if (skip)
+447     {
+448       getLog().info("Execution of hibernate-maven-plugin was skipped!");
+449       project.getProperties().setProperty(SKIPPED, "true");
+450       return;
+451     }
+452 
+453     ModificationTracker tracker;
+454     try
+455     {
+456       tracker = new ModificationTracker(buildDirectory, filename, getLog());
+457     }
+458     catch (NoSuchAlgorithmException e)
+459     {
+460       throw new MojoFailureException("Digest-Algorithm MD5 is missing!", e);
+461     }
+462 
+463     final SimpleConnectionProvider connectionProvider =
+464         new SimpleConnectionProvider(getLog());
+465 
+466     try
+467     {
+468       /** Start extended logging */
+469       MavenLogAppender.startPluginLog(this);
+470 
+471       /** Load checksums for old mapping and configuration */
+472       tracker.load();
+473 
+474       /** Create the ClassLoader */
+475       MutableClassLoader classLoader = createClassLoader();
+476 
+477       /** Create a BootstrapServiceRegistry with the created ClassLoader */
+478       BootstrapServiceRegistry bootstrapServiceRegitry =
+479           new BootstrapServiceRegistryBuilder()
+480               .applyClassLoader(classLoader)
+481               .build();
+482       ClassLoaderService classLoaderService =
+483           bootstrapServiceRegitry.getService(ClassLoaderService.class);
+484 
+485       Properties properties = new Properties();
+486       ConfigLoader configLoader = new ConfigLoader(bootstrapServiceRegitry);
+487 
+488       /** Loading and merging configuration */
+489       properties.putAll(loadProperties(configLoader));
+490       LoadedConfig config = loadConfig(configLoader);
+491       if (config != null)
+492         properties.putAll(config.getConfigurationValues());
+493       ParsedPersistenceXmlDescriptor unit =
+494           loadPersistenceUnit(classLoaderService, properties);
+495       if (unit != null)
+496         properties.putAll(unit.getProperties());
+497 
+498       /** Overwriting/Completing configuration */
+499       configure(properties, tracker);
+500 
+501       /** Check configuration for modifications */
+502       if(tracker.track(properties))
+503         getLog().debug("Configuration has changed.");
+504       else
+505         getLog().debug("Configuration unchanged.");
+506 
+507       /** Check, that the outputfile is writable */
+508       final File output = getOutputFile(filename);
+509       /** Check, if the outputfile is missing or was changed */
+510       checkOutputFile(output, tracker);
+511 
+512       /** Configure Hibernate */
+513       final StandardServiceRegistry serviceRegistry =
+514           new StandardServiceRegistryBuilder(bootstrapServiceRegitry)
+515               .applySettings(properties)
+516               .addService(ConnectionProvider.class, connectionProvider)
+517               .build();
+518       final MetadataSources sources = new MetadataSources(serviceRegistry);
+519 
+520       /** Add the remaining class-path-elements */
+521       completeClassPath(classLoader);
+522 
+523       /** Apply mappings from hibernate-configuration, if present */
+524       if (config != null)
+525       {
+526         for (MappingReference mapping : config.getMappingReferences())
+527           mapping.apply(sources);
+528       }
+529 
+530       Set<String> classes;
+531       if (unit == null)
+532       {
+533         /** No persistent unit: default behaviour */
+534         if (scanClasses == null)
+535           scanClasses = true;
+536         Set<URL> urls = new HashSet<URL>();
+537         if (scanClasses)
+538           addRoot(urls, outputDirectory);
+539         if (scanTestClasses)
+540           addRoot(urls, testOutputDirectory);
+541         addDependencies(urls);
+542         classes = scanUrls(urls);
+543       }
+544       else
+545       {
+546         /** Follow configuration in persisten unit */
+547         if (scanClasses == null)
+548           scanClasses = !unit.isExcludeUnlistedClasses();
+549         Set<URL> urls = new HashSet<URL>();
+550         if (scanClasses)
+551         {
+552           /**
+553            * Scan the root of the persiten unit and configured jars for
+554            * annotated classes
+555            */
+556           urls.add(unit.getPersistenceUnitRootUrl());
+557           for (URL url : unit.getJarFileUrls())
+558             urls.add(url);
+559         }
+560         if (scanTestClasses)
+561           addRoot(urls, testOutputDirectory);
+562         classes = scanUrls(urls);
+563         for (String className : unit.getManagedClassNames())
+564           classes.add(className);
+565         /**
+566          * Add mappings from the default mapping-file
+567          * <code>META-INF/orm.xml</code>, if present
+568          */
+569         boolean error = false;
+570         InputStream is;
+571         is = classLoader.getResourceAsStream("META-INF/orm.xml");
+572         if (is != null)
+573         {
+574           getLog().info("Adding default JPA-XML-mapping from META-INF/orm.xml");
+575           try
+576           {
+577             tracker.track("META-INF/orm.xml", is);
+578             sources.addResource("META-INF/orm.xml");
+579           }
+580           catch (IOException e)
+581           {
+582             getLog().error("cannot read META-INF/orm.xml: " + e);
+583             error = true;
+584           }
+585         }
+586         else
+587         {
+588           getLog().debug("no META-INF/orm.xml found");
+589         }
+590         /**
+591          * Add mappings from files, that are explicitly configured in the
+592          * persistence unit
+593          */
+594         for (String mapping : unit.getMappingFileNames())
+595         {
+596           getLog().info("Adding explicitly configured mapping from " + mapping);
+597           is = classLoader.getResourceAsStream(mapping);
+598           if (is != null)
+599           {
+600             try
+601             {
+602               tracker.track(mapping, is);
+603               sources.addResource(mapping);
+604             }
+605             catch (IOException e)
+606             {
+607               getLog().info("cannot read mapping-file " + mapping + ": " + e);
+608               error = true;
+609             }
+610           }
+611           else
+612           {
+613             getLog().error("cannot find mapping-file " + mapping);
+614             error = true;
+615           }
+616         }
+617         if (error)
+618           throw new MojoFailureException(
+619               "error, while reading mappings configured in persistence-unit \"" +
+620               unit.getName() +
+621               "\""
+622               );
+623       }
+624 
+625       /** Add the configured/collected annotated classes */
+626       for (String className : classes)
+627         addAnnotated(className, sources, classLoaderService, tracker);
+628 
+629       /** Add explicitly configured classes */
+630       addMappings(sources, tracker);
+631 
+632       /** Skip execution, if mapping and configuration is unchanged */
+633       if (!tracker.modified())
+634       {
+635         getLog().info("Mapping and configuration unchanged.");
+636         if (force)
+637           getLog().info("Generation/execution is forced!");
+638         else
+639         {
+640           getLog().info("Skipping schema generation!");
+641           project.getProperties().setProperty(SKIPPED, "true");
+642           return;
+643         }
+644       }
+645 
+646 
+647       /** Truncate output file */
+648       try
+649       {
+650         new FileOutputStream(output).getChannel().truncate(0).close();
+651       }
+652       catch (IOException e)
+653       {
+654         String error =
+655             "Error while truncating " + output.getAbsolutePath() + ": "
+656             + e.getMessage();
+657         getLog().warn(error);
+658         throw new MojoExecutionException(error);
+659       }
+660 
+661       /** Create a connection, if sufficient configuration infromation is available */
+662       connectionProvider.open(classLoaderService, properties);
+663 
+664       MetadataBuilder metadataBuilder = sources.getMetadataBuilder();
+665 
+666       StrategySelector strategySelector =
+667           serviceRegistry.getService(StrategySelector.class);
+668 
+669       if (properties.containsKey(IMPLICIT_NAMING_STRATEGY))
+670       {
+671         metadataBuilder.applyImplicitNamingStrategy(
+672             strategySelector.resolveStrategy(
+673                 ImplicitNamingStrategy.class,
+674                 properties.getProperty(IMPLICIT_NAMING_STRATEGY)
+675                 )
+676             );
+677       }
+678 
+679       if (properties.containsKey(PHYSICAL_NAMING_STRATEGY))
+680       {
+681         metadataBuilder.applyPhysicalNamingStrategy(
+682             strategySelector.resolveStrategy(
+683                 PhysicalNamingStrategy.class,
+684                 properties.getProperty(PHYSICAL_NAMING_STRATEGY)
+685                 )
+686             );
+687       }
+688 
+689       /** Prepare the generation of the SQL */
+690       Map settings = new HashMap();
+691       settings.putAll(
+692           serviceRegistry
+693               .getService(ConfigurationService.class)
+694               .getSettings()
+695               );
+696       ExceptionHandlerCollectingImpl handler =
+697           new ExceptionHandlerCollectingImpl();
+698       ExecutionOptions options =
+699           SchemaManagementToolCoordinator
+700               .buildExecutionOptions(settings, handler);
+701       final EnumSet<TargetType> targetTypes = EnumSet.of(TargetType.SCRIPT);
+702       if (execute)
+703         targetTypes.add(TargetType.DATABASE);
+704       TargetDescriptor target = new TargetDescriptor()
+705       {
+706         @Override
+707         public EnumSet<TargetType> getTargetTypes()
+708         {
+709           return targetTypes;
+710         }
+711 
+712         @Override
+713         public ScriptTargetOutput getScriptTargetOutput()
+714         {
+715           String charset =
+716               (String)
+717               serviceRegistry
+718                   .getService(ConfigurationService.class)
+719                   .getSettings()
+720                   .get(AvailableSettings.HBM2DDL_CHARSET_NAME);
+721           return new ScriptTargetOutputToFile(output, charset);
+722         }
+723       };
+724 
+725       /**
+726        * Change class-loader of current thread.
+727        * This is necessary, because still not all parts of Hibernate 5 use
+728        * the newly introduced ClassLoaderService and will fail otherwise!
+729        */
+730       Thread thread = Thread.currentThread();
+731       ClassLoader contextClassLoader = thread.getContextClassLoader();
+732       try
+733       {
+734         thread.setContextClassLoader(classLoader);
+735         build((MetadataImplementor)metadataBuilder.build(), options, target);
+736         if (handler.getExceptions().size() > 0)
+737         {
+738           StringBuilder builder = new StringBuilder();
+739           builder.append("Hibernate failed:");
+740           for (Exception e : handler.getExceptions())
+741           {
+742             builder.append("\n * ");
+743             builder.append(e.getMessage());
+744             AbstractSchemaMojo.printStrackTrace(builder, e);
+745             builder.append("\n");
+746           }
+747           String error = builder.toString();
+748           getLog().error(error);
+749           throw new MojoFailureException(error);
+750         }
+751       }
+752       finally
+753       {
+754         thread.setContextClassLoader(contextClassLoader);
+755         /** Track, the content of the generated script */
+756         checkOutputFile(output, tracker);
+757       }
+758     }
+759     catch (MojoExecutionException e)
+760     {
+761       tracker.failed();
+762       throw e;
+763     }
+764     catch (MojoFailureException e)
+765     {
+766       tracker.failed();
+767       throw e;
+768     }
+769     catch (RuntimeException e)
+770     {
+771       tracker.failed();
+772       throw e;
+773     }
+774     finally
+775     {
+776       /** Remember mappings and configuration */
+777       tracker.save();
+778 
+779       /** Close the connection - if one was opened */
+780       connectionProvider.close();
+781 
+782       /** Stop Log-Capturing */
+783       MavenLogAppender.endPluginLog(this);
+784     }
+785   }
+786 
+787 
+788   abstract void build(
+789       MetadataImplementor metadata,
+790       ExecutionOptions options,
+791       TargetDescriptor target
+792       )
+793     throws
+794       MojoFailureException,
+795       MojoExecutionException;
+796 
+797 
+798   private MutableClassLoader createClassLoader() throws MojoExecutionException
+799   {
+800     try
+801     {
+802       getLog().debug("Creating ClassLoader for project-dependencies...");
+803       LinkedHashSet<URL> urls = new LinkedHashSet<URL>();
+804       File file;
+805 
+806       file = new File(testOutputDirectory);
+807       if (!file.exists())
+808       {
+809         getLog().info("Creating test-output-directory: " + testOutputDirectory);
+810         file.mkdirs();
+811       }
+812       urls.add(file.toURI().toURL());
+813 
+814       file = new File(outputDirectory);
+815       if (!file.exists())
+816       {
+817         getLog().info("Creating output-directory: " + outputDirectory);
+818         file.mkdirs();
+819       }
+820       urls.add(file.toURI().toURL());
+821 
+822       return new MutableClassLoader(urls, getLog());
+823     }
+824     catch (Exception e)
+825     {
+826       getLog().error("Error while creating ClassLoader!", e);
+827       throw new MojoExecutionException(e.getMessage());
+828     }
+829   }
+830 
+831   private void completeClassPath(MutableClassLoader classLoader)
+832       throws
+833         MojoExecutionException
+834   {
+835     try
+836     {
+837       getLog().debug("Completing class-paths of the ClassLoader for project-dependencies...");
+838       List<String> classpathFiles = project.getCompileClasspathElements();
+839       if (scanTestClasses)
+840         classpathFiles.addAll(project.getTestClasspathElements());
+841       LinkedHashSet<URL> urls = new LinkedHashSet<URL>();
+842       for (String pathElement : classpathFiles)
+843       {
+844         getLog().debug("Dependency: " + pathElement);
+845         urls.add(new File(pathElement).toURI().toURL());
+846       }
+847       classLoader.add(urls);
+848     }
+849     catch (Exception e)
+850     {
+851       getLog().error("Error while creating ClassLoader!", e);
+852       throw new MojoExecutionException(e.getMessage());
+853     }
+854   }
+855 
+856   private Map loadProperties(ConfigLoader configLoader)
+857       throws
+858         MojoExecutionException
+859   {
+860     /** Try to read configuration from properties-file */
+861     if (hibernateProperties == null)
+862     {
+863       try
+864       {
+865         return configLoader.loadProperties("hibernate.properties");
+866       }
+867       catch (ConfigurationException e)
+868       {
+869         getLog().debug(e.getMessage());
+870         return Collections.EMPTY_MAP;
+871       }
+872     }
+873     else
+874     {
+875       try
+876       {
+877         File file = new File(hibernateProperties);
+878         if (file.exists())
+879         {
+880           getLog().info("Reading settings from file " + hibernateProperties + "...");
+881           return configLoader.loadProperties(file);
+882         }
+883         else
+884           return configLoader.loadProperties(hibernateProperties);
+885       }
+886       catch (ConfigurationException e)
+887       {
+888         getLog().error("Error while reading properties!", e);
+889         throw new MojoExecutionException(e.getMessage());
+890       }
+891     }
+892   }
+893 
+894   private LoadedConfig loadConfig(ConfigLoader configLoader)
+895       throws MojoExecutionException
+896   {
+897     /** Try to read configuration from configuration-file */
+898     if (hibernateConfig == null)
+899     {
+900       try
+901       {
+902         return configLoader.loadConfigXmlResource("hibernate.cfg.xml");
+903       }
+904       catch (ConfigurationException e)
+905       {
+906         getLog().debug(e.getMessage());
+907         return null;
+908       }
+909     }
+910     else
+911     {
+912       try
+913       {
+914         File file = new File(hibernateConfig);
+915         if (file.exists())
+916         {
+917           getLog().info("Reading configuration from file " + hibernateConfig + "...");
+918           return configLoader.loadConfigXmlFile(file);
+919         }
+920         else
+921         {
+922           return configLoader.loadConfigXmlResource(hibernateConfig);
+923         }
+924       }
+925       catch (ConfigurationException e)
+926       {
+927         getLog().error("Error while reading configuration!", e);
+928         throw new MojoExecutionException(e.getMessage());
+929       }
+930     }
+931   }
+932 
+933   private void configure(Properties properties, ModificationTracker tracker)
+934       throws MojoFailureException
+935   {
+936     /**
+937      * Special treatment for the configuration-value "execute": if it is
+938      * switched to "true", the genearation fo the schema should be forced!
+939      */
+940     if (tracker.check(EXECUTE, execute.toString()) && execute)
+941     {
+942       getLog().info(
+943           "hibernate.schema.execute was switched on: " +
+944           "forcing generation/execution of SQL"
+945           );
+946       tracker.touch();
+947     }
+948     configure(properties, execute, EXECUTE);
+949 
+950     /**
+951      * Configure the generation of the SQL.
+952      * Overwrite values from properties-file if the configuration parameter is
+953      * known to Hibernate.
+954      */
+955     configure(properties, dialect, DIALECT);
+956     configure(properties, delimiter, HBM2DDL_DELIMITER);
+957     configure(properties, format, FORMAT_SQL);
+958     configure(properties, createNamespaces, HBM2DLL_CREATE_NAMESPACES);
+959     configure(properties, implicitNamingStrategy, IMPLICIT_NAMING_STRATEGY);
+960     configure(properties, physicalNamingStrategy, PHYSICAL_NAMING_STRATEGY);
+961     configure(properties, outputDirectory, OUTPUTDIRECTORY);
+962     configure(properties, scanDependencies, SCAN_DEPENDENCIES);
+963     configure(properties, scanTestClasses, SCAN_TESTCLASSES);
+964     configure(properties, testOutputDirectory, TEST_OUTPUTDIRECTORY);
+965 
+966     /**
+967      * Special treatment for the configuration-value "show": a change of its
+968      * configured value should not lead to a regeneration of the database
+969      * schama!
+970      */
+971     if (show == null)
+972       show = Boolean.valueOf(properties.getProperty(SHOW_SQL));
+973     else
+974       properties.setProperty(SHOW_SQL, show.toString());
+975 
+976     /**
+977      * Configure the connection parameters.
+978      * Overwrite values from properties-file.
+979      */
+980     configure(properties, driver, DRIVER, JPA_JDBC_DRIVER);
+981     configure(properties, url, URL, JPA_JDBC_URL);
+982     configure(properties, username, USER, JPA_JDBC_USER);
+983     configure(properties, password, PASS, JPA_JDBC_PASSWORD);
+984 
+985     if (properties.isEmpty())
+986     {
+987       getLog().error("No properties set!");
+988       throw new MojoFailureException("Hibernate configuration is missing!");
+989     }
+990 
+991     getLog().info("Gathered configuration:");
+992     for (Entry<Object,Object> entry : properties.entrySet())
+993       getLog().info("  " + entry.getKey() + " = " + entry.getValue());
+994   }
+995 
+996   private void configure(
+997       Properties properties,
+998       String value,
+999       String key,
+1000       String alternativeKey
+1001       )
+1002   {
+1003     configure(properties, value, key);
+1004 
+1005     if (properties.containsKey(alternativeKey))
+1006     {
+1007       if (properties.containsKey(key))
+1008       {
+1009         getLog().warn(
+1010             "Ignoring property " + alternativeKey + "=\"" +
+1011             properties.getProperty(alternativeKey) +
+1012             "\" in favour for property " + key + "=\"" +
+1013             properties.getProperty(key) + "\""
+1014             );
+1015         properties.remove(alternativeKey);
+1016       }
+1017       else
+1018       {
+1019         value = properties.getProperty(alternativeKey);
+1020         properties.remove(alternativeKey);
+1021         getLog().info(
+1022             "Using value \"" + value + "\" from property " + alternativeKey +
+1023             " for property " + key
+1024             );
+1025         properties.setProperty(key, value);
+1026       }
+1027     }
+1028   }
+1029 
+1030   private void configure(Properties properties, String value, String key)
+1031   {
+1032     if (value != null)
+1033     {
+1034       if (properties.containsKey(key))
+1035       {
+1036         if (!properties.getProperty(key).equals(value))
+1037         {
+1038           getLog().info(
+1039               "Overwriting property " + key + "=\"" +
+1040               properties.getProperty(key) +
+1041               "\" with value \"" + value + "\""
+1042               );
+1043           properties.setProperty(key, value);
+1044         }
+1045       }
+1046       else
+1047       {
+1048         getLog().debug("Using value \"" + value + "\" for property " + key);
+1049         properties.setProperty(key, value);
+1050       }
+1051     }
+1052   }
+1053 
+1054   private void configure(Properties properties, Boolean value, String key)
+1055   {
+1056     configure(properties, value == null ? null : value.toString(), key);
+1057   }
+1058 
+1059   private File getOutputFile(String filename)
+1060       throws
+1061         MojoExecutionException
+1062   {
+1063     File output = new File(filename);
+1064 
+1065     if (!output.isAbsolute())
+1066     {
+1067       // Interpret relative file path relative to build directory
+1068       output = new File(buildDirectory, filename);
+1069     }
+1070     getLog().debug("Output file: " + output.getPath());
+1071 
+1072     // Ensure that directory path for specified file exists
+1073     File outFileParentDir = output.getParentFile();
+1074     if (null != outFileParentDir && !outFileParentDir.exists())
+1075     {
+1076       try
+1077       {
+1078         getLog().info(
+1079             "Creating directory path for output file:" +
+1080             outFileParentDir.getPath()
+1081             );
+1082         outFileParentDir.mkdirs();
+1083       }
+1084       catch (Exception e)
+1085       {
+1086         String error =
+1087             "Error creating directory path for output file: " + e.getMessage();
+1088         getLog().error(error);
+1089         throw new MojoExecutionException(error);
+1090       }
+1091     }
+1092 
+1093     try
+1094     {
+1095       output.createNewFile();
+1096     }
+1097     catch (IOException e)
+1098     {
+1099       String error = "Error creating output file: " + e.getMessage();
+1100       getLog().error(error);
+1101       throw new MojoExecutionException(error);
+1102     }
+1103 
+1104     if (!output.canWrite())
+1105     {
+1106       String error =
+1107           "Output file " + output.getAbsolutePath() + " is not writable!";
+1108       getLog().error(error);
+1109       throw new MojoExecutionException(error);
+1110     }
+1111 
+1112     return output;
+1113   }
+1114 
+1115   private void checkOutputFile(File output, ModificationTracker tracker)
+1116       throws
+1117         MojoExecutionException
+1118   {
+1119     try
+1120     {
+1121       if (output.exists())
+1122         tracker.track(SCRIPT, new FileInputStream(output));
+1123       else
+1124         tracker.track(SCRIPT, ZonedDateTime.now().toString());
+1125     }
+1126     catch (IOException e)
+1127     {
+1128       String error =
+1129           "Error while checking the generated script: " + e.getMessage();
+1130       getLog().error(error);
+1131       throw new MojoExecutionException(error);
+1132     }
+1133   }
+1134 
+1135   private void addMappings(MetadataSources sources, ModificationTracker tracker)
+1136       throws MojoFailureException
+1137   {
+1138     getLog().debug("Adding explicitly configured mappings...");
+1139     if (mappings != null)
+1140     {
+1141       try
+1142       {
+1143         for (String filename : mappings.split("[\\s,]+"))
+1144         {
+1145           // First try the filename as absolute/relative path
+1146           File file = new File(filename);
+1147           if (!file.exists())
+1148           {
+1149             // If the file was not found, search for it in the resource-directories
+1150             for (Resource resource : project.getResources())
+1151             {
+1152               file = new File(resource.getDirectory() + File.separator + filename);
+1153               if (file.exists())
+1154                 break;
+1155             }
+1156           }
+1157           if (file.exists())
+1158           {
+1159             if (file.isDirectory())
+1160               // TODO: add support to read all mappings under a directory
+1161               throw new MojoFailureException(file.getAbsolutePath() + " is a directory");
+1162             if (tracker.track(filename, new FileInputStream(file)))
+1163               getLog().debug("Found new or modified mapping-file: " + filename);
+1164             else
+1165               getLog().debug("Mapping-file unchanged: " + filename);
+1166 
+1167             sources.addFile(file);
+1168           }
+1169           else
+1170             throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!");
+1171         }
+1172       }
+1173       catch (IOException e)
+1174       {
+1175         throw new MojoFailureException("Cannot calculate MD5 sums!", e);
+1176       }
+1177     }
+1178   }
+1179 
+1180   private void addRoot(Set<URL> urls, String path) throws MojoFailureException
+1181   {
+1182     try
+1183     {
+1184       File dir = new File(path);
+1185       if (dir.exists())
+1186       {
+1187         getLog().info("Adding " + dir.getAbsolutePath() + " to the list of roots to scan...");
+1188         urls.add(dir.toURI().toURL());
+1189       }
+1190       else
+1191         getLog().warn(
+1192             "the directory cannot be scanned for annotated classes, " +
+1193             "because it does not exist: " +
+1194             dir.getAbsolutePath()
+1195             );
+1196     }
+1197     catch (MalformedURLException e)
+1198     {
+1199       getLog().error("error while adding the project-root to the list of roots to scan!", e);
+1200       throw new MojoFailureException(e.getMessage());
+1201     }
+1202   }
+1203 
+1204   private void addDependencies(Set<URL> urls) throws MojoFailureException
+1205   {
+1206     try
+1207     {
+1208       if (scanDependencies != null)
+1209       {
+1210         Matcher matcher = SPLIT.matcher(scanDependencies);
+1211         while (matcher.find())
+1212         {
+1213           getLog().info("Adding dependencies from scope " + matcher.group() + " to the list of roots to scan");
+1214           for (Artifact artifact : project.getDependencyArtifacts())
+1215           {
+1216             if (!artifact.getScope().equalsIgnoreCase(matcher.group()))
+1217               continue;
+1218             if (artifact.getFile() == null)
+1219             {
+1220               getLog().warn("Cannot add dependency " + artifact.getId() + ": no JAR-file available!");
+1221               continue;
+1222             }
+1223             getLog().info("Adding dependencies from scope " + artifact.getId() + " to the list of roots to scan");
+1224             urls.add(artifact.getFile().toURI().toURL());
+1225           }
+1226         }
+1227       }
+1228     }
+1229     catch (MalformedURLException e)
+1230     {
+1231       getLog().error("Error while adding dependencies to the list of roots to scan!", e);
+1232       throw new MojoFailureException(e.getMessage());
+1233     }
+1234   }
+1235 
+1236   private Set<String> scanUrls(Set<URL> scanRoots)
+1237       throws
+1238         MojoFailureException
+1239   {
+1240     try
+1241     {
+1242       AnnotationDB db = new AnnotationDB();
+1243       for (URL root : scanRoots)
+1244         db.scanArchives(root);
+1245 
+1246       Set<String> classes = new HashSet<String>();
+1247       if (db.getAnnotationIndex().containsKey(Entity.class.getName()))
+1248         classes.addAll(db.getAnnotationIndex().get(Entity.class.getName()));
+1249       if (db.getAnnotationIndex().containsKey(MappedSuperclass.class.getName()))
+1250         classes.addAll(db.getAnnotationIndex().get(MappedSuperclass.class.getName()));
+1251       if (db.getAnnotationIndex().containsKey(Embeddable.class.getName()))
+1252         classes.addAll(db.getAnnotationIndex().get(Embeddable.class.getName()));
+1253 
+1254       return classes;
+1255     }
+1256     catch (Exception e)
+1257     {
+1258       getLog().error("Error while scanning!", e);
+1259       throw new MojoFailureException(e.getMessage());
+1260     }
+1261   }
+1262 
+1263   private void addAnnotated(
+1264       String name,
+1265       MetadataSources sources,
+1266       ClassLoaderService classLoaderService,
+1267       ModificationTracker tracker
+1268       )
+1269       throws
+1270         MojoFailureException,
+1271         MojoExecutionException
+1272   {
+1273     try
+1274     {
+1275       getLog().info("Adding annotated resource: " + name);
+1276       String packageName = null;
+1277 
+1278       boolean error = false;
+1279       try
+1280       {
+1281         Class<?> annotatedClass = classLoaderService.classForName(name);
+1282         String resourceName = annotatedClass.getName();
+1283         resourceName =
+1284             resourceName.substring(
+1285                 resourceName.lastIndexOf(".") + 1,
+1286                 resourceName.length()
+1287                 ) + ".class";
+1288         InputStream is = annotatedClass.getResourceAsStream(resourceName);
+1289         if (is != null)
+1290         {
+1291           if (tracker.track(name, is))
+1292             getLog().debug("New or modified class: " + name);
+1293           else
+1294             getLog().debug("Unchanged class: " + name);
+1295           sources.addAnnotatedClass(annotatedClass);
+1296           packageName = annotatedClass.getPackage().getName();
+1297         }
+1298         else
+1299         {
+1300           getLog().error("cannot find ressource " + resourceName + " for class " + name);
+1301           error = true;
+1302         }
+1303       }
+1304       catch(ClassLoadingException e)
+1305       {
+1306         packageName = name;
+1307       }
+1308       if (error)
+1309       {
+1310         throw new MojoExecutionException("error while inspecting annotated class " + name);
+1311       }
+1312 
+1313       while (packageName != null)
+1314       {
+1315         if (packages.contains(packageName))
+1316           return;
+1317         String resource = packageName.replace('.', '/') + "/package-info.class";
+1318         InputStream is = classLoaderService.locateResourceStream(resource);
+1319         if (is == null)
+1320         {
+1321           // No compiled package-info available: no package-level annotations!
+1322           getLog().debug("Package " + packageName + " is not annotated.");
+1323         }
+1324         else
+1325         {
+1326           if (tracker.track(packageName, is))
+1327             getLog().debug("New or modified package: " + packageName);
+1328           else
+1329            getLog().debug("Unchanged package: " + packageName);
+1330           getLog().info("Adding annotations from package " + packageName);
+1331           sources.addPackage(packageName);
+1332         }
+1333         packages.add(packageName);
+1334         int i = packageName.lastIndexOf('.');
+1335         if (i < 0)
+1336           packageName = null;
+1337         else
+1338           packageName = packageName.substring(0,i);
+1339       }
+1340     }
+1341     catch (Exception e)
+1342     {
+1343       getLog().error("Error while adding the annotated class " + name, e);
+1344       throw new MojoFailureException(e.getMessage());
+1345     }
+1346   }
+1347 
+1348   private ParsedPersistenceXmlDescriptor loadPersistenceUnit(
+1349       ClassLoaderService classLoaderService,
+1350       Properties properties
+1351       )
+1352       throws
+1353         MojoFailureException
+1354   {
+1355     PersistenceXmlParser parser =
+1356         new PersistenceXmlParser(
+1357             classLoaderService,
+1358             PersistenceUnitTransactionType.RESOURCE_LOCAL
+1359              );
+1360 
+1361     Map<String, ParsedPersistenceXmlDescriptor> units =
+1362         parser.doResolve(properties);
+1363 
+1364     if (persistenceUnit == null)
+1365     {
+1366       Iterator<String> names = units.keySet().iterator();
+1367       if (!names.hasNext())
+1368       {
+1369         getLog().info("Found no META-INF/persistence.xml.");
+1370         return null;
+1371       }
+1372 
+1373       String name = names.next();
+1374       if (!names.hasNext())
+1375       {
+1376           getLog().info("Using persistence-unit " + name);
+1377           return units.get(name);
+1378       }
+1379 
+1380       StringBuilder builder = new StringBuilder();
+1381       builder.append("No name provided and multiple persistence units found: ");
+1382       builder.append(name);
+1383       while(names.hasNext())
+1384       {
+1385         builder.append(", ");
+1386         builder.append(names.next());
+1387       }
+1388       builder.append('.');
+1389       throw new MojoFailureException(builder.toString());
+1390     }
+1391 
+1392     if (units.containsKey(persistenceUnit))
+1393     {
+1394       getLog().info("Using configured persistence-unit " + persistenceUnit);
+1395       return units.get(persistenceUnit);
+1396     }
+1397 
+1398     throw new MojoFailureException("Could not find persistence-unit " + persistenceUnit);
+1399   }
+1400 
+1401 
+1402   public static void printStrackTrace(StringBuilder builder, Throwable t)
+1403   {
+1404     while (t != null)
+1405     {
+1406       builder.append("\n\tCause: ");
+1407       builder.append(t.getMessage() == null ? "" : t.getMessage().replaceAll("\\s+", " "));
+1408       for (StackTraceElement trace : t.getStackTrace())
+1409       {
+1410         builder.append("\n\t");
+1411         builder.append(trace.getClassName());
+1412         builder.append(".");
+1413         builder.append(trace.getMethodName());
+1414         builder.append("():");
+1415         builder.append(trace.getLineNumber());
+1416       }
+1417       t = t.getCause();
+1418     }
+1419   }
+1420 }
+
+
+ + +