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