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