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 public InputLocation getLocation(Object key) { 231 return locations.get(key); 232 } 233 234 /** 235 * Gets the keys of the locations of the input source. 236 */ 237 public Set<Object> getLocationKeys() { 238 return locations.keySet(); 239 } 240 241 protected Stream<Object> getLocationKeyStream() { 242 return locations.keySet().stream(); 243 } 244 245 /** 246 * Gets the input location that caused this model to be read. 247 */ 248 public InputLocation getImportedFrom() 249 { 250 return importedFrom; 251 } 252 253 /** 254 * Creates a new builder with this object as the basis. 255 * 256 * @return a {@code Builder} 257 */ 258 @Nonnull 259 public Builder with() { 260 return newBuilder(this); 261 } 262 /** 263 * Creates a new {@code Activation} instance using the specified activeByDefault. 264 * 265 * @param activeByDefault the new {@code boolean} to use 266 * @return a {@code Activation} with the specified activeByDefault 267 */ 268 @Nonnull 269 public Activation withActiveByDefault(boolean activeByDefault) { 270 return newBuilder(this, true).activeByDefault(activeByDefault).build(); 271 } 272 /** 273 * Creates a new {@code Activation} instance using the specified jdk. 274 * 275 * @param jdk the new {@code String} to use 276 * @return a {@code Activation} with the specified jdk 277 */ 278 @Nonnull 279 public Activation withJdk(String jdk) { 280 return newBuilder(this, true).jdk(jdk).build(); 281 } 282 /** 283 * Creates a new {@code Activation} instance using the specified os. 284 * 285 * @param os the new {@code ActivationOS} to use 286 * @return a {@code Activation} with the specified os 287 */ 288 @Nonnull 289 public Activation withOs(ActivationOS os) { 290 return newBuilder(this, true).os(os).build(); 291 } 292 /** 293 * Creates a new {@code Activation} instance using the specified property. 294 * 295 * @param property the new {@code ActivationProperty} to use 296 * @return a {@code Activation} with the specified property 297 */ 298 @Nonnull 299 public Activation withProperty(ActivationProperty property) { 300 return newBuilder(this, true).property(property).build(); 301 } 302 /** 303 * Creates a new {@code Activation} instance using the specified file. 304 * 305 * @param file the new {@code ActivationFile} to use 306 * @return a {@code Activation} with the specified file 307 */ 308 @Nonnull 309 public Activation withFile(ActivationFile file) { 310 return newBuilder(this, true).file(file).build(); 311 } 312 /** 313 * Creates a new {@code Activation} instance using the specified packaging. 314 * 315 * @param packaging the new {@code String} to use 316 * @return a {@code Activation} with the specified packaging 317 */ 318 @Nonnull 319 public Activation withPackaging(String packaging) { 320 return newBuilder(this, true).packaging(packaging).build(); 321 } 322 /** 323 * Creates a new {@code Activation} instance using the specified condition. 324 * 325 * @param condition the new {@code String} to use 326 * @return a {@code Activation} with the specified condition 327 */ 328 @Nonnull 329 public Activation withCondition(String condition) { 330 return newBuilder(this, true).condition(condition).build(); 331 } 332 333 /** 334 * Creates a new {@code Activation} instance. 335 * Equivalent to {@code newInstance(true)}. 336 * @see #newInstance(boolean) 337 * 338 * @return a new {@code Activation} 339 */ 340 @Nonnull 341 public static Activation newInstance() { 342 return newInstance(true); 343 } 344 345 /** 346 * Creates a new {@code Activation} instance using default values or not. 347 * Equivalent to {@code newBuilder(withDefaults).build()}. 348 * 349 * @param withDefaults the boolean indicating whether default values should be used 350 * @return a new {@code Activation} 351 */ 352 @Nonnull 353 public static Activation newInstance(boolean withDefaults) { 354 return newBuilder(withDefaults).build(); 355 } 356 357 /** 358 * Creates a new {@code Activation} builder instance. 359 * Equivalent to {@code newBuilder(true)}. 360 * @see #newBuilder(boolean) 361 * 362 * @return a new {@code Builder} 363 */ 364 @Nonnull 365 public static Builder newBuilder() { 366 return newBuilder(true); 367 } 368 369 /** 370 * Creates a new {@code Activation} builder instance using default values or not. 371 * 372 * @param withDefaults the boolean indicating whether default values should be used 373 * @return a new {@code Builder} 374 */ 375 @Nonnull 376 public static Builder newBuilder(boolean withDefaults) { 377 return new Builder(withDefaults); 378 } 379 380 /** 381 * Creates a new {@code Activation} builder instance using the specified object as a basis. 382 * Equivalent to {@code newBuilder(from, false)}. 383 * 384 * @param from the {@code Activation} instance to use as a basis 385 * @return a new {@code Builder} 386 */ 387 @Nonnull 388 public static Builder newBuilder(Activation from) { 389 return newBuilder(from, false); 390 } 391 392 /** 393 * Creates a new {@code Activation} builder instance using the specified object as a basis. 394 * 395 * @param from the {@code Activation} instance to use as a basis 396 * @param forceCopy the boolean indicating if a copy should be forced 397 * @return a new {@code Builder} 398 */ 399 @Nonnull 400 public static Builder newBuilder(Activation from, boolean forceCopy) { 401 return new Builder(from, forceCopy); 402 } 403 404 /** 405 * Builder class used to create Activation instances. 406 * @see #with() 407 * @see #newBuilder() 408 */ 409 @NotThreadSafe 410 public static class Builder 411 { 412 Activation base; 413 Boolean activeByDefault; 414 String jdk; 415 ActivationOS os; 416 ActivationProperty property; 417 ActivationFile file; 418 String packaging; 419 String condition; 420 Map<Object, InputLocation> locations; 421 InputLocation importedFrom; 422 423 protected Builder(boolean withDefaults) { 424 if (withDefaults) { 425 this.activeByDefault = false; 426 } 427 } 428 429 protected Builder(Activation base, boolean forceCopy) { 430 if (forceCopy) { 431 this.activeByDefault = base.activeByDefault; 432 this.jdk = base.jdk; 433 this.os = base.os; 434 this.property = base.property; 435 this.file = base.file; 436 this.packaging = base.packaging; 437 this.condition = base.condition; 438 this.locations = base.locations; 439 this.importedFrom = base.importedFrom; 440 } else { 441 this.base = base; 442 } 443 } 444 445 @Nonnull 446 public Builder activeByDefault(boolean activeByDefault) { 447 this.activeByDefault = activeByDefault; 448 return this; 449 } 450 451 @Nonnull 452 public Builder jdk(String jdk) { 453 this.jdk = jdk; 454 return this; 455 } 456 457 @Nonnull 458 public Builder os(ActivationOS os) { 459 this.os = os; 460 return this; 461 } 462 463 @Nonnull 464 public Builder property(ActivationProperty property) { 465 this.property = property; 466 return this; 467 } 468 469 @Nonnull 470 public Builder file(ActivationFile file) { 471 this.file = file; 472 return this; 473 } 474 475 @Nonnull 476 public Builder packaging(String packaging) { 477 this.packaging = packaging; 478 return this; 479 } 480 481 @Nonnull 482 public Builder condition(String condition) { 483 this.condition = condition; 484 return this; 485 } 486 487 488 @Nonnull 489 public Builder location(Object key, InputLocation location) { 490 if (location != null) { 491 if (!(this.locations instanceof HashMap)) { 492 this.locations = this.locations != null ? new HashMap<>(this.locations) : new HashMap<>(); 493 } 494 this.locations.put(key, location); 495 } 496 return this; 497 } 498 499 @Nonnull 500 public Builder importedFrom(InputLocation importedFrom) { 501 this.importedFrom = importedFrom; 502 return this; 503 } 504 505 @Nonnull 506 public Activation build() { 507 // this method should not contain any logic other than creating (or reusing) an object in order to ease subclassing 508 if (base != null 509 && (activeByDefault == null || activeByDefault == base.activeByDefault) 510 && (jdk == null || jdk == base.jdk) 511 && (os == null || os == base.os) 512 && (property == null || property == base.property) 513 && (file == null || file == base.file) 514 && (packaging == null || packaging == base.packaging) 515 && (condition == null || condition == base.condition) 516 ) { 517 return base; 518 } 519 return new Activation(this); 520 } 521 522 Map<Object, InputLocation> computeLocations() { 523 Map<Object, InputLocation> newlocs = locations != null ? locations : Map.of(); 524 Map<Object, InputLocation> oldlocs = base != null ? base.locations : Map.of(); 525 if (newlocs.isEmpty()) { 526 return Map.copyOf(oldlocs); 527 } 528 if (oldlocs.isEmpty()) { 529 return Map.copyOf(newlocs); 530 } 531 return Stream.concat(newlocs.entrySet().stream(), oldlocs.entrySet().stream()) 532 // Keep value from newlocs in case of duplicates 533 .collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1)); 534 } 535 } 536 537 }