1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.impl.model.profile;
20
21 import java.nio.file.Path;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.function.Function;
25
26 import org.apache.maven.api.di.Inject;
27 import org.apache.maven.api.di.Named;
28 import org.apache.maven.api.di.Singleton;
29 import org.apache.maven.api.model.Activation;
30 import org.apache.maven.api.model.Profile;
31 import org.apache.maven.api.services.BuilderProblem.Severity;
32 import org.apache.maven.api.services.ModelProblem.Version;
33 import org.apache.maven.api.services.ModelProblemCollector;
34 import org.apache.maven.api.services.VersionParser;
35 import org.apache.maven.api.services.model.ProfileActivationContext;
36 import org.apache.maven.api.services.model.ProfileActivator;
37 import org.apache.maven.api.services.model.RootLocator;
38 import org.apache.maven.internal.impl.model.DefaultInterpolator;
39 import org.apache.maven.internal.impl.model.ProfileActivationFilePathInterpolator;
40
41 import static org.apache.maven.internal.impl.model.profile.ConditionParser.toBoolean;
42
43
44
45
46
47 @Named("condition")
48 @Singleton
49 public class ConditionProfileActivator implements ProfileActivator {
50
51 private final VersionParser versionParser;
52 private final ProfileActivationFilePathInterpolator interpolator;
53 private final RootLocator rootLocator;
54
55
56
57
58
59
60
61
62 @Inject
63 public ConditionProfileActivator(
64 VersionParser versionParser, ProfileActivationFilePathInterpolator interpolator, RootLocator rootLocator) {
65 this.versionParser = versionParser;
66 this.interpolator = interpolator;
67 this.rootLocator = rootLocator;
68 }
69
70
71
72
73
74
75
76
77
78 @Override
79 public boolean isActive(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
80 if (profile.getActivation() == null || profile.getActivation().getCondition() == null) {
81 return false;
82 }
83 String condition = profile.getActivation().getCondition();
84 try {
85 Map<String, ConditionParser.ExpressionFunction> functions =
86 registerFunctions(context, versionParser, interpolator);
87 Function<String, String> propertyResolver = s -> property(context, rootLocator, s);
88 return toBoolean(new ConditionParser(functions, propertyResolver).parse(condition));
89 } catch (Exception e) {
90 problems.add(
91 Severity.ERROR, Version.V41, "Error parsing profile activation condition: " + e.getMessage(), e);
92 return false;
93 }
94 }
95
96
97
98
99
100
101
102
103
104 @Override
105 public boolean presentInConfig(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
106 Activation activation = profile.getActivation();
107 if (activation == null) {
108 return false;
109 }
110 return activation.getCondition() != null && !activation.getCondition().isBlank();
111 }
112
113
114
115
116
117
118
119
120
121 public static Map<String, ConditionParser.ExpressionFunction> registerFunctions(
122 ProfileActivationContext context,
123 VersionParser versionParser,
124 ProfileActivationFilePathInterpolator interpolator) {
125 Map<String, ConditionParser.ExpressionFunction> functions = new HashMap<>();
126
127 ConditionFunctions conditionFunctions = new ConditionFunctions(context, versionParser, interpolator);
128
129 for (java.lang.reflect.Method method : ConditionFunctions.class.getDeclaredMethods()) {
130 String methodName = method.getName();
131 if (methodName.endsWith("_")) {
132 methodName = methodName.substring(0, methodName.length() - 1);
133 }
134 final String finalMethodName = methodName;
135
136 functions.put(finalMethodName, args -> {
137 try {
138 return method.invoke(conditionFunctions, args);
139 } catch (Exception e) {
140 StringBuilder causeChain = new StringBuilder();
141 Throwable cause = e;
142 while (cause != null) {
143 if (!causeChain.isEmpty()) {
144 causeChain.append(" Caused by: ");
145 }
146 causeChain.append(cause.toString());
147 cause = cause.getCause();
148 }
149 throw new RuntimeException(
150 "Error invoking function '" + finalMethodName + "': " + e + ". Cause chain: " + causeChain,
151 e);
152 }
153 });
154 }
155
156 return functions;
157 }
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173 static String property(ProfileActivationContext context, RootLocator rootLocator, String name) {
174 String value = doGetProperty(context, rootLocator, name);
175 return new DefaultInterpolator().interpolate(value, s -> doGetProperty(context, rootLocator, s));
176 }
177
178 static String doGetProperty(ProfileActivationContext context, RootLocator rootLocator, String name) {
179
180 if ("project.basedir".equals(name)) {
181 Path basedir = context.getModel().getProjectDirectory();
182 return basedir != null ? basedir.toFile().getAbsolutePath() : null;
183 }
184 if ("project.rootDirectory".equals(name)) {
185 Path basedir = context.getModel().getProjectDirectory();
186 if (basedir != null) {
187 Path root = rootLocator.findMandatoryRoot(basedir);
188 return root.toFile().getAbsolutePath();
189 }
190 return null;
191 }
192 if ("project.artifactId".equals(name)) {
193 return context.getModel().getArtifactId();
194 }
195 if ("project.packaging".equals(name)) {
196 return context.getModel().getPackaging();
197 }
198
199
200 String v = context.getUserProperties().get(name);
201 if (v == null) {
202
203
204
205 v = context.getModel().getProperties().get(name);
206 }
207 if (v == null) {
208
209 v = context.getSystemProperties().get(name);
210 }
211 return v;
212 }
213 }