1 package org.codehaus.mojo.jaxb2;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.plugin.AbstractMojo;
23 import org.apache.maven.plugin.MojoExecution;
24 import org.apache.maven.plugin.MojoExecutionException;
25 import org.apache.maven.plugin.MojoFailureException;
26 import org.apache.maven.plugin.logging.Log;
27 import org.apache.maven.plugins.annotations.Component;
28 import org.apache.maven.plugins.annotations.Parameter;
29 import org.apache.maven.project.MavenProject;
30 import org.codehaus.mojo.jaxb2.shared.FileSystemUtilities;
31 import org.codehaus.mojo.jaxb2.shared.Validate;
32 import org.codehaus.mojo.jaxb2.shared.environment.EnvironmentFacet;
33 import org.codehaus.mojo.jaxb2.shared.filters.Filter;
34 import org.codehaus.mojo.jaxb2.shared.filters.pattern.PatternFileFilter;
35 import org.codehaus.mojo.jaxb2.shared.version.DependencyInfo;
36 import org.codehaus.mojo.jaxb2.shared.version.DependsFileParser;
37 import org.sonatype.plexus.build.incremental.BuildContext;
38
39 import java.io.File;
40 import java.io.IOException;
41 import java.net.URL;
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.Collections;
45 import java.util.List;
46 import java.util.Locale;
47 import java.util.Map;
48 import java.util.SortedMap;
49 import java.util.TreeMap;
50 import java.util.regex.Pattern;
51
52
53
54
55
56
57
58 public abstract class AbstractJaxbMojo extends AbstractMojo {
59
60
61
62
63 public static final String STANDARD_EPISODE_FILENAME = "sun-jaxb.episode";
64
65
66
67
68
69 public static final String PACKAGE_INFO_FILENAME = "package-info.java";
70
71
72
73
74 public static final String NEWLINE = System.getProperty("line.separator");
75
76
77
78
79 public static final Pattern CONTAINS_WHITESPACE = Pattern.compile("(\\S*\\s+\\S*)+", Pattern.UNICODE_CASE);
80
81
82
83
84
85 public static final List<Filter<File>> STANDARD_EXCLUDE_FILTERS;
86
87 private static final List<String> RELEVANT_GROUPIDS =
88 Arrays.asList("org.glassfish.jaxb", "javax.xml.bind");
89 private static final String OWN_ARTIFACT_ID = "jaxb2-maven-plugin";
90 private static final String SYSTEM_FILE_ENCODING_PROPERTY = "file.encoding";
91 private static final String[] STANDARD_EXCLUDE_SUFFIXES = {"README.*", "\\.xml", "\\.txt"};
92
93 static {
94
95
96 final List<Filter<File>> tmp = new ArrayList<Filter<File>>();
97 tmp.add(new PatternFileFilter(Arrays.asList(STANDARD_EXCLUDE_SUFFIXES), true));
98
99
100 STANDARD_EXCLUDE_FILTERS = (List<Filter<File>>) Collections.unmodifiableList(tmp);
101 }
102
103
104
105
106
107 @Component
108 private BuildContext buildContext;
109
110
111
112
113 @Parameter(defaultValue = "${project}", readonly = true)
114 private MavenProject project;
115
116
117
118
119
120
121
122 @Parameter(defaultValue = "${mojoExecution}", readonly = true)
123 private MojoExecution execution;
124
125
126
127
128
129
130
131
132
133
134 @Parameter(defaultValue = "${project.build.directory}/jaxb2", readonly = true, required = true)
135 protected File staleFileDirectory;
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152 @Parameter(defaultValue = "${project.build.sourceEncoding}")
153 private String encoding;
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175 @Parameter(required = false)
176 protected String locale;
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 @Parameter(required = false)
203 protected List<EnvironmentFacet> extraFacets;
204
205
206
207
208
209
210
211 protected final BuildContext getBuildContext() {
212 return getInjectedObject(buildContext, "buildContext");
213 }
214
215
216
217
218 protected final MavenProject getProject() {
219 return getInjectedObject(project, "project");
220 }
221
222
223
224
225 public MojoExecution getExecution() {
226 return getInjectedObject(execution, "execution");
227 }
228
229
230
231
232 @Override
233 public final void execute() throws MojoExecutionException, MojoFailureException {
234
235
236 final Log log = getLog();
237 final boolean isDebugEnabled = log.isDebugEnabled();
238 final boolean isInfoEnabled = log.isInfoEnabled();
239
240
241 if (shouldExecutionBeSkipped()) {
242
243 if (isDebugEnabled) {
244 log.debug("Skipping execution, as instructed.");
245 }
246 return;
247 }
248
249
250 if (isDebugEnabled) {
251 logPluginAndJaxbDependencyInfo();
252 }
253
254
255 if (isReGenerationRequired()) {
256
257 if (performExecution()) {
258
259
260
261 updateStaleFileTimestamp();
262
263
264 buildContext.refresh(getOutputDirectory());
265
266 } else if (isInfoEnabled) {
267 log.info("Not updating staleFile timestamp as instructed.");
268 }
269 } else if (isInfoEnabled) {
270 log.info("No changes detected in schema or binding files - skipping JAXB generation.");
271 }
272 }
273
274
275
276
277
278
279 protected abstract boolean shouldExecutionBeSkipped();
280
281
282
283
284
285 protected abstract boolean isReGenerationRequired();
286
287
288
289
290
291
292
293
294
295
296
297 protected abstract boolean performExecution() throws MojoExecutionException, MojoFailureException;
298
299
300
301
302
303
304
305
306 protected abstract List<URL> getSources();
307
308
309
310
311
312
313 protected abstract File getOutputDirectory();
314
315
316
317
318
319
320
321
322
323 protected abstract List<String> getClasspath() throws MojoExecutionException;
324
325
326
327
328
329
330
331
332 @SuppressWarnings("all")
333 protected void warnAboutIncorrectPluginConfiguration(final String propertyName, final String description) {
334
335 final StringBuilder builder = new StringBuilder();
336 builder.append("\n+=================== [Incorrect Plugin Configuration Detected]\n");
337 builder.append("|\n");
338 builder.append("| Property : " + propertyName + "\n");
339 builder.append("| Problem : " + description + "\n");
340 builder.append("|\n");
341 builder.append("+=================== [End Incorrect Plugin Configuration Detected]\n\n");
342 getLog().warn(builder.toString().replace("\n", NEWLINE));
343 }
344
345
346
347
348
349
350 protected final String[] logAndReturnToolArguments(final String[] arguments, final String toolName) {
351
352
353 Validate.notNull(arguments, "arguments");
354
355 if (getLog().isDebugEnabled()) {
356
357 final StringBuilder argBuilder = new StringBuilder();
358 argBuilder.append("\n+=================== [" + arguments.length + " " + toolName + " Arguments]\n");
359 argBuilder.append("|\n");
360 for (int i = 0; i < arguments.length; i++) {
361 argBuilder.append("| [").append(i).append("]: ").append(arguments[i]).append("\n");
362 }
363 argBuilder.append("|\n");
364 argBuilder.append("+=================== [End " + arguments.length + " " + toolName + " Arguments]\n\n");
365 getLog().debug(argBuilder.toString().replace("\n", NEWLINE));
366 }
367
368
369 return arguments;
370 }
371
372
373
374
375
376
377
378
379
380 protected abstract String getStaleFileName();
381
382
383
384
385
386
387 protected final File getStaleFile() {
388 final String staleFileName = "."
389 + (getExecution() == null ? "nonExecutionJaxb" : getExecution().getExecutionId())
390 + "-" + getStaleFileName();
391 return new File(staleFileDirectory, staleFileName);
392 }
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410 protected final String getEncoding(final boolean warnIfConfiguredEncodingDiffersFromFileEncoding) {
411
412
413 final boolean configuredEncoding = encoding != null;
414 final String fileEncoding = System.getProperty(SYSTEM_FILE_ENCODING_PROPERTY);
415 final String effectiveEncoding = configuredEncoding ? encoding : fileEncoding;
416
417
418 if (warnIfConfiguredEncodingDiffersFromFileEncoding
419 && !fileEncoding.equalsIgnoreCase(effectiveEncoding)
420 && getLog().isWarnEnabled()) {
421 getLog().warn("Configured encoding [" + effectiveEncoding
422 + "] differs from encoding given in system property '" + SYSTEM_FILE_ENCODING_PROPERTY
423 + "' [" + fileEncoding + "]");
424 }
425
426 if (getLog().isDebugEnabled()) {
427 getLog().debug("Using " + (configuredEncoding ? "explicitly configured" : "system property")
428 + " encoding [" + effectiveEncoding + "]");
429 }
430
431
432 return effectiveEncoding;
433 }
434
435
436
437
438
439
440
441
442
443
444 protected File getEpisodeFile(final String customEpisodeFileName) throws MojoExecutionException {
445
446
447 final String effectiveEpisodeFileName = customEpisodeFileName == null
448 ? "sun-jaxb.episode"
449 : customEpisodeFileName;
450 Validate.notEmpty(effectiveEpisodeFileName, "effectiveEpisodeFileName");
451
452
453 final File generatedMetaInfDirectory = new File(getOutputDirectory(), "META-INF");
454
455 if (!generatedMetaInfDirectory.exists()) {
456
457 FileSystemUtilities.createDirectory(generatedMetaInfDirectory, false);
458 if (getLog().isDebugEnabled()) {
459 getLog().debug("Created episode directory ["
460 + FileSystemUtilities.getCanonicalPath(generatedMetaInfDirectory) + "]: " +
461 generatedMetaInfDirectory.exists());
462 }
463 }
464
465
466 return new File(generatedMetaInfDirectory, effectiveEpisodeFileName);
467 }
468
469
470
471
472
473 private void logPluginAndJaxbDependencyInfo() {
474
475 if (getLog().isDebugEnabled()) {
476 final StringBuilder builder = new StringBuilder();
477 builder.append("\n+=================== [Brief Plugin Build Dependency Information]\n");
478 builder.append("|\n");
479 builder.append("| Note: These dependencies pertain to what was used to build *the plugin*.\n");
480 builder.append("| Check project dependencies to see the ones used in *your build*.\n");
481 builder.append("|\n");
482
483
484 final SortedMap<String, String> versionMap = DependsFileParser.getVersionMap(OWN_ARTIFACT_ID);
485
486 builder.append("|\n");
487 builder.append("| Plugin's own information\n");
488 builder.append("| GroupId : " + versionMap.get(DependsFileParser.OWN_GROUPID_KEY) + "\n");
489 builder.append("| ArtifactID : " + versionMap.get(DependsFileParser.OWN_ARTIFACTID_KEY) + "\n");
490 builder.append("| Version : " + versionMap.get(DependsFileParser.OWN_VERSION_KEY) + "\n");
491 builder.append("| Buildtime : " + versionMap.get(DependsFileParser.BUILDTIME_KEY) + "\n");
492 builder.append("|\n");
493 builder.append("| Plugin's JAXB-related dependencies\n");
494 builder.append("|\n");
495
496 final SortedMap<String, DependencyInfo> diMap = DependsFileParser.createDependencyInfoMap(versionMap);
497
498 int dependencyIndex = 0;
499 for (Map.Entry<String, DependencyInfo> current : diMap.entrySet()) {
500
501 final String key = current.getKey().trim();
502 for (String currentRelevantGroupId : RELEVANT_GROUPIDS) {
503 if (key.startsWith(currentRelevantGroupId)) {
504
505 final DependencyInfo di = current.getValue();
506 builder.append("| " + (++dependencyIndex) + ") [" + di.getArtifactId() + "]\n");
507 builder.append("| GroupId : " + di.getGroupId() + "\n");
508 builder.append("| ArtifactID : " + di.getArtifactId() + "\n");
509 builder.append("| Version : " + di.getVersion() + "\n");
510 builder.append("| Scope : " + di.getScope() + "\n");
511 builder.append("| Type : " + di.getType() + "\n");
512 builder.append("|\n");
513 }
514 }
515 }
516
517 builder.append("+=================== [End Brief Plugin Build Dependency Information]\n\n");
518 getLog().debug(builder.toString().replace("\n", NEWLINE));
519 }
520 }
521
522 private <T> T getInjectedObject(final T objectOrNull, final String objectName) {
523
524 if (objectOrNull == null) {
525 getLog().error(
526 "Found null '" + objectName + "', implying that Maven @Component injection was not done properly.");
527 }
528
529 return objectOrNull;
530 }
531
532 private void updateStaleFileTimestamp() throws MojoExecutionException {
533
534 final File staleFile = getStaleFile();
535 if (!staleFile.exists()) {
536
537
538 FileSystemUtilities.createDirectory(staleFile.getParentFile(), false);
539
540 try {
541 staleFile.createNewFile();
542
543 if (getLog().isDebugEnabled()) {
544 getLog().debug("Created staleFile [" + FileSystemUtilities.getCanonicalPath(staleFile) + "]");
545 }
546 } catch (IOException e) {
547 throw new MojoExecutionException("Could not create staleFile.", e);
548 }
549
550 } else {
551 if (!staleFile.setLastModified(System.currentTimeMillis())) {
552 getLog().warn("Failed updating modification time of staleFile ["
553 + FileSystemUtilities.getCanonicalPath(staleFile) + "]");
554 }
555 }
556 }
557
558
559
560
561 protected void logSystemPropertiesAndBasedir() {
562 if (getLog().isDebugEnabled()) {
563
564 final StringBuilder builder = new StringBuilder();
565
566 builder.append("\n+=================== [System properties]\n");
567 builder.append("|\n");
568
569
570 final SortedMap<String, Object> props = new TreeMap<String, Object>();
571 props.put("basedir", FileSystemUtilities.getCanonicalPath(getProject().getBasedir()));
572
573 for (Map.Entry<Object, Object> current : System.getProperties().entrySet()) {
574 props.put("" + current.getKey(), current.getValue());
575 }
576 for (Map.Entry<String, Object> current : props.entrySet()) {
577 builder.append("| [" + current.getKey() + "]: " + current.getValue() + "\n");
578 }
579
580 builder.append("|\n");
581 builder.append("+=================== [End System properties]\n");
582
583
584 getLog().debug(builder.toString().replace("\n", NEWLINE));
585 }
586 }
587 }