1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.maven.plugin;
28
29 import org.apache.maven.plugin.AbstractMojo;
30 import org.apache.maven.plugin.MojoExecution;
31 import org.apache.maven.plugins.annotations.Component;
32 import org.apache.maven.plugins.annotations.Parameter;
33 import org.apache.maven.project.MavenProject;
34 import org.codehaus.plexus.util.DirectoryScanner;
35 import org.sonatype.plexus.build.incremental.BuildContext;
36
37 import java.io.File;
38 import java.net.URI;
39 import java.util.Objects;
40 import java.util.stream.Collectors;
41 import java.util.stream.Stream;
42
43 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
44
45 public abstract class AbstractMetaschemaMojo
46 extends AbstractMojo {
47 private static final String SYSTEM_FILE_ENCODING_PROPERTY = "file.encoding";
48 private static final String[] DEFAULT_INCLUDES = { "**/*.xml" };
49
50
51
52
53
54
55
56
57 @Parameter(defaultValue = "${project}", required = true, readonly = true)
58 MavenProject mavenProject;
59
60
61
62
63
64
65 @Parameter(defaultValue = "${mojoExecution}", readonly = true)
66 private MojoExecution mojoExecution;
67
68 @Component
69 private BuildContext buildContext;
70
71
72
73
74
75
76
77
78
79
80
81
82
83 @Parameter(defaultValue = "${project.build.directory}/metaschema", readonly = true, required = true)
84 protected File staleFileDirectory;
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 @Parameter(defaultValue = "${project.build.sourceEncoding}")
107 private String encoding;
108
109
110
111
112 @Parameter(defaultValue = "${project.build.directory}/generated-sources/metaschema", required = true)
113 private File outputDirectory;
114
115
116
117
118 @Parameter(defaultValue = "${basedir}/src/main/metaschema")
119 private File metaschemaDir;
120
121
122
123
124
125 @Parameter
126 protected String[] includes;
127
128
129
130
131
132 @Parameter
133 protected String[] excludes;
134
135
136
137
138 @Parameter(property = "metaschema.skip", defaultValue = "false")
139 private boolean skip;
140
141
142
143
144
145
146
147
148 protected final BuildContext getBuildContext() {
149 return buildContext;
150 }
151
152
153
154
155
156
157 protected final MavenProject getMavenProject() {
158 return mavenProject;
159 }
160
161
162
163
164
165
166 @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "this is a data holder")
167 public MojoExecution getMojoExecution() {
168 return mojoExecution;
169 }
170
171
172
173
174
175
176 protected File getOutputDirectory() {
177 return outputDirectory;
178 }
179
180
181
182
183
184
185
186 protected void setOutputDirectory(File outputDirectory) {
187 Objects.requireNonNull(outputDirectory, "outputDirectory");
188 this.outputDirectory = outputDirectory;
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208 protected final String getEncoding() {
209 String encoding;
210 if (this.encoding != null) {
211
212 encoding = this.encoding;
213 getLog().debug(String.format("Using configured encoding [%s].", encoding));
214 } else {
215 encoding = System.getProperty(SYSTEM_FILE_ENCODING_PROPERTY);
216 getLog().warn(String.format("Using system encoding [%s]. This build is platform dependent!", encoding));
217 }
218 return encoding;
219 }
220
221
222
223
224
225
226 protected Stream<File> getSources() {
227 DirectoryScanner ds = new DirectoryScanner();
228 ds.setBasedir(metaschemaDir);
229 ds.setIncludes(includes != null && includes.length > 0 ? includes : DEFAULT_INCLUDES);
230 ds.setExcludes(excludes != null && excludes.length > 0 ? excludes : null);
231 ds.addDefaultExcludes();
232 ds.setCaseSensitive(true);
233 ds.setFollowSymlinks(false);
234 ds.scan();
235 return Stream.of(ds.getIncludedFiles()).map(filename -> new File(metaschemaDir, filename)).distinct();
236 }
237
238
239
240
241
242
243
244 protected boolean shouldExecutionBeSkipped() {
245 return skip;
246 }
247
248
249
250
251
252
253 protected abstract String getStaleFileName();
254
255
256
257
258
259
260 protected final File getStaleFile() {
261 StringBuilder builder = new StringBuilder();
262 if (getMojoExecution() != null) {
263 builder.append(getMojoExecution().getExecutionId()).append('-');
264 }
265 builder.append(getStaleFileName());
266 return new File(staleFileDirectory, builder.toString());
267 }
268
269
270
271
272
273
274
275
276
277 protected boolean isGenerationRequired() {
278 final File staleFile = getStaleFile();
279 boolean generate = !staleFile.exists();
280 if (generate) {
281 getLog().info(String.format("Stale file '%s' doesn't exist! Generating source files.", staleFile.getPath()));
282 generate = true;
283 } else {
284 generate = false;
285
286 long staleLastModified = staleFile.lastModified();
287
288 BuildContext buildContext = getBuildContext();
289 URI metaschemaDirRelative = getMavenProject().getBasedir().toURI().relativize(metaschemaDir.toURI());
290
291 if (buildContext.isIncremental() && buildContext.hasDelta(metaschemaDirRelative.toString())) {
292 getLog().info("metaschemaDirRelative: " + metaschemaDirRelative.toString());
293 generate = true;
294 }
295
296 if (!generate) {
297 for (File sourceFile : getSources().collect(Collectors.toList())) {
298 getLog().info("Source file: " + sourceFile.getPath());
299 if (sourceFile.lastModified() > staleLastModified) {
300 generate = true;
301 }
302 }
303 }
304 }
305 return generate;
306 }
307 }