001/* 002// $Id: //open/util/resgen/src/org/eigenbase/resgen/ResourceGenTask.java#7 $ 003// Package org.eigenbase.resgen is an i18n resource generator. 004// Copyright (C) 2005-2005 The Eigenbase Project 005// Copyright (C) 2005-2005 Disruptive Tech 006// Copyright (C) 2005-2005 LucidEra, Inc. 007// Portions Copyright (C) 2002-2005 Kana Software, Inc. and others. 008// 009// This library is free software; you can redistribute it and/or modify it 010// under the terms of the GNU Lesser General Public License as published by the 011// Free Software Foundation; either version 2 of the License, or (at your 012// option) any later version approved by The Eigenbase Project. 013// 014// This library is distributed in the hope that it will be useful, 015// but WITHOUT ANY WARRANTY; without even the implied warranty of 016// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017// GNU Lesser General Public License for more details. 018// 019// You should have received a copy of the GNU Lesser General Public License 020// along with this library; if not, write to the Free Software 021// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 022// 023// jhyde, Oct 8, 2002 024*/ 025 026package org.eigenbase.resgen; 027 028import org.apache.tools.ant.BuildException; 029import org.apache.tools.ant.Task; 030 031import java.io.File; 032import java.io.IOException; 033import java.util.ArrayList; 034 035/** 036 * A <code>ResourceGenTask</code> is an ANT task to invoke the Eigenbase 037 * Resource Generator. 038 * 039 * <p>Example:<blockquote> 040 * 041 * <pre><resgen srcdir="source" locales="en_US"> 042 * <include name="happy/BirthdayResource.xml"/> 043 *</resgen></pre> 044 * 045 * </blockquote>generates<blockquote> 046 * 047 * <pre>source/happy/BirthdayResource.properties 048 *source/happy/BirthdayResource_en_US.properties 049 *source/happy/BirthdayResource.java 050 *source/happy/BirthdayResource_en_US.java</pre> 051 * 052 * </blockquote> 053 * 054 * <p>C++ Example:<blockquote> 055 * 056 * <pre><resgen mode="c++" srcdir="source" locales="en_US"> 057 * <include name="happy/BirthdayResource.xml"/> 058 *</resgen></pre> 059 * 060 * </blockquote>generates<blockquote> 061 * 062 * <pre>source/happy/BirthdayResource.resources 063 *source/happy/BirthdayResource_en_US.resources 064 *source/happy/BirthdayResource.h 065 *source/happy/BirthdayResource.cpp</pre></blockquote> 066 * 067 * <p>Files are not generated if there is an existing newer one.</p> 068 * 069 * <p>The output path is determined by 'destdir' (or 'resdir' for .properties 070 * files) and the package-name (derived from the XML file's path relative to 071 * 'srcdir'). Since the Java runtime environment searches for resource bundles 072 * on the classpath, it is typical to set srcdir="src", destdir="src", 073 * resdir="classes".</p> 074 * 075 * <h2>Element <resourceGen></h2> 076 * 077 * <table border="2"> 078 * <tr> 079 * <th>Attribute</th> 080 * <th>Description</th> 081 * <th>Required</th> 082 * </tr> 083 * 084 * <tr> 085 * <td><a name="mode">mode</a></td> 086 * <td>Generation mode. Acceptable values are "java", "c++" or "all". 087 * The default is "java".</td> 088 * <td>No</td> 089 * </tr> 090 * 091 * <tr> 092 * <td><a name="srcdir">srcdir</a></td> 093 * <td>Source directory. The paths of resource files, and hence the 094 * package names of generated Java classes, are relative to this 095 * directory.</td> 096 * <td>Yes</td> 097 * </tr> 098 * 099 * <tr> 100 * <td><a name="destdir">destdir</a></td> 101 * <td>Destination directory. Output .java files are generated relative to this 102 * directory. If not specified, has the same value as 103 * <a href="#srcdir">srcdir</a>.</td> 104 * <td>No</td> 105 * </tr> 106 * 107 * <tr> 108 * <td><a name="resdir">resdir</a></td> 109 * <td>Resource directory. Output .properties files are generated relative to 110 * this directory. If not specified, has the same value as 111 * <a href="#destdir">destdir</a>.</td> 112 * <td>No</td> 113 * </tr> 114 * 115 * <tr> 116 * <td><a name="locales">locales</a></td> 117 * <td>Comma-separated list of locales to generate files for. 118 * If not specified, uses the locale of the resource file.</td> 119 * <td>No</td> 120 * </tr> 121 * 122 * <tr> 123 * <td><a name="style">style</a></td> 124 * <td>Code-generation style. Values are "dynamic" or "functor". 125 * Default is "dynamic": generate several non-static methods for each 126 * resource. 127 * In the "functor" style, there is one member per resource, which has 128 * several methods.</td> 129 * <td>No</td> 130 * </tr> 131 * 132 * <tr> 133 * <td><a name="force">force</a></td> 134 * <td>Whether to generate files even if they do not appear to be out of 135 * date. Default is false.</td> 136 * <td>No</td> 137 * </tr> 138 * 139 * <tr> 140 * <td><a name="commentstyle">commentstyle</a></td> 141 * <td>Generated comment style. Values are "normal" and "scm-safe". The 142 * default is "normal": generates comments that indicate the source file's 143 * original path and states that the file should not be checked into source 144 * control systems. The "scm-safe" comment style modifies the comments 145 * to make storage of the output files in an SCM more palatable. It omits 146 * the source file's path and states that the file was generated and should 147 * not be edited manually.</td> 148 * <td>No</td> 149 * </table> 150 * 151 * Nested element: <{@link Include include}>. 152 * 153 * @author jhyde 154 * @since Oct 8, 2002 155 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/ResourceGenTask.java#7 $ 156 **/ 157public class ResourceGenTask extends Task 158{ 159 private ArrayList resources = new ArrayList(); 160 int mode = MODE_JAVA; 161 File src; 162 File dest; 163 File res; 164 int style = STYLE_DYNAMIC; 165 String locales; 166 boolean force; 167 int commentStyle = COMMENT_STYLE_NORMAL; 168 169 private static final int MODE_UNKNOWN = -1; 170 private static final int MODE_JAVA = 1; 171 private static final int MODE_CPP = 2; 172 private static final int MODE_ALL = 3; 173 174 public static final int STYLE_DYNAMIC = 1; 175 public static final int STYLE_FUNCTOR = 2; 176 177 public static final int COMMENT_STYLE_NORMAL = 1; 178 public static final int COMMENT_STYLE_SCM_SAFE = 2; 179 180 public ResourceGenTask() 181 { 182 } 183 184 public void execute() throws BuildException 185 { 186 validate(); 187 try { 188 new ResourceGen().run(this); 189 } catch (IOException e) { 190 throw new BuildException(e); 191 } 192 } 193 194 /** Called by ANT. **/ 195 public void addInclude(Include resourceArgs) 196 { 197 resources.add(resourceArgs); 198 resourceArgs.root = this; 199 } 200 201 void validate() 202 { 203 if (mode != MODE_JAVA && mode != MODE_CPP && mode != MODE_ALL) { 204 throw new BuildException("You must specify a value mode: java, c++, or all"); 205 } 206 207 if (src == null) { 208 throw new BuildException("You must specify 'srcdir'"); 209 } 210 if (dest == null) { 211 dest = src; 212 } 213 if (res == null) { 214 res = dest; 215 } 216 final Include[] args = getIncludes(); 217 for (int i = 0; i < args.length; i++) { 218 args[i].validate(); 219 } 220 } 221 222 Include[] getIncludes() 223 { 224 return (Include[]) resources.toArray(new Include[0]); 225 } 226 227 /** Sets <a href="#mode">mode</a>. **/ 228 public void setMode(String mode) 229 throws BuildException 230 { 231 if ("java".equals(mode)) { 232 this.mode = MODE_JAVA; 233 } else if ("c++".equals(mode)) { 234 this.mode = MODE_CPP; 235 } else if ("all".equals(mode)) { 236 this.mode = MODE_ALL; 237 } else { 238 this.mode = MODE_UNKNOWN; 239 } 240 } 241 242 /** Sets <a href="#srcdir">srcdir</a>. **/ 243 public void setSrcdir(File srcDir) 244 { 245 this.src = srcDir; 246 } 247 248 /** Returns <a href="#srcdir">srcdir</a>. **/ 249 public File getSrcdir() 250 { 251 return src; 252 } 253 254 /** Sets <a href="#destdir">destdir</a>. **/ 255 public void setDestdir(File destDir) 256 { 257 this.dest = destDir; 258 } 259 260 /** Returns <a href="#destdir">destdir</a>. **/ 261 public File getDestdir() 262 { 263 return dest; 264 } 265 266 /** Sets <a href="#resdir">resdir</a>. **/ 267 public void setResdir(File resDir) 268 { 269 this.res = resDir; 270 } 271 272 /** Sets <a href="#style">style</a>. */ 273 public void setStyle(String style) throws BuildException 274 { 275 if (style.equals("dynamic")) { 276 this.style = STYLE_DYNAMIC; 277 } else if (style.equals("functor")) { 278 this.style = STYLE_FUNCTOR; 279 } else { 280 throw new BuildException("Invalid style '" + style + "'"); 281 } 282 } 283 284 /** Sets <a href="#locales">locales</a>. **/ 285 public void setLocales(String locales) throws BuildException 286 { 287 this.locales = locales; 288 } 289 290 /** Sets <a href="#force">force</a>. **/ 291 public void setForce(boolean force) 292 { 293 this.force = force; 294 } 295 296 /** Sets <a href="#commentstyle">commentstyle</a>. */ 297 public void setCommentStyle(String commentStyle) throws BuildException 298 { 299 if (commentStyle.equals("normal")) { 300 this.commentStyle = COMMENT_STYLE_NORMAL; 301 } else if (commentStyle.equals("scm-safe")) { 302 this.commentStyle = COMMENT_STYLE_SCM_SAFE; 303 } else { 304 throw new BuildException( 305 "Invalid commentstyle '" + commentStyle + "'"); 306 } 307 } 308 309 /** 310 * <code>Include</code> implements <include> element nested 311 * within a <resgen> task (see {@link ResourceGenTask}). 312 * 313 * <table border="2"> 314 * <tr> 315 * <th>Attribute</th> 316 * <th>Description</th> 317 * <th>Required</th> 318 * </tr> 319 * 320 * <tr> 321 * <td><a name="name">name</a></td> 322 * <td>The name, relative to <a href="#srcdir">srcdir</a>, of the XML file 323 * which defines the resources.</td> 324 * <td>Yes</td> 325 * </tr> 326 * 327 * <tr> 328 * <td><a name="className">className</a></td> 329 * <td>The name of the class to be generated, including the package, but 330 * not including any locale suffix. By default, the class name is 331 * derived from the name of the source file, for example 332 * <code>happy/BirthdayResource_en_US.xml</code> becomes class 333 * <code>happy.BirthdayResource</code>.</td> 334 * <td>No</td> 335 * </tr> 336 * <tr> 337 * 338 * <td><a name="cppClassName">cppClassName</a></td> 339 * <td>The name of the C++ class to be generated. By default, the class 340 * name is derived from the name of the source file, for example 341 * <code>happy/BirthdayResource_en_US.xml</code> becomes class 342 * <code>happy.BirthdayResource</code>.</td> 343 * <td>No</td> 344 * </tr> 345 * 346 * <tr> 347 * <td><a name="baseClassName">baseClassName</a></td> 348 * <td>The fully-qualified name of the base class of the resource bundle. 349 * Defaults to "org.eigenbase.resgen.ShadowResourceBundle".</td> 350 * <td>No</td> 351 * </tr> 352 * 353 * <tr> 354 * <td><a name="cppBaseClassName">cppBaseClassName</a></td> 355 * <td>The fully-qualified name of the base class of the resource bundle 356 * for C++. Defaults to "ResourceBundle".</td> 357 * <td>No</td> 358 * </tr> 359 * 360 * </table> 361 */ 362 public static class Include 363 { 364 public Include() 365 { 366 } 367 ResourceGenTask root; 368 /** Name of source file, relative to 'srcdir'. **/ 369 String fileName; 370 /** Class name. **/ 371 String className; 372 /** Base class. */ 373 String baseClassName; 374 375 /** C++ Class name. **/ 376 String cppClassName; 377 /** C++ Base class. */ 378 String cppBaseClassName; 379 380 void validate() throws BuildException 381 { 382 if (fileName == null) { 383 throw new BuildException("You must specify attribute 'name'"); 384 } 385 } 386 387 void process(ResourceGen generator) throws BuildException 388 { 389 390 boolean outputJava = (root.mode != ResourceGenTask.MODE_CPP); 391 boolean outputCpp = (root.mode != ResourceGenTask.MODE_JAVA); 392 393 FileTask task; 394 if (fileName.endsWith(".xml")) { 395 task = generator.createXmlTask(this, fileName, 396 className, baseClassName, outputJava, 397 cppClassName, cppBaseClassName, 398 outputCpp); 399 } else if (fileName.endsWith(".properties")) { 400 task = generator.createPropertiesTask(this, fileName); 401 } else { 402 throw new BuildException( 403 "File '" + fileName + "' is not of a supported " + 404 "type (.java or .properties)"); 405 } 406 try { 407 task.process(generator); 408 } catch (IOException e) { 409 e.printStackTrace(); 410 throw new BuildException( 411 "Failed while processing '" + fileName + "'", e); 412 } 413 } 414 415 /** Sets <a href="#name">name</a>. **/ 416 public void setName(String name) 417 { 418 this.fileName = name; 419 } 420 421 /** Sets <a href="#className">className</a>. **/ 422 public void setClassName(String className) 423 { 424 this.className = className; 425 } 426 427 /** Sets <a href="#baseClassName">baseClassName</a>. **/ 428 public void setBaseClassName(String baseClassName) 429 { 430 this.baseClassName = baseClassName; 431 } 432 433 String getBaseClassName() 434 { 435 return baseClassName; 436 } 437 438 /** Sets <a href="#cppClassName">cppClassName</a>. **/ 439 public void setCppClassName(String className) 440 { 441 this.cppClassName = className; 442 } 443 444 /** Sets <a href="#cppBaseClassName">cppBaseClassName</a>. **/ 445 public void setCppBaseClassName(String baseClassName) 446 { 447 this.cppBaseClassName = baseClassName; 448 } 449 450 String getCppBaseClassName() 451 { 452 return cppBaseClassName; 453 } 454 } 455} 456 457// End ResourceGenTask.java