Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 910   Methods: 44
NCLOC: 421   Classes: 5
 
 Source file Conditionals Statements Methods TOTAL
XSLTProcess.java 51.3% 67.9% 81.8% 65.7%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
 5   
  * reserved.
 6   
  *
 7   
  * Redistribution and use in source and binary forms, with or without
 8   
  * modification, are permitted provided that the following conditions
 9   
  * are met:
 10   
  *
 11   
  * 1. Redistributions of source code must retain the above copyright
 12   
  *    notice, this list of conditions and the following disclaimer.
 13   
  *
 14   
  * 2. Redistributions in binary form must reproduce the above copyright
 15   
  *    notice, this list of conditions and the following disclaimer in
 16   
  *    the documentation and/or other materials provided with the
 17   
  *    distribution.
 18   
  *
 19   
  * 3. The end-user documentation included with the redistribution, if
 20   
  *    any, must include the following acknowlegement:
 21   
  *       "This product includes software developed by the
 22   
  *        Apache Software Foundation (http://www.apache.org/)."
 23   
  *    Alternately, this acknowlegement may appear in the software itself,
 24   
  *    if and wherever such third-party acknowlegements normally appear.
 25   
  *
 26   
  * 4. The names "Ant" and "Apache Software
 27   
  *    Foundation" must not be used to endorse or promote products derived
 28   
  *    from this software without prior written permission. For written
 29   
  *    permission, please contact apache@apache.org.
 30   
  *
 31   
  * 5. Products derived from this software may not be called "Apache"
 32   
  *    nor may "Apache" appear in their names without prior written
 33   
  *    permission of the Apache Group.
 34   
  *
 35   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 36   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 37   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 38   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 39   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 41   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 42   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 43   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 44   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 45   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 46   
  * SUCH DAMAGE.
 47   
  * ====================================================================
 48   
  *
 49   
  * This software consists of voluntary contributions made by many
 50   
  * individuals on behalf of the Apache Software Foundation.  For more
 51   
  * information on the Apache Software Foundation, please see
 52   
  * <http://www.apache.org/>.
 53   
  */
 54   
 
 55   
 package org.apache.tools.ant.taskdefs;
 56   
 
 57   
 import java.io.File;
 58   
 import java.util.Enumeration;
 59   
 import java.util.Vector;
 60   
 import org.apache.tools.ant.AntClassLoader;
 61   
 import org.apache.tools.ant.BuildException;
 62   
 import org.apache.tools.ant.DirectoryScanner;
 63   
 import org.apache.tools.ant.DynamicConfigurator;
 64   
 import org.apache.tools.ant.Project;
 65   
 import org.apache.tools.ant.taskdefs.optional.TraXLiaison;
 66   
 import org.apache.tools.ant.types.Path;
 67   
 import org.apache.tools.ant.types.Reference;
 68   
 import org.apache.tools.ant.types.XMLCatalog;
 69   
 import org.apache.tools.ant.util.FileUtils;
 70   
 import javax.xml.transform.URIResolver;
 71   
 
 72   
 /**
 73   
  * Processes a set of XML documents via XSLT. This is
 74   
  * useful for building views of XML based documentation.
 75   
  *
 76   
  * @version $Revision: 1.62 $
 77   
  *
 78   
  * @author <a href="mailto:kvisco@exoffice.com">Keith Visco</a>
 79   
  * @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a>
 80   
  * @author <a href="mailto:russgold@acm.org">Russell Gold</a>
 81   
  * @author Stefan Bodewig
 82   
  * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
 83   
  *
 84   
  * @since Ant 1.1
 85   
  *
 86   
  * @ant.task name="xslt" category="xml"
 87   
  */
 88   
 
 89   
 public class XSLTProcess extends MatchingTask implements XSLTLogger {
 90   
     /** destination directory */
 91   
     private File destDir = null;
 92   
 
 93   
     /** where to find the source XML file, default is the project's basedir */
 94   
     private File baseDir = null;
 95   
 
 96   
     /** XSL stylesheet */
 97   
     private String xslFile = null;
 98   
 
 99   
     /** extension of the files produced by XSL processing */
 100   
     private String targetExtension = ".html";
 101   
 
 102   
     /** additional parameters to be passed to the stylesheets */
 103   
     private Vector params = new Vector();
 104   
 
 105   
     /** Input XML document to be used */
 106   
     private File inFile = null;
 107   
 
 108   
     /** Output file */
 109   
     private File outFile = null;
 110   
 
 111   
     /** The name of the XSL processor to use */
 112   
     private String processor;
 113   
 
 114   
     /** Classpath to use when trying to load the XSL processor */
 115   
     private Path classpath = null;
 116   
     
 117   
     /** The Liason implementation to use to communicate with the XSL 
 118   
      *  processor */
 119   
     private XSLTLiaison liaison;
 120   
 
 121   
     /** Flag which indicates if the stylesheet has been loaded into
 122   
      *  the processor */
 123   
     private boolean stylesheetLoaded = false;
 124   
 
 125   
     /** force output of target files even if they already exist */
 126   
     private boolean force = false;
 127   
 
 128   
     /** Utilities used for file operations */
 129   
     private FileUtils fileUtils;
 130   
 
 131   
     /** XSL output properties to be used */
 132   
     private Vector outputProperties = new Vector();
 133   
 
 134   
     /** for resolving entities such as dtds */
 135   
     private XMLCatalog xmlCatalog = new XMLCatalog();
 136   
 
 137   
     /** Name of the TRAX Liaison class */
 138   
     private static final String TRAX_LIAISON_CLASS =
 139   
                         "org.apache.tools.ant.taskdefs.optional.TraXLiaison";
 140   
 
 141   
     /** Name of the now-deprecated XSLP Liaison class */
 142   
     private static final String XSLP_LIAISON_CLASS =
 143   
                         "org.apache.tools.ant.taskdefs.optional.XslpLiaison";
 144   
 
 145   
     /** Name of the now-deprecated Xalan liaison class */
 146   
     private static final String XALAN_LIAISON_CLASS =
 147   
                         "org.apache.tools.ant.taskdefs.optional.XalanLiaison";
 148   
 
 149   
     /**
 150   
      * Whether to style all files in the included directories as well.
 151   
      *
 152   
      * @since Ant 1.5
 153   
      */
 154   
     private boolean performDirectoryScan = true;
 155   
 
 156   
     /**
 157   
      * factory element for TraX processors only
 158   
      * @since Ant 1.6
 159   
      */
 160   
     private Factory factory = null;
 161   
 
 162   
     /**
 163   
      * whether to reuse Transformer if transforming multiple files.
 164   
      * @since 1.5.2
 165   
      */
 166   
     private boolean reuseLoadedStylesheet = true;
 167   
 
 168   
     /**
 169   
      * Creates a new XSLTProcess Task.
 170   
      */
 171  9
     public XSLTProcess() {
 172  9
         fileUtils = FileUtils.newFileUtils();
 173   
     } //-- XSLTProcess
 174   
 
 175   
     /**
 176   
      * Whether to style all files in the included directories as well;
 177   
      * optional, default is true.
 178   
      *
 179   
      * @param b true if files in included directories are processed.
 180   
      * @since Ant 1.5
 181   
      */
 182  0
     public void setScanIncludedDirectories(boolean b) {
 183  0
         performDirectoryScan = b;
 184   
     }
 185   
 
 186   
     /**
 187   
      * Controls whether the stylesheet is reloaded for every transform
 188   
      *
 189   
      * <p>Setting this to true may get around a bug in certain
 190   
      * Xalan-J versions, default is false.</p>
 191   
      *
 192   
      * @since Ant 1.5.2
 193   
      */
 194  0
     public void setReloadStylesheet(boolean b) {
 195  0
         reuseLoadedStylesheet = !b;
 196   
     }
 197   
 
 198   
     /**
 199   
      * Executes the task.
 200   
      *
 201   
      * @exception BuildException if there is an execution problem.
 202   
      * @todo validate that if either in or our is defined, then both are
 203   
      */
 204  9
     public void execute() throws BuildException {
 205  9
         File savedBaseDir = baseDir;
 206   
 
 207  9
         DirectoryScanner scanner;
 208  9
         String[]         list;
 209  9
         String[]         dirs;
 210   
 
 211  9
         if (xslFile == null) {
 212  0
             throw new BuildException("no stylesheet specified", getLocation());
 213   
         }
 214   
 
 215  9
         try {
 216  9
             if (baseDir == null) {
 217  4
                 baseDir = getProject().resolveFile(".");
 218   
             }
 219   
 
 220  9
             liaison = getLiaison();
 221   
 
 222   
             // check if liaison wants to log errors using us as logger
 223  9
             if (liaison instanceof XSLTLoggerAware) {
 224  9
                 ((XSLTLoggerAware) liaison).setLogger(this);
 225   
             }
 226   
 
 227  9
             log("Using " + liaison.getClass().toString(), Project.MSG_VERBOSE);
 228   
 
 229  9
             File stylesheet = getProject().resolveFile(xslFile);
 230  9
             if (!stylesheet.exists()) {
 231  0
                 stylesheet = fileUtils.resolveFile(baseDir, xslFile);
 232   
                 /*
 233   
                  * shouldn't throw out deprecation warnings before we know,
 234   
                  * the wrong version has been used.
 235   
                  */
 236  0
                 if (stylesheet.exists()) {
 237  0
                     log("DEPRECATED - the style attribute should be relative "
 238   
                         + "to the project\'s");
 239  0
                     log("             basedir, not the tasks\'s basedir.");
 240   
                 }
 241   
             }
 242   
 
 243   
             // if we have an in file and out then process them
 244  9
             if (inFile != null && outFile != null) {
 245  7
                 process(inFile, outFile, stylesheet);
 246  7
                 return;
 247   
             }
 248   
 
 249   
             /*
 250   
              * if we get here, in and out have not been specified, we are
 251   
              * in batch processing mode.
 252   
              */
 253   
 
 254   
             //-- make sure Source directory exists...
 255  2
             if (destDir == null) {
 256  0
                 String msg = "destdir attributes must be set!";
 257  0
                 throw new BuildException(msg);
 258   
             }
 259  2
             scanner = getDirectoryScanner(baseDir);
 260  2
             log("Transforming into " + destDir, Project.MSG_INFO);
 261   
 
 262   
             // Process all the files marked for styling
 263  2
             list = scanner.getIncludedFiles();
 264  2
             for (int i = 0; i < list.length; ++i) {
 265  1
                 process(baseDir, list[i], destDir, stylesheet);
 266   
             }
 267  1
             if (performDirectoryScan) {
 268   
                 // Process all the directories marked for styling
 269  1
                 dirs = scanner.getIncludedDirectories();
 270  1
                 for (int j = 0; j < dirs.length; ++j){
 271  0
                     list = new File(baseDir, dirs[j]).list();
 272  0
                     for (int i = 0; i < list.length; ++i) {
 273  0
                         process(baseDir, list[i], destDir, stylesheet);
 274   
                     }
 275   
                 }
 276   
             }
 277   
         } finally {
 278  9
             liaison = null;
 279  9
             stylesheetLoaded = false;
 280  9
             baseDir = savedBaseDir;
 281   
         }
 282   
     }
 283   
 
 284   
     /**
 285   
      * Set whether to check dependencies, or always generate;
 286   
      * optional, default is false.
 287   
      *
 288   
      * @param force true if always generate.
 289   
      */
 290  0
     public void setForce(boolean force) {
 291  0
         this.force = force;
 292   
     }
 293   
 
 294   
     /**
 295   
      * Set the base directory;
 296   
      * optional, default is the project's basedir.
 297   
      *
 298   
      * @param dir the base directory
 299   
      **/
 300  5
     public void setBasedir(File dir) {
 301  5
         baseDir = dir;
 302   
     }
 303   
 
 304   
     /**
 305   
      * Set the destination directory into which the XSL result
 306   
      * files should be copied to;
 307   
      * required, unless <tt>in</tt> and <tt>out</tt> are
 308   
      * specified.
 309   
      * @param dir the name of the destination directory
 310   
      **/
 311  6
     public void setDestdir(File dir) {
 312  6
         destDir = dir;
 313   
     }
 314   
 
 315   
     /**
 316   
      * Set the desired file extension to be used for the target;
 317   
      * optional, default is html.
 318   
      * @param name the extension to use
 319   
      **/
 320  6
     public void setExtension(String name) {
 321  6
         targetExtension = name;
 322   
     }
 323   
 
 324   
     /**
 325   
      * Name of the stylesheet to use - given either relative
 326   
      * to the project's basedir or as an absolute path; required.
 327   
      *
 328   
      * @param xslFile the stylesheet to use
 329   
      */
 330  9
     public void setStyle(String xslFile) {
 331  9
         this.xslFile = xslFile;
 332   
     }
 333   
 
 334   
     /**
 335   
      * Set the optional classpath to the XSL processor
 336   
      *
 337   
      * @param classpath the classpath to use when loading the XSL processor
 338   
      */
 339  0
     public void setClasspath(Path classpath) {
 340  0
         createClasspath().append(classpath);
 341   
     }
 342   
 
 343   
     /**
 344   
      * Set the optional classpath to the XSL processor
 345   
      *
 346   
      * @return a path instance to be configured by the Ant core.
 347   
      */
 348  0
     public Path createClasspath() {
 349  0
         if (classpath == null) {
 350  0
             classpath = new Path(getProject());
 351   
         }
 352  0
         return classpath.createPath();
 353   
     }
 354   
 
 355   
     /**
 356   
      * Set the reference to an optional classpath to the XSL processor
 357   
      *
 358   
      * @param r the id of the Ant path instance to act as the classpath
 359   
      *          for loading the XSL processor
 360   
      */
 361  0
     public void setClasspathRef(Reference r) {
 362  0
         createClasspath().setRefid(r);
 363   
     }
 364   
 
 365   
     /**
 366   
      * Set the name of the XSL processor to use; optional, default trax.
 367   
      * Other values are "xalan" for Xalan1 and "xslp" for XSL:P, though the
 368   
      * later is strongly deprecated.
 369   
      *
 370   
      * @param processor the name of the XSL processor
 371   
      */
 372  0
     public void setProcessor(String processor) {
 373  0
         this.processor = processor;
 374   
     }
 375   
 
 376   
     /**
 377   
      * Add the catalog to our internal catalog
 378   
      *
 379   
      * @param xmlCatalog the XMLCatalog instance to use to look up DTDs
 380   
      */
 381  3
     public void addConfiguredXMLCatalog(XMLCatalog xmlCatalog) {
 382  3
         this.xmlCatalog.addConfiguredXMLCatalog(xmlCatalog);
 383   
     }
 384   
 
 385   
     /**
 386   
      * Load processor here instead of in setProcessor - this will be
 387   
      * called from within execute, so we have access to the latest
 388   
      * classpath.
 389   
      *
 390   
      * @param proc the name of the processor to load.
 391   
      * @exception Exception if the processor cannot be loaded.
 392   
      */
 393  9
     private void resolveProcessor(String proc) throws Exception {
 394  9
         if (proc.equals("trax")) {
 395  9
             final Class clazz = loadClass(TRAX_LIAISON_CLASS);
 396  9
             liaison = (XSLTLiaison) clazz.newInstance();
 397  0
         } else if (proc.equals("xslp")) {
 398  0
             log("DEPRECATED - xslp processor is deprecated. Use trax "
 399   
                 + "instead.");
 400  0
             final Class clazz = loadClass(XSLP_LIAISON_CLASS);
 401  0
             liaison = (XSLTLiaison) clazz.newInstance();
 402  0
         } else if (proc.equals("xalan")) {
 403  0
             log("DEPRECATED - xalan processor is deprecated. Use trax "
 404   
                 + "instead.");
 405  0
             final Class clazz = loadClass(XALAN_LIAISON_CLASS);
 406  0
             liaison = (XSLTLiaison) clazz.newInstance();
 407   
         } else {
 408  0
             liaison = (XSLTLiaison) loadClass(proc).newInstance();
 409   
         }
 410   
     }
 411   
 
 412   
     /**
 413   
      * Load named class either via the system classloader or a given
 414   
      * custom classloader.
 415   
      *
 416   
      * @param classname the name of the class to load.
 417   
      * @return the requested class.
 418   
      * @exception Exception if the class could not be loaded.
 419   
      */
 420  9
     private Class loadClass(String classname) throws Exception {
 421  9
         if (classpath == null) {
 422  9
             return Class.forName(classname);
 423   
         } else {
 424  0
             AntClassLoader al = getProject().createClassLoader(classpath);
 425  0
             Class c = al.loadClass(classname);
 426  0
             AntClassLoader.initializeClass(c);
 427  0
             return c;
 428   
         }
 429   
     }
 430   
 
 431   
     /**
 432   
      * Specifies the output name for the styled result from the
 433   
      * <tt>in</tt> attribute; required if <tt>in</tt> is set
 434   
      *
 435   
      * @param outFile the output File instance.
 436   
      */
 437  7
     public void setOut(File outFile){
 438  7
         this.outFile = outFile;
 439   
     }
 440   
 
 441   
     /**
 442   
      * specifies a single XML document to be styled. Should be used
 443   
      * with the <tt>out</tt> attribute; ; required if <tt>out</tt> is set
 444   
      *
 445   
      * @param inFile the input file
 446   
      */
 447  7
     public void setIn(File inFile){
 448  7
         this.inFile = inFile;
 449   
     }
 450   
 
 451   
     /**
 452   
      * Processes the given input XML file and stores the result
 453   
      * in the given resultFile.
 454   
      *
 455   
      * @param baseDir the base directory for resolving files.
 456   
      * @param xmlFile the input file
 457   
      * @param destDir the destination directory
 458   
      * @param stylesheet the stylesheet to use.
 459   
      * @exception BuildException if the processing fails.
 460   
      */
 461  1
     private void process(File baseDir, String xmlFile, File destDir,
 462   
                          File stylesheet)
 463   
         throws BuildException {
 464   
 
 465  1
         String fileExt = targetExtension;
 466  1
         File   outFile = null;
 467  1
         File   inFile = null;
 468   
 
 469  1
         try {
 470  1
             long styleSheetLastModified = stylesheet.lastModified();
 471  1
             inFile = new File(baseDir, xmlFile);
 472   
 
 473  1
             if (inFile.isDirectory()) {
 474  0
                 log("Skipping " + inFile + " it is a directory.",
 475   
                     Project.MSG_VERBOSE);
 476  0
                 return;
 477   
             }
 478   
 
 479  1
             int dotPos = xmlFile.lastIndexOf('.');
 480  1
             if (dotPos > 0) {
 481  1
                 outFile = new File(destDir,
 482   
                     xmlFile.substring(0, xmlFile.lastIndexOf('.')) + fileExt);
 483   
             } else {
 484  0
                 outFile = new File(destDir, xmlFile + fileExt);
 485   
             }
 486  1
             if (force ||
 487   
                 inFile.lastModified() > outFile.lastModified() ||
 488   
                 styleSheetLastModified > outFile.lastModified()) {
 489  1
                 ensureDirectoryFor(outFile);
 490  1
                 log("Processing " + inFile + " to " + outFile);
 491   
 
 492  1
                 configureLiaison(stylesheet);
 493  1
                 liaison.transform(inFile, outFile);
 494   
             }
 495   
         } catch (Exception ex) {
 496   
             // If failed to process document, must delete target document,
 497   
             // or it will not attempt to process it the second time
 498  1
             log("Failed to process " + inFile, Project.MSG_INFO);
 499  1
             if (outFile != null) {
 500  1
                 outFile.delete();
 501   
             }
 502   
 
 503  1
             throw new BuildException(ex);
 504   
         }
 505   
 
 506   
     } //-- processXML
 507   
 
 508   
     /**
 509   
      * Process the input file to the output file with the given stylesheet.
 510   
      *
 511   
      * @param inFile the input file to process.
 512   
      * @param outFile the detination file.
 513   
      * @param stylesheet the stylesheet to use.
 514   
      * @exception BuildException if the processing fails.
 515   
      */
 516  7
     private void process(File inFile, File outFile, File stylesheet)
 517   
          throws BuildException {
 518  7
         try {
 519  7
             long styleSheetLastModified = stylesheet.lastModified();
 520  7
             log("In file " + inFile + " time: " + inFile.lastModified(),
 521   
                 Project.MSG_DEBUG);
 522  7
             log("Out file " + outFile + " time: " + outFile.lastModified(),
 523   
                 Project.MSG_DEBUG);
 524  7
             log("Style file " + xslFile + " time: " + styleSheetLastModified,
 525   
                 Project.MSG_DEBUG);
 526  7
             if (force ||
 527   
                 inFile.lastModified() > outFile.lastModified() ||
 528   
                 styleSheetLastModified > outFile.lastModified()) {
 529  7
                 ensureDirectoryFor(outFile);
 530  7
                 log("Processing " + inFile + " to " + outFile,
 531   
                     Project.MSG_INFO);
 532  7
                 configureLiaison(stylesheet);
 533  7
                 liaison.transform(inFile, outFile);
 534   
             }
 535   
         } catch (Exception ex) {
 536  0
             log("Failed to process " + inFile, Project.MSG_INFO);
 537  0
             if (outFile != null) {
 538  0
                 outFile.delete();
 539   
             }
 540  0
             throw new BuildException(ex);
 541   
         }
 542   
     }
 543   
 
 544   
     /**
 545   
      * Ensure the directory exists for a given file
 546   
      *
 547   
      * @param targetFile the file for which the directories are required.
 548   
      * @exception BuildException if the directories cannot be created.
 549   
      */
 550  8
     private void ensureDirectoryFor(File targetFile)
 551   
          throws BuildException {
 552  8
         File directory = fileUtils.getParentFile(targetFile);
 553  8
         if (!directory.exists()) {
 554  0
             if (!directory.mkdirs()) {
 555  0
                 throw new BuildException("Unable to create directory: "
 556   
                                          + directory.getAbsolutePath());
 557   
             }
 558   
         }
 559   
     }
 560   
 
 561   
     /**
 562   
      * Get the Liason implementation to use in processing.
 563   
      *
 564   
      * @return an instance of the XSLTLiason interface.
 565   
      */
 566  9
     protected XSLTLiaison getLiaison() {
 567   
         // if processor wasn't specified, see if TraX is available.  If not,
 568   
         // default it to xslp or xalan, depending on which is in the classpath
 569  9
         if (liaison == null) {
 570  9
             if (processor != null) {
 571  0
                 try {
 572  0
                     resolveProcessor(processor);
 573   
                 } catch (Exception e) {
 574  0
                     throw new BuildException(e);
 575   
                 }
 576   
             } else {
 577  9
                 try {
 578  9
                     resolveProcessor("trax");
 579   
                 } catch (Throwable e1) {
 580  0
                     try {
 581  0
                         resolveProcessor("xalan");
 582   
                     } catch (Throwable e2) {
 583  0
                         try {
 584  0
                             resolveProcessor("xslp");
 585   
                         } catch (Throwable e3) {
 586  0
                             e3.printStackTrace();
 587  0
                             e2.printStackTrace();
 588  0
                             throw new BuildException(e1);
 589   
                         }
 590   
                     }
 591   
                 }
 592   
             }
 593   
         }
 594  9
         return liaison;
 595   
     }
 596   
 
 597   
     /**
 598   
      * Create an instance of an XSL parameter for configuration by Ant.
 599   
      *
 600   
      * @return an instance of the Param class to be configured.
 601   
      */
 602  4
     public Param createParam() {
 603  4
         Param p = new Param();
 604  4
         params.addElement(p);
 605  4
         return p;
 606   
     }
 607   
 
 608   
     /**
 609   
      * The Param inner class used to store XSL parameters
 610   
      */
 611   
     public static class Param {
 612   
         /** The parameter name */
 613   
         private String name = null;
 614   
 
 615   
         /** The parameter's XSL expression */
 616   
         private String expression = null;
 617   
 
 618   
         /**
 619   
          * Set the parameter name.
 620   
          *
 621   
          * @param name the name of the parameter.
 622   
          */
 623  4
         public void setName(String name){
 624  4
             this.name = name;
 625   
         }
 626   
 
 627   
         /**
 628   
          * The XSL expression for the parameter value
 629   
          *
 630   
          * @param expression the XSL expression representing the
 631   
          *   parameter's value.
 632   
          */
 633  4
         public void setExpression(String expression){
 634  4
             this.expression = expression;
 635   
         }
 636   
 
 637   
         /**
 638   
          * Get the parameter name
 639   
          *
 640   
          * @return the parameter name
 641   
          * @exception BuildException if the name is not set.
 642   
          */
 643  4
         public String getName() throws BuildException{
 644  4
             if (name == null) {
 645  0
                 throw new BuildException("Name attribute is missing.");
 646   
             }
 647  4
             return name;
 648   
         }
 649   
 
 650   
         /**
 651   
          * Get the parameter expression
 652   
          *
 653   
          * @return the parameter expression
 654   
          * @exception BuildException if the expression is not set.
 655   
          */
 656  4
         public String getExpression() throws BuildException{
 657  4
             if (expression == null) {
 658  0
                 throw new BuildException("Expression attribute is missing.");
 659   
             }
 660  4
             return expression;
 661   
         }
 662   
     } // Param
 663   
 
 664   
 
 665   
     /**
 666   
      * Create an instance of an output property to be configured.
 667   
      * @return the newly created output property.
 668   
      * @since Ant 1.5
 669   
      */
 670  4
     public OutputProperty createOutputProperty() {
 671  4
         OutputProperty p = new OutputProperty();
 672  4
         outputProperties.addElement(p);
 673  4
         return p;
 674   
     }
 675   
 
 676   
 
 677   
     /**
 678   
      * Specify how the result tree should be output as specified
 679   
      * in the <a href="http://www.w3.org/TR/xslt#output">
 680   
      * specification</a>.
 681   
      * @since Ant 1.5
 682   
      */
 683   
     public static class OutputProperty {
 684   
         /** output property name */
 685   
         private String name;
 686   
 
 687   
         /** output property value */
 688   
         private String value;
 689   
 
 690   
         /**
 691   
          * @return the output property name.
 692   
          */
 693  4
         public String getName() {
 694  4
             return name;
 695   
         }
 696   
 
 697   
         /**
 698   
          * set the name for this property
 699   
          * @param name A non-null String that specifies an
 700   
          * output property name, which may be namespace qualified.
 701   
          */
 702  4
         public void setName(String name) {
 703  4
             this.name = name;
 704   
         }
 705   
 
 706   
         /**
 707   
          * @return the output property value.
 708   
          */
 709  4
         public String getValue() {
 710  4
             return value;
 711   
         }
 712   
 
 713   
         /**
 714   
          * set the value for this property
 715   
          * @param value The non-null string value of the output property.
 716   
          */
 717  4
         public void setValue(String value) {
 718  4
             this.value = value;
 719   
         }
 720   
     }
 721   
 
 722   
     /**
 723   
      * Initialize internal instance of XMLCatalog
 724   
      */
 725  9
     public void init() throws BuildException {
 726  9
         super.init();
 727  9
         xmlCatalog.setProject(getProject());
 728   
     }
 729   
 
 730   
     /**
 731   
      * Loads the stylesheet and set xsl:param parameters.
 732   
      *
 733   
      * @param stylesheet the file form which to load the stylesheet.
 734   
      * @exception BuildException if the stylesheet cannot be loaded.
 735   
      */
 736  8
     protected void configureLiaison(File stylesheet) throws BuildException {
 737  8
         if (stylesheetLoaded && reuseLoadedStylesheet) {
 738  0
             return;
 739   
         }
 740  8
         stylesheetLoaded = true;
 741   
 
 742  8
         try {
 743  8
             log("Loading stylesheet " + stylesheet, Project.MSG_INFO);
 744  8
             liaison.setStylesheet(stylesheet);
 745  8
             for (Enumeration e = params.elements(); e.hasMoreElements();) {
 746  4
                 Param p = (Param) e.nextElement();
 747  4
                 liaison.addParam(p.getName(), p.getExpression());
 748   
             }
 749  8
             if (liaison instanceof TraXLiaison) {
 750  8
                 configureTraXLiaison((TraXLiaison)liaison);
 751   
             }
 752   
         } catch (Exception ex) {
 753  0
             log("Failed to transform using stylesheet " + stylesheet, Project.MSG_INFO);
 754  0
             throw new BuildException(ex);
 755   
         }
 756   
     }
 757   
 
 758   
     /**
 759   
      * Specific configuration for the TRaX liaison. Support for
 760   
      * all others has been dropped so this liaison will soon look
 761   
      * like the exact copy of JAXP interface..
 762   
      * @param liaison the TRaXLiaison to configure.
 763   
      */
 764  8
     protected void configureTraXLiaison(TraXLiaison liaison){
 765  8
         if (factory != null) {
 766  2
             liaison.setFactory(factory.getName());
 767   
 
 768   
             // configure factory attributes
 769  2
             for (Enumeration attrs = factory.getAttributes();
 770  3
                     attrs.hasMoreElements();) {
 771  1
                 Factory.Attribute attr =
 772   
                         (Factory.Attribute)attrs.nextElement();
 773  1
                 liaison.setAttribute(attr.getName(), attr.getValue());
 774   
             }
 775   
         }
 776   
 
 777   
         // use XMLCatalog as the entity resolver and URI resolver
 778  8
         if (xmlCatalog != null) {
 779  8
             liaison.setEntityResolver(xmlCatalog);
 780  8
             liaison.setURIResolver(xmlCatalog);
 781   
         }
 782   
 
 783   
         // configure output properties
 784  8
         for (Enumeration props = outputProperties.elements();
 785  12
                 props.hasMoreElements();) {
 786  4
             OutputProperty prop = (OutputProperty)props.nextElement();
 787  4
             liaison.setOutputProperty(prop.getName(), prop.getValue());
 788   
         }
 789   
     }
 790   
 
 791   
     /**
 792   
      * Create the factory element to configure a trax liaison.
 793   
      * @return the newly created factory element.
 794   
      * @throws BuildException if the element is created more than one time.
 795   
      */
 796  2
     public Factory createFactory() throws BuildException {
 797  2
         if (factory != null) {
 798  0
             throw new BuildException("'factory' element must be unique");
 799   
         }
 800  2
         factory = new Factory();
 801  2
         return factory;
 802   
     }
 803   
 
 804   
     /**
 805   
      * The factory element to configure a transformer factory
 806   
      * @since Ant 1.6
 807   
      */
 808   
     public static class Factory {
 809   
 
 810   
         /** the factory class name to use for TraXLiaison */
 811   
         private String name;
 812   
 
 813   
         /**
 814   
          * the list of factory attributes to use for TraXLiaison
 815   
          */
 816   
         private Vector attributes = new Vector();
 817   
 
 818   
         /**
 819   
          * @return the name of the factory.
 820   
          */
 821  2
         public String getName() {
 822  2
             return name;
 823   
         }
 824   
 
 825   
         /**
 826   
          * Set the name of the factory
 827   
          * @param name the name of the factory.
 828   
          */
 829  2
         public void setName(String name) {
 830  2
             this.name = name;
 831   
         }
 832   
 
 833   
         /**
 834   
          * Create an instance of a factory attribute.
 835   
          * the newly created factory attribute
 836   
          */
 837  1
         public void addAttribute(Attribute attr) {
 838  1
             attributes.addElement(attr);
 839   
         }
 840   
 
 841   
         /**
 842   
          * return the attribute elements.
 843   
          * @return the enumeration of attributes
 844   
          */
 845  2
         public Enumeration getAttributes() {
 846  2
             return attributes.elements();
 847   
         }
 848   
 
 849   
         /**
 850   
          * A JAXP factory attribute. This is mostly processor specific, for
 851   
          * example for Xalan 2.3+, the following attributes could be set:
 852   
          * <ul>
 853   
          *  <li>http://xml.apache.org/xalan/features/optimize (true|false) </li>
 854   
          *  <li>http://xml.apache.org/xalan/features/incremental (true|false) </li>
 855   
          * </ul>
 856   
          */
 857   
         public static class Attribute implements DynamicConfigurator {
 858   
 
 859   
             /** attribute name, mostly processor specific */
 860   
             private String name;
 861   
 
 862   
             /** attribute value, often a boolean string */
 863   
             private Object value;
 864   
 
 865   
             /**
 866   
              * @return the attribute name.
 867   
              */
 868  1
             public String getName() {
 869  1
                 return name;
 870   
             }
 871   
 
 872   
             /**
 873   
              * @return the output property value.
 874   
              */
 875  1
             public Object getValue() {
 876  1
                 return value;
 877   
             }
 878   
 
 879  0
             public Object createDynamicElement(String name) throws BuildException {
 880  0
                 return null;
 881   
             }
 882   
 
 883  2
             public void setDynamicAttribute(String name, String value)
 884   
                     throws BuildException {
 885   
                 // only 'name' and 'value' exist.
 886  2
                 if ("name".equalsIgnoreCase(name)) {
 887  1
                     this.name = value;
 888  1
                 } else if ("value".equalsIgnoreCase(name)) {
 889   
                     // a value must be of a given type
 890   
                     // say boolean|integer|string that are mostly used.
 891  1
                     if ("true".equalsIgnoreCase(value)
 892   
                             || "false".equalsIgnoreCase(value) ){
 893  1
                         this.value = new Boolean(value);
 894   
                     } else {
 895  0
                         try {
 896  0
                             this.value = new Integer(value);
 897   
                         } catch (NumberFormatException e) {
 898  0
                             this.value = value;
 899   
                         }
 900   
                     }
 901   
                 } else {
 902  0
                     throw new BuildException("Unsupported attribute: " + name);
 903   
                 }
 904   
             }
 905   
         } // -- class Attribute
 906   
 
 907   
     } // -- class Factory
 908   
 
 909   
 } //-- XSLTProcess
 910