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 private static final String ERR_MSG_FRAGMENT = ". For more information consult the velocity log, or invoke ant "
40 + "with the -debug flag.";
41
42 protected String templatePath;
43
44 protected String outputEncoding;
45
46 protected String inputEncoding;
47
48 protected ExtendedProperties contextProperties;
49
50 protected boolean useClasspath;
51
52 public void setTemplatePath(String templatePath) throws Exception {
53 StringBuffer resolvedPath = new StringBuffer();
54 StringTokenizer st = new StringTokenizer(templatePath, ",");
55 while (st.hasMoreTokens()) {
56 final File fullPath = project.resolveFile(st.nextToken());
57 resolvedPath.append(fullPath.getCanonicalPath());
58 if (st.hasMoreTokens()) {
59 resolvedPath.append(",");
60 }
61 }
62 this.templatePath = resolvedPath.toString();
63 System.out.println(templatePath);
64 }
65
66 public String getTemplatePath() {
67 return templatePath;
68 }
69
70 public void setOutputEncoding(String outputEncoding) {
71 this.outputEncoding = outputEncoding;
72 }
73
74 public void setInputEncoding(String inputEncoding) {
75 this.inputEncoding = inputEncoding;
76 }
77
78 public void setContextProperties(String file) {
79 final String[] sources = StringUtils.split(file, ",");
80 contextProperties = new ExtendedProperties();
81 for (int i = 0; i < sources.length; i++) {
82 ExtendedProperties source = new ExtendedProperties();
83 try {
84 final File fullPath = project.resolveFile(sources[i]);
85 log("Using contextProperties file: " + fullPath);
86 source.load(new FileInputStream(fullPath));
87 } catch (Exception e) {
88 final ClassLoader classLoader = this.getClass().getClassLoader();
89 try {
90 final InputStream inputStream = classLoader.getResourceAsStream(sources[i]);
91
92 if (inputStream == null) {
93 throw new BuildException("Context properties file " + sources[i]
94 + " could not be found in the file system or on the classpath!");
95 } else {
96 source.load(inputStream);
97 }
98 } catch (IOException ioe) {
99 source = null;
100 }
101 }
102 for (Iterator j = source.getKeys(); j.hasNext();) {
103 final String name = (String) j.next();
104 final String value = source.getString(name);
105 contextProperties.setProperty(name, value);
106 }
107 }
108 }
109
110 public ExtendedProperties getContextProperties() {
111 return contextProperties;
112 }
113
114 public void setUseClasspath(boolean useClasspath) {
115 this.useClasspath = useClasspath;
116 }
117
118 public Context initControlContext() {
119 return new VelocityContext();
120 }
121
122 protected void populateInitialContext(Context context) {
123 context.put("now", new Date().toString());
124 }
125
126 protected void cleanup() throws Exception {
127
128 }
129
130 protected List initTargets() {
131 return null;
132 }
133
134 private final Log log = LogFactory.getLog(this.getClass());
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 = Generator.getInstance();
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 private VelocityEngine initVelocityEngine() {
209 VelocityEngine ve = new VelocityEngine();
210
211 if (templatePath != null) {
212 log("Using templatePath: " + templatePath, Project.MSG_VERBOSE);
213 ve.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, templatePath);
214 }
215 if (useClasspath) {
216 log("Using classpath");
217 ve.addProperty(VelocityEngine.RESOURCE_LOADER, "classpath");
218 ve.setProperty("classpath." + VelocityEngine.RESOURCE_LOADER + ".class",
219 "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
220 ve.setProperty("classpath." + VelocityEngine.RESOURCE_LOADER + ".cache", "false");
221 ve.setProperty("classpath." + VelocityEngine.RESOURCE_LOADER + ".modificationCheckInterval", "2");
222 }
223 try {
224 ve.init();
225 } catch (Exception e) {
226 throw new BuildException("VelocityEngine#init() failed " + ERR_MSG_FRAGMENT, e);
227 }
228 return ve;
229 }
230
231 /***
232 * @param c
233 * @throws IOException
234 */
235 private void prepareContextProperties(final Context c) throws IOException {
236 if (contextProperties != null) {
237 final Iterator i = contextProperties.getKeys();
238
239 while (i.hasNext()) {
240 String property = (String) i.next();
241 String value = contextProperties.getString(property);
242 try {
243 c.put(property, new Integer(value));
244 } catch (NumberFormatException nfe) {
245 final String booleanString = contextProperties.testBoolean(value);
246 if (booleanString != null) {
247 c.put(property, new Boolean(booleanString));
248 } else {
249 if (property.endsWith("file.contents")) {
250 value = StringUtils.fileContentsToString(project.resolveFile(value).getCanonicalPath());
251 property = property.substring(0, property.indexOf("file.contents") - 1);
252 }
253 c.put(property, value);
254 }
255 }
256 }
257 }
258 }
259
260 }