View Javadoc

1   package org.modeshape.util;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.util.Properties;
6   import org.hibernate.cfg.Environment;
7   import org.hibernate.dialect.Dialect;
8   import org.hibernate.ejb.Ejb3Configuration;
9   import org.hibernate.tool.hbm2ddl.SchemaExport;
10  import org.modeshape.connector.store.jpa.JpaSource;
11  import org.modeshape.connector.store.jpa.Model;
12  import org.modeshape.connector.store.jpa.util.StoreOptionEntity;
13  
14  /**
15   * Main class to generate DDL that can be used to build the schema for the {@link JpaSource JPA connector}. The class is intended
16   * to be bundled into an executable jar file and invoked with the following syntax:
17   * 
18   * <pre>
19   * java -jar &lt;jar_name&gt; -dialect &lt;dialect name&gt; -model &lt;model_name&gt; [-out &lt;path to output directory&gt;]
20   *     Example: java -jar dna-jpa-ddl-gen-0.7-jar-with-dependencies.jar -dialect HSQL -model Basic -out /tmp
21   * </pre>
22   */
23  public class SchemaGen {
24  
25      public static final String CREATE_FILE_NAME = "create.dna-jpa-connector.ddl";
26      public static final String DROP_FILE_NAME = "drop.dna-jpa-connector.ddl";
27  
28      private final Dialect dialect;
29      private final Model model;
30      private final File outputPath;
31  
32      public SchemaGen( String dialect,
33                        String model,
34                        File outputPath ) {
35  
36          this.dialect = dialectFor(dialect);
37          this.model = JpaSource.Models.getModel(model);
38          this.outputPath = outputPath;
39      }
40  
41      /**
42       * Returns the {@link Dialect Hibernate dialect} that corresponds to the provided name.
43       * <p>
44       * This method will tolerate certain kinds of abbreviations for the dialect. Since all Hibernate dialects have a name equal to
45       * their fully-qualified name, all valid dialect names start with &quot;org.hibernate.dialect.&quot;. If the given {@code
46       * dialectName} does not begin with this string, this string will be prepended.
47       * </p>
48       * <p>
49       * Additionally, all Hibernate dialect names end in &quot;Dialect&quot;. If the given dialect name does not end with
50       * &quot;Dialect&quot;, this will be appended to the dialect name before the Hibernate dialect is looked up.
51       * </p>
52       * <p>
53       * The net effect of these rules is that callers wishing to retrieve a dialect (e.g., org.hibernate.dialect.HSQLDialect) can
54       * specify the dialect as "org.hibernate.dialect.HSQLDialect", "HSQLDialect", "org.hibernate.dialect.HSQL", or just "HSQL".
55       * </p>
56       * 
57       * @param dialectName the name of the {@code Dialect} to return
58       * @return the {@link Dialect Hibernate dialect} that corresponds to the provided name.
59       */
60      private Dialect dialectFor( String dialectName ) {
61          Properties props = new Properties();
62  
63          if (!dialectName.endsWith("Dialect")) dialectName += "Dialect";
64          if (!dialectName.startsWith("org.hibernate.dialect.")) dialectName = "org.hibernate.dialect." + dialectName;
65  
66          props.put(Environment.DIALECT, dialectName);
67  
68          return Dialect.getDialect(props);
69      }
70  
71      /**
72       * Writes {@link SchemaExport#create(boolean, boolean) create} and {@link SchemaExport#drop(boolean, boolean) drop} DDL files
73       * to the given {@link #outputPath output directory} or the current directory if no output directory was provided.
74       * 
75       * @throws IOException
76       */
77      void generate() throws IOException {
78          Ejb3Configuration configurator = new Ejb3Configuration();
79          configurator.setProperty(Environment.DIALECT, dialect.toString());
80          model.configure(configurator);
81          configurator.addAnnotatedClass(StoreOptionEntity.class);
82  
83          // cfg.setProperties(properties);
84          SchemaExport export = new SchemaExport(configurator.getHibernateConfiguration());
85          export.setOutputFile(new File(outputPath, CREATE_FILE_NAME).getCanonicalPath());
86          export.create(false, false);
87  
88          export.setOutputFile(new File(outputPath, DROP_FILE_NAME).getCanonicalPath());
89          export.drop(false, false);
90      }
91  
92      public static final String USAGE = "java -jar <jar_name> -dialect <dialect name> -model <model_name> [-out <path to output directory>]\n"
93                                         + "\tExample: java -jar modeshape-jpa-ddl-gen-1.2-jar-with-dependencies.jar -dialect HSQL -model Basic -out /tmp";
94  
95      public static void main( String[] args ) throws IOException {
96          String modelName = null;
97          String dialectName = null;
98          File outputFile = new File(".");
99  
100         int i = 0;
101         while (i < args.length) {
102             if ("-dialect".equals(args[i])) {
103                 if (i == args.length - 1) printUsage();
104                 dialectName = args[++i];
105             } else if ("-model".equals(args[i])) {
106                 if (i == args.length - 1) printUsage();
107                 modelName = args[++i];
108             } else if ("-out".equals(args[i])) {
109                 if (i == args.length - 1) printUsage();
110                 outputFile = new File(args[++i]);
111             } else if ("-help".equals(args[i]) || "-?".equals(args[i])) {
112                 printUsage();
113             }
114             i++;
115         }
116 
117         if (modelName == null || dialectName == null) printUsage();
118 
119         SchemaGen main = new SchemaGen(dialectName, modelName, outputFile);
120         main.generate();
121     }
122 
123     /**
124      * Print the usage message and exit with a non-zero return code.
125      */
126     private static void printUsage() {
127         System.err.println(USAGE);
128         System.exit(1);
129     }
130 
131 }