1 // =================== DO NOT EDIT THIS FILE ====================
2 // Generated by Modello Velocity from model.vm
3 // template, any modifications will be overwritten.
4 // ==============================================================
5 package org.apache.maven.api.model;
6
7 import java.io.Serializable;
8 import java.util.Collections;
9 import java.util.HashMap;
10 import java.util.Map;
11 import java.util.Objects;
12 import java.util.Optional;
13 import java.util.Set;
14 import java.util.stream.Collectors;
15 import java.util.stream.Stream;
16 import org.apache.maven.api.annotations.Experimental;
17 import org.apache.maven.api.annotations.Generated;
18 import org.apache.maven.api.annotations.Immutable;
19 import org.apache.maven.api.annotations.Nonnull;
20 import org.apache.maven.api.annotations.NotThreadSafe;
21 import org.apache.maven.api.annotations.ThreadSafe;
22
23 /**
24 * The conditions within the build runtime environment which will trigger the
25 * automatic inclusion of the build profile. Multiple conditions can be defined, which must
26 * be all satisfied to activate the profile.
27 *
28 * <p>In addition to the traditional activation mechanisms (JDK version, OS properties,
29 * file existence, etc.), Maven now supports a powerful condition-based activation
30 * through the {@code condition} field. This new mechanism allows for more flexible
31 * and expressive profile activation rules.</p>
32 *
33 * <h2>Condition Syntax</h2>
34 *
35 * <p>The condition is specified as a string expression that can include various
36 * functions, comparisons, and logical operators. Some key features include:</p>
37 *
38 * <ul>
39 * <li>Property access: {@code ${property.name}}</li>
40 * <li>Comparison operators: {@code ==}, {@code !=}, {@code <}, {@code >}, {@code <=}, {@code >=}</li>
41 * <li>Logical operators: {@code &&} (AND), {@code ||} (OR), {@code not(...)}</li>
42 * <li>Functions: {@code exists(...)}, {@code missing(...)}, {@code matches(...)}, {@code inrange(...)}, and more</li>
43 * </ul>
44 *
45 * <h2>Supported Functions</h2>
46 *
47 * <p>The following functions are supported in condition expressions:</p>
48 *
49 * <ul>
50 * <li>{@code length(string)}: Returns the length of the given string.</li>
51 * <li>{@code upper(string)}: Converts the string to uppercase.</li>
52 * <li>{@code lower(string)}: Converts the string to lowercase.</li>
53 * <li>{@code substring(string, start, [end])}: Returns a substring of the given string.</li>
54 * <li>{@code indexOf(string, substring)}: Returns the index of the first occurrence of substring in string, or -1 if not found.</li>
55 * <li>{@code contains(string, substring)}: Checks if the string contains the substring.</li>
56 * <li>{@code matches(string, regex)}: Checks if the string matches the given regular expression.</li>
57 * <li>{@code not(condition)}: Negates the given condition.</li>
58 * <li>{@code if(condition, trueValue, falseValue)}: Returns trueValue if the condition is true, falseValue otherwise.</li>
59 * <li>{@code exists(path)}: Checks if a file matching the given glob pattern exists.</li>
60 * <li>{@code missing(path)}: Checks if a file matching the given glob pattern does not exist.</li>
61 * <li>{@code inrange(version, range)}: Checks if the given version is within the specified version range.</li>
62 * </ul>
63 *
64 * <h2>Supported properties</h2>
65 *
66 * <p>The following properties are supported in expressions:</p>
67 *
68 * <ul>
69 * <li>`project.basedir`: The project directory</li>
70 * <li>`project.rootDirectory`: The root directory of the project</li>
71 * <li>`project.artifactId`: The artifactId of the project</li>
72 * <li>`project.packaging`: The packaging of the project</li>
73 * <li>user properties</li>
74 * <li>system properties (including environment variables prefixed with `env.`)</li>
75 * </ul>
76 *
77 * <h2>Examples</h2>
78 *
79 * <ul>
80 * <li>JDK version range: {@code inrange(${java.version}, '[11,)')} (JDK 11 or higher)</li>
81 * <li>OS check: {@code ${os.name} == 'windows'}</li>
82 * <li>File existence: {@code exists('${project.basedir}/src/**}{@code /*.xsd')}</li>
83 * <li>Property check: {@code ${my.property} != 'some-value'}</li>
84 * <li>Regex matching: {@code matches(${os.version}, '.*aws')}</li>
85 * <li>Complex condition: {@code ${os.name} == 'windows' && ${os.arch} != 'amd64' && inrange(${os.version}, '[10,)')}</li>
86 * <li>String length check: {@code length(${user.name}) > 5}</li>
87 * <li>Substring with version: {@code substring(${java.version}, 0, 3) == '1.8'}</li>
88 * <li>Using indexOf: {@code indexOf(${java.version}, '-') > 0}</li>
89 * <li>Conditional logic: {@code if(contains(${java.version}, '-'), substring(${java.version}, 0, indexOf(${java.version}, '-')), ${java.version})}</li>
90 * </ul>
91 *
92 * <p>This flexible condition mechanism allows for more precise control over profile
93 * activation, enabling developers to create profiles that respond to a wide range of
94 * environmental factors and project states.</p>
95 */
96 @Experimental
97 @Generated @ThreadSafe @Immutable
98 public class Activation
99 implements Serializable, InputLocationTracker
100 {
101 /**
102 * If set to true, this profile will be active unless another profile in this
103 * pom is activated using the command line -P option or by one of that profile's
104 * activators.
105 */
106 final boolean activeByDefault;
107 /**
108 * Specifies that this profile will be activated when a matching JDK is detected.
109 * For example, {@code 1.4} only activates on JDKs versioned 1.4,
110 * while {@code !1.4} matches any JDK that is not version 1.4. Ranges are supported too:
111 * {@code [1.5,)} activates when the JDK is 1.5 minimum.
112 */
113 final String jdk;
114 /**
115 * Specifies that this profile will be activated when matching operating system
116 * attributes are detected.
117 */
118 final ActivationOS os;
119 /**
120 * Specifies that this profile will be activated when this property is
121 * specified.
122 */
123 final ActivationProperty property;
124 /**
125 * Specifies that this profile will be activated based on existence of a file.
126 */
127 final ActivationFile file;
128 /**
129 * Specifies that this profile will be activated based on the project's packaging.
130 */
131 final String packaging;
132 /**
133 * The condition which must be satisfied to activate the profile.
134 */
135 final String condition;
136 /** Locations */
137 final Map<Object, InputLocation> locations;
138 /** Location tracking */
139 final InputLocation importedFrom;
140
141 /**
142 * Constructor for this class, to be called from its subclasses and {@link Builder}.
143 * @see Builder#build()
144 */
145 protected Activation(Builder builder) {
146 this.activeByDefault = builder.activeByDefault != null ? builder.activeByDefault : (builder.base != null ? builder.base.activeByDefault : false);
147 this.jdk = builder.jdk != null ? builder.jdk : (builder.base != null ? builder.base.jdk : null);
148 this.os = builder.os != null ? builder.os : (builder.base != null ? builder.base.os : null);
149 this.property = builder.property != null ? builder.property : (builder.base != null ? builder.base.property : null);
150 this.file = builder.file != null ? builder.file : (builder.base != null ? builder.base.file : null);
151 this.packaging = builder.packaging != null ? builder.packaging : (builder.base != null ? builder.base.packaging : null);
152 this.condition = builder.condition != null ? builder.condition : (builder.base != null ? builder.base.condition : null);
153 this.locations = builder.computeLocations();
154 this.importedFrom = builder.importedFrom;
155 }
156
157 /**
158 * If set to true, this profile will be active unless another profile in this
159 * pom is activated using the command line -P option or by one of that profile's
160 * activators.
161 *
162 * @return a {@code boolean}
163 */
164 public boolean isActiveByDefault() {
165 return this.activeByDefault;
166 }
167
168 /**
169 * Specifies that this profile will be activated when a matching JDK is detected.
170 * For example, {@code 1.4} only activates on JDKs versioned 1.4,
171 * while {@code !1.4} matches any JDK that is not version 1.4. Ranges are supported too:
172 * {@code [1.5,)} activates when the JDK is 1.5 minimum.
173 *
174 * @return a {@code String}
175 */
176 public String getJdk() {
177 return this.jdk;
178 }
179
180 /**
181 * Specifies that this profile will be activated when matching operating system
182 * attributes are detected.
183 *
184 * @return a {@code ActivationOS}
185 */
186 public ActivationOS getOs() {
187 return this.os;
188 }
189
190 /**
191 * Specifies that this profile will be activated when this property is
192 * specified.
193 *
194 * @return a {@code ActivationProperty}
195 */
196 public ActivationProperty getProperty() {
197 return this.property;
198 }
199
200 /**
201 * Specifies that this profile will be activated based on existence of a file.
202 *
203 * @return a {@code ActivationFile}
204 */
205 public ActivationFile getFile() {
206 return this.file;
207 }
208
209 /**
210 * Specifies that this profile will be activated based on the project's packaging.
211 *
212 * @return a {@code String}
213 */
214 public String getPackaging() {
215 return this.packaging;
216 }
217
218 /**
219 * The condition which must be satisfied to activate the profile.
220 *
221 * @return a {@code String}
222 */
223 public String getCondition() {
224 return this.condition;
225 }
226
227 /**
228 * Gets the location of the specified field in the input source.
229 *
230 * @param key the key of the field, must not be {@code null}
231 * @return the location of the field in the input source or {@code null} if unknown
232 * @throws NullPointerException if {@code key} is {@code null}
233 */
234 public InputLocation getLocation(Object key) {
235 Objects.requireNonNull(key, "key");
236 return locations.get(key);
237 }
238
239 /**
240 * Gets the keys of the locations of the input source.
241 */
242 public Set<Object> getLocationKeys() {
243 return locations.keySet();
244 }
245
246 protected Stream<Object> getLocationKeyStream() {
247 return locations.keySet().stream();
248 }
249
250 /**
251 * Gets the input location that caused this model to be read.
252 */
253 public InputLocation getImportedFrom() {
254 return importedFrom;
255 }
256
257 /**
258 * Creates a new builder with this object as the basis.
259 *
260 * @return a {@code Builder}
261 */
262 @Nonnull
263 public Builder with() {
264 return newBuilder(this);
265 }
266 /**
267 * Creates a new {@code Activation} instance using the specified activeByDefault.
268 *
269 * @param activeByDefault the new {@code boolean} to use
270 * @return a {@code Activation} with the specified activeByDefault
271 */
272 @Nonnull
273 public Activation withActiveByDefault(boolean activeByDefault) {
274 return newBuilder(this, true).activeByDefault(activeByDefault).build();
275 }
276 /**
277 * Creates a new {@code Activation} instance using the specified jdk.
278 *
279 * @param jdk the new {@code String} to use
280 * @return a {@code Activation} with the specified jdk
281 */
282 @Nonnull
283 public Activation withJdk(String jdk) {
284 return newBuilder(this, true).jdk(jdk).build();
285 }
286 /**
287 * Creates a new {@code Activation} instance using the specified os.
288 *
289 * @param os the new {@code ActivationOS} to use
290 * @return a {@code Activation} with the specified os
291 */
292 @Nonnull
293 public Activation withOs(ActivationOS os) {
294 return newBuilder(this, true).os(os).build();
295 }
296 /**
297 * Creates a new {@code Activation} instance using the specified property.
298 *
299 * @param property the new {@code ActivationProperty} to use
300 * @return a {@code Activation} with the specified property
301 */
302 @Nonnull
303 public Activation withProperty(ActivationProperty property) {
304 return newBuilder(this, true).property(property).build();
305 }
306 /**
307 * Creates a new {@code Activation} instance using the specified file.
308 *
309 * @param file the new {@code ActivationFile} to use
310 * @return a {@code Activation} with the specified file
311 */
312 @Nonnull
313 public Activation withFile(ActivationFile file) {
314 return newBuilder(this, true).file(file).build();
315 }
316 /**
317 * Creates a new {@code Activation} instance using the specified packaging.
318 *
319 * @param packaging the new {@code String} to use
320 * @return a {@code Activation} with the specified packaging
321 */
322 @Nonnull
323 public Activation withPackaging(String packaging) {
324 return newBuilder(this, true).packaging(packaging).build();
325 }
326 /**
327 * Creates a new {@code Activation} instance using the specified condition.
328 *
329 * @param condition the new {@code String} to use
330 * @return a {@code Activation} with the specified condition
331 */
332 @Nonnull
333 public Activation withCondition(String condition) {
334 return newBuilder(this, true).condition(condition).build();
335 }
336
337 /**
338 * Creates a new {@code Activation} instance.
339 * Equivalent to {@code newInstance(true)}.
340 * @see #newInstance(boolean)
341 *
342 * @return a new {@code Activation}
343 */
344 @Nonnull
345 public static Activation newInstance() {
346 return newInstance(true);
347 }
348
349 /**
350 * Creates a new {@code Activation} instance using default values or not.
351 * Equivalent to {@code newBuilder(withDefaults).build()}.
352 *
353 * @param withDefaults the boolean indicating whether default values should be used
354 * @return a new {@code Activation}
355 */
356 @Nonnull
357 public static Activation newInstance(boolean withDefaults) {
358 return newBuilder(withDefaults).build();
359 }
360
361 /**
362 * Creates a new {@code Activation} builder instance.
363 * Equivalent to {@code newBuilder(true)}.
364 * @see #newBuilder(boolean)
365 *
366 * @return a new {@code Builder}
367 */
368 @Nonnull
369 public static Builder newBuilder() {
370 return newBuilder(true);
371 }
372
373 /**
374 * Creates a new {@code Activation} builder instance using default values or not.
375 *
376 * @param withDefaults the boolean indicating whether default values should be used
377 * @return a new {@code Builder}
378 */
379 @Nonnull
380 public static Builder newBuilder(boolean withDefaults) {
381 return new Builder(withDefaults);
382 }
383
384 /**
385 * Creates a new {@code Activation} builder instance using the specified object as a basis.
386 * Equivalent to {@code newBuilder(from, false)}.
387 *
388 * @param from the {@code Activation} instance to use as a basis
389 * @return a new {@code Builder}
390 */
391 @Nonnull
392 public static Builder newBuilder(Activation from) {
393 return newBuilder(from, false);
394 }
395
396 /**
397 * Creates a new {@code Activation} builder instance using the specified object as a basis.
398 *
399 * @param from the {@code Activation} instance to use as a basis
400 * @param forceCopy the boolean indicating if a copy should be forced
401 * @return a new {@code Builder}
402 */
403 @Nonnull
404 public static Builder newBuilder(Activation from, boolean forceCopy) {
405 return new Builder(from, forceCopy);
406 }
407
408 /**
409 * Builder class used to create Activation instances.
410 * @see #with()
411 * @see #newBuilder()
412 */
413 @NotThreadSafe
414 public static class Builder
415 {
416 Activation base;
417 Boolean activeByDefault;
418 String jdk;
419 ActivationOS os;
420 ActivationProperty property;
421 ActivationFile file;
422 String packaging;
423 String condition;
424 Map<Object, InputLocation> locations;
425 InputLocation importedFrom;
426
427 protected Builder(boolean withDefaults) {
428 if (withDefaults) {
429 this.activeByDefault = false;
430 }
431 }
432
433 protected Builder(Activation base, boolean forceCopy) {
434 if (forceCopy) {
435 this.activeByDefault = base.activeByDefault;
436 this.jdk = base.jdk;
437 this.os = base.os;
438 this.property = base.property;
439 this.file = base.file;
440 this.packaging = base.packaging;
441 this.condition = base.condition;
442 this.locations = base.locations;
443 this.importedFrom = base.importedFrom;
444 } else {
445 this.base = base;
446 }
447 }
448
449 @Nonnull
450 public Builder activeByDefault(boolean activeByDefault) {
451 this.activeByDefault = activeByDefault;
452 return this;
453 }
454
455 @Nonnull
456 public Builder jdk(String jdk) {
457 this.jdk = jdk;
458 return this;
459 }
460
461 @Nonnull
462 public Builder os(ActivationOS os) {
463 this.os = os;
464 return this;
465 }
466
467 @Nonnull
468 public Builder property(ActivationProperty property) {
469 this.property = property;
470 return this;
471 }
472
473 @Nonnull
474 public Builder file(ActivationFile file) {
475 this.file = file;
476 return this;
477 }
478
479 @Nonnull
480 public Builder packaging(String packaging) {
481 this.packaging = packaging;
482 return this;
483 }
484
485 @Nonnull
486 public Builder condition(String condition) {
487 this.condition = condition;
488 return this;
489 }
490
491
492 @Nonnull
493 public Builder location(Object key, InputLocation location) {
494 if (location != null) {
495 if (!(this.locations instanceof HashMap)) {
496 this.locations = this.locations != null ? new HashMap<>(this.locations) : new HashMap<>();
497 }
498 this.locations.put(key, location);
499 }
500 return this;
501 }
502
503 @Nonnull
504 public Builder importedFrom(InputLocation importedFrom) {
505 this.importedFrom = importedFrom;
506 return this;
507 }
508
509 @Nonnull
510 public Activation build() {
511 // this method should not contain any logic other than creating (or reusing) an object in order to ease subclassing
512 if (base != null
513 && (activeByDefault == null || activeByDefault == base.activeByDefault)
514 && (jdk == null || jdk == base.jdk)
515 && (os == null || os == base.os)
516 && (property == null || property == base.property)
517 && (file == null || file == base.file)
518 && (packaging == null || packaging == base.packaging)
519 && (condition == null || condition == base.condition)
520 ) {
521 return base;
522 }
523 return new Activation(this);
524 }
525
526 Map<Object, InputLocation> computeLocations() {
527 Map<Object, InputLocation> newlocs = locations != null ? locations : Map.of();
528 Map<Object, InputLocation> oldlocs = base != null ? base.locations : Map.of();
529 if (newlocs.isEmpty()) {
530 return Map.copyOf(oldlocs);
531 }
532 if (oldlocs.isEmpty()) {
533 return Map.copyOf(newlocs);
534 }
535 return Stream.concat(newlocs.entrySet().stream(), oldlocs.entrySet().stream())
536 // Keep value from newlocs in case of duplicates
537 .collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1));
538 }
539 }
540
541 }