]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.support.ant/src/main/java/org/argeo/slc/ant/AntSlcApplication.java
Properly pass properties
[gpl/argeo-slc.git] / runtime / org.argeo.slc.support.ant / 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.argeo.slc.SlcException;
23 import org.argeo.slc.core.structure.SimpleSElement;
24 import org.argeo.slc.core.structure.tree.TreeSPath;
25 import org.argeo.slc.core.structure.tree.TreeSRegistry;
26 import org.argeo.slc.logging.Log4jUtils;
27 import org.argeo.slc.process.SlcExecution;
28 import org.argeo.slc.runtime.SlcApplication;
29 import org.argeo.slc.runtime.SlcExecutionOutput;
30 import org.argeo.slc.spring.SpringUtils;
31 import org.argeo.slc.structure.StructureRegistry;
32 import org.springframework.beans.factory.BeanFactoryUtils;
33 import org.springframework.beans.factory.ListableBeanFactory;
34 import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
35 import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
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 implements SlcApplication<AntExecutionContext> {
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 private Resource slcRootFile;
56
57 public void execute(SlcExecution slcExecution, Properties properties,
58 Map<String, Object> references,
59 SlcExecutionOutput<AntExecutionContext> executionOutput) {
60
61 // Properties and application logging initialization
62 initSystemProperties(properties);
63 Log4jUtils.initLog4j("classpath:" + DEFAULT_APP_LOG4J_PROPERTIES);
64
65 log.info("\n###\n### Start SLC execution " + slcExecution.getUuid()
66 + "\n###\n");
67 if (log.isDebugEnabled()) {
68 log.debug("rootDir=" + rootDir);
69 log.debug("confDir=" + confDir);
70 log.debug("workDir=" + workDir);
71 }
72
73 // Ant coordinates
74 String scriptRelativePath = findAntScript(slcExecution);
75 List<String> targets = findAntTargets(slcExecution);
76
77 // Spring initialization
78 ConfigurableApplicationContext ctx = createExecutionContext(slcExecution);
79
80 // Ant project initialization
81 Project project = new Project();
82 AntExecutionContext executionContext = new AntExecutionContext(project);
83 project.addReference(AntConstants.REF_ROOT_CONTEXT, ctx);
84 project.addReference(AntConstants.REF_SLC_EXECUTION, slcExecution);
85
86 try {
87 initProject(project, properties, references);
88 parseProject(project, scriptRelativePath);
89
90 // Execute project
91 initStructure(project, scriptRelativePath);
92 runProject(project, targets);
93
94 if (executionOutput != null)
95 executionOutput.postExecution(executionContext);
96 } finally {
97 ctx.close();
98 }
99 }
100
101 protected void initSystemProperties(Properties userProperties) {
102 // Set user properties as system properties so that Spring can access
103 // them
104 if (userProperties != null) {
105 for (Object key : userProperties.keySet()) {
106 System.setProperty(key.toString(), userProperties
107 .getProperty(key.toString()));
108 }
109 }
110
111 if (System.getProperty(AntConstants.DEFAULT_TEST_RUN_PROPERTY) == null) {
112 System.setProperty(AntConstants.DEFAULT_TEST_RUN_PROPERTY,
113 "defaultTestRun");
114 }
115
116 try {
117 if (rootDir != null)
118 setSystemPropertyForRes(AntConstants.ROOT_DIR_PROPERTY, rootDir);
119 if (confDir != null)
120 setSystemPropertyForRes(AntConstants.CONF_DIR_PROPERTY, confDir);
121 if (workDir != null)
122 System.setProperty(AntConstants.WORK_DIR_PROPERTY, workDir
123 .getCanonicalPath());
124
125 // Additional properties in slc.properties file. Already set sytem
126 // properties (such as the various directories) can be resolved in
127 // placeholders.
128 if (confDir != null) {
129 Resource slcPropertiesRes = confDir
130 .createRelative("slc.properties");
131 if (slcPropertiesRes.exists()) {
132 Properties slcProperties = new Properties();
133 InputStream in = slcPropertiesRes.getInputStream();
134 try {
135 slcProperties.load(in);
136 } finally {
137 IOUtils.closeQuietly(in);
138 }
139
140 for (Object obj : slcProperties.keySet()) {
141 String key = obj.toString();
142 if (!System.getProperties().containsKey(key)) {
143 String value = SystemPropertyUtils
144 .resolvePlaceholders(slcProperties
145 .getProperty(key));
146 System.setProperty(key, value);
147 }
148 }
149 }
150 }
151 } catch (Exception e) {
152 throw new SlcException("Cannot init system properties.", e);
153 }
154 }
155
156 /**
157 * Set property as an absolute file path if the resource can be located on
158 * the file system, or as an url.
159 */
160 private void setSystemPropertyForRes(String key, Resource res)
161 throws IOException {
162 String value = null;
163 try {
164 value = res.getFile().getCanonicalPath();
165 } catch (IOException e) {
166 value = res.getURL().toString();
167 }
168 System.setProperty(key, value);
169 }
170
171 protected ConfigurableApplicationContext createExecutionContext(
172 SlcExecution slcExecution) {
173 try {
174
175 // Find runtime definition
176 Resource runtimeRes = null;
177 String runtimeStr = slcExecution.getAttributes().get(
178 AntConstants.EXECATTR_RUNTIME);
179 if (runtimeStr == null)
180 runtimeStr = System.getProperty(AntConstants.RUNTIME_PROPERTY,
181 "default");
182
183 ResourceLoader rl = new DefaultResourceLoader(getClass()
184 .getClassLoader());
185 try {// tries absolute reference
186 runtimeRes = rl.getResource(runtimeStr);
187 } catch (Exception e) {
188 // silent
189 }
190 if (runtimeRes == null || !runtimeRes.exists()) {
191 if (confDir != null)
192 runtimeRes = confDir.createRelative("runtime/" + runtimeStr
193 + ".xml");
194 }
195
196 // Find runtime independent application context definition
197 if (confDir != null && contextLocation == null) {
198 contextLocation = confDir
199 .createRelative("applicationContext.xml");
200 }
201
202 GenericApplicationContext ctx = new GenericApplicationContext(
203 parentContext);
204 ctx.setDisplayName("SLC Execution #" + slcExecution.getUuid());
205
206 XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
207 if (runtimeRes != null && runtimeRes.exists())
208 xmlReader.loadBeanDefinitions(runtimeRes);
209 else
210 log.warn("No runtime context defined");
211
212 if (contextLocation != null && contextLocation.exists())
213 xmlReader.loadBeanDefinitions(contextLocation);
214 else
215 log.warn("No runtime independent application context defined");
216
217 // Add property place holder
218 PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
219 ppc.setIgnoreUnresolvablePlaceholders(true);
220 ctx.addBeanFactoryPostProcessor(ppc);
221
222 ctx.refresh();
223 return ctx;
224 } catch (Exception e) {
225 throw new SlcException(
226 "Cannot create SLC execution application context.", e);
227 }
228 }
229
230 protected String findAntScript(SlcExecution slcExecution) {
231 String scriptStr = slcExecution.getAttributes().get(
232 AntConstants.EXECATTR_ANT_FILE);
233 if (scriptStr == null)
234 throw new SlcException("No Ant script provided");
235
236 return scriptStr;
237 }
238
239 protected List<String> findAntTargets(SlcExecution slcExecution) {
240 String targetList = slcExecution.getAttributes().get(
241 AntConstants.EXECATTR_ANT_TARGETS);
242 List<String> targets = new Vector<String>();
243 if (targetList != null) {
244 StringTokenizer stTargets = new StringTokenizer(targetList, ",");
245 while (stTargets.hasMoreTokens()) {
246 targets.add(stTargets.nextToken());
247 }
248 }
249 return targets;
250 }
251
252 protected void initProject(Project project, Properties properties,
253 Map<String, Object> references) {
254 if (properties != null) {
255 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
256 project.setUserProperty(entry.getKey().toString(), entry
257 .getValue().toString());
258 }
259 }
260
261 if (references != null) {
262 for (Map.Entry<String, Object> entry : references.entrySet()) {
263 project.addReference(entry.getKey(), entry.getValue());
264 }
265 }
266
267 // project.addBuildListener(new CommonsLoggingListener());
268
269 ListableBeanFactory context = (ListableBeanFactory) project
270 .getReference(AntConstants.REF_ROOT_CONTEXT);
271 // Register build listeners
272 Map<String, BuildListener> listeners = BeanFactoryUtils
273 .beansOfTypeIncludingAncestors(context, BuildListener.class,
274 false, false);
275 for (BuildListener listener : listeners.values()) {
276 project.addBuildListener(listener);
277 }
278
279 // Register log4j appenders from context
280 MDC.put(AntConstants.MDC_ANT_PROJECT, project);
281 Map<String, Appender> appenders = context.getBeansOfType(
282 Appender.class, false, true);
283 for (Appender appender : appenders.values()) {
284 LogManager.getRootLogger().addAppender(appender);
285 }
286
287 project.init();
288 addCustomTaskAndTypes(project);
289 }
290
291 /** Loads the SLC specific Ant tasks. */
292 protected void addCustomTaskAndTypes(Project project) {
293 Properties taskdefs = getDefs(project,
294 AntConstants.SLC_TASKDEFS_RESOURCE_PATH);
295 for (Object o : taskdefs.keySet()) {
296 String name = o.toString();
297 String className = taskdefs.getProperty(name);
298 try {
299 project.addTaskDefinition(name, Class.forName(className));
300 } catch (ClassNotFoundException e) {
301 log.warn("Unknown class " + className + " for task " + name);
302 }
303 }
304 Properties typedefs = getDefs(project,
305 AntConstants.SLC_TYPEDEFS_RESOURCE_PATH);
306 for (Object o : typedefs.keySet()) {
307 String name = o.toString();
308 try {
309 project.addDataTypeDefinition(name, Class.forName(typedefs
310 .getProperty(name)));
311 } catch (ClassNotFoundException e) {
312 log.error("Unknown class for type " + name, e);
313 }
314 }
315 }
316
317 private Properties getDefs(Project project, String path) {
318 Properties defs = new Properties();
319 try {
320 InputStream in = project.getClass().getResourceAsStream(path);
321 defs.load(in);
322 in.close();
323 } catch (IOException e) {
324 throw new SlcException("Cannot load task definitions", e);
325 }
326 return defs;
327 }
328
329 protected void initStructure(Project project, String scriptRelativePath) {
330 // Init structure registry
331 StructureRegistry<TreeSPath> registry = new TreeSRegistry();
332 project.addReference(AntConstants.REF_STRUCTURE_REGISTRY, registry);
333
334 // Lowest levels
335 StringTokenizer st = new StringTokenizer(scriptRelativePath, "/");
336 TreeSPath currPath = null;
337 while (st.hasMoreTokens()) {
338 String name = st.nextToken();
339 if (currPath == null) {
340 currPath = TreeSPath.createRootPath(name);
341 } else {
342 if (st.hasMoreTokens())// don't register project file
343 currPath = currPath.createChild(name);
344 }
345 registry.register(currPath, new SimpleSElement(name));
346 }
347
348 // Project level
349 String projectName = project.getName() != null
350 && !project.getName().equals("") ? project.getName()
351 : "project";
352 TreeSPath projectPath = currPath.createChild(projectName);
353
354 String projectDesc = project.getDescription() != null
355 && !project.getDescription().equals("") ? project
356 .getDescription() : projectPath.getName();
357
358 registry.register(projectPath, new SimpleSElement(projectDesc));
359 project.addReference(AntConstants.REF_PROJECT_PATH, projectPath);
360
361 if (log.isDebugEnabled())
362 log.debug("Project path: " + projectPath);
363 }
364
365 protected void parseProject(Project project, String scriptRelativePath) {
366 try {
367 Resource script = rootDir.createRelative(scriptRelativePath);
368 File baseDir = null;
369 try {
370 File scriptFile = script.getFile();
371 baseDir = scriptFile.getParentFile();
372 } catch (IOException e) {// resource is not a file
373 baseDir = new File(System.getProperty("user.dir"));
374 }
375 project.setBaseDir(baseDir);
376 // Reset basedir property, in order to avoid base dir override when
377 // running in Maven
378 project.setProperty("basedir", baseDir.getAbsolutePath());
379
380 ProjectHelper2 projectHelper = new ProjectHelper2();
381 project.addReference(ProjectHelper.PROJECTHELPER_REFERENCE,
382 projectHelper);
383 projectHelper.parse(project, script.getURL());
384 } catch (Exception e) {
385 throw new SlcException("Could not parse project for script "
386 + scriptRelativePath, e);
387 }
388
389 }
390
391 protected void runProject(Project p, List<String> targets) {
392 p.fireBuildStarted();
393 Throwable exception = null;
394 try {
395 if (targets.size() == 0) {// no target defined
396 p.executeTarget(p.getDefaultTarget());
397 } else {
398 p.executeTargets(new Vector<String>(targets));
399 }
400 } catch (Throwable e) {
401 exception = e;
402 throw new SlcException("SLC Ant execution failed", exception);
403 } finally {
404 p.fireBuildFinished(exception);
405 }
406 }
407
408 public void setContextLocation(Resource contextLocation) {
409 this.contextLocation = contextLocation;
410 }
411
412 public void setRootDir(Resource rootDir) {
413 this.rootDir = rootDir;
414 }
415
416 public void setConfDir(Resource confDir) {
417 this.confDir = confDir;
418 }
419
420 public void setWorkDir(File workDir) {
421 this.workDir = workDir;
422 }
423
424 public void setParentContext(ConfigurableApplicationContext runtimeContext) {
425 this.parentContext = runtimeContext;
426 }
427
428 public void setSlcRootFile(Resource slcRootFile) {
429 this.slcRootFile = slcRootFile;
430 }
431
432 /**
433 * Init all directories based on the SLC root file. TODO: don't override
434 * already specified dirs.
435 */
436 public void initFromSlcRootFile() {
437 // AntSlcApplication application = new AntSlcApplication();
438 InputStream inRootFile = null;
439 try {
440 // Remove basedir property in order to avoid conflict with Maven
441 // if (all.containsKey("basedir"))
442 // all.remove("basedir");
443
444 inRootFile = slcRootFile.getInputStream();
445 Properties rootProps = loadFile(inRootFile);
446
447 Resource confDir = null;
448 File workDir = null;
449 // Root dir
450 final Resource rootDir = SpringUtils.getParent(slcRootFile);
451
452 // Conf dir
453 String confDirStr = rootProps
454 .getProperty(AntConstants.CONF_DIR_PROPERTY);
455 if (confDirStr != null)
456 confDir = new DefaultResourceLoader(getClass().getClassLoader())
457 .getResource(confDirStr);
458
459 if (confDir == null || !confDir.exists()) {
460 // confDir = rootDir.createRelative("../conf");
461 confDir = SpringUtils.getParent(rootDir)
462 .createRelative("conf/");
463 }
464
465 // Work dir
466 String workDirStr = rootProps
467 .getProperty(AntConstants.WORK_DIR_PROPERTY);
468 if (workDirStr != null) {
469 workDir = new File(workDirStr);
470 }
471
472 if (workDir == null || !workDir.exists()) {
473 try {
474 File rootDirAsFile = rootDir.getFile();
475 workDir = new File(rootDirAsFile.getParent()
476 + File.separator + "work").getCanonicalFile();
477 } catch (IOException e) {
478 workDir = new File(System.getProperty("java.io.tmpdir")
479 + File.separator + "slcExecutions" + File.separator
480 + slcRootFile.getURL().getPath());
481 log.debug("Root dir is not a file: " + e.getMessage()
482 + ", creating work dir in temp: " + workDir);
483 }
484 workDir.mkdirs();
485 }
486
487 setConfDir(confDir);
488 setRootDir(rootDir);
489 setWorkDir(workDir);
490
491 if (log.isDebugEnabled())
492 log.debug("Ant SLC application initialized based on root file "
493 + slcRootFile);
494 } catch (IOException e) {
495 throw new SlcException(
496 "Could not prepare SLC application for root file "
497 + slcRootFile, e);
498 } finally {
499 IOUtils.closeQuietly(inRootFile);
500 }
501 }
502
503 /** Loads the content of a file as <code>Properties</code>. */
504 private Properties loadFile(InputStream in) {
505 Properties p = new Properties();
506 try {
507 p.load(in);
508 } catch (IOException e) {
509 throw new SlcException("Cannot read SLC root file", e);
510 }
511 return p;
512 }
513
514 }