X-Git-Url: https://juplo.de/gitweb/?p=website;a=blobdiff_plain;f=dist%2Fhibernate4-maven-plugin-1.0.5%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate4%2FHbm2DdlMojo.html;fp=dist%2Fhibernate4-maven-plugin-1.0.5%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate4%2FHbm2DdlMojo.html;h=6189278dc615963287549c82341f19f407e3506b;hp=0000000000000000000000000000000000000000;hb=a53595184bd6e57bdc45292cc92c393c4e2dfe6e;hpb=c48c9ee0e9faa89a4c0a5323b367b9f5a6abe602 diff --git a/dist/hibernate4-maven-plugin-1.0.5/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html b/dist/hibernate4-maven-plugin-1.0.5/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html new file mode 100644 index 00000000..6189278d --- /dev/null +++ b/dist/hibernate4-maven-plugin-1.0.5/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html @@ -0,0 +1,1075 @@ + + + + +Hbm2DdlMojo xref + + + +
View Javadoc
+
+1   package de.juplo.plugins.hibernate4;
+2   
+3   /*
+4    * Copyright 2001-2005 The Apache Software Foundation.
+5    *
+6    * Licensed under the Apache License, Version 2.0 (the "License");
+7    * you may not use this file except in compliance with the License.
+8    * You may obtain a copy of the License at
+9    *
+10   *      http://www.apache.org/licenses/LICENSE-2.0
+11   *
+12   * Unless required by applicable law or agreed to in writing, software
+13   * distributed under the License is distributed on an "AS IS" BASIS,
+14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+15   * See the License for the specific language governing permissions and
+16   * limitations under the License.
+17   */
+18  
+19  import com.pyx4j.log4j.MavenLogAppender;
+20  import java.io.File;
+21  import java.io.FileInputStream;
+22  import java.io.FileNotFoundException;
+23  import java.io.FileOutputStream;
+24  import java.io.IOException;
+25  import java.io.InputStream;
+26  import java.io.ObjectInputStream;
+27  import java.io.ObjectOutputStream;
+28  import java.math.BigInteger;
+29  import java.net.URL;
+30  import java.net.URLClassLoader;
+31  import java.security.MessageDigest;
+32  import java.security.NoSuchAlgorithmException;
+33  import java.sql.Connection;
+34  import java.sql.Driver;
+35  import java.sql.DriverManager;
+36  import java.sql.DriverPropertyInfo;
+37  import java.sql.SQLException;
+38  import java.sql.SQLFeatureNotSupportedException;
+39  import java.util.Comparator;
+40  import java.util.Enumeration;
+41  import java.util.HashMap;
+42  import java.util.HashSet;
+43  import java.util.List;
+44  import java.util.Map;
+45  import java.util.Map.Entry;
+46  import java.util.Properties;
+47  import java.util.Set;
+48  import java.util.TreeSet;
+49  import java.util.logging.Logger;
+50  import java.util.regex.Matcher;
+51  import java.util.regex.Pattern;
+52  import javax.persistence.Embeddable;
+53  import javax.persistence.Entity;
+54  import javax.persistence.MappedSuperclass;
+55  import org.apache.maven.artifact.Artifact;
+56  import org.apache.maven.model.Resource;
+57  import org.apache.maven.plugin.AbstractMojo;
+58  import org.apache.maven.plugin.MojoExecutionException;
+59  import org.apache.maven.plugin.MojoFailureException;
+60  import org.apache.maven.project.MavenProject;
+61  import org.hibernate.cfg.NamingStrategy;
+62  import org.hibernate.envers.configuration.spi.AuditConfiguration;
+63  import org.hibernate.tool.hbm2ddl.SchemaExport;
+64  import org.hibernate.tool.hbm2ddl.SchemaExport.Type;
+65  import org.hibernate.tool.hbm2ddl.Target;
+66  import org.scannotation.AnnotationDB;
+67  
+68  
+69  /**
+70   * Goal which extracts the hibernate-mapping-configuration and
+71   * exports an according SQL-database-schema.
+72   *
+73   * @goal export
+74   * @phase process-classes
+75   * @threadSafe
+76   * @requiresDependencyResolution runtime
+77   */
+78  public class Hbm2DdlMojo extends AbstractMojo
+79  {
+80    public final static String EXPORT_SKIPPED_PROPERTY = "hibernate.export.skipped";
+81  
+82    public final static String DRIVER_CLASS = "hibernate.connection.driver_class";
+83    public final static String URL = "hibernate.connection.url";
+84    public final static String USERNAME = "hibernate.connection.username";
+85    public final static String PASSWORD = "hibernate.connection.password";
+86    public final static String DIALECT = "hibernate.dialect";
+87    public final static String NAMING_STRATEGY="hibernate.ejb.naming_strategy";
+88    public final static String ENVERS = "hibernate.export.envers";
+89  
+90    public final static String MD5S = "hibernate4-generatedschema.md5s";
+91  
+92    private final static Pattern split = Pattern.compile("[^,\\s]+");
+93  
+94  
+95    /**
+96     * The maven project.
+97     * <p>
+98     * Only needed internally.
+99     *
+100    * @parameter property="project"
+101    * @required
+102    * @readonly
+103    */
+104   private MavenProject project;
+105 
+106   /**
+107    * Build-directory.
+108    * <p>
+109    * Only needed internally.
+110    *
+111    * @parameter property="project.build.directory"
+112    * @required
+113    * @readonly
+114    */
+115   private String buildDirectory;
+116 
+117   /**
+118    * Classes-Directory to scan.
+119    * <p>
+120    * This parameter defaults to the maven build-output-directory for classes.
+121    * Additionally, all dependencies are scanned for annotated classes.
+122    *
+123    * @parameter property="project.build.outputDirectory"
+124    * @since 1.0
+125    */
+126   private String outputDirectory;
+127 
+128   /**
+129    * Whether to scan test-classes too, or not.
+130    * <p>
+131    * If this parameter is set to <code>true</code> the test-classes of the
+132    * artifact will be scanned for hibernate-annotated classes additionally.
+133    *
+134    * @parameter property="hibernate.export.scan_testclasses" default-value="false"
+135    * @since 1.0.1
+136    */
+137   private boolean scanTestClasses;
+138 
+139   /**
+140    * Dependency-Scopes, that should be scanned for annotated classes.
+141    * <p>
+142    * By default, only dependencies in the scope <code>compile</code> are
+143    * scanned for annotated classes. Multiple scopes can be seperated by
+144    * white space or commas.
+145    * <p>
+146    * If you do not want any dependencies to be scanned for annotated
+147    * classes, set this parameter to <code>none</code>.
+148    * <p>
+149    * The plugin does not scan for annotated classes in transitive
+150    * dependencies. If some of your annotated classes are hidden in a
+151    * transitive dependency, you can simply add that dependency explicitly.
+152    *
+153    * @parameter property="hibernate.export.scan_dependencies" default-value="compile"
+154    * @since 1.0.3
+155    */
+156   private String scanDependencies;
+157 
+158   /**
+159    * Test-Classes-Directory to scan.
+160    * <p>
+161    * This parameter defaults to the maven build-output-directory for
+162    * test-classes.
+163    * <p>
+164    * This parameter is only used, when <code>scanTestClasses</code> is set
+165    * to <code>true</code>!
+166    *
+167    * @parameter property="project.build.testOutputDirectory"
+168    * @since 1.0.2
+169    */
+170   private String testOutputDirectory;
+171 
+172   /**
+173    * Skip execution
+174    * <p>
+175    * If set to <code>true</code>, the execution is skipped.
+176    * <p>
+177    * A skipped execution is signaled via the maven-property
+178    * <code>${hibernate.export.skipped}</code>.
+179    * <p>
+180    * The execution is skipped automatically, if no modified or newly added
+181    * annotated classes are found and the dialect was not changed.
+182    *
+183    * @parameter property="hibernate.skip" default-value="${maven.test.skip}"
+184    * @since 1.0
+185    */
+186   private boolean skip;
+187 
+188   /**
+189    * Force execution
+190    * <p>
+191    * Force execution, even if no modified or newly added annotated classes
+192    * where found and the dialect was not changed.
+193    * <p>
+194    * <code>skip</code> takes precedence over <code>force</code>.
+195    *
+196    * @parameter property="hibernate.export.force" default-value="false"
+197    * @since 1.0
+198    */
+199   private boolean force;
+200 
+201   /**
+202    * SQL-Driver name.
+203    *
+204    * @parameter property="hibernate.connection.driver_class"
+205    * @since 1.0
+206    */
+207   private String driverClassName;
+208 
+209   /**
+210    * Database URL.
+211    *
+212    * @parameter property="hibernate.connection.url"
+213    * @since 1.0
+214    */
+215   private String url;
+216 
+217   /**
+218    * Database username
+219    *
+220    * @parameter property="hibernate.connection.username"
+221    * @since 1.0
+222    */
+223   private String username;
+224 
+225   /**
+226    * Database password
+227    *
+228    * @parameter property="hibernate.connection.password"
+229    * @since 1.0
+230    */
+231   private String password;
+232 
+233   /**
+234    * Hibernate dialect.
+235    *
+236    * @parameter property="hibernate.dialect"
+237    * @since 1.0
+238    */
+239   private String hibernateDialect;
+240 
+241   /**
+242    * Hibernate Naming Strategy
+243    *
+244    * @parameter property="hibernate.ejb.naming_strategy"
+245    * @since 1.0.2
+246    */
+247   private String hibernateNamingStrategy;
+248 
+249   /**
+250    * Path to Hibernate configuration file.
+251    *
+252    * @parameter default-value="${project.build.outputDirectory}/hibernate.properties"
+253    * @since 1.0
+254    */
+255   private String hibernateProperties;
+256 
+257   /**
+258    * List of Hibernate-Mapping-Files (XML).
+259    * Multiple files can be separated with white-spaces and/or commas.
+260    *
+261    * @parameter property="hibernate.mapping"
+262    * @since 1.0.2
+263    */
+264   private String hibernateMapping;
+265 
+266   /**
+267    * Target of execution:
+268    * <ul>
+269    *   <li><strong>NONE</strong> only export schema to SQL-script (forces execution, signals skip)</li>
+270    *   <li><strong>EXPORT</strong> create database (<strong>DEFAULT!</strong>). forces execution, signals skip)</li>
+271    *   <li><strong>SCRIPT</strong> export schema to SQL-script and print it to STDOUT</li>
+272    *   <li><strong>BOTH</strong></li>
+273    * </ul>
+274    *
+275    * A database connection is only needed for EXPORT and BOTH, but a
+276    * Hibernate-Dialect must always be chosen.
+277    *
+278    * @parameter property="hibernate.export.target" default-value="EXPORT"
+279    * @since 1.0
+280    */
+281   private String target;
+282 
+283   /**
+284    * Type of execution.
+285    * <ul>
+286    *   <li><strong>NONE</strong> do nothing - just validate the configuration</li>
+287    *   <li><strong>CREATE</strong> create database-schema</li>
+288    *   <li><strong>DROP</strong> drop database-schema</li>
+289    *   <li><strong>BOTH</strong> (<strong>DEFAULT!</strong>)</li>
+290    * </ul>
+291    *
+292    * If NONE is choosen, no databaseconnection is needed.
+293    *
+294    * @parameter property="hibernate.export.type" default-value="BOTH"
+295    * @since 1.0
+296    */
+297   private String type;
+298 
+299   /**
+300    * Output file.
+301    *
+302    * @parameter property="hibernate.export.schema.filename" default-value="${project.build.directory}/schema.sql"
+303    * @since 1.0
+304    */
+305   private String outputFile;
+306 
+307   /**
+308    * Delimiter in output-file.
+309    *
+310    * @parameter property="hibernate.export.schema.delimiter" default-value=";"
+311    * @since 1.0
+312    */
+313   private String delimiter;
+314 
+315   /**
+316    * Format output-file.
+317    *
+318    * @parameter property="hibernate.export.schema.format" default-value="true"
+319    * @since 1.0
+320    */
+321   private boolean format;
+322 
+323   /**
+324    * Generate envers schema for auditing tables.
+325    *
+326    * @parameter property="hibernate.export.envers" default-value="false"
+327    * @since 1.0.3
+328    */
+329   private boolean envers;
+330 
+331 
+332   @Override
+333   public void execute()
+334     throws
+335       MojoFailureException,
+336       MojoExecutionException
+337   {
+338     if (skip)
+339     {
+340       getLog().info("Execution of hibernate4-maven-plugin:export was skipped!");
+341       project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
+342       return;
+343     }
+344 
+345     Map<String,String> md5s;
+346     boolean modified = false;
+347     File saved = new File(buildDirectory + File.separator + MD5S);
+348 
+349     if (saved.isFile() && saved.length() > 0)
+350     {
+351       try
+352       {
+353         FileInputStream fis = new FileInputStream(saved);
+354         ObjectInputStream ois = new ObjectInputStream(fis);
+355         md5s = (HashMap<String,String>)ois.readObject();
+356         ois.close();
+357       }
+358       catch (Exception e)
+359       {
+360         md5s = new HashMap<String,String>();
+361         getLog().warn("Cannot read timestamps from saved: " + e);
+362       }
+363     }
+364     else
+365     {
+366       md5s = new HashMap<String,String>();
+367       try
+368       {
+369         saved.createNewFile();
+370       }
+371       catch (IOException e)
+372       {
+373         getLog().debug("Cannot create file \"" + saved.getPath() + "\" for timestamps: " + e);
+374       }
+375     }
+376 
+377     ClassLoader classLoader = null;
+378     try
+379     {
+380       getLog().debug("Creating ClassLoader for project-dependencies...");
+381       List<String> classpathFiles = project.getCompileClasspathElements();
+382       if (scanTestClasses)
+383         classpathFiles.addAll(project.getTestClasspathElements());
+384       URL[] urls = new URL[classpathFiles.size()];
+385       for (int i = 0; i < classpathFiles.size(); ++i)
+386       {
+387         getLog().debug("Dependency: " + classpathFiles.get(i));
+388         urls[i] = new File(classpathFiles.get(i)).toURI().toURL();
+389       }
+390       classLoader = new URLClassLoader(urls, getClass().getClassLoader());
+391     }
+392     catch (Exception e)
+393     {
+394       getLog().error("Error while creating ClassLoader!", e);
+395       throw new MojoExecutionException(e.getMessage());
+396     }
+397 
+398     Set<Class<?>> classes =
+399         new TreeSet<Class<?>>(
+400             new Comparator<Class<?>>() {
+401               @Override
+402               public int compare(Class<?> a, Class<?> b)
+403               {
+404                 return a.getName().compareTo(b.getName());
+405               }
+406             }
+407           );
+408 
+409     try
+410     {
+411       AnnotationDB db = new AnnotationDB();
+412       File dir = new File(outputDirectory);
+413       if (dir.exists())
+414       {
+415         getLog().info("Scanning directory " + outputDirectory + " for annotated classes...");
+416         URL dirUrl = dir.toURI().toURL();
+417         db.scanArchives(dirUrl);
+418       }
+419       if (scanTestClasses)
+420       {
+421         dir = new File(testOutputDirectory);
+422         if (dir.exists())
+423         {
+424           getLog().info("Scanning directory " + testOutputDirectory + " for annotated classes...");
+425           URL dirUrl = dir.toURI().toURL();
+426           db.scanArchives(dirUrl);
+427         }
+428       }
+429       if (scanDependencies != null)
+430       {
+431         Matcher matcher = split.matcher(scanDependencies);
+432         while (matcher.find())
+433         {
+434           getLog().info("Scanning dependencies for scope " + matcher.group());
+435           for (Artifact artifact : project.getDependencyArtifacts())
+436           {
+437             if (!artifact.getScope().equalsIgnoreCase(matcher.group()))
+438               continue;
+439             if (artifact.getFile() == null)
+440             {
+441               getLog().warn(
+442                   "Cannot scan dependency " +
+443                   artifact.getId() +
+444                   ": no JAR-file available!"
+445                   );
+446               continue;
+447             }
+448             getLog().info(
+449                 "Scanning dependency " +
+450                 artifact.getId() +
+451                 " for annotated classes..."
+452                 );
+453             db.scanArchives(artifact.getFile().toURI().toURL());
+454           }
+455         }
+456       }
+457 
+458       Set<String> classNames = new HashSet<String>();
+459       if (db.getAnnotationIndex().containsKey(Entity.class.getName()))
+460         classNames.addAll(db.getAnnotationIndex().get(Entity.class.getName()));
+461       if (db.getAnnotationIndex().containsKey(MappedSuperclass.class.getName()))
+462         classNames.addAll(db.getAnnotationIndex().get(MappedSuperclass.class.getName()));
+463       if (db.getAnnotationIndex().containsKey(Embeddable.class.getName()))
+464         classNames.addAll(db.getAnnotationIndex().get(Embeddable.class.getName()));
+465 
+466       MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
+467       for (String name : classNames)
+468       {
+469         Class<?> annotatedClass = classLoader.loadClass(name);
+470         classes.add(annotatedClass);
+471         String resourceName = annotatedClass.getName();
+472         resourceName = resourceName.substring(resourceName.lastIndexOf(".") + 1, resourceName.length()) + ".class";
+473         InputStream is =
+474             annotatedClass
+475                 .getResourceAsStream(resourceName);
+476         byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
+477         int i;
+478         while((i = is.read(buffer)) > -1)
+479           digest.update(buffer, 0, i);
+480         is.close();
+481         byte[] bytes = digest.digest();
+482         BigInteger bi = new BigInteger(1, bytes);
+483         String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
+484         String oldMd5 = !md5s.containsKey(name) ? "" : md5s.get(name);
+485         if (!newMd5.equals(oldMd5))
+486         {
+487           getLog().debug("Found new or modified annotated class: " + name);
+488           modified = true;
+489           md5s.put(name, newMd5);
+490         }
+491         else
+492         {
+493           getLog().debug(oldMd5 + " -> class unchanged: " + name);
+494         }
+495       }
+496     }
+497     catch (ClassNotFoundException e)
+498     {
+499       getLog().error("Error while adding annotated classes!", e);
+500       throw new MojoExecutionException(e.getMessage());
+501     }
+502     catch (Exception e)
+503     {
+504       getLog().error("Error while scanning!", e);
+505       throw new MojoFailureException(e.getMessage());
+506     }
+507 
+508     if (classes.isEmpty())
+509     {
+510       if (hibernateMapping == null || hibernateMapping.isEmpty())
+511         throw new MojoFailureException("No annotated classes found in directory " + outputDirectory);
+512     }
+513     else
+514     {
+515       getLog().debug("Detected classes with mapping-annotations:");
+516       for (Class<?> annotatedClass : classes)
+517         getLog().debug("  " + annotatedClass.getName());
+518     }
+519 
+520 
+521     Properties properties = new Properties();
+522 
+523     /** Try to read configuration from properties-file */
+524     try
+525     {
+526       File file = new File(hibernateProperties);
+527       if (file.exists())
+528       {
+529         getLog().info("Reading properties from file " + hibernateProperties + "...");
+530         properties.load(new FileInputStream(file));
+531       }
+532       else
+533         getLog().info("No hibernate-properties-file found! (Checked path: " + hibernateProperties + ")");
+534     }
+535     catch (IOException e)
+536     {
+537       getLog().error("Error while reading properties!", e);
+538       throw new MojoExecutionException(e.getMessage());
+539     }
+540 
+541     /** Overwrite values from properties-file or set, if given */
+542     if (driverClassName != null)
+543     {
+544       if (properties.containsKey(DRIVER_CLASS))
+545         getLog().debug(
+546             "Overwriting property " +
+547             DRIVER_CLASS + "=" + properties.getProperty(DRIVER_CLASS) +
+548             " with the value " + driverClassName
+549           );
+550       else
+551         getLog().debug("Using the value " + driverClassName);
+552       properties.setProperty(DRIVER_CLASS, driverClassName);
+553     }
+554     if (url != null)
+555     {
+556       if (properties.containsKey(URL))
+557         getLog().debug(
+558             "Overwriting property " +
+559             URL + "=" + properties.getProperty(URL) +
+560             " with the value " + url
+561           );
+562       else
+563         getLog().debug("Using the value " + url);
+564       properties.setProperty(URL, url);
+565     }
+566     if (username != null)
+567     {
+568       if (properties.containsKey(USERNAME))
+569         getLog().debug(
+570             "Overwriting property " +
+571             USERNAME + "=" + properties.getProperty(USERNAME) +
+572             " with the value " + username
+573           );
+574       else
+575         getLog().debug("Using the value " + username);
+576       properties.setProperty(USERNAME, username);
+577     }
+578     if (password != null)
+579     {
+580       if (properties.containsKey(PASSWORD))
+581         getLog().debug(
+582             "Overwriting property " +
+583             PASSWORD + "=" + properties.getProperty(PASSWORD) +
+584             " with value " + password
+585           );
+586       else
+587         getLog().debug("Using value " + password + " for property " + PASSWORD);
+588       properties.setProperty(PASSWORD, password);
+589     }
+590     if (hibernateDialect != null)
+591     {
+592       if (properties.containsKey(DIALECT))
+593         getLog().debug(
+594             "Overwriting property " +
+595             DIALECT + "=" + properties.getProperty(DIALECT) +
+596             " with value " + hibernateDialect
+597           );
+598       else
+599         getLog().debug(
+600             "Using value " + hibernateDialect + " for property " + DIALECT
+601             );
+602       properties.setProperty(DIALECT, hibernateDialect);
+603     }
+604     else
+605     {
+606       hibernateDialect = properties.getProperty(DIALECT);
+607     }
+608     if ( hibernateNamingStrategy != null )
+609     {
+610       if ( properties.contains(NAMING_STRATEGY))
+611         getLog().debug(
+612             "Overwriting property " +
+613             NAMING_STRATEGY + "=" + properties.getProperty(NAMING_STRATEGY) +
+614             " with value " + hibernateNamingStrategy
+615            );
+616       else
+617         getLog().debug(
+618             "Using value " + hibernateNamingStrategy + " for property " +
+619             NAMING_STRATEGY
+620             );
+621       properties.setProperty(NAMING_STRATEGY, hibernateNamingStrategy);
+622     }
+623 
+624     /** The generated SQL varies with the dialect! */
+625     if (md5s.containsKey(DIALECT))
+626     {
+627       String dialect = properties.getProperty(DIALECT);
+628       if (md5s.get(DIALECT).equals(dialect))
+629         getLog().debug("SQL-dialect unchanged.");
+630       else
+631       {
+632         modified = true;
+633         if (dialect == null)
+634         {
+635           getLog().debug("SQL-dialect was unset.");
+636           md5s.remove(DIALECT);
+637         }
+638         else
+639         {
+640           getLog().debug("SQL-dialect changed: " + dialect);
+641           md5s.put(DIALECT, dialect);
+642         }
+643       }
+644     }
+645     else
+646     {
+647       String dialect = properties.getProperty(DIALECT);
+648       if (dialect != null)
+649       {
+650         modified = true;
+651         md5s.put(DIALECT, properties.getProperty(DIALECT));
+652       }
+653     }
+654 
+655     /** The generated SQL varies with the envers-configuration */
+656     if (md5s.get(ENVERS) != null)
+657     {
+658       if (md5s.get(ENVERS).equals(Boolean.toString(envers)))
+659         getLog().debug("Envers-Configuration unchanged. Enabled: " + envers);
+660       else
+661       {
+662         getLog().debug("Envers-Configuration changed. Enabled: " + envers);
+663         modified = true;
+664         md5s.put(ENVERS, Boolean.toString(envers));
+665       }
+666     }
+667     else
+668     {
+669       modified = true;
+670       md5s.put(ENVERS, Boolean.toString(envers));
+671     }
+672 
+673     if (properties.isEmpty())
+674     {
+675       getLog().error("No properties set!");
+676       throw new MojoFailureException("Hibernate configuration is missing!");
+677     }
+678 
+679     final ValidationConfiguration config = new ValidationConfiguration(hibernateDialect);
+680 
+681     config.setProperties(properties);
+682 
+683     if ( properties.containsKey(NAMING_STRATEGY))
+684     {
+685       String namingStrategy = properties.getProperty(NAMING_STRATEGY);
+686       getLog().debug("Explicitly set NamingStrategy: " + namingStrategy);
+687       try
+688       {
+689         @SuppressWarnings("unchecked")
+690         Class<NamingStrategy> namingStrategyClass = (Class<NamingStrategy>) Class.forName(namingStrategy);
+691         config.setNamingStrategy(namingStrategyClass.newInstance());
+692       }
+693       catch (Exception e)
+694       {
+695         getLog().error("Error setting NamingStrategy", e);
+696         throw new MojoExecutionException(e.getMessage());
+697       }
+698     }
+699 
+700     ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+701     Connection connection = null;
+702     MavenLogAppender.startPluginLog(this);
+703     try
+704     {
+705       /**
+706        * Change class-loader of current thread, so that hibernate can
+707        * see all dependencies!
+708        */
+709       Thread.currentThread().setContextClassLoader(classLoader);
+710 
+711       getLog().debug("Adding annotated classes to hibernate-mapping-configuration...");
+712       // build annotated packages
+713       Set<String> packages = new HashSet<String>();
+714       for (Class<?> annotatedClass : classes)
+715       {
+716         String packageName = annotatedClass.getPackage().getName();
+717         if (!packages.contains(packageName))
+718         {
+719           getLog().debug("Add package " + packageName);
+720           packages.add(packageName);
+721           config.addPackage(packageName);
+722           getLog().debug("type definintions" + config.getTypeDefs());
+723         }
+724         getLog().debug("Class " + annotatedClass);
+725         config.addAnnotatedClass(annotatedClass);
+726       }
+727 
+728       if (hibernateMapping != null)
+729       {
+730         try
+731         {
+732           MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
+733           for (String filename : hibernateMapping.split("[\\s,]+"))
+734           {
+735             // First try the filename as absolute/relative path
+736             File file = new File(filename);
+737             if (!file.exists())
+738             {
+739               // If the file was not found, search for it in the resource-directories
+740               for (Resource resource : project.getResources())
+741               {
+742                 file = new File(resource.getDirectory() + File.separator + filename);
+743                 if (file.exists())
+744                   break;
+745               }
+746             }
+747             if (file != null && file.exists())
+748             {
+749               InputStream is = new FileInputStream(file);
+750               byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
+751               int i;
+752               while((i = is.read(buffer)) > -1)
+753                 digest.update(buffer, 0, i);
+754               is.close();
+755               byte[] bytes = digest.digest();
+756               BigInteger bi = new BigInteger(1, bytes);
+757               String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
+758               String oldMd5 = !md5s.containsKey(filename) ? "" : md5s.get(filename);
+759               if (!newMd5.equals(oldMd5))
+760               {
+761                 getLog().debug("Found new or modified mapping-file: " + filename);
+762                 modified = true;
+763                 md5s.put(filename, newMd5);
+764               }
+765               else
+766               {
+767                 getLog().debug(oldMd5 + " -> mapping-file unchanged: " + filename);
+768               }
+769               getLog().debug("Adding mappings from XML-configurationfile: " + file);
+770               config.addFile(file);
+771             }
+772             else
+773               throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!");
+774           }
+775         }
+776         catch (NoSuchAlgorithmException e)
+777         {
+778           throw new MojoFailureException("Cannot calculate MD5 sums!", e);
+779         }
+780         catch (FileNotFoundException e)
+781         {
+782           throw new MojoFailureException("Cannot calculate MD5 sums!", e);
+783         }
+784         catch (IOException e)
+785         {
+786           throw new MojoFailureException("Cannot calculate MD5 sums!", e);
+787         }
+788       }
+789 
+790       Target target = null;
+791       try
+792       {
+793         target = Target.valueOf(this.target.toUpperCase());
+794       }
+795       catch (IllegalArgumentException e)
+796       {
+797         getLog().error("Invalid value for configuration-option \"target\": " + this.target);
+798         getLog().error("Valid values are: NONE, SCRIPT, EXPORT, BOTH");
+799         throw new MojoExecutionException("Invalid value for configuration-option \"target\"");
+800       }
+801       Type type = null;
+802       try
+803       {
+804         type = Type.valueOf(this.type.toUpperCase());
+805       }
+806       catch (IllegalArgumentException e)
+807       {
+808         getLog().error("Invalid value for configuration-option \"type\": " + this.type);
+809         getLog().error("Valid values are: NONE, CREATE, DROP, BOTH");
+810         throw new MojoExecutionException("Invalid value for configuration-option \"type\"");
+811       }
+812 
+813       if (target.equals(Target.SCRIPT) || target.equals(Target.NONE))
+814       {
+815         project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
+816       }
+817       if (
+818           !modified
+819           && !target.equals(Target.SCRIPT)
+820           && !target.equals(Target.NONE)
+821           && !force
+822         )
+823       {
+824         getLog().info("No modified annotated classes or mapping-files found and dialect unchanged.");
+825         getLog().info("Skipping schema generation!");
+826         project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
+827         return;
+828       }
+829 
+830       getLog().info("Gathered hibernate-configuration (turn on debugging for details):");
+831       for (Entry<Object,Object> entry : properties.entrySet())
+832         getLog().info("  " + entry.getKey() + " = " + entry.getValue());
+833 
+834       try
+835       {
+836         /**
+837          * The connection must be established outside of hibernate, because
+838          * hibernate does not use the context-classloader of the current
+839          * thread and, hence, would not be able to resolve the driver-class!
+840          */
+841         getLog().debug("Target: " + target + ", Type: " + type);
+842         switch (target)
+843         {
+844           case EXPORT:
+845           case BOTH:
+846             switch (type)
+847             {
+848               case CREATE:
+849               case DROP:
+850               case BOTH:
+851                 Class driverClass = classLoader.loadClass(properties.getProperty(DRIVER_CLASS));
+852                 getLog().debug("Registering JDBC-driver " + driverClass.getName());
+853                 DriverManager.registerDriver(new DriverProxy((Driver)driverClass.newInstance()));
+854                 getLog().debug(
+855                     "Opening JDBC-connection to "
+856                     + properties.getProperty(URL)
+857                     + " as "
+858                     + properties.getProperty(USERNAME)
+859                     + " with password "
+860                     + properties.getProperty(PASSWORD)
+861                     );
+862                 connection = DriverManager.getConnection(
+863                     properties.getProperty(URL),
+864                     properties.getProperty(USERNAME),
+865                     properties.getProperty(PASSWORD)
+866                     );
+867             }
+868         }
+869       }
+870       catch (ClassNotFoundException e)
+871       {
+872         getLog().error("Dependency for driver-class " + properties.getProperty(DRIVER_CLASS) + " is missing!");
+873         throw new MojoExecutionException(e.getMessage());
+874       }
+875       catch (Exception e)
+876       {
+877         getLog().error("Cannot establish connection to database!");
+878         Enumeration<Driver> drivers = DriverManager.getDrivers();
+879         if (!drivers.hasMoreElements())
+880           getLog().error("No drivers registered!");
+881         while (drivers.hasMoreElements())
+882           getLog().debug("Driver: " + drivers.nextElement());
+883         throw new MojoExecutionException(e.getMessage());
+884       }
+885 
+886       config.buildMappings();
+887 
+888       if (envers)
+889       {
+890         getLog().info("Automatic auditing via hibernate-envers enabled!");
+891         AuditConfiguration.getFor(config);
+892       }
+893 
+894       SchemaExport export = new SchemaExport(config, connection);
+895       export.setDelimiter(delimiter);
+896       export.setFormat(format);
+897 
+898       File outF = new File(outputFile);
+899 
+900       if (!outF.isAbsolute())
+901       {
+902         // Interpret relative file path relative to build directory
+903         outF = new File(buildDirectory, outputFile);
+904         getLog().info("Adjusted relative path, resulting path is " + outF.getPath());
+905       }
+906 
+907       // Ensure that directory path for specified file exists
+908       File outFileParentDir = outF.getParentFile();
+909       if (null != outFileParentDir && !outFileParentDir.exists())
+910       {
+911         try
+912         {
+913           getLog().info("Creating directory path for output file:" + outFileParentDir.getPath());
+914           outFileParentDir.mkdirs();
+915         }
+916         catch (Exception e)
+917         {
+918           getLog().error("Error creating directory path for output file: " + e.getLocalizedMessage());
+919         }
+920       }
+921 
+922       export.setOutputFile(outF.getPath());
+923       export.execute(target, type);
+924 
+925       for (Object exception : export.getExceptions())
+926         getLog().debug(exception.toString());
+927     }
+928     finally
+929     {
+930       /** Stop Log-Capturing */
+931       MavenLogAppender.endPluginLog(this);
+932 
+933       /** Restore the old class-loader (TODO: is this really necessary?) */
+934       Thread.currentThread().setContextClassLoader(contextClassLoader);
+935 
+936       /** Close the connection */
+937       try
+938       {
+939         if (connection != null)
+940           connection.close();
+941       }
+942       catch (SQLException e)
+943       {
+944         getLog().error("Error while closing connection: " + e.getMessage());
+945       }
+946     }
+947 
+948     /** Write md5-sums for annotated classes to file */
+949     try
+950     {
+951       FileOutputStream fos = new FileOutputStream(saved);
+952       ObjectOutputStream oos = new ObjectOutputStream(fos);
+953       oos.writeObject(md5s);
+954       oos.close();
+955       fos.close();
+956     }
+957     catch (Exception e)
+958     {
+959       getLog().error("Cannot write md5-sums to file: " + e);
+960     }
+961   }
+962 
+963   /**
+964    * Needed, because DriverManager won't pick up drivers, that were not
+965    * loaded by the system-classloader!
+966    * See:
+967    * http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-fromodifiedm-an-arbitrary-location
+968    */
+969   static final class DriverProxy implements Driver
+970   {
+971     private final Driver target;
+972 
+973     DriverProxy(Driver target)
+974     {
+975       if (target == null)
+976         throw new NullPointerException();
+977       this.target = target;
+978     }
+979 
+980     public java.sql.Driver getTarget()
+981     {
+982       return target;
+983     }
+984 
+985     @Override
+986     public boolean acceptsURL(String url) throws SQLException
+987     {
+988       return target.acceptsURL(url);
+989     }
+990 
+991     @Override
+992     public java.sql.Connection connect(
+993         String url,
+994         java.util.Properties info
+995       )
+996       throws
+997         SQLException
+998     {
+999       return target.connect(url, info);
+1000     }
+1001 
+1002     @Override
+1003     public int getMajorVersion()
+1004     {
+1005       return target.getMajorVersion();
+1006     }
+1007 
+1008     @Override
+1009     public int getMinorVersion()
+1010     {
+1011       return target.getMinorVersion();
+1012     }
+1013 
+1014     @Override
+1015     public DriverPropertyInfo[] getPropertyInfo(
+1016         String url,
+1017         Properties info
+1018       )
+1019       throws
+1020         SQLException
+1021     {
+1022       return target.getPropertyInfo(url, info);
+1023     }
+1024 
+1025     @Override
+1026     public boolean jdbcCompliant()
+1027     {
+1028       return target.jdbcCompliant();
+1029     }
+1030 
+1031     /**
+1032      * This Method cannot be annotated with @Override, becaus the plugin
+1033      * will not compile then under Java 1.6!
+1034      */
+1035     public Logger getParentLogger() throws SQLFeatureNotSupportedException
+1036     {
+1037       throw new SQLFeatureNotSupportedException("Not supported, for backward-compatibility with Java 1.6");
+1038     }
+1039 
+1040     @Override
+1041     public String toString()
+1042     {
+1043       return "Proxy: " + target;
+1044     }
+1045 
+1046     @Override
+1047     public int hashCode()
+1048     {
+1049       return target.hashCode();
+1050     }
+1051 
+1052     @Override
+1053     public boolean equals(Object obj)
+1054     {
+1055       if (!(obj instanceof DriverProxy))
+1056         return false;
+1057       DriverProxy other = (DriverProxy) obj;
+1058       return this.target.equals(other.target);
+1059     }
+1060   }
+1061 }
+
+
+ +