001package com.hfg.anttask;
002
003
004import org.apache.tools.ant.BuildException;
005import org.apache.tools.ant.DirectoryScanner;
006import org.apache.tools.ant.FileScanner;
007import org.apache.tools.ant.Task;
008import org.apache.tools.ant.types.PatternSet;
009
010import java.io.File;
011
012import com.hfg.util.BooleanUtil;
013import com.hfg.util.StringUtil;
014
015
016//------------------------------------------------------------------------------
017/**
018 Ant task for assigning a file to a property.
019 <h3>Description</h3>
020 <p>If the specified file exists, this task sets the properties
021 <code><i>&lt;name&gt;</i></code>, <code><i>&lt;name&gt;</i>.name</code>,
022 <code><i>&lt;name&gt;</i>.wildcard</code>,
023 in the project. Properties are case sensitive.</p>
024 <p>Normally, this task is used with files whose names contain a variable portion, the
025 matching of which is facilitated by a PatternSet which allows '*' and '?' wildcarding
026 (see Ant's documentation).
027 </p>
028 <p>
029 If multiple files are found which match the file pattern, a BuildException is thrown.
030 </p>
031
032 <h3>Parameters</h3>
033 <table border="1" cellpadding="2" cellspacing="0">
034   <caption>Parameter descriptions</caption>
035   <tr>
036     <td valign="top"><b>Attribute</b></td>
037     <td valign="top"><b>Description</b></td>
038     <td valign="top" align="center"><b>Required</b></td>
039   </tr>
040   <tr>
041     <td valign="top">name</td>
042     <td valign="top">The name (handle) of the property.</td>
043     <td valign="top" align="center">Yes</td>
044   </tr>
045   <tr>
046     <td valign="top">dir</td>
047     <td valign="top">The directory containing the file. If not
048                      set, it defaults to the current directory.</td>
049     <td valign="top" align='center' rowspan='2'>Yes</td>
050   </tr>
051   <tr>
052     <td valign="top">file</td>
053     <td valign="top">The name of the file (may contain wildcards).
054     If not set, a directory is searched for in place of a file.</td>
055   </tr>
056    <tr>
057     <td valign="top">if</td>
058     <td valign="top">Only execute if a property of the given name exists in the current project.</td>
059     <td valign="top" align="center">No</td>
060   </tr>
061   <tr>
062     <td valign="top">unless</td>
063     <td valign="top">Only execute if a property of the given name doesn't exist in the current project.</td>
064     <td valign="top" align="center">No</td>
065   </tr>
066  </table>
067  <p>
068   The <code>if</code> and <code>unless</code> attributes make the
069  execution conditional -both probe for the named property being defined.
070  The <code>if</code> tests for the property being defined, the
071  <code>unless</code> for a property being undefined.
072  </p>
073  If both attributes are set, then the task executes only if both tests
074  are true. i.e.
075  <pre>execute := defined(ifProperty) &amp;&amp; !defined(unlessProperty)</pre>
076
077 <h3>Examples</h3>
078 If <code>${lib.dir}</code> contained the file <code>commons-net-20040324.jar</code>
079 <pre>
080 &lt;fileproperty name='commons_net' dir='${lib.dir}' file='commons-net-*.jar' /&gt;
081 </pre>
082 would set the <code>commons_net</code> property to <code>${lib.dir}/commons-net-20040324.jar</code>,
083 the <code>commons_net.name</code> property to <code>commons-net-20040324.jar</code>,
084 the <code>commons_net.wildcard</code> property to <code>20040324</code>
085
086 @author J. Alex Taylor, hairyfatguy.com
087 */
088//------------------------------------------------------------------------------
089// com.hfg XML/HTML Coding Library
090//
091// This library is free software; you can redistribute it and/or
092// modify it under the terms of the GNU Lesser General Public
093// License as published by the Free Software Foundation; either
094// version 2.1 of the License, or (at your option) any later version.
095//
096// This library is distributed in the hope that it will be useful,
097// but WITHOUT ANY WARRANTY; without even the implied warranty of
098// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
099// Lesser General Public License for more details.
100//
101// You should have received a copy of the GNU Lesser General Public
102// License along with this library; if not, write to the Free Software
103// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
104//
105// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
106// jataylor@hairyfatguy.com
107//------------------------------------------------------------------------------
108
109
110
111public class FileProperty extends Task
112{
113
114   private String mName;
115   private PatternSet mPattern;
116   private File mDir = new File(".");
117   private String  mIfCondition;
118   private String  mUnlessCondition;
119   private boolean mDebug;
120
121   private int mMode = FILE_MODE;
122
123   private static int FILE_MODE = 1;
124   private static int DIR_MODE = 2;
125
126   //--------------------------------------------------------------------------
127   public void setName(String name)
128   {
129      mName = name;
130   }
131
132   //--------------------------------------------------------------------------
133   public void setFile(String file)
134   {
135      mPattern = new PatternSet();
136      mPattern.setIncludes(file);
137   }
138
139   //--------------------------------------------------------------------------
140   public void setDir(File dir) throws BuildException
141   {
142      mDir = dir;
143   }
144
145   //--------------------------------------------------------------------------
146   public void setDebug(String inValue) throws BuildException
147   {
148      mDebug = BooleanUtil.valueOf(inValue);
149   }
150
151
152   //---------------------------------------------------------------------------
153   /**
154    * Only execute if a property of the given name exists in the current project
155    *
156    * @param inPropertyName property name
157    */
158   public void setIf(String inPropertyName)
159   {
160       mIfCondition = inPropertyName;
161   }
162
163   //---------------------------------------------------------------------------
164   /**
165    * Only execute if a property of the given name does not exist in the current project
166    *
167    * @param inPropertyName property name
168    */
169   public void setUnless(String inPropertyName)
170   {
171       mUnlessCondition = inPropertyName;
172   }
173
174   //--------------------------------------------------------------------------
175   public void execute()
176         throws BuildException
177   {
178      if (TaskUtil.testIfCondition(mIfCondition, getProject())
179          && TaskUtil.testUnlessCondition(mUnlessCondition, getProject()))
180      {
181         try
182         {
183            if (null == mPattern)
184            {
185               // No file pattern specified. Use the dir as a pattern
186               mPattern = new PatternSet();
187               mPattern.setIncludes(mDir.getName());
188
189               mDir = mDir.getParentFile();
190               mMode = DIR_MODE;
191            }
192
193            if (mDir.exists()
194                  && mDir.isDirectory())
195            {
196               DirectoryScanner ds = getDirectoryScanner();
197
198               if (mDebug)
199               {
200                  System.out.println("Looking for file pattern " + StringUtil.singleQuote(mPattern.toString()) + " ...");
201               }
202
203               String[] srcFiles = (mMode == FILE_MODE ? ds.getIncludedFiles() : ds.getIncludedDirectories());
204
205               if (mDebug)
206               {
207                  System.out.println(srcFiles.length + " matching files found.");
208               }
209
210               if (srcFiles.length > 1)
211               {
212                  throw new BuildException("More than one file matches pattern.");
213               }
214               else if (srcFiles.length == 1)
215               {
216                  File file = new File(mDir, srcFiles[0]);
217                  getProject().setProperty(mName, file.getAbsolutePath());
218                  getProject().setProperty(mName + ".name", file.getName());
219                  setWildcardProperty(file.getName());
220               }
221            }
222            else if (mDebug)
223            {
224               System.out.println("Directory " + StringUtil.singleQuote(mDir.getPath()) + " doesn't exist!");
225            }
226
227         }
228         catch (Exception e)
229         {
230            throw new BuildException(e);
231         }
232      }
233   }
234
235
236   //--------------------------------------------------------------------------
237   private void setWildcardProperty(String matchedFilename)
238   {
239      String patternString = mPattern.getIncludePatterns(getProject())[0];
240      int wildcardIndex = patternString.indexOf("*");
241      if (wildcardIndex >= 0)
242      {
243         String wildcard = "";
244         if (wildcardIndex > 0)
245         {
246            String leftSide = patternString.substring(0, wildcardIndex);
247            wildcard = matchedFilename.substring(leftSide.length());
248         }
249
250         String rightSide = patternString.substring(wildcardIndex + 1);
251         if (wildcardIndex < patternString.length()
252             && rightSide.length() < wildcard.length())
253         {
254            wildcard = wildcard.substring(0,  wildcard.length() - rightSide.length());
255         }
256
257         getProject().setProperty(mName + ".wildcard", wildcard);
258      }
259      else
260      {
261         wildcardIndex = patternString.indexOf("?");
262         if (wildcardIndex >= 0)
263         {
264            StringBuilder wildcard = new StringBuilder();
265            while (wildcardIndex < patternString.length())
266            {
267               if (patternString.charAt(wildcardIndex) == '?')
268               {
269                  wildcard.append(matchedFilename.charAt(wildcardIndex));
270               }
271               else
272               {
273                  break;
274               }
275               wildcardIndex++;
276            }
277
278            getProject().setProperty(mName + ".wildcard", wildcard.toString());
279         }
280      }
281   }
282
283   //--------------------------------------------------------------------------
284   /**
285    * Returns the directory scanner needed to access the files to process.
286    */
287   private DirectoryScanner getDirectoryScanner()
288   {
289      DirectoryScanner ds = new DirectoryScanner();
290      setupDirectoryScanner(ds);
291      ds.scan();
292
293      return ds;
294   }
295
296   //--------------------------------------------------------------------------
297   private void setupDirectoryScanner(FileScanner ds)
298   {
299      if (ds == null)
300      {
301         throw new IllegalArgumentException("ds cannot be null");
302      }
303
304      ds.setBasedir(mDir);
305      ds.setIncludes(mPattern.getIncludePatterns(getProject()));
306   }
307
308}