001 package com.nativelibs4java.velocity;
002
003 /*
004 * Copyright 2001-2005 The Apache Software Foundation.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 import static com.nativelibs4java.velocity.Utils.*;
019 import com.google.common.base.Function;
020 import java.io.BufferedReader;
021 import org.apache.maven.plugin.AbstractMojo;
022 import org.apache.maven.plugin.MojoExecutionException;
023 import org.apache.maven.project.MavenProject;
024 import org.apache.maven.model.Resource;
025
026 import java.io.File;
027 import java.io.FileReader;
028 import java.io.FileWriter;
029 import java.io.IOException;
030 import java.io.PrintWriter;
031 import java.io.StringWriter;
032 import java.util.ArrayList;
033 import java.util.Collection;
034 import java.util.Map;
035 import java.util.List;
036 import java.util.regex.Matcher;
037 import java.util.regex.Pattern;
038 import org.apache.velocity.*;
039 import org.apache.velocity.app.VelocityEngine;
040 import org.apache.velocity.app.Velocity;
041 import org.codehaus.plexus.util.IOUtil;
042
043 /**
044 * Generates source code with velocity templates
045 *
046 * @goal generate
047 * @phase generate-sources
048 * @description Generates source code with velocity templates
049 */
050 public class VelocityMojo
051 extends AbstractMojo {
052
053 /**
054 * Extra properties
055 *
056 * @parameter
057 * @optional
058 */
059 private Map<String, String> properties;
060 /**
061 * Source folder for velocity templates
062 *
063 * @parameter expression="${basedir}/src/"
064 * @required
065 */
066 private File sourcePathRoot;
067 /**
068 * Source folder for velocity templates
069 *
070 * @parameter expression="${basedir}/src/main/velocity/"
071 * @required
072 */
073 private File velocitySources;
074 /**
075 * Source folder for velocity test templates
076 *
077 * @parameter expression="${basedir}/src/test/velocity/"
078 * @required
079 */
080 private File velocityTestSources;
081 /**
082 * Output directory for generated sources.
083 *
084 * @parameter expression="${project.build.directory}/generated-sources/main"
085 * @optional
086 */
087 private File sourcesOutputDirectory;
088 /**
089 * Output directory for generated test sources.
090 *
091 * @parameter expression="${project.build.directory}/generated-sources/test"
092 * @optional
093 */
094 private File testSourcesOutputDirectory;
095 /**
096 * Output directory for resources.
097 *
098 * @parameter expression="${project.build.directory}/generated-resources/"
099 * @optional
100 */
101 private File resourcesOutputDirectory;
102 /**
103 * Output directory test resources.
104 *
105 * @parameter
106 * expression="${project.build.directory}/generated-test-resources/"
107 * @optional
108 */
109 private File testResourcesOutputDirectory;
110 /**
111 * @parameter expression="${project}"
112 * @required
113 * @readonly
114 * @since 1.0
115 */
116 private MavenProject project;
117
118 static void listVeloFiles(File f, Collection<File> out) throws IOException {
119 if (f.isHidden()) {
120 return;
121 }
122
123 String n = f.getName().toLowerCase();
124 if (f.isDirectory()) {
125 if (n.equals(".svn") || n.equals("CVS")) {
126 return;
127 }
128
129 for (File ff : f.listFiles()) {
130 listVeloFiles(ff.getAbsoluteFile(), out);
131 }
132 } else if (f.isFile()) {
133 //if (n.endsWith(".velo") || n.endsWith(".vm") || n.endsWith(".velocity"))
134 if (!n.startsWith("."))//endsWith(".velo") || n.endsWith(".vm") || n.endsWith(".velocity"))
135 {
136 out.add(f);
137 }
138 }
139 }
140
141 public File getOutputFile(File vmFile, File velocitySources, File outputDirectory) throws IOException {
142 //String canoRoot = sourcePathRoot.getCanonicalPath();
143 String canoRoot = velocitySources.getCanonicalPath();
144 //String canoSrc = velocitySources.getCanonicalPath();
145 String abs = vmFile.getCanonicalPath();
146 String rel = abs.substring(canoRoot.length());
147 String relLow = rel.toLowerCase();
148 for (String suf : new String[]{".vm", ".velo", ".velocity"}) {
149 if (relLow.endsWith(suf)) {
150 rel = rel.substring(0, rel.length() - suf.length());
151 break;
152 }
153 }
154 int i = rel.lastIndexOf('.');
155 File out = outputDirectory;
156 //if (i >= 0) {
157 // String ext = rel.substring(i + 1);
158 // out = new File(out, ext);
159 //}
160
161 return new File(out.getCanonicalPath() + rel);
162 }
163
164 public void execute()
165 throws MojoExecutionException {
166 if (executeAll(velocitySources, false)) {
167 //File jf = new File(outputDirectory, "java");
168 //if (jf.exists())
169 // outputDirectory = jf;
170 project.addCompileSourceRoot(sourcesOutputDirectory.toString());
171 Resource res = new Resource();
172 res.setDirectory(resourcesOutputDirectory.getAbsolutePath());
173 project.addResource(res);
174 }
175
176 if (executeAll(velocityTestSources, true)) {
177 //File jf = new File(testOutputDirectory, "java");
178 //if (jf.exists())
179 // testOutputDirectory = jf;
180 project.addTestCompileSourceRoot(testSourcesOutputDirectory.toString());
181 Resource res = new Resource();
182 res.setDirectory(testResourcesOutputDirectory.getAbsolutePath());
183 project.addTestResource(res);
184 }
185
186 /*if (templates == null)
187 getLog().error("Did not find <templates> !");
188 else {
189 getLog().info("Found " + templates.size() + " templates");
190 for (Template conf : templates)
191 conf.execute(this);
192 }*/
193 }
194
195 private VelocityEngine createEngine(String canoPath) throws Exception {
196 VelocityEngine ve = new VelocityEngine();
197 ve.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, new MavenLogChute(getLog()));
198 ve.setProperty("velocimacro.permissions.allow.inline.to.replace.global", "true");
199 ve.setProperty("velocimacro.permissions.allow.inline.local.scope", "false");
200 ve.setProperty("velocimacro.context.localscope", "false");
201 ve.setProperty("file.resource.loader.path", canoPath);
202 ve.init();
203 return ve;
204 }
205
206 private boolean executeAll(File velocitySources, boolean isTest) throws MojoExecutionException {
207
208 List<File> files = new ArrayList<File>();
209 String canoPath;
210 try {
211 velocitySources = velocitySources.getCanonicalFile();
212 listVeloFiles(velocitySources, files);
213
214 canoPath = sourcePathRoot.getCanonicalPath();
215 getLog().info("Velocity root path = " + canoPath);
216
217
218 } catch (Exception ex) {
219 throw new MojoExecutionException("Failed to list files from '" + velocitySources + "'", ex);
220 }
221
222
223 getLog().info("Found " + files.size() + " files in '" + velocitySources + "'...");
224 getLog().info("Got Maven properties : " + project.getProperties());
225 getLog().info("Got properties : " + properties);
226
227 if (files.isEmpty()) {
228 return false;
229 }
230
231 for (File file : files) {
232 try {
233 file = file.getCanonicalFile();
234
235 String name = file.getName();
236 if (name.endsWith("~") || name.endsWith(".bak")) {
237 getLog().info("Skipping: '" + name + "'");
238 continue;
239 }
240 String lowName = name.toLowerCase();
241
242 File outputDirectory;
243 boolean isSource = name.endsWith(".java") || name.endsWith(".scala");
244 if (isSource) {
245 outputDirectory = isTest ? testSourcesOutputDirectory : sourcesOutputDirectory;
246 } else {
247 outputDirectory = isTest ? testResourcesOutputDirectory : resourcesOutputDirectory;
248 }
249
250 File outFile = getOutputFile(file, velocitySources, outputDirectory);
251 if (outFile.exists() && outFile.lastModified() > file.lastModified()) {
252 getLog().info("Up-to-date: '" + name + "'");
253 continue;
254 }
255 getLog().info("Executing template '" + name + "'...");
256
257 //context = new VelocityContext();
258 String cano = file.getCanonicalPath();
259 cano = cano.substring(canoPath.length());
260 if (cano.startsWith(File.separator)) {
261 cano = cano.substring(File.separator.length());
262 }
263
264 VelocityEngine ve = createEngine(canoPath);
265 VelocityContext context = new VelocityContext();//execution.getParameters());
266 context.put("primitives", Primitive.getPrimitives());
267 context.put("primitivesNoBool", Primitive.getPrimitivesNoBool());
268 context.put("bridJPrimitives", Primitive.getBridJPrimitives());
269 context.put("pom", project);
270
271 for (Map.Entry<Object, Object> e : project.getProperties().entrySet()) {
272 String propName = ((String) e.getKey()).replace('.', '_'), propValue = (String) e.getValue();
273 getLog().debug("Got property : " + propName + " = " + propValue);
274
275 context.put(propName, propValue);
276 }
277
278 if (properties != null) {
279 for (Map.Entry<String, String> e : properties.entrySet()) {
280 String propName = e.getKey(), propValue = e.getValue();
281 getLog().debug("Got property : " + propName + " = " + propValue);
282
283 context.put(propName, propValue);
284 }
285 }
286
287 StringWriter out = new StringWriter();
288
289 boolean quoteComments = true;
290 if (quoteComments) {
291 String source = readTextFile(file);
292 String quoted = quoteSharpsInComments(source);
293 ve.evaluate(context, out, "velocity", quoted);
294 } else {
295 org.apache.velocity.Template template = ve.getTemplate(cano);//file.getName());
296 template.merge(context, out);
297 }
298 out.close();
299
300 outFile.getParentFile().mkdirs();
301 String transformed = out.toString();
302 writeTextFile(outFile, transformed);
303 //getLog().info("\tGenerated '" + outFile.getName() + "'");
304
305 } catch (Exception ex) {
306 //throw
307 new MojoExecutionException("Failed to execute template '" + file + "'", ex).printStackTrace();
308 }
309 }
310
311 return true;
312 }
313 }