]> git.argeo.org Git - gpl/argeo-slc.git/blob - org.argeo.slc.core/src/main/java/org/argeo/slc/ant/SlcProjectHelper.java
Introduce XSLT view
[gpl/argeo-slc.git] / org.argeo.slc.core / src / main / java / org / argeo / slc / ant / SlcProjectHelper.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.net.InetAddress;
7 import java.net.UnknownHostException;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Properties;
11 import java.util.UUID;
12 import java.util.Vector;
13
14 import org.springframework.beans.factory.ListableBeanFactory;
15 import org.springframework.context.ApplicationContext;
16 import org.springframework.context.support.AbstractApplicationContext;
17 import org.springframework.context.support.FileSystemXmlApplicationContext;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.apache.log4j.LogManager;
22 import org.apache.tools.ant.BuildException;
23 import org.apache.tools.ant.BuildListener;
24 import org.apache.tools.ant.Project;
25 import org.apache.tools.ant.helper.ProjectHelper2;
26
27 import org.argeo.slc.core.process.SlcExecution;
28 import org.argeo.slc.core.process.SlcExecutionNotifier;
29 import org.argeo.slc.core.structure.DefaultSRegistry;
30 import org.argeo.slc.core.structure.SimpleSElement;
31 import org.argeo.slc.core.structure.StructureRegistry;
32 import org.argeo.slc.core.structure.tree.TreeSPath;
33
34 /**
35 * Custom implementation of an Ant <code>ProjectHelper</code> binding a Spring
36 * application context and a structure registry with the Ant project.
37 */
38 public class SlcProjectHelper extends ProjectHelper2 {
39 private static Log log;
40
41 /** The Ant reference to the Spring application context used. */
42 public static String REF_ROOT_CONTEXT = "slcApplicationContext";
43 /** The Ant reference to the SLC structure registry used. */
44 public static String REF_STRUCTURE_REGISTRY = "slcStructureRegistry";
45 /** The Ant reference to the <code>TreePath</code> of the current project */
46 public static String REF_PROJECT_PATH = "slcProjectPath";
47 /**
48 * Resource path to the property file listing the SLC specific Ant tasks:
49 * /org/argeo/slc/ant/taskdefs.properties
50 */
51 private static String SLC_TASKDEFS_RESOURCE_PATH = "/org/argeo/slc/ant/taskdefs.properties";
52 private static String SLC_TYPEDEFS_RESOURCE_PATH = "/org/argeo/slc/ant/typedefs.properties";
53
54 protected SlcAntConfig slcAntConfig = null;
55
56 @Override
57 public void parse(Project project, Object source) throws BuildException {
58
59 if (source instanceof File) {
60 File sourceFile = (File) source;
61 // Reset basedir property, in order to avoid base dir override when
62 // running in Maven
63 project.setProperty("basedir", sourceFile.getParentFile()
64 .getAbsolutePath());
65 }
66
67 if (slcAntConfig != null) {
68 // Config already initialized (probably import), only parse
69 super.parse(project, source);
70 return;
71 }
72
73 // Initialize config
74 slcAntConfig = new SlcAntConfig();
75
76 if (!slcAntConfig.initProject(project)) {
77 // not SLC compatible, do normal Ant
78 super.parse(project, source);
79 return;
80 }
81
82 if (log == null) {
83 // log4j is initialized only now
84 log = LogFactory.getLog(SlcProjectHelper.class);
85 }
86
87 if (log.isDebugEnabled())
88 log.debug("SLC properties are set, starting initialization for "
89 + source + " (projectHelper=" + this + ")");
90
91 beforeParsing(project);
92
93 // Calls the underlying implementation to do the actual work
94 super.parse(project, source);
95
96 afterParsing(project);
97 }
98
99 /**
100 * Performs operations after config initialization and before Ant file
101 * parsing. Performed only once when the main project file is parsed. Should
102 * be called by overriding methods.
103 */
104 protected void beforeParsing(Project project) {
105 // Init Spring application context
106 initSpringContext(project);
107
108 // Init structure registry
109 DefaultSRegistry registry = new DefaultSRegistry();
110 project.addReference(REF_STRUCTURE_REGISTRY, registry);
111 }
112
113 /**
114 * Performs operations after parsing of the main file. Called only once (not
115 * for imports).
116 */
117 protected void afterParsing(Project project) {
118 // Creates structure root
119 registerProjectAndParents(project, slcAntConfig);
120 addCustomTaskAndTypes(project);
121 }
122
123 /** Creates the tree-based structure for this project. */
124 private void registerProjectAndParents(Project project,
125 SlcAntConfig slcAntConfig) {
126 StructureRegistry<TreeSPath> registry = (StructureRegistry<TreeSPath>) project
127 .getReference(REF_STRUCTURE_REGISTRY);
128 File rootDir = new File(project
129 .getUserProperty(SlcAntConfig.ROOT_DIR_PROPERTY))
130 .getAbsoluteFile();
131 File baseDir = project.getBaseDir().getAbsoluteFile();
132 List<File> dirs = new Vector<File>();
133 File currentDir = baseDir;
134 do {
135 dirs.add(currentDir);
136 currentDir = currentDir.getParentFile();
137 if (log.isTraceEnabled())
138 log.trace("List " + currentDir);
139 } while (!currentDir.equals(rootDir.getParentFile()));
140
141 // first path is root dir (because of previous algorithm)
142 TreeSPath currPath = TreeSPath.createRootPath(rootDir.getName());
143 for (int i = dirs.size() - 1; i >= 0; i--) {
144 File dir = dirs.get(i);
145
146 // retrieves description for this path
147 final String description;
148 if (i == 0) {// project itself
149 description = project.getDescription() != null
150 && !project.getDescription().equals("") ? project
151 .getDescription() : project.getName() != null ? project
152 .getName() : slcAntConfig.getDescriptionForDir(dir);
153 } else {
154 description = slcAntConfig.getDescriptionForDir(dir);
155 if (log.isTraceEnabled())
156 log.trace("Dir desc " + i + "/" + dirs.size() + ": "
157 + description);
158 }
159 SimpleSElement element = new SimpleSElement(description);
160
161 // creates and register path
162 if (!dir.equals(rootDir)) {// already set
163 currPath = currPath.createChild(dir.getName());
164 }
165 registry.register(currPath, element);
166 }
167 project.addReference(REF_PROJECT_PATH, currPath);
168 }
169
170 /** Gets the path of a project (root). */
171 // private static TreeSPath getProjectPath(Project project) {
172 // return (TreeSPath) project.getReference(REF_PROJECT_PATH);
173 // }
174 /** Initializes the Spring application context. */
175 private void initSpringContext(Project project) {
176 System.getProperties().putAll((Map<?, ?>) project.getProperties());
177 String acPath = project
178 .getUserProperty(SlcAntConfig.APPLICATION_CONTEXT_PROPERTY);
179 if (log.isDebugEnabled())
180 log.debug("Loading Spring application context from " + acPath);
181 // FIXME: workaround to the removal of leading '/' by Spring
182 // use URL instead?
183 AbstractApplicationContext context = new FileSystemXmlApplicationContext(
184 '/' + acPath);
185 context.registerShutdownHook();
186 project.addReference(REF_ROOT_CONTEXT, context);
187
188 createAndRegisterSlcExecution(project);
189 // Add build listeners declared in Spring context
190 // Map<String, BuildListener> listeners = context.getBeansOfType(
191 // BuildListener.class, false, true);
192 // for (BuildListener listener : listeners.values()) {
193 // project.addBuildListener(listener);
194 // }
195 }
196
197 /** Loads the SLC specific Ant tasks. */
198 protected static void addCustomTaskAndTypes(Project project) {
199 Properties taskdefs = getDefs(project, SLC_TASKDEFS_RESOURCE_PATH);
200 for (Object o : taskdefs.keySet()) {
201 String name = o.toString();
202 try {
203 project.addTaskDefinition(name, Class.forName(taskdefs
204 .getProperty(name)));
205 } catch (ClassNotFoundException e) {
206 log.error("Unknown class for task " + name, e);
207 }
208 }
209 Properties typedefs = getDefs(project, SLC_TYPEDEFS_RESOURCE_PATH);
210 for (Object o : typedefs.keySet()) {
211 String name = o.toString();
212 try {
213 project.addDataTypeDefinition(name, Class.forName(typedefs
214 .getProperty(name)));
215 } catch (ClassNotFoundException e) {
216 log.error("Unknown class for type " + name, e);
217 }
218 }
219 }
220
221 private static Properties getDefs(Project project, String path) {
222 Properties defs = new Properties();
223 try {
224 InputStream in = project.getClass().getResourceAsStream(path);
225 defs.load(in);
226 in.close();
227 } catch (IOException e) {
228 throw new SlcAntException("Cannot load task definitions", e);
229 }
230 return defs;
231 }
232
233 protected static void createAndRegisterSlcExecution(Project project) {
234 SlcExecution slcExecution = new SlcExecution();
235 slcExecution.setUuid(UUID.randomUUID().toString());
236 try {
237 slcExecution.setHost(InetAddress.getLocalHost().getHostName());
238 } catch (UnknownHostException e) {
239 slcExecution.setHost(SlcExecution.UNKOWN_HOST);
240 }
241
242 if (project.getReference(SlcProjectHelper.REF_ROOT_CONTEXT) != null) {
243 slcExecution.setType(SlcExecutionBuildListener.SLC_ANT_TYPE);
244 } else {
245 slcExecution.setType(SlcExecutionBuildListener.ANT_TYPE);
246 }
247
248 slcExecution.setUser(System.getProperty("user.name"));
249 slcExecution.setStatus(SlcExecution.STATUS_RUNNING);
250 slcExecution.getAttributes().put("ant.file",
251 project.getProperty("ant.file"));
252
253 project.addReference(SlcExecutionBuildListener.REF_SLC_EXECUTION,
254 slcExecution);
255
256 // Add build listeners declared in Spring context
257 Map<String, ProjectRelatedBuildListener> listeners = ((ListableBeanFactory) project
258 .getReference(REF_ROOT_CONTEXT)).getBeansOfType(
259 ProjectRelatedBuildListener.class, false, true);
260 for (ProjectRelatedBuildListener listener : listeners.values()) {
261 listener.init(project);
262 project.addBuildListener(listener);
263 }
264
265 }
266 }