You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by co...@apache.org on 2002/03/05 14:49:47 UTC

cvs commit: jakarta-ant/src/main/org/apache/tools/ant/types DTDLocation.java XCatalog.java defaults.properties

conor       02/03/05 05:49:47

  Modified:    src/main/org/apache/tools/ant/taskdefs XSLTProcess.java
               src/main/org/apache/tools/ant/taskdefs/optional
                        TraXLiaison.java
               src/main/org/apache/tools/ant/types defaults.properties
  Added:       src/main/org/apache/tools/ant/types DTDLocation.java
                        XCatalog.java
  Log:
  New datatype - xcatalog - used to store information about locally available
  XML DTDs. This allows such info to be shared among a number of different
  tasks such as XMLValidate, ejbjar, style, etc.
  
  Also checkstyle cleanup of the affected files.
  
  Submitted by:	dIon Gillard <di...@multitask.com.au>
  
  Revision  Changes    Path
  1.38      +254 -100  jakarta-ant/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java
  
  Index: XSLTProcess.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -w -u -r1.37 -r1.38
  --- XSLTProcess.java	3 Mar 2002 01:46:20 -0000	1.37
  +++ XSLTProcess.java	5 Mar 2002 13:49:46 -0000	1.38
  @@ -54,11 +54,9 @@
   
   package org.apache.tools.ant.taskdefs;
   
  -
  +import java.lang.reflect.Method;
   import java.io.File;
   import java.util.Enumeration;
  -
  -
   import java.util.Vector;
   import org.apache.tools.ant.BuildException;
   import org.apache.tools.ant.DirectoryScanner;
  @@ -67,7 +65,8 @@
   import org.apache.tools.ant.types.Path;
   import org.apache.tools.ant.types.Reference;
   import org.apache.tools.ant.util.FileUtils;
  -
  +import org.apache.tools.ant.types.XCatalog;
  +import org.xml.sax.EntityResolver;
   
   /**
    * A Task to process via XSLT a set of XML documents. This is
  @@ -87,7 +86,7 @@
    * such as images, or html files in the source directory will be
    * copied into the destination directory.
    *
  - * @version $Revision: 1.37 $ 
  + * @version $Revision: 1.38 $ 
    *
    * @author <a href="mailto:kvisco@exoffice.com">Keith Visco</a>
    * @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a>
  @@ -98,31 +97,65 @@
    */
   
   public class XSLTProcess extends MatchingTask implements XSLTLogger {
  -
  +    /** destination directory */
       private File destDir = null;
   
  +    /** where to find the source XML file, default is the project's basedir */
       private File baseDir = null;
   
  +    /** XSL stylesheet */
       private String xslFile = null;
   
  +    /** extension of the files produced by XSL processing */
       private String targetExtension = ".html";
  +
  +    /** additional parameters to be passed to the stylesheets */
       private Vector params = new Vector();
   
  +    /** Input XML document to be used */
       private File inFile = null;
   
  +    /** Output file */
       private File outFile = null;
   
  +    /** The name of the XSL processor to use */
       private String processor;
  +    
  +    /** Classpath to use when trying to load the XSL processor */
       private Path classpath = null;
  +    
  +    /** The Liason implementation to use to communicate with the XSL 
  +     *  processor */
       private XSLTLiaison liaison;
  +    
  +    /** Flag which indicates if the stylesheet has been loaded into 
  +     *  the processor */
       private boolean stylesheetLoaded = false;
   
  +    /** force output of target files even if they already exist */
       private boolean force = false;
   
  +    /** Utilities used for file operations */
       private FileUtils fileUtils;
   
  +    /** XSL output method to be used */
       private String outputtype = null;
   
  +    /** for resolving entities such as dtds */
  +    private XCatalog xcatalog;
  +    
  +    /** Name of the TRAX Liason class */
  +    private static final String TRAX_LIAISON_CLASS =
  +                        "org.apache.tools.ant.taskdefs.optional.TraXLiaison";
  +
  +    /** Name of the now-deprecated XSLP Liason class */                        
  +    private static final String XSLP_LIASON_CLASS = 
  +                        "org.apache.tools.ant.taskdefs.optional.XslpLiaison";
  +
  +    /** Name of the Xalan liason class */                            
  +    private static final String XALAN_LIASON_CLASS =
  +                        "org.apache.tools.ant.taskdefs.optional.XalanLiaison";
  +                        
       /**
        * Whether to style all files in the included directories as well.
        *
  @@ -140,6 +173,7 @@
       /**
        * Whether to style all files in the included directories as well.
        *
  +     * @param b true if files in included directories are processed.
        * @since 1.35, Ant 1.5
        */
       public void setScanIncludedDirectories(boolean b) {
  @@ -148,6 +182,8 @@
       
       /**
        * Executes the task.
  +     *
  +     * @exception BuildException if there is an execution problem.
        */
       public void execute() throws BuildException {
           DirectoryScanner scanner;
  @@ -179,7 +215,8 @@
                * the wrong version has been used.
                */
               if (stylesheet.exists()) {
  -                log("DEPRECATED - the style attribute should be relative to the project\'s");
  +                log("DEPRECATED - the style attribute should be relative " 
  +                    + "to the project\'s");
                   log("             basedir, not the tasks\'s basedir.");
               }
           }
  @@ -208,7 +245,6 @@
           for (int i = 0;i < list.length; ++i) {
               process( baseDir, list[i], destDir, stylesheet );
           }
  -
           if (performDirectoryScan) {
               // Process all the directories marked for styling
               dirs = scanner.getIncludedDirectories();
  @@ -223,6 +259,8 @@
   
       /**
        * Set whether to check dependencies, or always generate.
  +     *
  +      * @param force true if always generate.
        **/
       public void setForce(boolean force) {
           this.force = force;
  @@ -230,6 +268,8 @@
   
       /**
        * Set the base directory.
  +     *
  +     * @param dir the base directory
        **/
       public void setBasedir(File dir) {
           baseDir = dir;
  @@ -255,6 +295,8 @@
       /**
        * Sets the file to use for styling relative to the base directory
        * of this task.
  +     *
  +     * @param xslFile the stylesheet to use
        */
       public void setStyle(String xslFile) {
           this.xslFile = xslFile;
  @@ -262,6 +304,8 @@
   
       /**
        * Set the classpath to load the Processor through (attribute).
  +     *
  +     * @param classpath the classpath to use when loading the XSL processor
        */
       public void setClasspath(Path classpath) {
           createClasspath().append(classpath);
  @@ -269,6 +313,8 @@
   
       /**
        * Set the classpath to load the Processor through (nested element).
  +     *
  +     * @return a path instance to be configured by the Ant core.
        */
       public Path createClasspath() {
           if (classpath == null) {
  @@ -280,34 +326,54 @@
       /**
        * Set the classpath to load the Processor through via reference
        * (attribute).
  +     *
  +     * @param r the id of the Ant path instance to act as the classpath 
  +     *          for loading the XSL processor
        */
       public void setClasspathRef(Reference r) {
           createClasspath().setRefid(r);
       }
   
  -
  +    /**
  +     * Set the name of the XSL processor to use 
  +     *
  +     * @param processor the name of the XSL processor
  +     */
       public void setProcessor(String processor) {
           this.processor = processor;
       }
   
       /**
  +     * store the xcatalog for resolving entities
  +     * 
  +     * @param xcatalog the xcatalog instance to use to look up DTDs
  +     */
  +    public void addXcatalog(XCatalog xcatalog) {
  +        this.xcatalog = xcatalog;
  +    }
  +    
  +    /**
        * Load processor here instead of in setProcessor - this will be
        * called from within execute, so we have access to the latest
        * classpath.
  +     *
  +     * @param proc the name of the processor to load.
  +     * @exception Exception if the processor cannot be loaded.
        */
       private void resolveProcessor(String proc) throws Exception {
           if (proc.equals("trax")) {
               final Class clazz =
  -                loadClass("org.apache.tools.ant.taskdefs.optional.TraXLiaison");
  +                loadClass(TRAX_LIAISON_CLASS);
               liaison = (XSLTLiaison)clazz.newInstance();
           } else if (proc.equals("xslp")) {
  -            log("DEPRECATED - xslp processor is deprecated. Use trax or xalan instead.");
  +            log("DEPRECATED - xslp processor is deprecated. Use trax or "
  +                + "xalan instead.");
               final Class clazz =
  -                loadClass("org.apache.tools.ant.taskdefs.optional.XslpLiaison");
  +                loadClass(XSLP_LIASON_CLASS);
               liaison = (XSLTLiaison) clazz.newInstance();
           } else if (proc.equals("xalan")) {
               final Class clazz =
  -                loadClass("org.apache.tools.ant.taskdefs.optional.XalanLiaison");
  +                loadClass(XALAN_LIASON_CLASS);
               liaison = (XSLTLiaison)clazz.newInstance();
           } else {
               liaison = (XSLTLiaison) loadClass(proc).newInstance();
  @@ -317,6 +383,10 @@
       /**
        * Load named class either via the system classloader or a given
        * custom classloader.
  +     *
  +     * @param classname the name of the class to load.
  +     * @return the requested class.
  +     * @exception Exception if the class could not be loaded.
        */
       private Class loadClass(String classname) throws Exception {
           if (classpath == null) {
  @@ -331,6 +401,8 @@
   
       /**
        * Sets an out file
  +     *
  +     * @param outFile the output File instance.
        */
       public void setOut(File outFile){
           this.outFile = outFile;
  @@ -338,6 +410,8 @@
   
       /**
        * Sets an input xml file to be styled
  +     *
  +     * @param inFile the input file
        */
       public void setIn(File inFile){
           this.inFile = inFile;
  @@ -346,6 +420,12 @@
       /**
        * Processes the given input XML file and stores the result
        * in the given resultFile.
  +     *
  +     * @param baseDir the base directory for resolving files.
  +     * @param xmlFile the input file
  +     * @param destDir the destination directory
  +     * @param stylesheet the stylesheet to use.
  +     * @exception BuildException if the processing fails.
        */
       private void process(File baseDir, String xmlFile, File destDir,
                            File stylesheet)
  @@ -367,7 +447,8 @@
               
               int dotPos = xmlFile.lastIndexOf('.');
               if(dotPos>0){
  -                outFile = new File(destDir,xmlFile.substring(0,xmlFile.lastIndexOf('.'))+fileExt);
  +                outFile = new File(destDir, 
  +                    xmlFile.substring(0, xmlFile.lastIndexOf('.')) + fileExt);
               }else{
                   outFile = new File(destDir,xmlFile+fileExt);
               }
  @@ -394,17 +475,30 @@
   
       } //-- processXML
   
  -    private void process(File inFile, File outFile, File stylesheet) throws BuildException {
  +    /**
  +     * Process the input file to the output file with the given stylesheet.
  +     *
  +     * @param inFile the input file to process.
  +     * @param outFile the detination file.
  +     * @param stylesheet the stylesheet to use.
  +     * @exception BuildException if the processing fails.
  +     */
  +    private void process(File inFile, File outFile, File stylesheet) 
  +         throws BuildException {
           try{
               long styleSheetLastModified = stylesheet.lastModified();
  -            log("In file "+inFile+" time: " + inFile.lastModified() , Project.MSG_DEBUG);
  -            log("Out file "+outFile+" time: " + outFile.lastModified() , Project.MSG_DEBUG);
  -            log("Style file "+xslFile+" time: " + styleSheetLastModified , Project.MSG_DEBUG);
  +            log("In file " + inFile + " time: " + inFile.lastModified(),
  +                Project.MSG_DEBUG);
  +            log("Out file " + outFile + " time: " + outFile.lastModified(),
  +                Project.MSG_DEBUG);
  +            log("Style file " + xslFile + " time: " + styleSheetLastModified,
  +                Project.MSG_DEBUG);
               if (force ||
                   inFile.lastModified() > outFile.lastModified() ||
                   styleSheetLastModified > outFile.lastModified()) {
                   ensureDirectoryFor( outFile );
  -                log("Processing " + inFile + " to " + outFile, Project.MSG_INFO);
  +                log("Processing " + inFile + " to " + outFile, 
  +                    Project.MSG_INFO);
                   configureLiaison(stylesheet);
                   liaison.transform(inFile, outFile);
               }
  @@ -417,7 +511,14 @@
           }
       }
   
  -    private void ensureDirectoryFor( File targetFile ) throws BuildException {
  +    /**
  +     * Ensure the directory exists for a given file 
  +     *
  +     * @param targetFile the file for which the directories are required.
  +     * @exception BuildException if the directories cannot be created.
  +     */
  +    private void ensureDirectoryFor(File targetFile) 
  +         throws BuildException {
           File directory = new File( targetFile.getParent() );
           if (!directory.exists()) {
               if (!directory.mkdirs()) {
  @@ -427,6 +528,11 @@
           }
       }
   
  +    /**
  +     * Get the Liason implementation to use in processing.
  +     *
  +     * @return an instance of the XSLTLiason interface.
  +     */
       protected XSLTLiaison getLiaison() {
           // if processor wasn't specified, see if TraX is available.  If not,
           // default it to xslp or xalan, depending on which is in the classpath
  @@ -458,24 +564,52 @@
           return liaison;
       }
   
  +    /**
  +     * Create an instance of an XSL parameter for configuration by Ant.
  +     *
  +     * @return an instance of the Param class to be configured.
  +     */
       public Param createParam() {
           Param p = new Param();
           params.addElement(p);
           return p;
       }
   
  +    /**
  +     * The Param inner class used to store XSL parameters
  +     */
       public class Param {
  +        /** The parameter name */
           private String name=null;
  +        
  +        /** The parameter's XSL expression */
           private String expression=null;
   
  +        /** 
  +         * Set the parameter name.
  +         * 
  +         * @param name the name of the parameter.
  +         */
           public void setName(String name){
               this.name = name;
           }
   
  +        /** 
  +         * The XSL expression for the parameter value
  +         *
  +         * @param expression the XSL expression representing the 
  +         *   parameter's value.
  +         */
           public void setExpression(String expression){
               this.expression = expression;
           }
   
  +        /**
  +         * Get the parameter name
  +         *
  +         * @return the parameter name
  +         * @exception BuildException if the name is not set.
  +         */
           public String getName() throws BuildException{
               if(name==null) {
                throw new BuildException("Name attribute is missing.");
  @@ -483,6 +617,12 @@
               return name;
           }
   
  +        /**
  +         * Get the parameter expression
  +         *
  +         * @return the parameter expression
  +         * @exception BuildException if the expression is not set.
  +         */
           public String getExpression() throws BuildException{
               if(expression==null) {
                throw new BuildException("Expression attribute is missing.");
  @@ -503,6 +643,9 @@
   
       /**
        * Loads the stylesheet and set xsl:param parameters.
  +     *
  +     * @param stylesheet the file form which to load the stylesheet.
  +     * @exception BuildException if the stylesheet cannot be loaded.
        */
       protected void configureLiaison(File stylesheet) throws BuildException {
           if (stylesheetLoaded) {
  @@ -517,6 +660,17 @@
                   Param p = (Param)e.nextElement();
                   liaison.addParam( p.getName(), p.getExpression() );
               }
  +            // if liaison is a TraxLiason, use XCatalog as the entity
  +            // resolver
  +            if (liaison.getClass().getName().equals(TRAX_LIAISON_CLASS) &&
  +                xcatalog != null) {
  +                log("Configuring TraxLiaison and calling entity resolver",
  +                    Project.MSG_DEBUG);
  +                Method resolver = liaison.getClass()
  +                                    .getDeclaredMethod("setEntityResolver", 
  +                                        new Class[] {EntityResolver.class});
  +                resolver.invoke(liaison, new Object[] {xcatalog});
  +            }
           } catch (Exception ex) {
               log("Failed to read stylesheet " + stylesheet, Project.MSG_INFO);
               throw new BuildException(ex);
  
  
  
  1.13      +35 -1     jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java
  
  Index: TraXLiaison.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -w -u -r1.12 -r1.13
  --- TraXLiaison.java	7 Feb 2002 22:01:57 -0000	1.12
  +++ TraXLiaison.java	5 Mar 2002 13:49:46 -0000	1.13
  @@ -63,6 +63,12 @@
   import org.apache.tools.ant.taskdefs.XSLTLoggerAware;
   import org.apache.tools.ant.taskdefs.XSLTLogger;
   
  +import org.xml.sax.InputSource;
  +import org.xml.sax.EntityResolver;
  +import org.xml.sax.XMLReader;
  +
  +import javax.xml.parsers.SAXParserFactory;
  +
   import javax.xml.transform.TransformerFactory;
   import javax.xml.transform.Transformer;
   import javax.xml.transform.TransformerException;
  @@ -72,6 +78,9 @@
   import javax.xml.transform.stream.StreamResult;
   import javax.xml.transform.stream.StreamSource;
   import javax.xml.transform.OutputKeys;
  +import javax.xml.transform.Source;
  +
  +import javax.xml.transform.sax.SAXSource;
   
   /**
    * Concrete liaison for XSLT processor implementing TraX. (ie JAXP 1.1)
  @@ -96,6 +105,9 @@
   
       private XSLTLogger logger;
   
  +    /** possible resolver for publicIds */
  +    private EntityResolver resolver;
  +
       public TraXLiaison() throws Exception {
           tfactory = TransformerFactory.newInstance();
           tfactory.setErrorListener(this);
  @@ -128,7 +140,23 @@
           try {
               fis = new FileInputStream(infile);
               fos = new FileOutputStream(outfile);
  -            StreamSource src = new StreamSource(fis);
  +            // FIXME: need to use a SAXSource as the source for the transform
  +            // so we can plug in our own entity resolver
  +            Source src = null;
  +            if (resolver != null) {
  +                if (tfactory.getFeature(SAXSource.FEATURE)) {
  +                    SAXParserFactory spFactory = SAXParserFactory.newInstance();
  +                    spFactory.setNamespaceAware( true ); 
  +                    XMLReader reader = spFactory.newSAXParser().getXMLReader();
  +                    reader.setEntityResolver(resolver);
  +                    src = new SAXSource(reader, new InputSource(fis));
  +                } else {
  +                    throw new IllegalStateException("xcatalog specified, but "+
  +                        "parser doesn't support SAX");
  +                }
  +            } else {
  +                src = new StreamSource(fis);
  +            }
               src.setSystemId(getSystemId(infile));
               StreamResult res = new StreamResult(fos);
               // not sure what could be the need of this...
  @@ -225,4 +253,10 @@
           logger.log(msg.toString());
       }
   
  +    /** Set the class to resolve entities during the transformation
  +     */
  +    public void setEntityResolver(EntityResolver aResolver) throws Exception {
  +        resolver = aResolver;
  +    }
  +    
   } //-- TraXLiaison
  
  
  
  1.9       +2 -0      jakarta-ant/src/main/org/apache/tools/ant/types/defaults.properties
  
  Index: defaults.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/types/defaults.properties,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -w -u -r1.8 -r1.9
  --- defaults.properties	19 Feb 2002 16:48:47 -0000	1.8
  +++ defaults.properties	5 Mar 2002 13:49:47 -0000	1.9
  @@ -8,3 +8,5 @@
   classfileset=org.apache.tools.ant.types.optional.depend.ClassfileSet
   substitution=org.apache.tools.ant.types.Substitution
   regexp=org.apache.tools.ant.types.RegularExpression
  +xcatalog=org.apache.tools.ant.types.XCatalog
  +
  
  
  
  1.1                  jakarta-ant/src/main/org/apache/tools/ant/types/DTDLocation.java
  
  Index: DTDLocation.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 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 apache@apache.org.
   *
   * 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;
  
  /**
   * Helper class to handle the DTD and Entity nested elements.
   *
   * @author <a href="mailto:conor@cortexebusiness.com.au">Conor MacNeill</a>
   * @author dIon Gillard
   */
  public class DTDLocation {
      /** publicId of the dtd/entity */
      private String publicId = null;
      /** location of the dtd/entity - a file/resource/URL */
      private String location = null;
  
      /**
       * @param publicId uniquely identifies the resource
       */
      public void setPublicId(String publicId) {
          this.publicId = publicId;
      }
  
      /**
       * @param location the location of the resource associated with the
       *      publicId
       */
      public void setLocation(String location) {
          this.location = location;
      }
  
      /**
       * @return the publicId
       */
      public String getPublicId() {
          return publicId;
      }
  
      /**
       * @return the location of the resource identified by the publicId
       */
      public String getLocation() {
          return location;
      }
  }
  
  
  
  
  1.1                  jakarta-ant/src/main/org/apache/tools/ant/types/XCatalog.java
  
  Index: XCatalog.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 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 apache@apache.org.
   *
   * 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;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.InputStream;
  import java.io.IOException;
  import java.net.URL;
  import java.util.Iterator;
  import java.util.Vector;
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.Project;
  import org.xml.sax.EntityResolver;
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  
  /**
   * This data type provides a catalog of DTD locations
   * <p>
   * <code>
   * &lt;catalog&gt;<br>
   * &nbsp;&nbsp;&lt;dtd publicId="" location="/path/to/file.jar" /&gt;<br>
   * &nbsp;&nbsp;&lt;dtd publicId location="/path/to/file2.jar" /gt;<br>
   * &nbsp;&nbsp;&lt;entity publicId="" location="/path/to/file3.jar" /&gt;<br>
   * &nbsp;&nbsp;&lt;entity publicId="" location="/path/to/file4.jar" /&gt;<br>
   * &lt;/catalog&gt;<br>
   * </code>
   * <p>
   * The object implemention <code>sometask</code> must provide a method called
   * <code>createCatalog</code> which returns an instance of <code>XCatalog</code>.
   * Nested dtd and entity definitions are handled by the XCatalog object and
   * must be labeled <code>dtd</code> and <code>entity</code> respectively.</p>
   *
   * <p>Possible future extension could allow a catalog file instead of nested
   * elements, or use Norman Walsh's entity resolver from xml-commons</p>
   *
   * @author  dIon Gillard
   * @version $Id: XCatalog.java,v 1.1 2002/03/05 13:49:47 conor Exp $
   */
  public class XCatalog extends DataType implements Cloneable, EntityResolver {
      
      //-- Fields ----------------------------------------------------------------
      
      /** holds dtd/entity objects until needed */
      private Vector elements = new Vector();
      
      //-- Methods ---------------------------------------------------------------
      
      /**
       * @return the elements of the catalog - DTDLocation objects
       */
      private Vector getElements() {
          return elements;
      }
      
      /**
       * Set the list of DTDLocation object sin the catalog
       *
       * @param aVector the new list of DTD Locations to use in the catalog.
       */
      private void setElements(Vector aVector) {
          elements = aVector;
      }
      
      /**
       * Add a DTD Location to the catalog
       *
       * @param aDTD the DTDLocation instance to be aded to the catalog
       */
      private void addElement(DTDLocation aDTD) {
          getElements().add(aDTD);
      }
      
      /**
       * Creates the nested <code>&lt;dtd&gt;</code> element.
       *
       * @param dtd the infromation about the DTD to be added to the catalog
       * @exception BuildException if this is a reference and no nested 
       *       elements are allowed.
       */
      public void addDTD(DTDLocation dtd) throws BuildException {
          if (isReference()) {
              throw noChildrenAllowed();
          }
          getElements().add(dtd);
      }
      
      /**
       * Creates the nested <code>&lt;entity&gt;</code> element
       *
       * @param dtd the infromation about the DTD to be added to the catalog
       * @exception BuildException if this is a reference and no nested 
       *       elements are allowed.
       */
      public void addEntity(DTDLocation dtd) throws BuildException {
          addDTD(dtd);
      }
  
      /**
       * Makes this instance in effect a reference to another XCatalog instance.
       *
       * <p>You must not set another attribute or nest elements inside
       * this element if you make it a reference.</p>
       *
       * @param r the reference to which this catalogi instance is associated
       * @exception BuildException if this instance already has been configured.
       */
      public void setRefid(Reference r) throws BuildException {
          if (!elements.isEmpty()) {
              throw tooManyAttributes();
          }
          // change this to get the objects from the other reference
          Object o = r.getReferencedObject(getProject());
          // we only support references to other XCatalogs
          if (o instanceof XCatalog) {
              // set all elements from referenced catalog to this one
              XCatalog catalog = (XCatalog) o;
              setElements(catalog.getElements());
          } else {
              String msg = r.getRefId() + " doesn\'t refer to an XCatalog";
              throw new BuildException(msg);
          }
  
          super.setRefid(r);
      }
  
      /**
       * @see org.xml.sax.EntityResolver#resolveEntity
       */
      public InputSource resolveEntity(String publicId, String systemId)
          throws SAXException, IOException {
          InputSource source = null;
          DTDLocation matchingDTD = findMatchingDTD(publicId);
          if (matchingDTD != null) {
              // check if publicId is mapped to a file
              log("Matching DTD found for publicId: '" + publicId +
                  "' location: '" + matchingDTD.getLocation() + "'",
                  Project.MSG_DEBUG);
              File dtdFile = new File(matchingDTD.getLocation());
              if (dtdFile.exists() && dtdFile.canRead()) {
                  source = new InputSource( new FileInputStream(dtdFile) );
                  source.setSystemId(dtdFile.toURL().toExternalForm());
                  log("matched a readable file", Project.MSG_DEBUG);
              } else {
                  // check if publicId is a resource
                  // FIXME: ClassLoader: should this be context?
                  ClassLoader loader 
                      = Thread.currentThread().getContextClassLoader();
                  InputStream is = loader.getResourceAsStream(
                      matchingDTD.getLocation() );
                  if (is != null) {
                      source = new InputSource(is);
                      source.setSystemId(loader.getResource(
                          matchingDTD.getLocation()).toExternalForm());
                      log("matched a resource", Project.MSG_DEBUG);
                  } else {
                      // check if it's a URL
                      try {
                          URL dtdUrl = new URL(matchingDTD.getLocation());
                          InputStream dtdIs = dtdUrl.openStream();
                          if (dtdIs != null) {
                              source = new InputSource(dtdIs);
                              source.setSystemId(dtdUrl.toExternalForm());
                              log("matched as a URL", Project.MSG_DEBUG);
                          } else {
                              log("No match, parser will use: '" + systemId + "'",
                                  Project.MSG_DEBUG);
                          }
                      } catch ( IOException ioe) {
                          //ignore
                      }
                  }
              }
          } else {
              log("No match, parser will use: '" + systemId + "'",
                  Project.MSG_DEBUG);
          }
          // else let the parser handle it as a URI as we don't know what to
          // do with it
          return source;
      }
      
      /**
       * Find a DTDLocation instance for the given publicId.
       *
       * @param publicId the publicId of the DTD for which local information is 
       *        required
       * @return a DTDLocation instance with information on the local location 
       *         of the DTD or null if no such information is available
       */
      private DTDLocation findMatchingDTD(String publicId) {
          Iterator elements = getElements().iterator();
          DTDLocation element = null;
          while (elements.hasNext()) {
              element = (DTDLocation)elements.next();
              if (element.getPublicId().equals(publicId)) {
                  return element;
              }
          }
          return null;
      }
        
  }
  
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>