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