1 package org.andromda.maven.plugin.andromdapp;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.InputStream;
6 import java.io.InputStreamReader;
7 import java.lang.reflect.Field;
8 import java.net.MalformedURLException;
9 import java.net.URL;
10 import java.net.URLClassLoader;
11 import java.sql.Connection;
12 import java.sql.Driver;
13 import java.sql.DriverManager;
14 import java.sql.SQLException;
15 import java.sql.Statement;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.HashMap;
19 import java.util.LinkedHashMap;
20 import java.util.LinkedHashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Properties;
24 import java.util.Set;
25 import org.andromda.core.common.AndroMDALogger;
26 import org.andromda.core.common.ClassUtils;
27 import org.andromda.core.common.ResourceUtils;
28 import org.andromda.maven.plugin.andromdapp.hibernate.HibernateCreateSchema;
29 import org.andromda.maven.plugin.andromdapp.hibernate.HibernateDropSchema;
30 import org.andromda.maven.plugin.andromdapp.hibernate.HibernateUpdateSchema;
31 import org.andromda.maven.plugin.andromdapp.hibernate.HibernateValidateSchema;
32 import org.apache.commons.lang.ObjectUtils;
33 import org.apache.commons.lang.StringUtils;
34 import org.apache.maven.artifact.Artifact;
35 import org.apache.maven.artifact.factory.ArtifactFactory;
36 import org.apache.maven.artifact.repository.ArtifactRepository;
37 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
38 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
39 import org.apache.maven.artifact.resolver.ArtifactResolver;
40 import org.apache.maven.model.Dependency;
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
46
47
48
49
50
51
52
53 public class SchemaMojo
54 extends AbstractMojo
55 {
56
57
58
59
60
61 private String tasks;
62
63
64
65
66
67
68
69 private String taskType;
70
71
72
73
74
75
76 private MavenProject project;
77
78
79
80
81
82
83 private String[] propertyFiles;
84
85
86
87
88
89
90 private Properties properties = new Properties();
91
92
93
94
95
96
97 private ArtifactFactory factory;
98
99
100
101
102
103
104
105 private boolean executeScripts = true;
106
107
108
109
110
111 private List<Artifact> pluginArtifacts;
112
113
114
115
116
117
118
119
120
121 private ArtifactResolver artifactResolver;
122
123
124
125
126
127
128 private ArtifactRepository localRepository;
129
130
131
132
133
134
135
136 private String jdbcDriver;
137
138
139
140
141
142
143
144 private String jdbcConnectionUrl;
145
146
147
148
149
150
151
152 private String jdbcUsername;
153
154
155
156
157
158
159 private String jdbcPassword = "";
160
161
162
163
164
165
166
167 private String jdbcDriverJar;
168
169
170
171
172
173
174 private List<String> scripts;
175
176
177
178
179 public void execute()
180 throws MojoExecutionException, MojoFailureException
181 {
182 Connection connection = null;
183 try
184 {
185 AndroMDALogger.initialize();
186 this.initializeClassLoaderWithJdbcDriver();
187
188 final List<String> tasks = this.getTasks();
189 if (tasks != null && !tasks.isEmpty())
190 {
191 final Map<String, Class> tasksMap = SchemaMojo.tasksCache.get(this.taskType);
192 if (tasksMap == null)
193 {
194 throw new MojoExecutionException('\'' + taskType +
195 "' is not a valid task type, valid task types are: " + tasksMap.keySet());
196 }
197
198 this.properties.putAll(this.project.getProperties());
199 for (String task : this.getTasks())
200 {
201 task = ObjectUtils.toString(task.trim());
202 if (this.propertyFiles != null)
203 {
204 final int numberOfPropertyFiles = propertyFiles.length;
205 for (int ctr2 = 0; ctr2 < numberOfPropertyFiles; ctr2++)
206 {
207 final URL propertyFileUri = ResourceUtils.toURL(propertyFiles[ctr2]);
208 if (propertyFileUri != null)
209 {
210 final InputStream stream = propertyFileUri.openStream();
211 this.properties.load(stream);
212 stream.close();
213 }
214 }
215 }
216
217
218 final Field[] fields = this.getClass().getDeclaredFields();
219 if (fields != null)
220 {
221 final int numberOfFields = fields.length;
222 for (int ctr = 0; ctr < numberOfFields; ctr++)
223 {
224 final Field field = fields[ctr];
225 final Object value = field.get(this);
226 if (value != null)
227 {
228 this.properties.put(
229 field.getName(),
230 value);
231 }
232 }
233 }
234
235 final Set<String> classpathElements = new LinkedHashSet<String>(this.project.getRuntimeClasspathElements());
236 classpathElements.addAll(this.getProvidedClasspathElements());
237 this.initializeClasspathFromClassPathElements(classpathElements);
238 final Class type = tasksMap.get(task);
239 if (type == null)
240 {
241 throw new MojoExecutionException('\'' + task + "' is not a valid task, valid types are: " +
242 tasksMap.keySet());
243 }
244
245 final SchemaManagement schemaManagement = (SchemaManagement)ClassUtils.newInstance(type);
246 connection = executeScripts ? this.getConnection() : null;
247 this.executeSql(
248 connection,
249 schemaManagement.execute(
250 connection,
251 this.properties));
252 }
253 }
254
255
256 this.executeScripts(connection);
257 }
258 catch (final Throwable throwable)
259 {
260 throw new MojoExecutionException("An error occurred while attempting to create the schema", throwable);
261 }
262 finally
263 {
264 if (connection != null)
265 {
266 try
267 {
268 connection.close();
269 }
270 catch (SQLException e)
271 {
272
273 }
274 }
275 }
276 }
277
278
279
280
281
282
283 private List<String> getTasks()
284 {
285 return this.tasks != null ? Arrays.asList(this.tasks.split(",")) : null;
286 }
287
288
289
290
291
292
293
294
295
296 private void executeScripts(final Connection connection)
297 throws MojoExecutionException
298 {
299 final List<String> tasks = this.getTasks();
300 if (this.scripts != null && !this.scripts.isEmpty())
301 {
302 for (final String location : scripts)
303 {
304 try
305 {
306 this.executeSql(
307 connection,
308 location);
309 }
310 catch (final Exception exception)
311 {
312 throw new MojoExecutionException("Execution failed on script: " + location, exception);
313 }
314 }
315 }
316 else if (tasks == null || tasks.isEmpty())
317 {
318 this.getLog().info("No scripts found to execute");
319 }
320 }
321
322
323
324
325
326
327
328 protected void initializeClasspathFromClassPathElements(final Set<String> classpathFiles)
329 throws MalformedURLException
330 {
331
332
333 if (this.pluginArtifacts != null)
334 {
335 for (final Artifact artifact : this.pluginArtifacts)
336 {
337 final File artifactFile = artifact.getFile();
338 if (artifactFile != null)
339 {
340 classpathFiles.add(artifactFile.toString());
341 }
342 }
343 }
344
345 final List<String> files = new ArrayList<String>(classpathFiles);
346 if (!files.isEmpty())
347 {
348 final URL[] classpathUrls = new URL[classpathFiles.size()];
349
350 for (int ctr = 0; ctr < classpathFiles.size(); ++ctr)
351 {
352 final File file = new File(files.get(ctr));
353 if (this.getLog().isDebugEnabled())
354 {
355 getLog().debug("adding to classpath '" + file + '\'');
356 }
357 classpathUrls[ctr] = file.toURI().toURL();
358 }
359
360 final URLClassLoader loader =
361 new URLClassLoader(classpathUrls,
362 Thread.currentThread().getContextClassLoader());
363 Thread.currentThread().setContextClassLoader(loader);
364 }
365 }
366
367
368
369
370
371
372
373 protected void initializeClassLoaderWithJdbcDriver()
374 throws MalformedURLException
375 {
376 Thread.currentThread().setContextClassLoader(
377 new URLClassLoader(
378 new URL[] {new File(this.jdbcDriverJar).toURI().toURL()},
379 Thread.currentThread().getContextClassLoader()));
380 }
381
382
383
384
385
386
387
388
389 protected List<String> getProvidedClasspathElements()
390 throws ArtifactResolutionException, ArtifactNotFoundException
391 {
392 final List<String> classpathElements = new ArrayList<String>();
393 final List<Dependency> dependencies = this.project.getDependencies();
394 if (dependencies != null && !dependencies.isEmpty())
395 {
396 for (final Dependency dependency : dependencies)
397 {
398 if (Artifact.SCOPE_PROVIDED.equals(dependency.getScope()))
399 {
400 final String file = this.getDependencyFile(dependency);
401 if (file != null)
402 {
403 classpathElements.add(file);
404 }
405 }
406 }
407 }
408 return classpathElements;
409 }
410
411
412
413
414
415
416
417
418 private String getDependencyFile(final Dependency dependency)
419 throws ArtifactResolutionException, ArtifactNotFoundException
420 {
421 String file = null;
422 if (dependency != null)
423 {
424 final Artifact artifact =
425 this.factory.createArtifact(
426 dependency.getGroupId(),
427 dependency.getArtifactId(),
428 dependency.getVersion(),
429 null,
430 dependency.getType());
431
432 this.artifactResolver.resolve(
433 artifact,
434 project.getRemoteArtifactRepositories(),
435 this.localRepository);
436 file = artifact.getFile() != null ? artifact.getFile().toString() : null;
437 }
438 return file;
439 }
440
441
442
443
444
445
446
447
448 protected Connection getConnection()
449 throws Exception
450 {
451 Driver driver = (Driver)ClassUtils.loadClass(this.jdbcDriver).newInstance();
452 DriverManager.registerDriver(new JdbcDriverWrapper(driver));
453 return DriverManager.getConnection(
454 this.jdbcConnectionUrl,
455 this.jdbcUsername,
456 this.jdbcPassword);
457 }
458
459
460
461
462 private static final String STATEMENT_END = ";";
463
464
465
466
467
468
469
470
471
472 public void executeSql(
473 final Connection connection,
474 final String sqlPath)
475 throws Exception
476 {
477 if (StringUtils.isNotBlank(sqlPath))
478 {
479 final URL sqlUrl = ResourceUtils.toURL(sqlPath);
480 if (sqlUrl != null)
481 {
482 this.successes = 0;
483 this.failures = 0;
484 Statement statement = null;
485 if (connection != null)
486 {
487 statement = connection.createStatement();
488 }
489 final InputStream stream = sqlUrl.openStream();
490 final BufferedReader resourceInput = new BufferedReader(new InputStreamReader(stream));
491 StringBuilder sql = new StringBuilder();
492 for (String line = resourceInput.readLine(); line != null; line = resourceInput.readLine())
493 {
494 if (line.startsWith("//"))
495 {
496 continue;
497 }
498 if (line.startsWith("--"))
499 {
500 continue;
501 }
502 sql.append(line);
503 if (line.endsWith(STATEMENT_END))
504 {
505 if (statement != null)
506 {
507 this.executeSql(
508 statement,
509 sql.toString().replaceAll(
510 STATEMENT_END,
511 ""));
512 }
513 sql = new StringBuilder();
514 }
515 sql.append('\n');
516 }
517 resourceInput.close();
518 if (statement != null)
519 {
520 statement.close();
521 }
522 }
523 this.getLog().info(" Executed script: " + sqlPath);
524 final String count = String.valueOf(this.successes + this.failures);
525 this.getLog().info(' ' + count + " SQL statements executed");
526 this.getLog().info(" Failures: " + this.failures);
527 this.getLog().info(" Successes: " + this.successes);
528 }
529 }
530
531
532
533
534 private int successes;
535
536
537
538
539 private int failures;
540
541
542
543
544
545
546
547
548
549 private void executeSql(
550 final Statement statement,
551 final String sql)
552 {
553 this.getLog().info(sql.trim());
554 try
555 {
556 statement.execute(sql);
557 this.successes++;
558 }
559 catch (final SQLException exception)
560 {
561 this.failures++;
562 this.getLog().warn(exception.toString());
563 }
564 }
565
566
567
568
569 private static final HashMap<String, Map<String, Class>> tasksCache = new LinkedHashMap<String, Map<String, Class>>();
570
571 static
572 {
573
574 final Map<String, Class> hibernateTasks = new LinkedHashMap<String, Class>();
575 tasksCache.put(
576 "hibernate",
577 hibernateTasks);
578 hibernateTasks.put(
579 "create",
580 HibernateCreateSchema.class);
581 hibernateTasks.put(
582 "drop",
583 HibernateDropSchema.class);
584 hibernateTasks.put(
585 "update",
586 HibernateUpdateSchema.class);
587 hibernateTasks.put(
588 "validate",
589 HibernateValidateSchema.class);
590 }
591 }