1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.micronaut.build.testresources;
17
18 import com.fasterxml.jackson.core.JsonProcessingException;
19 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
20 import io.micronaut.build.RunMojo;
21 import org.apache.maven.AbstractMavenLifecycleParticipant;
22 import org.apache.maven.execution.MavenSession;
23 import org.apache.maven.model.Build;
24 import org.apache.maven.model.Dependency;
25 import org.apache.maven.model.Plugin;
26 import org.apache.maven.plugin.MojoExecution;
27 import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
28 import org.apache.maven.project.MavenProject;
29 import org.codehaus.plexus.component.annotations.Component;
30 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
31 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
32 import org.codehaus.plexus.logging.Logger;
33 import org.codehaus.plexus.util.xml.Xpp3Dom;
34 import org.codehaus.plexus.util.xml.Xpp3DomWriter;
35 import org.eclipse.aether.util.artifact.JavaScopes;
36 import org.twdata.maven.mojoexecutor.MojoExecutor;
37
38 import javax.inject.Inject;
39 import java.io.File;
40 import java.io.StringWriter;
41 import java.io.Writer;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.concurrent.ConcurrentHashMap;
45 import java.util.function.Consumer;
46
47 import static io.micronaut.build.RunMojo.THIS_PLUGIN;
48 import static io.micronaut.build.services.DependencyResolutionService.TEST_RESOURCES_ARTIFACT_ID_PREFIX;
49 import static io.micronaut.build.services.DependencyResolutionService.TEST_RESOURCES_GROUP;
50 import static io.micronaut.build.testresources.AbstractTestResourcesMojo.CONFIG_PROPERTY_PREFIX;
51 import static io.micronaut.build.testresources.StopTestResourcesServerMojo.MICRONAUT_TEST_RESOURCES_KEEPALIVE;
52
53
54
55
56
57 @Component(role = AbstractMavenLifecycleParticipant.class, hint = "test-resources")
58 public class TestResourcesLifecycleExtension extends AbstractMavenLifecycleParticipant {
59
60 private static final String EXPLICIT_START_SERVICE_GOAL_NAME = "mn:" + StartTestResourcesServerMojo.NAME;
61 private static final String EXPLICIT_STOP_SERVICE_GOAL_NAME = "mn:" + StopTestResourcesServerMojo.NAME;
62
63 private final Map<MavenProject, ExpressionEvaluator> perProjectEvaluator = new ConcurrentHashMap<>();
64 private final Map<MavenProject, TestResourcesConfiguration> perProjectConfiguration = new ConcurrentHashMap<>();
65
66 private final Logger logger;
67 private final XmlMapper mapper;
68
69 @Inject
70 @SuppressWarnings("CdiInjectionPointsInspection")
71 public TestResourcesLifecycleExtension(Logger logger, XmlMapper mapper) {
72 this.logger = logger;
73 this.mapper = mapper;
74 }
75
76 @Override
77 public void afterProjectsRead(MavenSession session) {
78 session.getAllProjects().forEach(currentProject -> {
79 Build build = currentProject.getBuild();
80 withPlugin(build, plugin -> {
81 ExpressionEvaluator evaluator = perProjectEvaluator.computeIfAbsent(currentProject, p -> initEvaluator(p, session));
82 TestResourcesConfiguration configuration = perProjectConfiguration.computeIfAbsent(currentProject, mavenProject -> initConfiguration(plugin));
83
84 boolean enabled = isEnabled(evaluator, configuration);
85 if (enabled) {
86 List<String> goals = session.getGoals();
87 if (goals.stream().anyMatch(EXPLICIT_START_SERVICE_GOAL_NAME::equals)) {
88
89
90 Xpp3Dom flag = new Xpp3Dom(MICRONAUT_TEST_RESOURCES_KEEPALIVE);
91 Xpp3Dom pluginConfiguration = (Xpp3Dom) plugin.getConfiguration();
92 pluginConfiguration.addChild(flag);
93 flag.setValue("true");
94 }
95 Dependency clientDependency = new Dependency();
96 clientDependency.setGroupId(TEST_RESOURCES_GROUP);
97 clientDependency.setArtifactId(TEST_RESOURCES_ARTIFACT_ID_PREFIX + "client");
98 clientDependency.setVersion(String.valueOf(currentProject.getProperties().get(CONFIG_PROPERTY_PREFIX + "version")));
99 clientDependency.setScope(JavaScopes.TEST);
100 currentProject.getDependencies().add(clientDependency);
101 }
102 });
103 });
104 }
105
106 @Override
107 public void afterSessionEnd(MavenSession session) {
108 if (session.getGoals().stream().noneMatch(s -> s.equals(EXPLICIT_START_SERVICE_GOAL_NAME) || s.equals(EXPLICIT_STOP_SERVICE_GOAL_NAME))) {
109 session.getAllProjects().forEach(currentProject -> {
110 Build build = currentProject.getBuild();
111 withPlugin(build, plugin -> {
112 ExpressionEvaluator evaluator = perProjectEvaluator.computeIfAbsent(currentProject, p -> initEvaluator(p, session));
113 TestResourcesConfiguration configuration = perProjectConfiguration.computeIfAbsent(currentProject, mavenProject -> initConfiguration(plugin));
114 boolean enabled = isEnabled(evaluator, configuration);
115 boolean keepAlive = isKeepAlive(evaluator, configuration);
116 boolean shared = isShared(evaluator, configuration);
117 File buildDirectory = new File(build.getDirectory());
118
119 TestResourcesHelper helper = new TestResourcesHelper(enabled, keepAlive, shared, buildDirectory);
120 if (shared) {
121 String sharedServerNamespace = findSharedServerNamespace(evaluator, configuration);
122 helper.setSharedServerNamespace(sharedServerNamespace);
123 }
124 try {
125 helper.stop();
126 } catch (Exception e) {
127 logger.error(e.getMessage(), e);
128 }
129 });
130 });
131 }
132 }
133
134 private String findSharedServerNamespace(ExpressionEvaluator evaluator, TestResourcesConfiguration configuration) {
135 try {
136 String result = (String) evaluator.evaluate("${" + CONFIG_PROPERTY_PREFIX + "namespace" + "}");
137 if (result != null) {
138 return result;
139 } else if (configuration != null) {
140 return configuration.getSharedServerNamespace();
141 }
142 } catch (ExpressionEvaluationException e) {
143 return null;
144 }
145 return null;
146 }
147
148 private boolean isShared(ExpressionEvaluator evaluator, TestResourcesConfiguration configuration) {
149 Boolean result = evaluateBooleanProperty(evaluator, CONFIG_PROPERTY_PREFIX + "shared");
150 if (result != null) {
151 return result;
152 } else if (configuration != null) {
153 return configuration.isShared();
154 }
155 return false;
156 }
157
158 private boolean isKeepAlive(ExpressionEvaluator evaluator, TestResourcesConfiguration configuration) {
159 Boolean result = evaluateBooleanProperty(evaluator, MICRONAUT_TEST_RESOURCES_KEEPALIVE);
160 if (result != null) {
161 return result;
162 } else if (configuration != null) {
163 return configuration.isKeepAlive();
164 }
165 return false;
166 }
167
168 private boolean isEnabled(ExpressionEvaluator evaluator, TestResourcesConfiguration configuration) {
169 Boolean result = evaluateBooleanProperty(evaluator, CONFIG_PROPERTY_PREFIX + "enabled");
170 if (result != null) {
171 return result;
172 } else if (configuration != null) {
173 return configuration.isTestResourcesEnabled();
174 }
175 return false;
176 }
177
178 private TestResourcesConfiguration initConfiguration(Plugin plugin) {
179 Xpp3Dom configuration = (Xpp3Dom) plugin.getConfiguration();
180 if (configuration == null) {
181 configuration = MojoExecutor.configuration();
182 plugin.setConfiguration(configuration);
183 }
184 Writer writer = new StringWriter();
185 Xpp3DomWriter.write(writer, configuration);
186 try {
187 return mapper.readValue(writer.toString(), TestResourcesConfiguration.class);
188 } catch (JsonProcessingException e) {
189 logger.error(e.getMessage(), e);
190 return new TestResourcesConfiguration();
191 }
192 }
193
194 private Boolean evaluateBooleanProperty(ExpressionEvaluator evaluator, String property) {
195 try {
196 Object result = evaluator.evaluate("${" + property + "}");
197 if (result instanceof Boolean) {
198 return (Boolean) result;
199 } else if (result instanceof String && (result.equals(Boolean.TRUE.toString()) || result.equals(Boolean.FALSE.toString()))) {
200 return Boolean.parseBoolean((String) result);
201 }
202 } catch (ExpressionEvaluationException e) {
203 return false;
204 }
205 return null;
206 }
207
208 private ExpressionEvaluator initEvaluator(MavenProject currentProject, MavenSession session) {
209 Plugin thisPlugin = currentProject.getPlugin(THIS_PLUGIN);
210 MojoExecution execution = new MojoExecution(thisPlugin, null, null);
211 MavenProject actualCurrentProject = session.getCurrentProject();
212 ExpressionEvaluator evaluator;
213
214
215
216 synchronized (perProjectEvaluator) {
217 session.setCurrentProject(currentProject);
218 evaluator = new PluginParameterExpressionEvaluator(session, execution);
219 session.setCurrentProject(actualCurrentProject);
220 }
221
222 return evaluator;
223 }
224
225 private static void withPlugin(Build build, Consumer<? super Plugin> consumer) {
226 build.getPlugins()
227 .stream()
228 .filter(p -> RunMojo.THIS_PLUGIN.equals(p.getGroupId() + ":" + p.getArtifactId()))
229 .findFirst()
230 .ifPresent(consumer);
231 }
232 }