1 package de.juplo.plugins.hibernate4;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import com.pyx4j.log4j.MavenLogAppender;
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.net.URL;
24 import java.net.URLClassLoader;
25 import java.sql.Connection;
26 import java.sql.Driver;
27 import java.sql.DriverManager;
28 import java.sql.DriverPropertyInfo;
29 import java.sql.SQLException;
30 import java.sql.SQLFeatureNotSupportedException;
31 import java.util.Enumeration;
32 import java.util.HashSet;
33 import java.util.List;
34 import java.util.Map.Entry;
35 import java.util.Properties;
36 import java.util.Set;
37 import java.util.logging.Logger;
38 import javax.persistence.Embeddable;
39 import javax.persistence.Entity;
40 import javax.persistence.MappedSuperclass;
41 import org.apache.maven.plugin.AbstractMojo;
42 import org.apache.maven.plugin.MojoExecutionException;
43 import org.apache.maven.plugin.MojoFailureException;
44 import org.apache.maven.project.MavenProject;
45 import org.hibernate.cfg.Configuration;
46 import org.hibernate.tool.hbm2ddl.SchemaExport;
47 import org.hibernate.tool.hbm2ddl.SchemaExport.Type;
48 import org.hibernate.tool.hbm2ddl.Target;
49 import org.scannotation.AnnotationDB;
50
51
52
53
54
55
56
57
58
59
60
61 public class Hbm2DdlMojo extends AbstractMojo
62 {
63 public final static String DRIVER_CLASS = "hibernate.connection.driver_class";
64 public final static String URL = "hibernate.connection.url";
65 public final static String USERNAME = "hibernate.connection.username";
66 public final static String PASSWORD = "hibernate.connection.password";
67 public final static String DIALECT = "hibernate.dialect";
68
69
70
71
72
73
74
75
76
77 private MavenProject project;
78
79
80
81
82
83
84 private String outputDirectory;
85
86
87
88
89
90
91 private boolean skip;
92
93
94
95
96
97
98 private String driverClassName;
99
100
101
102
103
104
105 private String url;
106
107
108
109
110
111
112 private String username;
113
114
115
116
117
118
119 private String password;
120
121
122
123
124
125
126 private String hibernateDialect;
127
128
129
130
131
132
133 private String hibernateProperties;
134
135
136
137
138
139
140
141
142
143
144
145 private String target;
146
147
148
149
150
151
152
153
154
155
156
157 private String type;
158
159
160
161
162
163
164 private String outputFile;
165
166
167
168
169
170
171 private String delimiter;
172
173
174
175
176
177
178 private boolean format;
179
180
181 @Override
182 public void execute()
183 throws
184 MojoFailureException,
185 MojoExecutionException
186 {
187 if (skip)
188 {
189 getLog().info("Exectuion of hibernate4-maven-plugin:export was skipped!");
190 return;
191 }
192
193 File dir = new File(outputDirectory);
194 if (!dir.exists())
195 throw new MojoExecutionException("Cannot scan for annotated classes in " + outputDirectory + ": directory does not exist!");
196
197
198 Set<String> classes = new HashSet<String>();
199 try
200 {
201 AnnotationDB db = new AnnotationDB();
202 getLog().info("Scanning directory " + outputDirectory + " for annotated classes...");
203 URL dirUrl = dir.toURI().toURL();
204 db.scanArchives(dirUrl);
205 if (db.getAnnotationIndex().containsKey(Entity.class.getName()))
206 classes.addAll(db.getAnnotationIndex().get(Entity.class.getName()));
207 if (db.getAnnotationIndex().containsKey(MappedSuperclass.class.getName()))
208 classes.addAll(db.getAnnotationIndex().get(MappedSuperclass.class.getName()));
209 if (db.getAnnotationIndex().containsKey(Embeddable.class.getName()))
210 classes.addAll(db.getAnnotationIndex().get(Embeddable.class.getName()));
211 }
212 catch (IOException e)
213 {
214 getLog().error("Error while scanning!", e);
215 throw new MojoFailureException(e.getMessage());
216 }
217 if (classes.isEmpty())
218 throw new MojoFailureException("No annotated classes found in directory " + outputDirectory);
219
220 Properties properties = new Properties();
221
222
223 try
224 {
225 File file = new File(hibernateProperties);
226 if (file.exists())
227 {
228 getLog().info("Reading properties from file " + hibernateProperties + "...");
229 properties.load(new FileInputStream(file));
230 }
231 else
232 getLog().info("No hibernate-properties-file found! Checked path: " + hibernateProperties);
233 }
234 catch (IOException e)
235 {
236 getLog().error("Error while reading properties!", e);
237 throw new MojoExecutionException(e.getMessage());
238 }
239
240
241 if (driverClassName != null)
242 {
243 if (properties.containsKey(DRIVER_CLASS))
244 getLog().debug(
245 "Overwriting property " +
246 DRIVER_CLASS + "=" + properties.getProperty(DRIVER_CLASS) +
247 " with the value " + driverClassName +
248 " from the plugin-configuration-parameter driverClassName!"
249 );
250 else
251 getLog().debug(
252 "Using the value " + driverClassName +
253 " from the plugin-configuration-parameter driverClassName!"
254 );
255 properties.setProperty(DRIVER_CLASS, driverClassName);
256 }
257 if (url != null)
258 {
259 if (properties.containsKey(URL))
260 getLog().debug(
261 "Overwriting property " +
262 URL + "=" + properties.getProperty(URL) +
263 " with the value " + url +
264 " from the plugin-configuration-parameter url!"
265 );
266 else
267 getLog().debug(
268 "Using the value " + url +
269 " from the plugin-configuration-parameter url!"
270 );
271 properties.setProperty(URL, url);
272 }
273 if (username != null)
274 {
275 if (properties.containsKey(USERNAME))
276 getLog().debug(
277 "Overwriting property " +
278 USERNAME + "=" + properties.getProperty(USERNAME) +
279 " with the value " + username +
280 " from the plugin-configuration-parameter username!"
281 );
282 else
283 getLog().debug(
284 "Using the value " + username +
285 " from the plugin-configuration-parameter username!"
286 );
287 properties.setProperty(USERNAME, username);
288 }
289 if (password != null)
290 {
291 if (properties.containsKey(PASSWORD))
292 getLog().debug(
293 "Overwriting property " +
294 PASSWORD + "=" + properties.getProperty(PASSWORD) +
295 " with the value " + password +
296 " from the plugin-configuration-parameter password!"
297 );
298 else
299 getLog().debug(
300 "Using the value " + password +
301 " from the plugin-configuration-parameter password!"
302 );
303 properties.setProperty(PASSWORD, password);
304 }
305 if (hibernateDialect != null)
306 {
307 if (properties.containsKey(DIALECT))
308 getLog().debug(
309 "Overwriting property " +
310 DIALECT + "=" + properties.getProperty(DIALECT) +
311 " with the value " + hibernateDialect +
312 " from the plugin-configuration-parameter hibernateDialect!"
313 );
314 else
315 getLog().debug(
316 "Using the value " + hibernateDialect +
317 " from the plugin-configuration-parameter hibernateDialect!"
318 );
319 properties.setProperty(DIALECT, hibernateDialect);
320 }
321
322 getLog().info("Gathered hibernate-configuration (turn on debugging for details):");
323 if (properties.isEmpty())
324 {
325 getLog().error("No properties set!");
326 throw new MojoFailureException("Hibernate-Configuration is missing!");
327 }
328 for (Entry<Object,Object> entry : properties.entrySet())
329 getLog().info(" " + entry.getKey() + " = " + entry.getValue());
330
331 ClassLoader classLoader = null;
332 try
333 {
334 getLog().debug("Creating ClassLoader for project-dependencies...");
335 List<String> classpathFiles = project.getCompileClasspathElements();
336 URL[] urls = new URL[classpathFiles.size()];
337 for (int i = 0; i < classpathFiles.size(); ++i)
338 {
339 getLog().debug("Dependency: " + classpathFiles.get(i));
340 urls[i] = new File(classpathFiles.get(i)).toURI().toURL();
341 }
342 classLoader = new URLClassLoader(urls, getClass().getClassLoader());
343 }
344 catch (Exception e)
345 {
346 getLog().error("Error while creating ClassLoader!", e);
347 throw new MojoExecutionException(e.getMessage());
348 }
349
350 Configuration config = new Configuration();
351 config.setProperties(properties);
352 try
353 {
354 getLog().debug("Adding annotated classes to hibernate-mapping-configuration...");
355 for (String annotatedClass : classes)
356 {
357 getLog().debug("Class " + annotatedClass);
358 config.addAnnotatedClass(classLoader.loadClass(annotatedClass));
359 }
360 }
361 catch (ClassNotFoundException e)
362 {
363 getLog().error("Error while adding annotated classes!", e);
364 throw new MojoExecutionException(e.getMessage());
365 }
366
367 Target target = null;
368 try
369 {
370 target = Target.valueOf(this.target);
371 }
372 catch (IllegalArgumentException e)
373 {
374 getLog().error("Invalid value for configuration-option \"target\": " + this.target);
375 getLog().error("Valid values are: NONE, SCRIPT, EXPORT, BOTH");
376 throw new MojoExecutionException("Invalid value for configuration-option \"target\"");
377 }
378 Type type = null;
379 try
380 {
381 type = Type.valueOf(this.type);
382 }
383 catch (IllegalArgumentException e)
384 {
385 getLog().error("Invalid value for configuration-option \"type\": " + this.type);
386 getLog().error("Valid values are: NONE, CREATE, DROP, BOTH");
387 throw new MojoExecutionException("Invalid value for configuration-option \"type\"");
388 }
389
390 Connection connection = null;
391 try
392 {
393
394
395
396
397
398 switch (target)
399 {
400 case EXPORT:
401 case BOTH:
402 switch (type)
403 {
404 case CREATE:
405 case DROP:
406 case BOTH:
407 Class driverClass = classLoader.loadClass(driverClassName);
408 getLog().debug("Registering JDBC-driver " + driverClass.getName());
409 DriverManager.registerDriver(new DriverProxy((Driver)driverClass.newInstance()));
410 getLog().debug("Opening JDBC-connection to " + url + " as " + username + " with password " + password);
411 connection = DriverManager.getConnection(url, username, password);
412 }
413 }
414 }
415 catch (ClassNotFoundException e)
416 {
417 getLog().error("Dependency for driver-class " + driverClassName + " is missing!");
418 throw new MojoExecutionException(e.getMessage());
419 }
420 catch (Exception e)
421 {
422 getLog().error("Cannot establish connection to database!");
423 Enumeration<Driver> drivers = DriverManager.getDrivers();
424 if (!drivers.hasMoreElements())
425 getLog().error("No drivers registered!");
426 while (drivers.hasMoreElements())
427 getLog().debug("Driver: " + drivers.nextElement());
428 throw new MojoExecutionException(e.getMessage());
429 }
430
431 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
432 MavenLogAppender.startPluginLog(this);
433 try
434 {
435
436
437
438
439 Thread.currentThread().setContextClassLoader(classLoader);
440
441 SchemaExport export = new SchemaExport(config, connection);
442 export.setOutputFile(outputFile);
443 export.setDelimiter(delimiter);
444 export.setFormat(format);
445 export.execute(target, type);
446
447 for (Object exception : export.getExceptions())
448 getLog().debug(exception.toString());
449 }
450 finally
451 {
452
453 MavenLogAppender.endPluginLog(this);
454
455
456 Thread.currentThread().setContextClassLoader(contextClassLoader);
457
458
459 try
460 {
461 connection.close();
462 }
463 catch (SQLException e)
464 {
465 getLog().error("Error while closing connection: " + e.getMessage());
466 }
467 }
468 }
469
470
471
472
473
474
475
476 static final class DriverProxy implements Driver
477 {
478 private final Driver target;
479
480 DriverProxy(Driver target)
481 {
482 if (target == null)
483 throw new NullPointerException();
484 this.target = target;
485 }
486
487 public java.sql.Driver getTarget()
488 {
489 return target;
490 }
491
492 @Override
493 public boolean acceptsURL(String url) throws SQLException
494 {
495 return target.acceptsURL(url);
496 }
497
498 @Override
499 public java.sql.Connection connect(
500 String url,
501 java.util.Properties info
502 )
503 throws
504 SQLException
505 {
506 return target.connect(url, info);
507 }
508
509 @Override
510 public int getMajorVersion()
511 {
512 return target.getMajorVersion();
513 }
514
515 @Override
516 public int getMinorVersion()
517 {
518 return target.getMinorVersion();
519 }
520
521 @Override
522 public DriverPropertyInfo[] getPropertyInfo(
523 String url,
524 Properties info
525 )
526 throws
527 SQLException
528 {
529 return target.getPropertyInfo(url, info);
530 }
531
532 @Override
533 public boolean jdbcCompliant()
534 {
535 return target.jdbcCompliant();
536 }
537
538
539
540
541
542 public Logger getParentLogger() throws SQLFeatureNotSupportedException
543 {
544 throw new SQLFeatureNotSupportedException("Not supported, for backward-compatibility with Java 1.6");
545 }
546
547 @Override
548 public String toString()
549 {
550 return "Proxy: " + target;
551 }
552
553 @Override
554 public int hashCode()
555 {
556 return target.hashCode();
557 }
558
559 @Override
560 public boolean equals(Object obj)
561 {
562 if (!(obj instanceof DriverProxy))
563 return false;
564 DriverProxy other = (DriverProxy) obj;
565 return this.target.equals(other.target);
566 }
567 }
568 }