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