1 package org.appfuse.mojo.exporter;
2
3 /*
4 * Copyright 2005 Johann Reyes.
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 org.apache.maven.plugin.MojoExecutionException;
20 import org.apache.maven.plugin.MojoFailureException;
21 import org.apache.commons.io.FileUtils;
22 import org.appfuse.mojo.HibernateExporterMojo;
23 import org.hibernate.tool.hbm2x.Exporter;
24 import org.hibernate.tool.hbm2x.POJOExporter;
25
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.InputStreamReader;
30 import java.io.BufferedReader;
31 import java.util.Iterator;
32
33 /**
34 * Generates Java classes from existing database tables. If you want to customize the
35 * reverse engineering strategy, you can modify the default <a href="http://tinyurl.com/3qqgcl">hibernate.reveng.xml</a>
36 * and put it in src/test/resources. You can also override the location by specifying the "revengfile"
37 * property in the <configuration>. For example:
38 *
39 * <pre>
40 <configuration>
41 <componentProperties>
42 <revengfile>path/to/hibernate.reveng.xml</revengfile>
43 </componentProperties>
44 <genericCore>${amp.genericCore}</genericCore>
45 <fullSource>${amp.fullSource}</fullSource>
46 </configuration>
47 * </pre>
48 *
49 * <p><b>Oracle Users</b>: If you create a custom hibernate.reveng.xml, make sure to capitalize the table names
50 * in <schema-selection match-schema="MY_SCHEMA_NAME"/>. You'll also need to add the following line to your
51 * jdbc.properties file:</p>
52 * <pre>
53 hibernatetool.metadatadialect=org.hibernate.cfg.reveng.dialect.OracleMetaDataDialect
54 </pre>
55 *
56 * @author <a href="mailto:jreyes@hiberforum.org">Johann Reyes</a>
57 * @version $Id: ModelGeneratorMojo.java 3535 2007-03-07 21:02:07Z jreyes $
58 * @goal gen-model
59 * @phase generate-sources
60 * @execute phase="process-resources"
61 */
62 public class ModelGeneratorMojo extends HibernateExporterMojo {
63 /**
64 * The path where the generated artifacts will be placed. This is intentionally not set to the
65 * default location for maven generated sources. This is to keep these files out of the
66 * eclipse/idea generated sources directory as the intention is that these files will be copied
67 * to a source directory to be edited and modified and not re generated each time the plugin is
68 * run. If you want to regenerate the files each time you build the project just set this value
69 * to ${basedir}/target/generated-sources or set the flag on eclipse/idea plugin to include this
70 * file in your project file as a source directory.
71 *
72 * @parameter expression="${appfuse.destinationDirectory}" default-value="${basedir}"
73 * @noinspection UnusedDeclaration
74 */
75 private String destinationDirectory;
76
77 /**
78 * The directory containing the source code.
79 *
80 * @parameter expression="${appfuse.sourceDirectory}" default-value="${basedir}/target/appfuse/generated-sources"
81 * @noinspection UnusedDeclaration
82 */
83 private String sourceDirectory;
84
85 /**
86 * Allows disabling installation - for tests and end users that don't want to do a full installation
87 *
88 * @parameter expression="${appfuse.disableInstallation}" default-value="false"
89 */
90 private boolean disableInstallation;
91
92 /**
93 * @parameter expression="${appfuse.templateDirectory}" default-value="${basedir}/src/test/resources"
94 * @noinspection UnusedDeclaration
95 */
96 private String templateDirectory;
97
98 /**
99 * Default constructor.
100 */
101 public ModelGeneratorMojo() {
102 addDefaultComponent("target/appfuse/generated-sources", "configuration", false);
103 addDefaultComponent("target/appfuse/generated-sources", "jdbcconfiguration", true);
104 addDefaultComponent("target/appfuse/generated-sources", "annotationconfiguration", true);
105 }
106
107 // --------------------- Interface ExporterMojo ---------------------
108
109 /**
110 * Returns <b>gen-model</b>.
111 *
112 * @return String goal's name
113 */
114 public String getName() {
115 return "gen-model";
116 }
117
118 @Override
119 public void execute() throws MojoExecutionException, MojoFailureException {
120 getComponentProperties().put("implementation", "jdbcconfiguration");
121 getComponentProperties().put("outputDirectory",
122 (sourceDirectory != null) ? sourceDirectory : "${basedir}/target/appfuse/generated-sources");
123
124 // default location for reveng file is src/test/resources
125 File revengFile = new File("src/test/resources/hibernate.reveng.xml");
126 if (revengFile.exists() && getComponentProperty("revengfile") == null) {
127 getComponentProperties().put("revengfile", "src/test/resources/hibernate.reveng.xml");
128 }
129
130 // Check for existence of hibernate.reveng.xml and if there isn't one, create it
131 // Specifying the file explicitly in pom.xml overrides default location
132 if (getComponentProperty("revengfile") == null) {
133 getComponentProperties().put("revengfile", "target/test-classes/hibernate.reveng.xml");
134 }
135
136 File existingConfig = new File(getComponentProperty("revengfile"));
137 if (!existingConfig.exists()) {
138 InputStream in = this.getClass().getResourceAsStream("/appfuse/model/hibernate.reveng.ftl");
139 StringBuffer configFile = new StringBuffer();
140 try {
141 InputStreamReader isr = new InputStreamReader(in);
142 BufferedReader reader = new BufferedReader(isr);
143 String line;
144 while ((line = reader.readLine()) != null) {
145 configFile.append(line).append("\n");
146 }
147 reader.close();
148
149 getLog().info("Writing 'hibernate.reveng.xml' to " + existingConfig.getPath());
150 FileUtils.writeStringToFile(existingConfig, configFile.toString());
151 } catch (IOException io) {
152 throw new MojoFailureException(io.getMessage());
153 }
154 }
155
156 // if package name is not configured, default to project's groupId
157 if (getComponentProperty("packagename") == null) {
158 getComponentProperties().put("packagename", getProject().getGroupId() + ".model");
159 }
160
161 if (getComponentProperty("configurationfile") == null) {
162 // look for jdbc.properties and set "propertyfile" to its path
163 File jdbcProperties = new File("target/classes/jdbc.properties");
164 if (!jdbcProperties.exists()) {
165 jdbcProperties = new File("target/test-classes/jdbc.properties");
166 }
167 if (jdbcProperties.exists()) {
168 if (getComponentProperty("propertyfile") == null) {
169 getComponentProperties().put("propertyfile", jdbcProperties.getPath());
170 getLog().debug("Set propertyfile to '" + jdbcProperties.getPath() + "'");
171 }
172 } else {
173 throw new MojoFailureException("Failed to find jdbc.properties in classpath.");
174 }
175 }
176
177 // For some reason, the classloader created in HibernateExporterMojo does not work
178 // when using jdbcconfiguration - it can't find the JDBC Driver (no suitable driver).
179 // Skipping the resetting of the classloader and manually adding the dependency (with XML) works.
180 // It's ugly, but it works. I wish there was a way to get get this plugin to recognize the jdbc driver
181 // from the project.
182
183 super.doExecute();
184
185 if (System.getProperty("disableInstallation") != null) {
186 disableInstallation = Boolean.valueOf(System.getProperty("disableInstallation"));
187 }
188
189 // allow installation to be supressed when testing
190 if (!disableInstallation) {
191 // copy the generated file to the model directory of the project
192 try {
193 String packageName = getComponentProperties().get("packagename");
194 String packageAsDir = packageName.replaceAll("\\.", "/");
195 File dir = new File(sourceDirectory + "/" + packageAsDir);
196 if (dir.exists()) {
197 Iterator filesIterator = FileUtils.iterateFiles(dir, new String[] {"java"}, false);
198 while (filesIterator.hasNext()) {
199 File f = (File) filesIterator.next();
200 getLog().info("Copying generated '" + f.getName() + "' to project...");
201 FileUtils.copyFileToDirectory(f, new File(destinationDirectory + "/src/main/java/" + packageAsDir));
202 }
203 } else {
204 throw new MojoFailureException("No tables found in database to generate code from.");
205 }
206 FileUtils.forceDelete(dir);
207 } catch (IOException io) {
208 throw new MojoFailureException(io.getMessage());
209 }
210 }
211 }
212
213 /**
214 * @see HibernateExporterMojo#configureExporter(org.hibernate.tool.hbm2x.Exporter)
215 */
216 protected Exporter configureExporter(Exporter exp) throws MojoExecutionException {
217 // add output directory to compile roots
218 getProject().addCompileSourceRoot(new File(getComponent().getOutputDirectory()).getPath());
219
220 // now set the extra properties for the POJO Exporter
221 POJOExporter exporter = (POJOExporter) super.configureExporter(exp);
222
223 // Add custom template path if specified
224 String[] templatePaths;
225 if (templateDirectory != null) {
226 templatePaths = new String[exporter.getTemplatePaths().length + 1];
227 templatePaths[0] = templateDirectory;
228 if (exporter.getTemplatePaths().length > 1) {
229 for (int i = 1; i < exporter.getTemplatePaths().length; i++) {
230 templatePaths[i] = exporter.getTemplatePaths()[i-1];
231 }
232 }
233 } else {
234 templatePaths = exporter.getTemplatePaths();
235 }
236
237 exporter.setTemplatePath(templatePaths);
238 exporter.setTemplateName("appfuse/model/Pojo.ftl");
239 exporter.getProperties().setProperty("basepackage", getProject().getGroupId());
240 exporter.getProperties().setProperty("ejb3", getComponentProperty("ejb3", "true"));
241 exporter.getProperties().setProperty("jdk5", getComponentProperty("jdk5", "true"));
242
243 if (isFullSource()) {
244 exporter.getProperties().setProperty("appfusepackage", getProject().getGroupId());
245 } else {
246 exporter.getProperties().setProperty("appfusepackage", "org.appfuse");
247 }
248
249
250 return exporter;
251 }
252
253 /**
254 * Instantiates a org.hibernate.tool.hbm2x.POJOExporter object.
255 *
256 * @return POJOExporter
257 */
258 protected Exporter createExporter() {
259 return new POJOExporter();
260 }
261 }