| @@ -3,6 +3,7 | |||||
| 3 | "java.compile.nullAnalysis.mode": "automatic", |
|
3 | "java.compile.nullAnalysis.mode": "automatic", | |
| 4 | "cSpell.words": [ |
|
4 | "cSpell.words": [ | |
| 5 | "implab", |
|
5 | "implab", | |
|
|
6 | "materializer", | |||
| 6 | "rawtypes" |
|
7 | "rawtypes" | |
| 7 | ] |
|
8 | ] | |
| 8 | } No newline at end of file |
|
9 | } | |
| @@ -10,3 +10,33 | |||||
| 10 | - `find*` ΡΠ°ΡΡΠΌΠ°ΡΡΠΈΠ²Π°Π΅ΡΡΡ ΠΊΠ°ΠΊ ΡΠΈΠ½ΠΎΠ½ΠΈΠΌ legacy `get*` (ΠΏΠΎΠΈΡΠΊ Π±Π΅Π· `fail-fast`). |
|
10 | - `find*` ΡΠ°ΡΡΠΌΠ°ΡΡΠΈΠ²Π°Π΅ΡΡΡ ΠΊΠ°ΠΊ ΡΠΈΠ½ΠΎΠ½ΠΈΠΌ legacy `get*` (ΠΏΠΎΠΈΡΠΊ Π±Π΅Π· `fail-fast`). | |
| 11 | - `require*` ΡΡΠΎ `find*` + `fail-fast` Ρ ΠΏΠΎΠ½ΡΡΠ½ΠΎΠΉ ΠΎΡΠΈΠ±ΠΊΠΎΠΉ Π² ΠΌΠ΅ΡΡΠ΅ Π²ΡΠ·ΠΎΠ²Π°. |
|
11 | - `require*` ΡΡΠΎ `find*` + `fail-fast` Ρ ΠΏΠΎΠ½ΡΡΠ½ΠΎΠΉ ΠΎΡΠΈΠ±ΠΊΠΎΠΉ Π² ΠΌΠ΅ΡΡΠ΅ Π²ΡΠ·ΠΎΠ²Π°. | |
| 12 | - ΠΠ»Ρ Π½ΠΎΠ²ΠΎΠ³ΠΎ API ΠΏΡΠ΅Π΄ΠΏΠΎΡΡΠΈΡΠ΅Π»ΡΠ½Ρ ΡΠΎΡΠΌΡ `find/require`; Π½ΠΎΠ²ΡΠ΅ `get*` ΠΏΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ Π½Π΅ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡ. |
|
12 | - ΠΠ»Ρ Π½ΠΎΠ²ΠΎΠ³ΠΎ API ΠΏΡΠ΅Π΄ΠΏΠΎΡΡΠΈΡΠ΅Π»ΡΠ½Ρ ΡΠΎΡΠΌΡ `find/require`; Π½ΠΎΠ²ΡΠ΅ `get*` ΠΏΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ Π½Π΅ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡ. | |
|
|
13 | ||||
|
|
14 | ## Identity-first modeling | |||
|
|
15 | ||||
|
|
16 | Prefer an **identity-first** split between: | |||
|
|
17 | ||||
|
|
18 | - **identity objects** used for discovery and selection | |||
|
|
19 | - **stateful/materialized objects** obtained through separate API calls | |||
|
|
20 | ||||
|
|
21 | ### Rules | |||
|
|
22 | ||||
|
|
23 | - Objects intended for replayable observation (`all(...)`, similar collection APIs) should be **identity objects**. | |||
|
|
24 | - Identity objects must be: | |||
|
|
25 | - cheap to create | |||
|
|
26 | - effectively immutable | |||
|
|
27 | - limited to identity and cheap selection metadata | |||
|
|
28 | - Heavy, computed, provider-based, or runtime-bound state must be resolved separately. | |||
|
|
29 | - Aggregate content should be accessed through dedicated lookup/materialization APIs. | |||
|
|
30 | - Eager observation of identity is acceptable. | |||
|
|
31 | - Eager observation of computed state is not. | |||
|
|
32 | ||||
|
|
33 | ### Do not | |||
|
|
34 | ||||
|
|
35 | - Do not store heavy computed state inside identity objects. | |||
|
|
36 | - Do not store runtime references to foreign domains inside identity objects. | |||
|
|
37 | - Do not use custom events when replayable identity registries plus on-demand lookup are sufficient. | |||
|
|
38 | ||||
|
|
39 | ### Rule of thumb | |||
|
|
40 | ||||
|
|
41 | **Identity objects contain selection metadata. | |||
|
|
42 | Aggregate content is obtained separately, on demand.** | |||
| @@ -5,6 +5,7 import java.util.function.Supplier; | |||||
| 5 |
|
5 | |||
| 6 | public class LazyValue<T> implements Supplier<T> { |
|
6 | public class LazyValue<T> implements Supplier<T> { | |
| 7 | private volatile T value; |
|
7 | private volatile T value; | |
|
|
8 | private volatile boolean initialized = false; | |||
| 8 |
|
9 | |||
| 9 | private final Supplier<T> innerSupplier; |
|
10 | private final Supplier<T> innerSupplier; | |
| 10 |
|
11 | |||
| @@ -15,7 +16,7 public class LazyValue<T> implements Sup | |||||
| 15 | @Override |
|
16 | @Override | |
| 16 | public T get() { |
|
17 | public T get() { | |
| 17 | var v = value; |
|
18 | var v = value; | |
| 18 |
if ( |
|
19 | if (initialized) { | |
| 19 | return v; |
|
20 | return v; | |
| 20 | } |
|
21 | } | |
| 21 |
|
22 | |||
| @@ -50,6 +50,11 public class Strings { | |||||
| 50 | throw new IllegalArgumentException(String.format("Argument %s can't be null or blank", argumentName)); |
|
50 | throw new IllegalArgumentException(String.format("Argument %s can't be null or blank", argumentName)); | |
| 51 | } |
|
51 | } | |
| 52 |
|
52 | |||
|
|
53 | public static String requireNonBlank(String value) { | |||
|
|
54 | argumentNotNullOrBlank(value, "value"); | |||
|
|
55 | return value; | |||
|
|
56 | } | |||
|
|
57 | ||||
| 53 | public static String sanitizeName(String value) { |
|
58 | public static String sanitizeName(String value) { | |
| 54 | return INVALID_NAME_CHAR.matcher(value).replaceAll("_"); |
|
59 | return INVALID_NAME_CHAR.matcher(value).replaceAll("_"); | |
| 55 | } |
|
60 | } | |
| @@ -7,11 +7,9 import org.implab.gradle.variants.model. | |||||
| 7 | public abstract class VariantsPlugin implements Plugin<Project> { |
|
7 | public abstract class VariantsPlugin implements Plugin<Project> { | |
| 8 | @Override |
|
8 | @Override | |
| 9 | public void apply(Project target) { |
|
9 | public void apply(Project target) { | |
| 10 | var extension = target.getExtensions().create("variants", VariantsExtension.class); |
|
|||
| 11 |
|
10 | |||
| 12 | target.afterEvaluate(project -> { |
|
11 | target.getExtensions().create("variants", VariantsExtension.class); | |
| 13 |
|
||||
| 14 | }); |
|
|||
| 15 |
|
12 | |||
| 16 | } |
|
13 | } | |
|
|
14 | ||||
| 17 | } |
|
15 | } | |
| @@ -1,35 +1,8 | |||||
| 1 | package org.implab.gradle.variants.model; |
|
1 | package org.implab.gradle.variants.model; | |
| 2 |
|
2 | |||
| 3 | import org.gradle.api.Named; |
|
3 | /** A binding between a role and a layer inside a specific variant. | |
| 4 | import org.gradle.api.provider.SetProperty; |
|
|||
| 5 |
|
||||
| 6 | /** |
|
|||
| 7 | * Binds a role to a set of layers inside a particular variant. |
|
|||
| 8 | * |
|
4 | * | |
| 9 | * The binding name is the role name, e.g. "production", "test", "tool". |
|
5 | * @see {@link VariantDefinition} for the context of this binding. | |
| 10 | */ |
|
|||
| 11 | public interface RoleBinding extends Named { |
|
|||
| 12 |
|
||||
| 13 | /** |
|
|||
| 14 | * Layer names participating in this (variant, role) selection. |
|
|||
| 15 | * |
|
|||
| 16 | * Core model keeps names here deliberately: |
|
|||
| 17 | * source/materialization semantics live elsewhere. |
|
|||
| 18 | */ |
|
6 | */ | |
| 19 | SetProperty<String> getLayerNames(); |
|
7 | public record RoleLayerBinding(String name, String layerName) { | |
| 20 |
|
||||
| 21 | /** |
|
|||
| 22 | * Adds one layer to this binding. |
|
|||
| 23 | */ |
|
|||
| 24 | void layer(String name); |
|
|||
| 25 |
|
||||
| 26 | /** |
|
|||
| 27 | * Adds several layers to this binding. |
|
|||
| 28 | */ |
|
|||
| 29 | void layers(String... names); |
|
|||
| 30 |
|
||||
| 31 | /** |
|
|||
| 32 | * Adds several layers to this binding. |
|
|||
| 33 | */ |
|
|||
| 34 | void layers(Iterable<String> names); |
|
|||
| 35 | } No newline at end of file |
|
8 | } | |
| @@ -1,11 +1,6 | |||||
| 1 | package org.implab.gradle.variants.model; |
|
1 | package org.implab.gradle.variants.model; | |
| 2 |
|
2 | |||
| 3 | import org.gradle.api.Action; |
|
|||
| 4 | import org.gradle.api.Named; |
|
3 | import org.gradle.api.Named; | |
| 5 | import org.gradle.api.NamedDomainObjectContainer; |
|
|||
| 6 | import org.implab.gradle.common.core.lang.Closures; |
|
|||
| 7 |
|
||||
| 8 | import groovy.lang.Closure; |
|
|||
| 9 |
|
4 | |||
| 10 | /** |
|
5 | /** | |
| 11 | * A named variant, e.g. "browser", "electron". |
|
6 | * A named variant, e.g. "browser", "electron". | |
| @@ -14,31 +9,4 import groovy.lang.Closure; | |||||
| 14 | * It owns a set of role bindings. |
|
9 | * It owns a set of role bindings. | |
| 15 | */ |
|
10 | */ | |
| 16 | public interface Variant extends Named { |
|
11 | public interface Variant extends Named { | |
| 17 |
|
||||
| 18 | /** |
|
|||
| 19 | * Role bindings declared inside this variant. |
|
|||
| 20 | * |
|
|||
| 21 | * The binding name is the role name. |
|
|||
| 22 | */ |
|
|||
| 23 | NamedDomainObjectContainer<RoleBinding> getRoleBindings(); |
|
|||
| 24 |
|
||||
| 25 | /** |
|
|||
| 26 | * Creates or returns an existing role binding and configures it. |
|
|||
| 27 | */ |
|
|||
| 28 | default RoleBinding role(String name) { |
|
|||
| 29 | return getRoleBindings().maybeCreate(name); |
|
|||
| 30 | } |
|
|||
| 31 |
|
||||
| 32 | /** |
|
|||
| 33 | * Creates or returns an existing role binding and configures it. |
|
|||
| 34 | */ |
|
|||
| 35 | default RoleBinding role(String name, Action<? super RoleBinding> action) { |
|
|||
| 36 | var role = role(name); |
|
|||
| 37 | action.execute(role); |
|
|||
| 38 | return role; |
|
|||
| 39 | } |
|
|||
| 40 |
|
||||
| 41 | default RoleBinding role(String name, Closure<?> closure) { |
|
|||
| 42 | return role(name, Closures.action(closure)); |
|
|||
| 43 | } |
|
|||
| 44 | } No newline at end of file |
|
12 | } | |
| @@ -33,27 +33,33 public interface VariantsExtension { | |||||
| 33 | NamedDomainObjectContainer<Role> getRoles(); |
|
33 | NamedDomainObjectContainer<Role> getRoles(); | |
| 34 |
|
34 | |||
| 35 | /** |
|
35 | /** | |
|
|
36 | * Domain of variants. | |||
|
|
37 | */ | |||
|
|
38 | NamedDomainObjectContainer<Variant> getVariants(); | |||
|
|
39 | ||||
|
|
40 | /** | |||
| 36 | * Declared variants. |
|
41 | * Declared variants. | |
| 37 | */ |
|
42 | */ | |
| 38 | NamedDomainObjectContainer<Variant> getVariantDefinitions(); |
|
43 | NamedDomainObjectContainer<VariantDefinition> getVariantDefinitions(); | |
| 39 |
|
44 | |||
| 40 | /** |
|
45 | /** | |
| 41 | * Creates or returns an existing variant and configures it. |
|
46 | * Creates or returns an existing variant and configures it. | |
| 42 | */ |
|
47 | */ | |
| 43 | default Variant variant(String name) { |
|
48 | default VariantDefinition variant(String name) { | |
|
|
49 | ||||
| 44 | return getVariantDefinitions().maybeCreate(name); |
|
50 | return getVariantDefinitions().maybeCreate(name); | |
| 45 | } |
|
51 | } | |
| 46 |
|
52 | |||
| 47 | /** |
|
53 | /** | |
| 48 | * Creates or returns an existing variant and configures it. |
|
54 | * Creates or returns an existing variant and configures it. | |
| 49 | */ |
|
55 | */ | |
| 50 | default Variant variant(String name, Action<? super Variant> action) { |
|
56 | default VariantDefinition variant(String name, Action<? super VariantDefinition> action) { | |
| 51 | var variant = variant(name); |
|
57 | var variant = variant(name); | |
| 52 | action.execute(variant); |
|
58 | action.execute(variant); | |
| 53 | return variant; |
|
59 | return variant; | |
| 54 | } |
|
60 | } | |
| 55 |
|
61 | |||
| 56 | default Variant variant(String name, Closure<?> closure) { |
|
62 | default VariantDefinition variant(String name, Closure<?> closure) { | |
| 57 | return variant(name, Closures.action(closure)); |
|
63 | return variant(name, Closures.action(closure)); | |
| 58 | } |
|
64 | } | |
| 59 | } No newline at end of file |
|
65 | } | |
General Comments 0
You need to be logged in to leave comments.
Login now
