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