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