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