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