1
2
3
4
5
6
7 package org.asyrinx.joey.gen.ant.task;
8
9 import java.io.File;
10 import java.io.FileInputStream;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.Writer;
14 import java.util.Date;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.StringTokenizer;
18
19 import org.apache.commons.collections.ExtendedProperties;
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.apache.tools.ant.BuildException;
23 import org.apache.tools.ant.Project;
24 import org.apache.tools.ant.Task;
25 import org.apache.velocity.VelocityContext;
26 import org.apache.velocity.app.VelocityEngine;
27 import org.apache.velocity.context.Context;
28 import org.apache.velocity.exception.MethodInvocationException;
29 import org.apache.velocity.exception.ParseErrorException;
30 import org.apache.velocity.exception.ResourceNotFoundException;
31 import org.apache.velocity.texen.Generator;
32 import org.apache.velocity.util.StringUtils;
33 import org.asyrinx.joey.gen.core.JoeyGenerateTarget;
34
35 /***
36 * @author takeshi
37 */
38 public class MultiTargetTexenTask extends Task {
39
40 protected final Log log = LogFactory.getLog(this.getClass());
41
42 private static final String ERR_MSG_FRAGMENT = ". For more information consult the velocity log, or invoke ant "
43 + "with the -debug flag.";
44
45 protected String templatePath;
46
47 protected String outputEncoding;
48
49 protected String inputEncoding;
50
51 protected ExtendedProperties contextProperties;
52
53 protected boolean useClasspath;
54
55 public void setTemplatePath(String templatePath) throws Exception {
56 StringBuffer resolvedPath = new StringBuffer();
57 StringTokenizer st = new StringTokenizer(templatePath, ",");
58 while (st.hasMoreTokens()) {
59 final File fullPath = project.resolveFile(st.nextToken());
60 resolvedPath.append(fullPath.getCanonicalPath());
61 if (st.hasMoreTokens()) {
62 resolvedPath.append(",");
63 }
64 }
65 this.templatePath = resolvedPath.toString();
66 System.out.println(templatePath);
67 }
68
69 public String getTemplatePath() {
70 return templatePath;
71 }
72
73 public void setOutputEncoding(String outputEncoding) {
74 this.outputEncoding = outputEncoding;
75 }
76
77 public void setInputEncoding(String inputEncoding) {
78 this.inputEncoding = inputEncoding;
79 }
80
81 public void setContextProperties(String file) {
82 final String[] sources = StringUtils.split(file, ",");
83 contextProperties = new ExtendedProperties();
84 for (int i = 0; i < sources.length; i++) {
85 ExtendedProperties source = new ExtendedProperties();
86 try {
87 final File fullPath = project.resolveFile(sources[i]);
88 log("Using contextProperties file: " + fullPath);
89 source.load(new FileInputStream(fullPath));
90 } catch (Exception e) {
91 final ClassLoader classLoader = this.getClass().getClassLoader();
92 try {
93 final InputStream inputStream = classLoader.getResourceAsStream(sources[i]);
94
95 if (inputStream == null) {
96 throw new BuildException("Context properties file " + sources[i]
97 + " could not be found in the file system or on the classpath!");
98 } else {
99 source.load(inputStream);
100 }
101 } catch (IOException ioe) {
102 source = null;
103 }
104 }
105 for (Iterator j = source.getKeys(); j.hasNext();) {
106 final String name = (String) j.next();
107 final String value = source.getString(name);
108 contextProperties.setProperty(name, value);
109 }
110 }
111 }
112
113 public ExtendedProperties getContextProperties() {
114 return contextProperties;
115 }
116
117 public void setUseClasspath(boolean useClasspath) {
118 this.useClasspath = useClasspath;
119 }
120
121 public Context initControlContext() {
122 return new VelocityContext();
123 }
124
125 protected void populateInitialContext(Context context) {
126 context.put("now", new Date().toString());
127 }
128
129 protected void cleanup() throws Exception {
130
131 }
132
133 protected List initTargets() {
134 return null;
135 }
136
137 protected void checkTargets(JoeyGenerateTarget target) {
138 if (target.getControlTemplate() == null)
139 throw new BuildException("The control template needs to be defined!");
140 if (target.getOutputDirectory() == null)
141 throw new BuildException("The output directory needs to be defined!");
142 if (target.getOutputFile() == null)
143 throw new BuildException("The output file needs to be defined!");
144 log.debug("target=" + target.getTargetName());
145 log.debug("outputDirectory=" + target.getOutputDirectory());
146 log.debug("controlTemplate=" + target.getControlTemplate());
147 }
148
149 public void execute() throws BuildException {
150 final List targets = initTargets();
151 if (templatePath == null && useClasspath == false) {
152 throw new BuildException("The template path needs to be defined if you are not using "
153 + "the classpath for locating templates!");
154 }
155
156 final Context c = initControlContext();
157 populateInitialContext(c);
158 try {
159 prepareContextProperties(c);
160 } catch (IOException e) {
161 throw new BuildException("failed to prepareContextProperties", e);
162 }
163
164 final VelocityEngine ve = initVelocityEngine();
165 for (Iterator j = targets.iterator(); j.hasNext();) {
166 final JoeyGenerateTarget target = (JoeyGenerateTarget) j.next();
167 checkTargets(target);
168 try {
169 final Generator generator = initGenerator();
170 generator.setVelocityEngine(ve);
171 generator.setOutputPath(target.getOutputDirectory());
172 generator.setInputEncoding(inputEncoding);
173 generator.setOutputEncoding(outputEncoding);
174
175 generate(c, target, generator);
176 } catch (BuildException e) {
177 throw e;
178 } catch (MethodInvocationException e) {
179 throw new BuildException("Exception thrown by '" + e.getReferenceName() + "." + e.getMethodName() + "'"
180 + ERR_MSG_FRAGMENT, e.getWrappedThrowable());
181 } catch (ParseErrorException e) {
182 throw new BuildException("Velocity syntax error" + ERR_MSG_FRAGMENT, e);
183 } catch (ResourceNotFoundException e) {
184 throw new BuildException("Resource not found" + ERR_MSG_FRAGMENT, e);
185 } catch (Exception e) {
186 throw new BuildException("Generation failed" + ERR_MSG_FRAGMENT, e);
187 }
188 }
189 }
190
191 /***
192 * @param c
193 * @param target
194 * @param generator
195 * @throws Exception
196 * @throws IOException
197 */
198 protected void generate(final Context c, final JoeyGenerateTarget target, final Generator generator)
199 throws Exception, IOException {
200 if (templatePath != null)
201 generator.setTemplatePath(templatePath);
202 final File file = new File(target.getOutputDirectory());
203 if (!file.exists())
204 file.mkdirs();
205 final String path = target.getOutputDirectory() + File.separator + target.getOutputFile();
206 log.debug("Generating to file " + path);
207 final Writer writer = generator.getWriter(path, outputEncoding);
208 writer.write(generator.parse(target.getControlTemplate(), c));
209 writer.flush();
210 writer.close();
211 generator.shutdown();
212 cleanup();
213 }
214
215 /***
216 * @return
217 */
218 protected Generator initGenerator() {
219 return Generator.getInstance();
220 }
221
222 /***
223 * @return
224 */
225 protected VelocityEngine initVelocityEngine() {
226 VelocityEngine ve = new VelocityEngine();
227
228 if (templatePath != null) {
229 log("Using templatePath: " + templatePath, Project.MSG_VERBOSE);
230 ve.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, templatePath);
231 }
232 if (useClasspath) {
233 log("Using classpath");
234 ve.addProperty(VelocityEngine.RESOURCE_LOADER, "classpath");
235 ve.setProperty("classpath." + VelocityEngine.RESOURCE_LOADER + ".class",
236 "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
237 ve.setProperty("classpath." + VelocityEngine.RESOURCE_LOADER + ".cache", "false");
238 ve.setProperty("classpath." + VelocityEngine.RESOURCE_LOADER + ".modificationCheckInterval", "2");
239 }
240 try {
241 ve.init();
242 } catch (Exception e) {
243 throw new BuildException("VelocityEngine#init() failed " + ERR_MSG_FRAGMENT, e);
244 }
245 return ve;
246 }
247
248 /***
249 * @param c
250 * @throws IOException
251 */
252 protected void prepareContextProperties(final Context c) throws IOException {
253 if (contextProperties != null) {
254 final Iterator i = contextProperties.getKeys();
255
256 while (i.hasNext()) {
257 String property = (String) i.next();
258 String value = contextProperties.getString(property);
259 try {
260 c.put(property, new Integer(value));
261 } catch (NumberFormatException nfe) {
262 final String booleanString = contextProperties.testBoolean(value);
263 if (booleanString != null) {
264 c.put(property, new Boolean(booleanString));
265 } else {
266 if (property.endsWith("file.contents")) {
267 value = StringUtils.fileContentsToString(project.resolveFile(value).getCanonicalPath());
268 property = property.substring(0, property.indexOf("file.contents") - 1);
269 }
270 c.put(property, value);
271 }
272 }
273 }
274 }
275 }
276
277 }