X-Git-Url: https://juplo.de/gitweb/?p=website;a=blobdiff_plain;f=dist%2Fhibernate4-maven-plugin-1.0.3%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate4%2FHbm2DdlMojo.html;fp=dist%2Fhibernate4-maven-plugin-1.0.3%2Fxref%2Fde%2Fjuplo%2Fplugins%2Fhibernate4%2FHbm2DdlMojo.html;h=fe3ef3fb2e619121628c858bfa7d63d4d9ce7ecc;hp=0000000000000000000000000000000000000000;hb=a53595184bd6e57bdc45292cc92c393c4e2dfe6e;hpb=c48c9ee0e9faa89a4c0a5323b367b9f5a6abe602 diff --git a/dist/hibernate4-maven-plugin-1.0.3/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html b/dist/hibernate4-maven-plugin-1.0.3/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html new file mode 100644 index 00000000..fe3ef3fb --- /dev/null +++ b/dist/hibernate4-maven-plugin-1.0.3/xref/de/juplo/plugins/hibernate4/Hbm2DdlMojo.html @@ -0,0 +1,1033 @@ + + + + +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.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 = "schema.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    * Additonally, 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    * Wether 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 excecution is signaled via the maven-property
+176    * <code>${hibernate.export.skipped}</code>.
+177    * <p>
+178    * The excecution is skipped automatically, if no modified or newly added
+179    * annotated classes are found and the dialect was not changed.
+180    *
+181    * @parameter property="maven.test.skip" default-value="false"
+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 excecution, signals skip)</li>
+268    *   <li><strong>EXPORT</strong> create database (<strong>DEFAULT!</strong>). forces excecution, 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 databaseconnection is only needed for EXPORT and BOTH, but a
+274    * Hibernate-Dialect must always be choosen.
+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("Exectuion 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.exists())
+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 propertie-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     Configuration config = new Configuration();
+674     config.setProperties(properties);
+675 
+676     if ( properties.containsKey(NAMING_STRATEGY))
+677     {
+678       String namingStrategy = properties.getProperty(NAMING_STRATEGY);
+679       getLog().debug("Explicitly set NamingStrategy: " + namingStrategy);
+680       try
+681       {
+682         @SuppressWarnings("unchecked")
+683         Class<NamingStrategy> namingStrategyClass = (Class<NamingStrategy>) Class.forName(namingStrategy);
+684         config.setNamingStrategy(namingStrategyClass.newInstance());
+685       }
+686       catch (Exception e)
+687       {
+688         getLog().error("Error setting NamingStrategy", e);
+689         throw new MojoExecutionException(e.getMessage());
+690       }
+691     }
+692 
+693     getLog().debug("Adding annotated classes to hibernate-mapping-configuration...");
+694     for (Class<?> annotatedClass : classes)
+695     {
+696       getLog().debug("Class " + annotatedClass);
+697       config.addAnnotatedClass(annotatedClass);
+698     }
+699 
+700     if (hibernateMapping != null)
+701     {
+702       try
+703       {
+704         MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
+705         for (String filename : hibernateMapping.split("[\\s,]+"))
+706         {
+707           // First try the filename as absolute/relative path
+708           File file = new File(filename);
+709           if (!file.exists())
+710           {
+711             // If the file was not found, search for it in the resource-directories
+712             for (Resource resource : project.getResources())
+713             {
+714               file = new File(resource.getDirectory() + File.separator + filename);
+715               if (file.exists())
+716                 break;
+717             }
+718           }
+719           if (file != null && file.exists())
+720           {
+721             InputStream is = new FileInputStream(file);
+722             byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
+723             int i;
+724             while((i = is.read(buffer)) > -1)
+725               digest.update(buffer, 0, i);
+726             is.close();
+727             byte[] bytes = digest.digest();
+728             BigInteger bi = new BigInteger(1, bytes);
+729             String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
+730             String oldMd5 = !md5s.containsKey(filename) ? "" : md5s.get(filename);
+731             if (!newMd5.equals(oldMd5))
+732             {
+733               getLog().debug("Found new or modified mapping-file: " + filename);
+734               modified = true;
+735               md5s.put(filename, newMd5);
+736             }
+737             else
+738             {
+739               getLog().debug(oldMd5 + " -> mapping-file unchanged: " + filename);
+740             }
+741             getLog().debug("Adding mappings from XML-configurationfile: " + file);
+742             config.addFile(file);
+743           }
+744           else
+745             throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!");
+746         }
+747       }
+748       catch (NoSuchAlgorithmException e)
+749       {
+750         throw new MojoFailureException("Cannot calculate MD5-summs!", e);
+751       }
+752       catch (FileNotFoundException e)
+753       {
+754         throw new MojoFailureException("Cannot calculate MD5-summs!", e);
+755       }
+756       catch (IOException e)
+757       {
+758         throw new MojoFailureException("Cannot calculate MD5-summs!", e);
+759       }
+760     }
+761 
+762     Target target = null;
+763     try
+764     {
+765       target = Target.valueOf(this.target.toUpperCase());
+766     }
+767     catch (IllegalArgumentException e)
+768     {
+769       getLog().error("Invalid value for configuration-option \"target\": " + this.target);
+770       getLog().error("Valid values are: NONE, SCRIPT, EXPORT, BOTH");
+771       throw new MojoExecutionException("Invalid value for configuration-option \"target\"");
+772     }
+773     Type type = null;
+774     try
+775     {
+776       type = Type.valueOf(this.type.toUpperCase());
+777     }
+778     catch (IllegalArgumentException e)
+779     {
+780       getLog().error("Invalid value for configuration-option \"type\": " + this.type);
+781       getLog().error("Valid values are: NONE, CREATE, DROP, BOTH");
+782       throw new MojoExecutionException("Invalid value for configuration-option \"type\"");
+783     }
+784 
+785     if (target.equals(Target.SCRIPT) || target.equals(Target.NONE))
+786     {
+787       project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
+788     }
+789     if (
+790         !modified
+791         && !target.equals(Target.SCRIPT)
+792         && !target.equals(Target.NONE)
+793         && !force
+794       )
+795     {
+796       getLog().info("No modified annotated classes or mapping-files found and dialect unchanged.");
+797       getLog().info("Skipping schema generation!");
+798       project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
+799       return;
+800     }
+801 
+802     getLog().info("Gathered hibernate-configuration (turn on debugging for details):");
+803     for (Entry<Object,Object> entry : properties.entrySet())
+804       getLog().info("  " + entry.getKey() + " = " + entry.getValue());
+805 
+806     Connection connection = null;
+807     try
+808     {
+809       /**
+810        * The connection must be established outside of hibernate, because
+811        * hibernate does not use the context-classloader of the current
+812        * thread and, hence, would not be able to resolve the driver-class!
+813        */
+814       getLog().debug("Target: " + target + ", Type: " + type);
+815       switch (target)
+816       {
+817         case EXPORT:
+818         case BOTH:
+819           switch (type)
+820           {
+821             case CREATE:
+822             case DROP:
+823             case BOTH:
+824               Class driverClass = classLoader.loadClass(properties.getProperty(DRIVER_CLASS));
+825               getLog().debug("Registering JDBC-driver " + driverClass.getName());
+826               DriverManager.registerDriver(new DriverProxy((Driver)driverClass.newInstance()));
+827               getLog().debug(
+828                   "Opening JDBC-connection to "
+829                   + properties.getProperty(URL)
+830                   + " as "
+831                   + properties.getProperty(USERNAME)
+832                   + " with password "
+833                   + properties.getProperty(PASSWORD)
+834                   );
+835               connection = DriverManager.getConnection(
+836                   properties.getProperty(URL),
+837                   properties.getProperty(USERNAME),
+838                   properties.getProperty(PASSWORD)
+839                   );
+840           }
+841       }
+842     }
+843     catch (ClassNotFoundException e)
+844     {
+845       getLog().error("Dependency for driver-class " + properties.getProperty(DRIVER_CLASS) + " is missing!");
+846       throw new MojoExecutionException(e.getMessage());
+847     }
+848     catch (Exception e)
+849     {
+850       getLog().error("Cannot establish connection to database!");
+851       Enumeration<Driver> drivers = DriverManager.getDrivers();
+852       if (!drivers.hasMoreElements())
+853         getLog().error("No drivers registered!");
+854       while (drivers.hasMoreElements())
+855         getLog().debug("Driver: " + drivers.nextElement());
+856       throw new MojoExecutionException(e.getMessage());
+857     }
+858 
+859     ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+860     MavenLogAppender.startPluginLog(this);
+861     try
+862     {
+863       /**
+864        * Change class-loader of current thread, so that hibernate can
+865        * see all dependencies!
+866        */
+867       Thread.currentThread().setContextClassLoader(classLoader);
+868 
+869       config.buildMappings();
+870 
+871       if (envers)
+872       {
+873         getLog().info("Automatic auditing via hibernate-envers enabled!");
+874         AuditConfiguration.getFor(config);
+875       }
+876 
+877       SchemaExport export = new SchemaExport(config, connection);
+878       export.setOutputFile(outputFile);
+879       export.setDelimiter(delimiter);
+880       export.setFormat(format);
+881       export.execute(target, type);
+882 
+883       for (Object exception : export.getExceptions())
+884         getLog().debug(exception.toString());
+885     }
+886     finally
+887     {
+888       /** Stop Log-Capturing */
+889       MavenLogAppender.endPluginLog(this);
+890 
+891       /** Restore the old class-loader (TODO: is this really necessary?) */
+892       Thread.currentThread().setContextClassLoader(contextClassLoader);
+893 
+894       /** Close the connection */
+895       try
+896       {
+897         if (connection != null)
+898           connection.close();
+899       }
+900       catch (SQLException e)
+901       {
+902         getLog().error("Error while closing connection: " + e.getMessage());
+903       }
+904     }
+905 
+906     /** Write md5-sums for annotated classes to file */
+907     try
+908     {
+909       FileOutputStream fos = new FileOutputStream(saved);
+910       ObjectOutputStream oos = new ObjectOutputStream(fos);
+911       oos.writeObject(md5s);
+912       oos.close();
+913       fos.close();
+914     }
+915     catch (Exception e)
+916     {
+917       getLog().error("Cannot write md5-sums to file: " + e);
+918     }
+919   }
+920 
+921   /**
+922    * Needed, because DriverManager won't pick up drivers, that were not
+923    * loaded by the system-classloader!
+924    * See:
+925    * http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-fromodifiedm-an-arbitrary-location
+926    */
+927   static final class DriverProxy implements Driver
+928   {
+929     private final Driver target;
+930 
+931     DriverProxy(Driver target)
+932     {
+933       if (target == null)
+934         throw new NullPointerException();
+935       this.target = target;
+936     }
+937 
+938     public java.sql.Driver getTarget()
+939     {
+940       return target;
+941     }
+942 
+943     @Override
+944     public boolean acceptsURL(String url) throws SQLException
+945     {
+946       return target.acceptsURL(url);
+947     }
+948 
+949     @Override
+950     public java.sql.Connection connect(
+951         String url,
+952         java.util.Properties info
+953       )
+954       throws
+955         SQLException
+956     {
+957       return target.connect(url, info);
+958     }
+959 
+960     @Override
+961     public int getMajorVersion()
+962     {
+963       return target.getMajorVersion();
+964     }
+965 
+966     @Override
+967     public int getMinorVersion()
+968     {
+969       return target.getMinorVersion();
+970     }
+971 
+972     @Override
+973     public DriverPropertyInfo[] getPropertyInfo(
+974         String url,
+975         Properties info
+976       )
+977       throws
+978         SQLException
+979     {
+980       return target.getPropertyInfo(url, info);
+981     }
+982 
+983     @Override
+984     public boolean jdbcCompliant()
+985     {
+986       return target.jdbcCompliant();
+987     }
+988 
+989     /**
+990      * This Method cannot be annotated with @Override, becaus the plugin
+991      * will not compile then under Java 1.6!
+992      */
+993     public Logger getParentLogger() throws SQLFeatureNotSupportedException
+994     {
+995       throw new SQLFeatureNotSupportedException("Not supported, for backward-compatibility with Java 1.6");
+996     }
+997 
+998     @Override
+999     public String toString()
+1000     {
+1001       return "Proxy: " + target;
+1002     }
+1003 
+1004     @Override
+1005     public int hashCode()
+1006     {
+1007       return target.hashCode();
+1008     }
+1009 
+1010     @Override
+1011     public boolean equals(Object obj)
+1012     {
+1013       if (!(obj instanceof DriverProxy))
+1014         return false;
+1015       DriverProxy other = (DriverProxy) obj;
+1016       return this.target.equals(other.target);
+1017     }
+1018   }
+1019 }
+
+
+ +