DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT <http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16279>. ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND INSERTED IN THE BUG DATABASE.
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16279 Velocity task Summary: Velocity task Product: Ant Version: 1.5.1 Platform: All OS/Version: All Status: NEW Severity: Enhancement Priority: Other Component: Optional Tasks AssignedTo: [EMAIL PROTECTED] ReportedBy: [EMAIL PROTECTED] The <velocity> task is meant to be a richer version of filter function of the <copy> task. I have been using the filter function for replacing parameters in configuration files. But I need more functionality than just replacing. I think this is where Velocity comes in. This template engine has directives like #if and #foreach, so it is more powerful. The <velocity> task has attributes and nested elements similar to the <copy> task. I thought it would be easy to use. But not all of <copy> attributes are supported. Please see the velocity.html in the patch. Here is a example of calling a <velocity> task: <velocity todir="c" propertyfile="velocity.properties"> <velocitycontext> <contextdata key="a" value="A1"/> <contextdata key="b" value="B1" if="SOME_PROP"/> <contextdata key="b" value="B2" unless="SOME_PROP"/> <contextdata key="str" classname="my.package.StringTool"/> </velocitycontext> <fileset dir="a"> <include name="**/*.vm"/> </fileset> <mapper type="glob" from="*.vm" to="*.html"/> </velocity> Opinions and suggestions are welcome. Here is the patch for the <velocity> task: diff -ruN jakarta-ant-1.5.1.orig/docs/manual/OptionalTasks/velocity.html jakarta-ant-1.5.1/docs/manual/OptionalTasks/velocity.html --- jakarta-ant-1.5.1.orig/docs/manual/OptionalTasks/velocity.html 1970-01-01 09:00:00.000000000 +0900 +++ jakarta-ant-1.5.1/docs/manual/OptionalTasks/velocity.html 2003-01-21 07:39:03.000000000 +0900 @@ -0,0 +1,232 @@ +<html> + +<head> +<meta http-equiv="Content-Language" content="en-us"> +<title>Velocity Task</title> +</head> + +<body> + +<h2><a name="velocity">Velocity</a></h2> +<h3>Description</h3> +<p>Run <a href="http://jakarta.apache.org/velocity/index.html" target="_top">Jakarta-Velocity</a> on a file or FileSet to a new file or directory. +By default, files are only copied if the source file is newer than the +destination file, or when the destination file does not exist. However, +you can explicitly overwrite files with the <code>overwrite</code> attribute.</p> +<p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select a +set of files to copy. +To use a <code><fileset></code>, the <code>todir</code> attribute +must be set.</p> +<h3>Parameters</h3> +<table border="1" cellpadding="2" cellspacing="0"> + <tr> + <td valign="top"><b>Attribute</b></td> + <td valign="top"><b>Description</b></td> + <td align="center" valign="top"><b>Required</b></td> + </tr> + <tr> + <td valign="top">propertyfile</td> + <td valign="top">The property file which is used to initialize Velocity. + </td> + <td valign="top" align="center">Yes</td> + </tr> + <tr> + <td valign="top">file</td> + <td valign="top">The file to copy.</td> + <td valign="top" align="center">Yes, unless a nested + <code><fileset></code> element is used.</td> + </tr> + <tr> + <td valign="top">tofile</td> + <td valign="top">The file to copy to.</td> + <td valign="top" align="center" rowspan="2">With the <code>file</code> + attribute, either <code>tofile</code> or <code>todir</code> can be used. + With nested <code><fileset></code> elements, if the set of files + is greater than 1, or if only the <code>dir</code> attribute is + specified in the <code><fileset></code>, or if the + <code>file</code> attribute is also specified, then only + <code>todir</code> is allowed.</td> + </tr> + <tr> + <td valign="top">todir</td> + <td valign="top">The directory to copy to.</td> + </tr> + <tr> + <td valign="top">overwrite</td> + <td valign="top">Overwrite existing files even if the destination + files are newer.</td> + <td valign="top" align="center">No; defaults to false.</td> + </tr> + <tr> + <td valign="top">flatten</td> + <td valign="top">Ignore the directory structure of the source files, + and copy all files into the directory specified by the <code>todir</code> + attribute. Note that you can achieve the same effect by using a + <a href="../CoreTypes/mapper.html#flatten-mapper">flatten mapper</a>.</td> + <td valign="top" align="center">No; defaults to false.</td> + </tr> + <tr> + <td valign="top">failonerror</td> + <td valign="top">Log a warning message, but do not stop the build, + when the file to copy does not exist. + Only meaningful when copying a single file. + </td> + <td valign="top" align="center">No; defaults to true.</td> + </tr> + <tr> + <td valign="top">templatebasedir</td> + <td valign="top">The template base directory. This is used to + caclutate a relative path of a template file. Velocity receives a + relative path and searches a template file in Velocity's search paths. + </td> + <td valign="top" align="center">No; defaults to project basedir.</td> + </tr> +</table> +<h3>Parameters specified as nested elements</h3> + +<h4>velocitycontext</h4> + <p>A <velocitycontext> is used to specify the VelocityContext data. + It has nested <contextdata> elements.</p> + +<h4>contextdata</h4> + <p>A <contextdata> is a nested element of <velocitycontext> + and is used to specify a VelocityContext datum.</p> + +<table border="1" cellpadding="2" cellspacing="0"> + <tr> + <td valign="top"><b>Attribute</b></td> + <td valign="top"><b>Description</b></td> + <td align="center" valign="top"><b>Required</b></td> + </tr> + <tr> + <td valign="top">key</td> + <td valign="top">The key of a VelocityContext datum. + </td> + <td valign="top" align="center">Yes</td> + </tr> + <tr> + <td valign="top">value</td> + <td valign="top">The value of a VelocityContext datum.</td> + <td valign="top" align="center" rowspan="2">One of either <var>value</var> + or <var>classname</var>.</td> + </tr> + <tr> + <td valign="top">classname</td> + <td valign="top">An instance of this classname is used as a VelocityContext + datum. The specified class must have the public non-argument constructor. + And if the class has a public method + <code>setContext(org.apache.velocity.context.Context)</code>, + it is invoked by reflection. + </td> + </tr> + <tr> + <td valign="top">if</td> + <td valign="top">Only use this data if the named property is set.</td> + <td align="center" valign="top">No</td> + </tr> + <tr> + <td valign="top">unless</td> + <td valign="top">Only use this data if the named property is + <b>not</b> set.</td> + <td align="center" valign="top">No</td> + </tr> +</table> + +<h4>fileset</h4> + <p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select +sets of files to run velocity on. + To use a fileset, the <code>todir</code> attribute must be set.</p> + +<h4>mapper</h4> + <p>You can define filename transformations by using a nested <a + href="../CoreTypes/mapper.html">mapper</a> element. The default mapper used by + <code><velocity></code> is the <a + href="../CoreTypes/mapper.html#identity-mapper">identity mapper</a>.</p> + +<h3>Examples</h3> +<p><b>Run velocity on a single file</b></p> +<pre> + <velocity file="myfile.txt" tofile="mycopy.txt" + propertyfile="velocity.properties"> + <velocitycontext> + <contextdata key="key1" value="value1"/> + <contextdata key="key2" classname="some.Class1"/> + <contextdata key="key3" value="value3" if="SOME_PROPERTY"/> + <contextdata key="key4" value="value4" unless="SOME_PROPERTY"/> + </velocitycontext> + </velocity> +</pre> +<p><b>Run velocity on a single file to a directory</b></p> +<pre> + <velocity file="myfile.txt" todir="../some/other/dir" + propertyfile="velocity.properties"> + <velocitycontext> + <contextdata key="key1" value="value1"/> + <contextdata key="key2" classname="some.Class1"/> + <contextdata key="key3" value="value3" if="SOME_PROPERTY"/> + <contextdata key="key4" value="value4" unless="SOME_PROPERTY"/> + </velocitycontext> + </velocity> +</pre> +<p><b>Run velocity on a set of files to a directory</b></p> +<pre> + <velocity todir="../dest/dir" + propertyfile="velocity.properties"> + <velocitycontext> + <contextdata key="key1" value="value1"/> + <contextdata key="key2" classname="some.Class1"/> + <contextdata key="key3" value="value3" if="SOME_PROPERTY"/> + <contextdata key="key4" value="value4" unless="SOME_PROPERTY"/> + </velocitycontext> + <fileset dir="src_dir"> + <exclude name="**/*.java"/> + </fileset> + </velocity> + + <velocity todir="../dest/dir" + propertyfile="velocity.properties"> + <velocitycontext> + <contextdata key="key1" value="value1"/> + <contextdata key="key2" classname="some.Class1"/> + <contextdata key="key3" value="value3" if="SOME_PROPERTY"/> + <contextdata key="key4" value="value4" unless="SOME_PROPERTY"/> + </velocitycontext> + <fileset dir="src_dir" excludes="**/*.java"/> + </velocity> +</pre> +<p><b>Run velocity on a set of files to a directory, appending +<code>.bak</code> to the file name on the fly</b></p> +<pre> + <velocity todir="../backup/dir" + propertyfile="velocity.properties"> + <velocitycontext> + <contextdata key="key1" value="value1"/> + <contextdata key="key2" classname="some.Class1"/> + <contextdata key="key3" value="value3" if="SOME_PROPERTY"/> + <contextdata key="key4" value="value4" unless="SOME_PROPERTY"/> + </velocitycontext> + <fileset dir="src_dir"/> + <mapper type="glob" from="*" to="*.bak"/> + </velocity> +</pre> + +<p><strong>Unix Note:</strong> Destination file permissions are not the same as +the template files; they end up with the default <code>UMASK</code> permissions +instead. This +is caused by the lack of any means to query or set file permissions in the +current Java runtimes. +</p> + +<p><strong>Windows Note:</strong> If you a destination file already exists, +but with different casing, the destination file takes on the case of the +original. The workaround is to +<a href="delete.html">delete</a> +the file in the destination directory before you run velocity. +</p> + +<hr><p align="center">Copyright © 2003 Apache Software Foundation. +All rights Reserved.</p> + +</body> +</html> + diff -ruN jakarta-ant-1.5.1.orig/docs/manual/install.html jakarta-ant- 1.5.1/docs/manual/install.html --- jakarta-ant-1.5.1.orig/docs/manual/install.html 2002-10-02 11:10:18.000000000 +0900 +++ jakarta-ant-1.5.1/docs/manual/install.html 2003-01-21 07:37:06.000000000 +0900 @@ -381,6 +381,12 @@ <td><a href="http://www.clarkware.com/software/JDepend.html" target="_top">http://www.clarkware.com/software/JDepend.html</a></td> </tr> + <tr> + <td>Velocity JAR(s)</td> + <td>velocity task</td> + <td><a href="http://jakarta.apache.org/velocity/index.html" + target="_top">http://jakarta.apache.org/velocity/index.html</a></td> + </tr> </table> <br> <hr> diff -ruN jakarta-ant-1.5.1.orig/docs/manual/optionaltasklist.html jakarta-ant- 1.5.1/docs/manual/optionaltasklist.html --- jakarta-ant-1.5.1.orig/docs/manual/optionaltasklist.html 2002-10-02 11:10:06.000000000 +0900 +++ jakarta-ant-1.5.1/docs/manual/optionaltasklist.html 2003-01-20 09:40:43.000000000 +0900 @@ -62,6 +62,7 @@ <a href="OptionalTasks/test.html">Test</a><br> <a href="OptionalTasks/translate.html">Translate</a><br> <a href="Integration/VAJAntTool.html#tasks">Visual Age for Java Tasks</a><br> +<a href="OptionalTasks/velocity.html">Velocity</a><br> <a href="OptionalTasks/vss.html#tasks">Microsoft Visual SourceSafe Tasks</a><br> <a href="OptionalTasks/wljspc.html">Weblogic JSP Compiler</a><br> <a href="OptionalTasks/xmlvalidate.html">XmlValidate</a><br> diff -ruN jakarta-ant- 1.5.1.orig/src/main/org/apache/tools/ant/taskdefs/defaults.properties jakarta-ant-1.5.1/src/main/org/apache/tools/ant/taskdefs/defaults.properties --- jakarta-ant- 1.5.1.orig/src/main/org/apache/tools/ant/taskdefs/defaults.properties 2002-10- 02 11:08:34.000000000 +0900 +++ jakarta-ant- 1.5.1/src/main/org/apache/tools/ant/taskdefs/defaults.properties 2003-01-21 07:29:56.000000000 +0900 @@ -169,6 +169,7 @@ jarlib- available=org.apache.tools.ant.taskdefs.optional.extension.JarLibAvailableTask jarlib- resolve=org.apache.tools.ant.taskdefs.optional.extension.JarLibResolveTask setproxy=org.apache.tools.ant.taskdefs.optional.net.SetProxy +velocity=org.apache.tools.ant.taskdefs.optional.VelocityTask # deprecated ant tasks (kept for back compatibility) starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut diff -ruN jakarta-ant- 1.5.1.orig/src/main/org/apache/tools/ant/taskdefs/optional/VelocityTask.java jakarta-ant- 1.5.1/src/main/org/apache/tools/ant/taskdefs/optional/VelocityTask.java --- jakarta-ant- 1.5.1.orig/src/main/org/apache/tools/ant/taskdefs/optional/VelocityTask.java 1970-01-01 09:00:00.000000000 +0900 +++ jakarta-ant- 1.5.1/src/main/org/apache/tools/ant/taskdefs/optional/VelocityTask.java 2003-01- 20 10:48:52.000000000 +0900 @@ -0,0 +1,478 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000-2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact [EMAIL PROTECTED] + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.taskdefs.optional; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.util.Enumeration; +import java.util.Vector; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.Mapper; +import org.apache.tools.ant.types.optional.velocity.VelocityContext; +import org.apache.tools.ant.util.FileNameMapper; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.FlatFileNameMapper; +import org.apache.tools.ant.util.IdentityMapper; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.context.Context; + + +/** + * Run velocity on a file or a fileset to a new file + * or directory. Velocity is only run for a file which is newer + * than the destination file, or when the destination file does not + * exist. It is possible to explicitly overwrite existing files.</p> + * + * <p>This task is supposed to be a richer version of filter function + * of copy task, and has similar attributes and nested elements.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Hiroaki Nakamura</a> + * + * @version $Revision$ + */ +public class VelocityTask extends Task { + protected File templateBaseDir = null; + protected File file = null; // the template file + protected File destFile = null; // the destination file + protected File destDir = null; // the destination directory + protected String encoding = System.getProperty("file.encoding"); // template and output file encoding + protected File propertyFile = null; // the destination file + protected VelocityContext velocityContext; // the <velocitycontext> nested element + protected Vector filesets = new Vector(); + + protected boolean forceOverwrite = false; + private boolean failonerror = true; + + protected boolean flatten = false; + protected Mapper mapperElement = null; + + private FileUtils fileUtils; + + /** + * Velocity task constructor. + */ + public VelocityTask() { + fileUtils = FileUtils.newFileUtils(); + } + + protected FileUtils getFileUtils() { + return fileUtils; + } + + /** + * Sets template files base directory. + */ + public void setTemplateBaseDir(File dir) { + this.templateBaseDir = dir; + } + + /** + * @return templatebasedir attribute value or project basedir if templatebasedir is not set. + */ + protected File getTemplateBaseDir() { + return templateBaseDir == null + ? project.getBaseDir() : templateBaseDir; + } + + /** + * Sets a single source file to copy. + */ + public void setFile(File file) { + this.file = file; + } + + /** + * Sets the destination file. + */ + public void setTofile(File destFile) { + this.destFile = destFile; + } + + /** + * Sets the destination directory. + */ + public void setTodir(File destDir) { + this.destDir = destDir; + } + + /** + * Sets the Velocity propertyfile. + */ + public void setPropertyFile(File propertyFile) { + this.propertyFile = propertyFile; + } + + /** + * Sets the encoding. + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** + * Create a nested velocitycontext element. + */ + public VelocityContext createVelocityContext() throws BuildException { + if (velocityContext != null) { + throw new BuildException("Cannot define more than one velocitycontext", + location); + } + velocityContext = new VelocityContext(); + return velocityContext; + } + + /** + * Adds a set of files to copy. + */ + public void addFileset(FileSet set) { + filesets.addElement(set); + } + + /** + * Overwrite any existing destination file(s). + */ + public void setOverwrite(boolean overwrite) { + this.forceOverwrite = overwrite; + } + + /** + * If false, note errors to the output but keep going. + * @param failonerror true or false + */ + public void setFailOnError(boolean failonerror) { + this.failonerror = failonerror; + } + + /** + * When copying directory trees, the files can be "flattened" + * into a single directory. If there are multiple files with + * the same name in the source directory tree, only the first + * file will be copied into the "flattened" directory, unless + * the forceoverwrite attribute is true. + */ + public void setFlatten(boolean flatten) { + this.flatten = flatten; + } + + /** + * Defines the mapper to map source to destination files. + */ + public Mapper createMapper() throws BuildException { + if (mapperElement != null) { + throw new BuildException("Cannot define more than one mapper", + location); + } + mapperElement = new Mapper(project); + return mapperElement; + } + + /** + * Performs the velocity template merge operation. + */ + public void execute() throws BuildException { + File savedFile = file; // may be altered in validateAttributes + File savedDestFile = destFile; + File savedDestDir = destDir; + FileSet savedFileSet = null; + if (file == null && destFile != null && filesets.size() == 1) { + // will be removed in validateAttributes + savedFileSet = (FileSet) filesets.elementAt(0); + } + + validateAttributes(); + + try { + initVelocity(); + Context ctx = createContext(); + File tmplBaseDir = getTemplateBaseDir(); + + if (file != null) { + if (!file.exists()) { + String message = "Warning: Could not find template file " + + file.getAbsolutePath() + "."; + if (!failonerror) { + log(message); + } else { + throw new BuildException(message); + } + } + + if (destFile == null) { + destFile = new File(destDir, file.getName()); + } + + mergeTemplateUnlessUpToDate( + tmplBaseDir, + file, + ctx, + destFile); + } + + if (filesets != null) { + FileNameMapper mapper = getFileNameMapper(); + for (Enumeration en = filesets.elements(); en.hasMoreElements ();) { + FileSet fs = (FileSet) en.nextElement(); + DirectoryScanner ds = fs.getDirectoryScanner(project); + File dsBaseDir = ds.getBasedir(); + String[] files = ds.getIncludedFiles(); + for (int i = 0; i < files.length; i++) { + String srcRelativePath = files[i]; + File srcFile = new File(dsBaseDir, srcRelativePath); + String[] destRelativePaths = mapper.mapFileName (srcRelativePath); + for (int j = 0; j < destRelativePaths.length; j++) { + String destRelativePath = destRelativePaths[j]; + File curDestFile = new File(destDir, destRelativePath); + mergeTemplateUnlessUpToDate( + tmplBaseDir, + srcFile, + ctx, + curDestFile); + } + } + } + } + } finally { + // clean up again, so this instance can be used a second + // time + file = savedFile; + destFile = savedDestFile; + destDir = savedDestDir; + if (savedFileSet != null && filesets.size() == 0) { + filesets.insertElementAt(savedFileSet, 0); + } + } + } + +//************************************************************************ +// protected and private methods +//************************************************************************ + + /** + * Ensure we have a consistent and legal set of attributes, and set + * any internal flags necessary based on different combinations + * of attributes. + */ + protected void validateAttributes() throws BuildException { + if (file == null && filesets.size() == 0) { + throw new BuildException("Specify at least one source " + + "- a file or a fileset."); + } + + if (destFile != null && destDir != null) { + throw new BuildException("Only one of tofile and todir " + + "may be set."); + } + + if (destFile == null && destDir == null) { + throw new BuildException("One of tofile or todir must be set."); + } + + if (file != null && file.exists() && file.isDirectory()) { + throw new BuildException("Use a fileset to copy directories."); + } + + if (destFile != null && filesets.size() > 0) { + if (filesets.size() > 1) { + throw new BuildException( + "Cannot concatenate multiple files into a single file."); + } else { + FileSet fs = (FileSet) filesets.elementAt(0); + DirectoryScanner ds = fs.getDirectoryScanner(project); + String[] srcFiles = ds.getIncludedFiles(); + + if (srcFiles.length == 0) { + throw new BuildException( + "Cannot perform operation from directory to file."); + } else if (srcFiles.length == 1) { + if (file == null) { + file = new File(ds.getBasedir(), srcFiles[0]); + filesets.removeElementAt(0); + } else { + throw new BuildException("Cannot concatenate multiple " + + "files into a single file."); + } + } else { + throw new BuildException("Cannot concatenate multiple " + + "files into a single file."); + } + } + } + + if (destFile != null) { + destDir = fileUtils.getParentFile(destFile); + } + + } + + /** + * @return FileNameMapper instance + */ + protected FileNameMapper getFileNameMapper() { + FileNameMapper mapper = null; + if (mapperElement != null) { + mapper = mapperElement.getImplementation(); + } else if (flatten) { + mapper = new FlatFileNameMapper(); + } else { + mapper = new IdentityMapper(); + } + return mapper; + } + + /** + * Initializes Velocity. + */ + protected void initVelocity() throws BuildException { + if (propertyFile == null) { + throw new BuildException("propertyfile must be set"); + } + try { + Velocity.init(propertyFile.getPath()); + } catch (Exception ex) { + throw new BuildException(ex); + } + } + + /** + * Merge Velocity template file to the corresponding destination file + * if the destination file is older than the template file or does not exist. + */ + protected void mergeTemplateUnlessUpToDate( + File templateBaseDir, + File templateFile, + Context ctx, + File destFile) + throws BuildException { + + if (forceOverwrite || + (templateFile.lastModified() > destFile.lastModified())) { + String templatePath = getRelativePath(templateFile, templateBaseDir); + mergeTemplate(templatePath, ctx, destFile); + } else { + log(templateFile + " omitted as " + destFile + + " is up to date.", Project.MSG_VERBOSE); + } + } + + /** + * Merge Velocity template file to the corresponding destination file. + */ + protected void mergeTemplate( + String templateRelativePath, + Context ctx, + File destFile) + throws BuildException { + try { + File destDir = fileUtils.getParentFile(destFile); + if (!destDir.exists()) { + destDir.mkdirs(); + } + + OutputStreamWriter osw = null; + FileOutputStream fos = new FileOutputStream(destFile); + try { + osw = new OutputStreamWriter(fos, encoding); + try { + Velocity.mergeTemplate( + templateRelativePath, + encoding, + ctx, + osw); + } finally { + osw.close(); + fos = null; + } + } finally { + if (fos != null) { + fos.close(); + } + } + } catch (Exception ex) { + throw new BuildException(ex); + } + } + + /** + * @return relative path of file from baseDir + */ + protected String getRelativePath(File file, File baseDir) { + int trimLen = baseDir.getAbsolutePath().length(); + if (!isRootDirectory(baseDir)) { + trimLen++; + } + return file.getAbsolutePath().substring(trimLen); + } + + /** + * @return whether dir is root directory or not. + */ + protected boolean isRootDirectory(File dir) { + return dir.getParent() == null; + } + + /** + * @return Velocity context created. + */ + protected Context createContext() + throws BuildException { + return velocityContext.createRealContext(); + } +} diff -ruN jakarta-ant- 1.5.1.orig/src/main/org/apache/tools/ant/types/optional/velocity/VelocityContext .java jakarta-ant- 1.5.1/src/main/org/apache/tools/ant/types/optional/velocity/VelocityContext.java --- jakarta-ant- 1.5.1.orig/src/main/org/apache/tools/ant/types/optional/velocity/VelocityContext .java 1970-01-01 09:00:00.000000000 +0900 +++ jakarta-ant- 1.5.1/src/main/org/apache/tools/ant/types/optional/velocity/VelocityContext.java 2003-01-20 11:00:10.000000000 +0900 @@ -0,0 +1,258 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000-2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact [EMAIL PROTECTED] + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.optional.velocity; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Enumeration; +import java.util.Vector; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.DataType; +import org.apache.velocity.context.Context; + +/** + * A VelocityContext is a nested element of Velocity task. + * It has nested <code><contextdata></code> elements. + * + * @author <a href="mailto:[EMAIL PROTECTED]">Hiroaki Nakamura</a> + * + * @version $Revision$ + */ +public class VelocityContext extends DataType { + private Vector contextData = new Vector(); + + /** + * Creates the nested <code><contextdata></code> element. + */ + public ContextData createContextData() throws BuildException { + ContextData cd = new ContextData(); + contextData.addElement(cd); + return cd; + } + + /** + * @return real org.apache.velocity.VelocityContext specified by + * <code><velocitycontext></code> element. + */ + public Context createRealContext() + throws BuildException { + Context context = new org.apache.velocity.VelocityContext(); + populateContext(context); + return context; + } + + /** + * Populates org.apache.velocity.VelocityContext with data specified by + * nested <code><contextdata></code> elements. + */ + protected void populateContext(Context context) + throws BuildException { + for (Enumeration en = contextData.elements(); en.hasMoreElements();) { + Object o = en.nextElement(); + ContextData cd = (ContextData) o; + cd.addIfValid(context); + } + } + + /** + * ContextData represents a nested <code><contextdata></code> element. + * The attribute <code>key</code> is necessary. One of attribute <code>value</code> + * or <code>className</code> is necessary. The attribute <code>value</code> + * is used to create immediate Context data. The attribute <code>className</code> + * is used to create a "tool" object which is later used from template files. + * The attribute <code>if</code> and <code>unless</code> are optional, which + * are used to control of enabling or disabling of a <code><contextdata></code> + * element. + */ + public class ContextData { + protected String key; + protected String value; + protected String ifCond; + protected String className; + protected String unlessCond; + + /** + * Sets the key. + * @param name The key to set + */ + public void setKey(String key) { + this.key = key; + } + + /** + * Sets the value. + * @param value The value to set + */ + public void setValue(String value) { + this.value = value; + } + + /** + * Sets the className. + * @param className The className to set + */ + public void setClassName(String className) { + this.className = className; + } + + /** + * Sets the ifCond. + * @param ifCond The ifCond to set + */ + public void setIf(String ifCond) { + this.ifCond = ifCond; + } + + /** + * Sets the unlessCond. + * @param unlessCond The unlessCond to set + */ + public void setUnless(String unlessCond) { + this.unlessCond = unlessCond; + } + + /** + * @return whether this element is valid or not + */ + public boolean isValid() { + Project p = getProject(); + if (ifCond != null && p.getProperty(ifCond) == null) { + return false; + } else if (unlessCond != null && p.getProperty(unlessCond) != null) { + return false; + } + return true; + } + + /** + * Add to a context if this element is valid. + */ + public void addIfValid(Context context) + throws BuildException { + if (!isValid()) { + return; + } + + if (key == null) { + throw new BuildException("name must be set"); + } + + if (value != null && className != null) { + throw new BuildException("value and className cannot both be set"); + } else if (value == null && className == null) { + throw new BuildException("value or className must be set"); + } + + if (value != null) { + context.put(key, value); + } else if (className != null) { + Object instance = createInstance(className); + invokeSetContext(instance, context); + context.put(key, instance); + } + } + + /** + * @return an instance of the specified class. + */ + protected Object createInstance(String className) + throws BuildException { + try { + return Class.forName(className).newInstance(); + } catch (ClassNotFoundException ex) { + throw new BuildException(ex); + } catch (IllegalAccessException ex) { + throw new BuildException(ex); + } catch (InstantiationException ex) { + throw new BuildException(ex); + } + } + + protected void invokeSetContext(Object instance, Context context) + throws BuildException { + try { + Class[] paramTypes = { Context.class }; + Method method = instance.getClass().getMethod("setContext", paramTypes); + Object[] args = { context }; + method.invoke(instance, args); + } catch (NoSuchMethodException ex) { + // ignore + } catch (IllegalAccessException ex) { + throw new BuildException(ex); + } catch (InvocationTargetException ex) { + throw new BuildException(ex); + } + } + + /** + * @return a string representation of an instance. + */ + public String toString() { + return "ContextVar[name=" + + key + + ", value=" + + value + + ", className=" + + className + + ", if=" + + ifCond + + ", unless=" + + unlessCond + + "]"; + } + } +} -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>