001package 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 */ 018import static com.nativelibs4java.velocity.Utils.*; 019import com.google.common.base.Function; 020import java.io.BufferedReader; 021import org.apache.maven.plugin.AbstractMojo; 022import org.apache.maven.plugin.MojoExecutionException; 023import org.apache.maven.project.MavenProject; 024import org.apache.maven.model.Resource; 025 026import java.io.File; 027import java.io.FileReader; 028import java.io.FileWriter; 029import java.io.IOException; 030import java.io.PrintWriter; 031import java.io.StringWriter; 032import java.util.ArrayList; 033import java.util.Collection; 034import java.util.Map; 035import java.util.List; 036import java.util.regex.Matcher; 037import java.util.regex.Pattern; 038import org.apache.velocity.*; 039import org.apache.velocity.app.VelocityEngine; 040import org.apache.velocity.app.Velocity; 041import 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 */ 050public 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}