]> git.argeo.org Git - gpl/argeo-slc.git/blob - org.argeo.slc.agent/src/main/java/org/argeo/slc/ant/AntSlcApplication.java
Introduce automated integration tests on the web app
[gpl/argeo-slc.git] / org.argeo.slc.agent / src / main / java / org / argeo / slc / ant / AntSlcApplication.java
1 package org.argeo.slc.ant;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Properties;
9 import java.util.StringTokenizer;
10 import java.util.Vector;
11
12 import org.apache.commons.io.IOUtils;
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15 import org.apache.log4j.Appender;
16 import org.apache.log4j.LogManager;
17 import org.apache.log4j.MDC;
18 import org.apache.tools.ant.BuildListener;
19 import org.apache.tools.ant.Project;
20 import org.apache.tools.ant.ProjectHelper;
21 import org.apache.tools.ant.helper.ProjectHelper2;
22 import org.apache.tools.ant.listener.CommonsLoggingListener;
23 import org.argeo.slc.core.SlcException;
24 import org.argeo.slc.core.process.SlcExecution;
25 import org.argeo.slc.core.structure.SimpleSElement;
26 import org.argeo.slc.core.structure.StructureRegistry;
27 import org.argeo.slc.core.structure.tree.TreeSPath;
28 import org.argeo.slc.core.structure.tree.TreeSRegistry;
29 import org.argeo.slc.logging.Log4jUtils;
30 import org.argeo.slc.runtime.SlcExecutionOutput;
31 import org.springframework.beans.factory.ListableBeanFactory;
32 import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
33 import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
34 import org.springframework.context.ApplicationContext;
35 import org.springframework.context.ConfigurableApplicationContext;
36 import org.springframework.context.support.GenericApplicationContext;
37 import org.springframework.core.io.DefaultResourceLoader;
38 import org.springframework.core.io.Resource;
39 import org.springframework.core.io.ResourceLoader;
40 import org.springframework.util.SystemPropertyUtils;
41
42 public class AntSlcApplication {
43 private final static String DEFAULT_APP_LOG4J_PROPERTIES = "org/argeo/slc/ant/defaultAppLog4j.properties";
44
45 private final static Log log = LogFactory.getLog(AntSlcApplication.class);
46
47 private Resource contextLocation;
48 private ApplicationContext parentContext;
49
50 private Resource rootDir;
51 private Resource confDir;
52 private File workDir;
53
54 public void execute(SlcExecution slcExecution, Properties properties,
55 Map<String, Object> references,
56 SlcExecutionOutput<AntExecutionContext> executionOutput) {
57
58 // Properties and application logging initialization
59 initSystemProperties(properties);
60 Log4jUtils.initLog4j("classpath:" + DEFAULT_APP_LOG4J_PROPERTIES);
61
62 log.info("\n###\n### Start SLC execution " + slcExecution.getUuid()
63 + "\n###\n");
64 if (log.isDebugEnabled()) {
65 log.debug("rootDir=" + rootDir);
66 log.debug("confDir=" + confDir);
67 log.debug("workDir=" + workDir);
68 }
69
70 // Spring initialization
71 ConfigurableApplicationContext ctx = createExecutionContext(slcExecution);
72
73 // Ant coordinates
74 String scriptRelativePath = findAntScript(slcExecution);
75 List<String> targets = findAntTargets(slcExecution);
76
77 // Ant project initialization
78 Project project = new Project();
79 AntExecutionContext executionContext = new AntExecutionContext(project);
80 project.addReference(AntConstants.REF_ROOT_CONTEXT, ctx);
81 project.addReference(AntConstants.REF_SLC_EXECUTION, slcExecution);
82 initProject(project, properties, references);
83 parseProject(project, scriptRelativePath);
84
85 // Execute project
86 initStructure(project, scriptRelativePath);
87 runProject(project, targets);
88
89 if (executionOutput != null)
90 executionOutput.postExecution(executionContext);
91
92 ctx.close();
93 }
94
95 protected void initSystemProperties(Properties userProperties) {
96 // Set user properties as system properties so that Spring can access
97 // them
98 if (userProperties != null) {
99 for (Object key : userProperties.keySet()) {
100 System.setProperty(key.toString(), userProperties
101 .getProperty(key.toString()));
102 }
103 }
104
105 if (System.getProperty(AntConstants.DEFAULT_TEST_RUN_PROPERTY) == null) {
106 System.setProperty(AntConstants.DEFAULT_TEST_RUN_PROPERTY,
107 "defaultTestRun");
108 }
109
110 try {
111 if (rootDir != null)
112 System.setProperty(AntConstants.ROOT_DIR_PROPERTY, rootDir
113 .getURL().toString());
114 if (confDir != null)
115 System.setProperty(AntConstants.CONF_DIR_PROPERTY, confDir
116 .getURL().toString());
117 if (workDir != null)
118 System.setProperty(AntConstants.WORK_DIR_PROPERTY, workDir
119 .getCanonicalPath());
120
121 // Additional properties in slc.properties file. Already set sytem
122 // properties (such as the various directories) can be resolved in
123 // placeholders.
124 if (confDir != null) {
125 Resource slcPropertiesRes = confDir
126 .createRelative("slc.properties");
127 if (slcPropertiesRes.exists()) {
128 Properties slcProperties = new Properties();
129 InputStream in = slcPropertiesRes.getInputStream();
130 try {
131 slcProperties.load(in);
132 } finally {
133 IOUtils.closeQuietly(in);
134 }
135
136 for (String key : slcProperties.stringPropertyNames()) {
137 if (!System.getProperties().containsKey(key)) {
138 String value = SystemPropertyUtils
139 .resolvePlaceholders(slcProperties
140 .getProperty(key));
141 System.setProperty(key, value);
142 }
143 }
144 }
145 }
146 } catch (Exception e) {
147 throw new SlcException("Cannot init system properties.", e);
148 }
149 }
150
151 protected ConfigurableApplicationContext createExecutionContext(
152 SlcExecution slcExecution) {
153 try {
154
155 // Find runtime definition
156 Resource runtimeRes = null;
157 String runtimeStr = slcExecution.getAttributes().get(
158 AntConstants.EXECATTR_RUNTIME);
159 if (runtimeStr == null)
160 runtimeStr = "default";
161
162 ResourceLoader rl = new DefaultResourceLoader(getClass()
163 .getClassLoader());
164 try {// tries absolute reference
165 runtimeRes = rl.getResource(runtimeStr);
166 } catch (Exception e) {
167 // silent
168 }
169 if (runtimeRes == null || !runtimeRes.exists()) {
170 if (confDir != null)
171 runtimeRes = confDir.createRelative("runtime/" + runtimeStr
172 + ".xml");
173 }
174
175 // Find runtime independent application context definition
176 if (confDir != null && contextLocation == null) {
177 contextLocation = confDir
178 .createRelative("applicationContext.xml");
179 }
180
181 GenericApplicationContext ctx = new GenericApplicationContext(
182 parentContext);
183 ctx.setDisplayName("SLC Execution #" + slcExecution.getUuid());
184
185 XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
186 if (runtimeRes != null && runtimeRes.exists())
187 xmlReader.loadBeanDefinitions(runtimeRes);
188 else
189 log.warn("No runtime context defined");
190
191 if (contextLocation != null && contextLocation.exists())
192 xmlReader.loadBeanDefinitions(contextLocation);
193 else
194 log.warn("No runtime independent application context defined");
195
196 // Add property place holder
197 PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
198 ppc.setIgnoreUnresolvablePlaceholders(true);
199 ctx.addBeanFactoryPostProcessor(ppc);
200
201 ctx.refresh();
202 return ctx;
203 } catch (Exception e) {
204 throw new SlcException(
205 "Cannot create SLC execution application context.", e);
206 }
207 }
208
209 protected String findAntScript(SlcExecution slcExecution) {
210 String scriptStr = slcExecution.getAttributes().get(
211 AntConstants.EXECATTR_ANT_FILE);
212 if (scriptStr == null)
213 throw new SlcException("No Ant script provided");
214
215 return scriptStr;
216 }
217
218 protected List<String> findAntTargets(SlcExecution slcExecution) {
219 String targetList = slcExecution.getAttributes().get(
220 AntConstants.EXECATTR_ANT_TARGETS);
221 List<String> targets = new Vector<String>();
222 if (targetList != null) {
223 StringTokenizer stTargets = new StringTokenizer(targetList, ",");
224 while (stTargets.hasMoreTokens()) {
225 targets.add(stTargets.nextToken());
226 }
227 }
228 return targets;
229 }
230
231 protected void initProject(Project project, Properties properties,
232 Map<String, Object> references) {
233 if (properties != null) {
234 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
235 project.setUserProperty(entry.getKey().toString(), entry
236 .getValue().toString());
237 }
238 }
239
240 if (references != null) {
241 for (Map.Entry<String, Object> entry : references.entrySet()) {
242 project.addReference(entry.getKey(), entry.getValue());
243 }
244 }
245
246 project.addBuildListener(new CommonsLoggingListener());
247
248 ListableBeanFactory context = (ListableBeanFactory) project
249 .getReference(AntConstants.REF_ROOT_CONTEXT);
250 // Register build listeners
251 Map<String, BuildListener> listeners = context.getBeansOfType(
252 BuildListener.class, false, true);
253 for (BuildListener listener : listeners.values()) {
254 project.addBuildListener(listener);
255 }
256
257 // Register log4j appenders from context
258 MDC.put(AntConstants.MDC_ANT_PROJECT, project);
259 Map<String, Appender> appenders = context.getBeansOfType(
260 Appender.class, false, true);
261 for (Appender appender : appenders.values()) {
262 LogManager.getRootLogger().addAppender(appender);
263 }
264
265 project.init();
266 addCustomTaskAndTypes(project);
267 }
268
269 /** Loads the SLC specific Ant tasks. */
270 protected void addCustomTaskAndTypes(Project project) {
271 Properties taskdefs = getDefs(project,
272 AntConstants.SLC_TASKDEFS_RESOURCE_PATH);
273 for (Object o : taskdefs.keySet()) {
274 String name = o.toString();
275 try {
276 project.addTaskDefinition(name, Class.forName(taskdefs
277 .getProperty(name)));
278 } catch (ClassNotFoundException e) {
279 log.error("Unknown class for task " + name, e);
280 }
281 }
282 Properties typedefs = getDefs(project,
283 AntConstants.SLC_TYPEDEFS_RESOURCE_PATH);
284 for (Object o : typedefs.keySet()) {
285 String name = o.toString();
286 try {
287 project.addDataTypeDefinition(name, Class.forName(typedefs
288 .getProperty(name)));
289 } catch (ClassNotFoundException e) {
290 log.error("Unknown class for type " + name, e);
291 }
292 }
293 }
294
295 private Properties getDefs(Project project, String path) {
296 Properties defs = new Properties();
297 try {
298 InputStream in = project.getClass().getResourceAsStream(path);
299 defs.load(in);
300 in.close();
301 } catch (IOException e) {
302 throw new SlcException("Cannot load task definitions", e);
303 }
304 return defs;
305 }
306
307 protected void initStructure(Project project, String scriptRelativePath) {
308 // Init structure registry
309 StructureRegistry<TreeSPath> registry = new TreeSRegistry();
310 project.addReference(AntConstants.REF_STRUCTURE_REGISTRY, registry);
311
312 // Lowest levels
313 StringTokenizer st = new StringTokenizer(scriptRelativePath, "/");
314 TreeSPath currPath = null;
315 while (st.hasMoreTokens()) {
316 String name = st.nextToken();
317 if (currPath == null) {
318 currPath = TreeSPath.createRootPath(name);
319 } else {
320 if (st.hasMoreTokens())// don't register project file
321 currPath = currPath.createChild(name);
322 }
323 registry.register(currPath, new SimpleSElement(name));
324 }
325
326 // Project level
327 String projectName = project.getName() != null
328 && !project.getName().equals("") ? project.getName()
329 : "project";
330 TreeSPath projectPath = currPath.createChild(projectName);
331
332 String projectDesc = project.getDescription() != null
333 && !project.getDescription().equals("") ? project
334 .getDescription() : projectPath.getName();
335
336 registry.register(projectPath, new SimpleSElement(projectDesc));
337 project.addReference(AntConstants.REF_PROJECT_PATH, projectPath);
338
339 if (log.isDebugEnabled())
340 log.debug("Project path: " + projectPath);
341 }
342
343 protected void parseProject(Project project, String scriptRelativePath) {
344 try {
345 Resource script = rootDir.createRelative(scriptRelativePath);
346 File baseDir = null;
347 try {
348 File scriptFile = script.getFile();
349 baseDir = scriptFile.getParentFile();
350 } catch (IOException e) {// resource is not a file
351 baseDir = new File(System.getProperty("user.dir"));
352 }
353 project.setBaseDir(baseDir);
354 // Reset basedir property, in order to avoid base dir override when
355 // running in Maven
356 project.setProperty("basedir", baseDir.getAbsolutePath());
357
358 ProjectHelper2 projectHelper = new ProjectHelper2();
359 project.addReference(ProjectHelper.PROJECTHELPER_REFERENCE,
360 projectHelper);
361 projectHelper.parse(project, script.getURL());
362 } catch (Exception e) {
363 throw new SlcException("Could not parse project for script "
364 + scriptRelativePath, e);
365 }
366
367 }
368
369 protected void runProject(Project p, List<String> targets) {
370 p.fireBuildStarted();
371 Throwable exception = null;
372 try {
373 if (targets.size() == 0) {// no target defined
374 p.executeTarget(p.getDefaultTarget());
375 } else {
376 p.executeTargets(new Vector<String>(targets));
377 }
378 } catch (Throwable e) {
379 exception = e;
380 throw new SlcException("SLC Ant execution failed", exception);
381 } finally {
382 p.fireBuildFinished(exception);
383 }
384 }
385
386 public void setContextLocation(Resource contextLocation) {
387 this.contextLocation = contextLocation;
388 }
389
390 public void setRootDir(Resource rootDir) {
391 this.rootDir = rootDir;
392 }
393
394 public void setConfDir(Resource confDir) {
395 this.confDir = confDir;
396 }
397
398 public void setWorkDir(File workDir) {
399 this.workDir = workDir;
400 }
401
402 public void setParentContext(ApplicationContext runtimeContext) {
403 this.parentContext = runtimeContext;
404 }
405
406 }