1 package org.codehaus.mojo.jaxb2.javageneration;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import com.sun.tools.xjc.Driver;
23 import org.apache.maven.model.Resource;
24 import org.apache.maven.plugin.MojoExecutionException;
25 import org.apache.maven.plugin.MojoFailureException;
26 import org.apache.maven.plugins.annotations.Parameter;
27 import org.apache.maven.settings.Proxy;
28 import org.apache.maven.settings.Settings;
29 import org.codehaus.mojo.jaxb2.AbstractJaxbMojo;
30 import org.codehaus.mojo.jaxb2.NoSchemasException;
31 import org.codehaus.mojo.jaxb2.shared.FileSystemUtilities;
32 import org.codehaus.mojo.jaxb2.shared.arguments.ArgumentBuilder;
33 import org.codehaus.mojo.jaxb2.shared.environment.EnvironmentFacet;
34 import org.codehaus.mojo.jaxb2.shared.environment.ToolExecutionEnvironment;
35 import org.codehaus.mojo.jaxb2.shared.environment.classloading.ThreadContextClassLoaderBuilder;
36 import org.codehaus.mojo.jaxb2.shared.environment.locale.LocaleFacet;
37 import org.codehaus.mojo.jaxb2.shared.environment.logging.LoggingHandlerEnvironmentFacet;
38 import org.codehaus.plexus.util.FileUtils;
39 import org.codehaus.plexus.util.IOUtil;
40
41 import java.io.File;
42 import java.io.FileWriter;
43 import java.net.HttpURLConnection;
44 import java.net.URL;
45 import java.net.URLConnection;
46 import java.util.ArrayList;
47 import java.util.List;
48
49
50
51
52
53
54
55
56
57
58 public abstract class AbstractJavaGeneratorMojo extends AbstractJaxbMojo {
59
60 private static final int XJC_COMPLETED_OK = 0;
61
62
63
64
65
66
67 @Parameter
68 protected File catalog;
69
70
71
72
73
74
75
76
77
78
79
80
81 @Parameter(defaultValue = "true")
82 protected boolean generateEpisode;
83
84
85
86
87
88
89 @Parameter(defaultValue = "${settings}", readonly = true)
90 protected Settings settings;
91
92
93
94
95
96
97
98
99
100
101 @Parameter(defaultValue = "XmlSchema")
102 protected SourceContentType sourceType;
103
104
105
106
107
108
109
110
111
112 @Parameter(defaultValue = "false")
113 protected boolean noPackageLevelAnnotations;
114
115
116
117
118
119
120
121
122 @Parameter(defaultValue = "false")
123 protected boolean noGeneratedHeaderComments;
124
125
126
127
128
129
130
131 @Parameter(defaultValue = "false")
132 protected boolean addGeneratedAnnotation;
133
134
135
136
137
138
139
140
141
142 @Parameter(defaultValue = "false")
143 protected boolean laxSchemaValidation;
144
145
146
147
148
149 @Parameter(defaultValue = "false")
150 protected boolean quiet;
151
152
153
154
155
156 @Parameter(property = "xjc.verbose", defaultValue = "false")
157 protected boolean verbose;
158
159
160
161
162
163
164
165
166
167 @Parameter(defaultValue = "false")
168 protected boolean extension;
169
170
171
172
173
174
175 @Parameter(defaultValue = "true")
176 protected boolean failOnNoSchemas;
177
178
179
180
181 @Parameter(defaultValue = "true")
182 protected boolean clearOutputDir;
183
184
185
186
187
188
189
190
191 @Parameter(defaultValue = "false")
192 protected boolean readOnly;
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214 @Parameter(property = "xjc.arguments")
215 protected List<String> arguments;
216
217
218
219
220
221
222
223 @Parameter(defaultValue = "false")
224 private boolean enableIntrospection;
225
226
227
228
229
230
231
232 @Parameter
233 protected String packageName;
234
235
236
237
238
239
240
241
242 @Parameter
243 protected String target;
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269 @Parameter
270 protected String xsdPathWithinArtifact;
271
272
273
274
275
276 @Override
277 protected boolean isReGenerationRequired() {
278
279
280
281
282
283
284
285
286
287 final File staleFile = getStaleFile();
288 final String debugPrefix = "StaleFile [" + FileSystemUtilities.getCanonicalPath(staleFile) + "]";
289
290 boolean stale = !staleFile.exists();
291 if (stale) {
292 getLog().debug(debugPrefix + " not found. JAXB (re-)generation required.");
293 } else {
294
295 final List<URL> sourceXSDs = getSources();
296 final List<File> sourceXJBs = getSourceXJBs();
297
298 if (getLog().isDebugEnabled()) {
299 getLog().debug(debugPrefix + " found. Checking timestamps on source XSD and XJB "
300 + "files to determine if JAXB (re-)generation is required.");
301 }
302
303 final long staleFileLastModified = staleFile.lastModified();
304 for (URL current : sourceXSDs) {
305
306 final URLConnection sourceXsdConnection;
307 try {
308 sourceXsdConnection = current.openConnection();
309 sourceXsdConnection.connect();
310 } catch (Exception e) {
311
312
313
314 stale = true;
315 break;
316 }
317
318 try {
319 if (sourceXsdConnection.getLastModified() > staleFileLastModified) {
320
321 if (getLog().isDebugEnabled()) {
322 getLog().debug(current.toString() + " is newer than the stale flag file.");
323 }
324 stale = true;
325 }
326 } finally {
327 if (sourceXsdConnection instanceof HttpURLConnection) {
328 ((HttpURLConnection) sourceXsdConnection).disconnect();
329 }
330 }
331 }
332
333 for (File current : sourceXJBs) {
334 if (current.lastModified() > staleFileLastModified) {
335
336 if (getLog().isDebugEnabled()) {
337 getLog().debug(FileSystemUtilities.getCanonicalPath(current)
338 + " is newer than the stale flag file.");
339 }
340
341 stale = true;
342 break;
343 }
344 }
345 }
346
347
348 return stale;
349 }
350
351
352
353
354 @Override
355 protected boolean performExecution() throws MojoExecutionException, MojoFailureException {
356
357 boolean updateStaleFileTimestamp = false;
358
359 try {
360
361
362 ToolExecutionEnvironment environment = null;
363 try {
364
365
366 final LocaleFacet localeFacet = locale == null ? null : LocaleFacet.createFor(locale, getLog());
367
368
369 environment = new ToolExecutionEnvironment(getLog(),
370 ThreadContextClassLoaderBuilder.createFor(this.getClass(), getLog()).addPaths(getClasspath()),
371 LoggingHandlerEnvironmentFacet.create(getLog(), getClass(), getEncoding(false)),
372 localeFacet);
373
374
375 if (extraFacets != null) {
376 for (EnvironmentFacet current : extraFacets) {
377 environment.add(current);
378 }
379 }
380
381
382 environment.setup();
383
384
385 final String[] xjcArguments = getXjcArguments(
386 environment.getClassPathAsArgument(),
387 STANDARD_EPISODE_FILENAME);
388
389
390 FileSystemUtilities.createDirectory(getOutputDirectory(), clearOutputDir);
391
392
393 final boolean reCreateEpisodeFileParentDirectory = generateEpisode && clearOutputDir;
394 if (reCreateEpisodeFileParentDirectory) {
395 getEpisodeFile(STANDARD_EPISODE_FILENAME);
396 }
397
398
399 logSystemPropertiesAndBasedir();
400
401
402 if (XJC_COMPLETED_OK != Driver.run(xjcArguments, new XjcLogAdapter(getLog()))) {
403
404 final StringBuilder errorMsgBuilder = new StringBuilder();
405 errorMsgBuilder.append("\n+=================== [XJC Error]\n");
406 errorMsgBuilder.append("|\n");
407
408 final List<URL> sourceXSDs = getSources();
409 for (int i = 0; i < sourceXSDs.size(); i++) {
410 errorMsgBuilder.append("| " + i + ": ").append(sourceXSDs.get(i).toString()).append("\n");
411 }
412
413 errorMsgBuilder.append("|\n");
414 errorMsgBuilder.append("+=================== [End XJC Error]\n");
415 throw new MojoExecutionException(errorMsgBuilder.toString());
416 }
417
418
419 getBuildContext().refresh(getOutputDirectory());
420
421
422 updateStaleFileTimestamp = true;
423
424 } finally {
425
426 if (environment != null) {
427 environment.restore();
428 }
429 }
430
431
432 addGeneratedSourcesToProjectSourceRoot();
433
434
435 if (xsdPathWithinArtifact != null) {
436
437 final String buildOutputDirectory = getProject().getBuild().getOutputDirectory();
438 final File targetXsdDirectory = new File(buildOutputDirectory, xsdPathWithinArtifact);
439 FileUtils.forceMkdir(targetXsdDirectory);
440
441 for (URL current : getSources()) {
442
443 String fileName = null;
444 if ("file".equalsIgnoreCase(current.getProtocol())) {
445 fileName = new File(current.getPath()).getName();
446 } else if ("jar".equalsIgnoreCase(current.getProtocol())) {
447
448
449
450 final int bangIndex = current.toString().indexOf("!");
451 if (bangIndex == -1) {
452 throw new MojoExecutionException("Illegal JAR URL [" + current.toString()
453 + "]: lacks a '!'");
454 }
455
456 final String internalPath = current.toString().substring(bangIndex + 1);
457 fileName = new File(internalPath).getName();
458 } else {
459 throw new MojoExecutionException("Could not extract FileName from URL [" + current + "]");
460 }
461
462 final File targetFile = new File(targetXsdDirectory, fileName);
463 if (targetFile.exists()) {
464
465
466 getLog().warn("File [" + FileSystemUtilities.getCanonicalPath(targetFile)
467 + "] already exists. Not copying XSD file [" + current.getPath() + "] to it.");
468 }
469 IOUtil.copy(current.openStream(), new FileWriter(targetFile));
470 }
471
472
473 getBuildContext().refresh(targetXsdDirectory);
474 }
475 } catch (MojoExecutionException e) {
476 throw e;
477 } catch (NoSchemasException e) {
478 if (failOnNoSchemas) {
479 throw new MojoExecutionException("", e);
480 }
481 } catch (Exception e) {
482 throw new MojoExecutionException(e.getMessage(), e);
483 }
484
485
486 return updateStaleFileTimestamp;
487 }
488
489
490
491
492
493
494
495
496
497 @Override
498 protected abstract List<URL> getSources();
499
500
501
502
503
504
505
506 protected abstract List<File> getSourceXJBs();
507
508
509
510
511
512
513 protected abstract void addGeneratedSourcesToProjectSourceRoot();
514
515
516
517
518
519
520
521 protected abstract void addResource(final Resource resource);
522
523
524
525
526
527 private String[] getXjcArguments(final String classPath, final String episodeFileNameOrNull)
528 throws MojoExecutionException, NoSchemasException {
529
530 final ArgumentBuilder builder = new ArgumentBuilder();
531
532
533 builder.withFlag(true, sourceType.getXjcArgument());
534 builder.withFlag(noPackageLevelAnnotations, "npa");
535 builder.withFlag(laxSchemaValidation, "nv");
536 builder.withFlag(verbose, "verbose");
537 builder.withFlag(quiet, "quiet");
538 builder.withFlag(enableIntrospection, "enableIntrospection");
539 builder.withFlag(extension, "extension");
540 builder.withFlag(readOnly, "readOnly");
541 builder.withFlag(noGeneratedHeaderComments, "no-header");
542 builder.withFlag(addGeneratedAnnotation, "mark-generated");
543
544
545
546 builder.withNamedArgument("httpproxy", getProxyString(settings.getActiveProxy()));
547 builder.withNamedArgument("encoding", getEncoding(true));
548 builder.withNamedArgument("p", packageName);
549 builder.withNamedArgument("target", target);
550 builder.withNamedArgument("d", getOutputDirectory().getAbsolutePath());
551 builder.withNamedArgument("classpath", classPath);
552
553 if (generateEpisode) {
554
555
556 if (!extension) {
557
558 if (getLog().isInfoEnabled()) {
559 getLog().info("Adding 'extension' flag to XJC arguments, since the 'generateEpisode' argument is "
560 + "given. (XJCs 'episode' argument requires that the 'extension' argument is provided).");
561 }
562 builder.withFlag(true, "extension");
563 }
564
565 final File episodeFile = getEpisodeFile(episodeFileNameOrNull);
566 builder.withNamedArgument("episode", FileSystemUtilities.getCanonicalPath(episodeFile));
567 }
568 if (catalog != null) {
569 builder.withNamedArgument("catalog", FileSystemUtilities.getCanonicalPath(catalog));
570 }
571
572 if (arguments != null) {
573 builder.withPreCompiledArguments(arguments);
574 }
575
576 for (File current : getSourceXJBs()) {
577
578
579
580
581
582
583 builder.withNamedArgument("-b", current.getAbsolutePath());
584 }
585
586 final List<URL> sourceXSDs = getSources();
587 if (sourceXSDs.isEmpty()) {
588
589
590 getLog().warn("No XSD files found. Please check your plugin configuration.");
591 throw new NoSchemasException();
592
593 } else {
594
595 final List<String> unwrappedSourceXSDs = new ArrayList<String>();
596 for (URL current : sourceXSDs) {
597
598
599 if ("file".equalsIgnoreCase(current.getProtocol())) {
600 unwrappedSourceXSDs.add(FileSystemUtilities.relativize(
601 current.getPath(),
602 new File(System.getProperty("user.dir"))));
603 } else {
604 unwrappedSourceXSDs.add(current.toString());
605 }
606 }
607
608 builder.withPreCompiledArguments(unwrappedSourceXSDs);
609 }
610
611
612 return logAndReturnToolArguments(builder.build(), "XJC");
613 }
614
615 private String getProxyString(final Proxy activeProxy) {
616
617
618 if (activeProxy == null) {
619 return null;
620 }
621
622
623
624
625
626
627 final StringBuilder proxyBuilder = new StringBuilder();
628 if (activeProxy.getUsername() != null) {
629
630
631 proxyBuilder.append(activeProxy.getUsername());
632
633
634 if (activeProxy.getPassword() != null) {
635 proxyBuilder.append(":").append(activeProxy.getPassword());
636 }
637
638 proxyBuilder.append("@");
639 }
640
641
642 proxyBuilder.append(activeProxy.getHost()).append(":").append(activeProxy.getPort());
643
644
645 return proxyBuilder.toString();
646 }
647 }