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