View Javadoc

1   /*
2    * joey-gen and its relative products are published under the terms
3    * of the Apache Software License.
4    * 
5    * Created on 2004/12/20 13:58:36
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         // Setup the Velocity Runtime.
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 }