1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.basepom.mojo.propertyhelper;
16
17 import static com.google.common.base.Preconditions.checkState;
18 import static java.lang.String.format;
19 import static org.basepom.mojo.propertyhelper.IgnoreWarnFail.checkIgnoreWarnFailState;
20
21 import org.basepom.mojo.propertyhelper.definitions.DateDefinition;
22 import org.basepom.mojo.propertyhelper.definitions.FieldDefinition;
23 import org.basepom.mojo.propertyhelper.definitions.MacroDefinition;
24 import org.basepom.mojo.propertyhelper.definitions.NumberDefinition;
25 import org.basepom.mojo.propertyhelper.definitions.PropertyGroupDefinition;
26 import org.basepom.mojo.propertyhelper.definitions.StringDefinition;
27 import org.basepom.mojo.propertyhelper.definitions.UuidDefinition;
28 import org.basepom.mojo.propertyhelper.fields.NumberField;
29 import org.basepom.mojo.propertyhelper.groups.PropertyGroup;
30 import org.basepom.mojo.propertyhelper.groups.PropertyResult;
31 import org.basepom.mojo.propertyhelper.macros.MacroType;
32
33 import java.io.File;
34 import java.io.IOException;
35 import java.util.Arrays;
36 import java.util.LinkedHashSet;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Properties;
40 import java.util.Random;
41 import java.util.Set;
42 import javax.inject.Inject;
43
44 import com.google.common.collect.ImmutableList;
45 import com.google.common.collect.ImmutableMap;
46 import com.google.common.collect.ImmutableSet;
47 import com.google.common.flogger.FluentLogger;
48 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
49 import org.apache.maven.plugin.AbstractMojo;
50 import org.apache.maven.plugin.MojoExecutionException;
51 import org.apache.maven.plugins.annotations.Parameter;
52 import org.apache.maven.project.MavenProject;
53 import org.apache.maven.settings.Settings;
54
55 public abstract class AbstractPropertyHelperMojo extends AbstractMojo implements FieldContext {
56
57 private static final FluentLogger LOG = FluentLogger.forEnclosingClass();
58
59 protected final ValueCache valueCache = new ValueCache();
60 private IgnoreWarnFail onDuplicateField = IgnoreWarnFail.FAIL;
61
62
63
64
65
66
67
68
69
70
71
72 @Parameter(defaultValue = "fail", alias = "onDuplicateProperty")
73 public void setOnDuplicateField(String onDuplicateField) {
74 this.onDuplicateField = IgnoreWarnFail.forString(onDuplicateField);
75 }
76
77 private List<String> activeGroups = List.of();
78
79
80
81
82
83
84
85
86
87
88
89 @Parameter
90 public void setActiveGroups(String... activeGroups) {
91 this.activeGroups = Arrays.asList(activeGroups);
92 }
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120 @Parameter
121 public void setPropertyGroups(PropertyGroupDefinition... propertyGroups) {
122 this.propertyGroupDefinitions = Arrays.asList(propertyGroups);
123 }
124
125 private List<PropertyGroupDefinition> propertyGroupDefinitions = List.of();
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 @Parameter
155 public void setNumbers(NumberDefinition... numberDefinitions) {
156 this.numberDefinitions = Arrays.asList(numberDefinitions);
157 }
158
159 private List<NumberDefinition> numberDefinitions = List.of();
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192 @Parameter
193 public void setStrings(StringDefinition... stringDefinitions) {
194 this.stringDefinitions = Arrays.asList(stringDefinitions);
195 }
196
197 private List<StringDefinition> stringDefinitions = List.of();
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226 @Parameter
227 public void setDates(DateDefinition... dateDefinitions) {
228 this.dateDefinitions = Arrays.asList(dateDefinitions);
229 }
230
231 private List<DateDefinition> dateDefinitions = List.of();
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265 @Parameter
266 public void setMacros(MacroDefinition... macroDefinitions) {
267 this.macroDefinitions = Arrays.asList(macroDefinitions);
268 }
269
270 private List<MacroDefinition> macroDefinitions = List.of();
271
272
273
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 @Parameter
299 public void setUuids(UuidDefinition... uuidDefinitions) {
300 this.uuidDefinitions = Arrays.asList(uuidDefinitions);
301 }
302
303 private List<UuidDefinition> uuidDefinitions = List.of();
304
305
306
307
308 @Parameter(defaultValue = "false")
309 boolean skip;
310
311
312
313
314 @Parameter(defaultValue = "${project}", readonly = true)
315 MavenProject project;
316
317 @Parameter(defaultValue = "${settings}", readonly = true)
318 Settings settings;
319
320 @Parameter(required = true, readonly = true, defaultValue = "${project.basedir}")
321 File basedir;
322
323
324
325
326
327
328 @Parameter(defaultValue = "${project.build.outputTimestamp}")
329 String outputTimestamp;
330
331
332 @Inject
333 public void setMacroMap(Map<String, MacroType> macroMap) {
334 this.macroMap = ImmutableMap.copyOf(macroMap);
335 }
336
337 private Map<String, MacroType> macroMap = Map.of();
338
339
340 private boolean isSnapshot;
341 private InterpolatorFactory interpolatorFactory;
342 private TransformerRegistry transformerRegistry;
343
344 private Map<String, FieldDefinition<?>> fieldDefinitions = Map.of();
345 private List<NumberField> numberFields = List.of();
346 private Map<String, String> values = Map.of();
347
348 private Random random;
349
350 @Override
351 public void execute() throws MojoExecutionException {
352 this.isSnapshot = project.getArtifact().isSnapshot();
353 this.interpolatorFactory = new InterpolatorFactory(project.getModel());
354 this.transformerRegistry = TransformerRegistry.INSTANCE;
355
356 LOG.atFine().log("Current build is a %s project.", isSnapshot ? "snapshot" : "release");
357 LOG.atFiner().log("On duplicate field definitions: %s", onDuplicateField);
358
359 try {
360 if (skip) {
361 LOG.atFine().log("skipping plugin execution!");
362 } else {
363 this.random = RandomUtil.createRandomFromSeed(outputTimestamp);
364
365 doExecute();
366 }
367 } catch (IOException e) {
368 throw new MojoExecutionException("While running mojo: ", e);
369 }
370 }
371
372 @Override
373 public MavenProject getProject() {
374 return project;
375 }
376
377 @Override
378 public File getBasedir() {
379 return basedir;
380 }
381
382 @Override
383 public Settings getSettings() {
384 return settings;
385 }
386
387 @Override
388 public Map<String, MacroType> getMacros() {
389 return macroMap;
390 }
391
392 @Override
393 public Properties getProjectProperties() {
394 return project.getProperties();
395 }
396
397 @Override
398 public InterpolatorFactory getInterpolatorFactory() {
399 return interpolatorFactory;
400 }
401
402 @Override
403 public TransformerRegistry getTransformerRegistry() {
404 return transformerRegistry;
405 }
406
407 @Override
408 public Random getRandom() {
409 return random;
410 }
411
412 protected List<NumberField> getNumbers() {
413 return numberFields;
414 }
415
416
417
418
419 protected abstract void doExecute() throws IOException, MojoExecutionException;
420
421 private void addDefinitions(ImmutableMap.Builder<String, FieldDefinition<?>> builder, List<? extends FieldDefinition<?>> newDefinitions) {
422 Map<String, FieldDefinition<?>> existingDefinitions = builder.build();
423
424 for (FieldDefinition<?> definition : newDefinitions) {
425 if (definition.isSkip()) {
426 continue;
427 }
428
429 String propertyName = definition.getId();
430
431 if (checkIgnoreWarnFailState(!existingDefinitions.containsKey(propertyName), onDuplicateField,
432 () -> format("field definition '%s' does not exist", propertyName),
433 () -> format("field definition '%s' already exists!", propertyName))) {
434 builder.put(propertyName, definition);
435 }
436 }
437 }
438
439 protected void createFieldDefinitions() {
440
441 ImmutableMap.Builder<String, FieldDefinition<?>> builder = ImmutableMap.builder();
442 addDefinitions(builder, numberDefinitions);
443 addDefinitions(builder, stringDefinitions);
444 addDefinitions(builder, macroDefinitions);
445 addDefinitions(builder, dateDefinitions);
446 addDefinitions(builder, uuidDefinitions);
447
448 this.fieldDefinitions = builder.build();
449 }
450
451 protected void createFields() throws MojoExecutionException, IOException {
452 ImmutableList.Builder<NumberField> numberFields = ImmutableList.builder();
453
454 var builder = ImmutableMap.<String, String>builder();
455
456 for (FieldDefinition<?> definition : fieldDefinitions.values()) {
457 Field<?, ?> field = definition.createField(this, valueCache);
458
459 if (field instanceof NumberField) {
460 numberFields.add((NumberField) field);
461 }
462
463 var fieldValue = field.getValue();
464 builder.put(field.getFieldName(), fieldValue);
465
466 if (field.isExposeAsProperty()) {
467 project.getProperties().setProperty(field.getFieldName(), fieldValue);
468 LOG.atFine().log("Exporting Property name: %s, value: %s", field.getFieldName(), fieldValue);
469 } else {
470 LOG.atFine().log("Property name: %s, value: %s", field.getFieldName(), fieldValue);
471 }
472 }
473
474 this.numberFields = numberFields.build();
475 this.values = builder.build();
476 }
477
478
479 @SuppressFBWarnings(value = "WMI_WRONG_MAP_ITERATOR")
480 public void createGroups() {
481 var groupMapBuilder = ImmutableMap.<String, PropertyGroup>builder();
482 var resultMapBuilder = ImmutableMap.<String, Set<PropertyResult>>builder();
483
484 Set<String> exportedFields = fieldDefinitions.values().stream()
485 .filter(FieldDefinition::isExport)
486 .map(FieldDefinition::getId).collect(ImmutableSet.toImmutableSet());
487
488 Set<String> propertyNames = new LinkedHashSet<>(exportedFields);
489
490 propertyGroupDefinitions.forEach(propertyGroupDefinition -> {
491 PropertyGroup propertyGroup = propertyGroupDefinition.createGroup(this);
492 Set<PropertyResult> propertyResults = propertyGroup.createProperties(values);
493 groupMapBuilder.put(propertyGroup.getId(), propertyGroup);
494 resultMapBuilder.put(propertyGroup.getId(), propertyResults);
495 });
496
497 var groupMap = groupMapBuilder.build();
498 var resultMap = resultMapBuilder.build();
499
500 var groupsToAdd = this.activeGroups == null
501 ? groupMap.keySet()
502 : this.activeGroups;
503
504 for (String groupToAdd : groupsToAdd) {
505
506 var activeGroup = groupMap.get(groupToAdd);
507 checkState(activeGroup != null, "activated group '%s' does not exist", groupToAdd);
508 var activeResult = resultMap.get(groupToAdd);
509 checkState(activeResult != null, "activated group '%s' has no result", groupToAdd);
510
511 if (activeGroup.checkActive(isSnapshot)) {
512 for (PropertyResult propertyResult : activeResult) {
513 String propertyName = propertyResult.getPropertyName();
514
515 if (checkIgnoreWarnFailState(!propertyNames.contains(propertyName), activeGroup.getOnDuplicateProperty(),
516 () -> format("property '%s' is not exposed", propertyName),
517 () -> format("property '%s' is already exposed!", propertyName))) {
518
519 project.getProperties().setProperty(propertyName, propertyResult.getPropertyValue());
520 }
521 }
522 } else {
523 LOG.atFine().log("Skipping property group %s, not active", activeGroup);
524 }
525 }
526 }
527
528
529 }