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.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         // Setup the Velocity Runtime.
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 }