Browse Source

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 <dion@multitask.com.au>


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271745 13f79535-47bb-0310-9956-ffa450edef68
master
Conor MacNeill 23 years ago
parent
commit
44735223d9
5 changed files with 644 additions and 100 deletions
  1. +253
    -99
      src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java
  2. +35
    -1
      src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java
  3. +97
    -0
      src/main/org/apache/tools/ant/types/DTDLocation.java
  4. +257
    -0
      src/main/org/apache/tools/ant/types/XCatalog.java
  5. +2
    -0
      src/main/org/apache/tools/ant/types/defaults.properties

+ 253
- 99
src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java View File

@@ -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.AntClassLoader;
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
@@ -98,31 +97,65 @@ import org.apache.tools.ant.util.FileUtils;
*/

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";
private Vector params = new Vector();

/** 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.
*
@@ -136,10 +169,11 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger {
public XSLTProcess() {
fileUtils = FileUtils.newFileUtils();
} //-- XSLTProcess
/**
* 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,29 +182,31 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger {
/**
* Executes the task.
*
* @exception BuildException if there is an execution problem.
*/
public void execute() throws BuildException {
DirectoryScanner scanner;
String[] list;
String[] dirs;
if (xslFile == null) {
throw new BuildException("no stylesheet specified", location);
}
if (baseDir == null) {
baseDir = project.resolveFile(".");
}
liaison = getLiaison();
// check if liaison wants to log errors using us as logger
if(liaison instanceof XSLTLoggerAware) {
if (liaison instanceof XSLTLoggerAware) {
((XSLTLoggerAware)liaison).setLogger(this);
}
log("Using "+liaison.getClass().toString(), Project.MSG_VERBOSE);
log("Using " + liaison.getClass().toString(), Project.MSG_VERBOSE);
File stylesheet = project.resolveFile(xslFile);
if (!stylesheet.exists()) {
stylesheet = fileUtils.resolveFile(baseDir, xslFile);
@@ -179,62 +215,66 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger {
* 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.");
}
}
// if we have an in file and out then process them
if (inFile != null && outFile != null) {
process(inFile, outFile, stylesheet);
return;
}
/*
* if we get here, in and out have not been specified, we are
* in batch processing mode.
*/
//-- make sure Source directory exists...
if (destDir == null ) {
String msg = "destdir attributes must be set!";
throw new BuildException(msg);
}
scanner = getDirectoryScanner(baseDir);
log("Transforming into "+destDir, Project.MSG_INFO);
log("Transforming into " + destDir, Project.MSG_INFO);
// Process all the files marked for styling
list = scanner.getIncludedFiles();
for (int i = 0;i < list.length; ++i) {
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();
for (int j = 0;j < dirs.length;++j){
list=new File(baseDir,dirs[j]).list();
for (int i = 0;i < list.length;++i) {
for (int j = 0; j < dirs.length; ++j){
list = new File(baseDir, dirs[j]).list();
for (int i = 0; i < list.length; ++i) {
process( baseDir, list[i], destDir, stylesheet );
}
}
}
} //-- execute
/**
* Set whether to check dependencies, or always generate.
*
* @param force true if always generate.
**/
public void setForce(boolean force) {
this.force = force;
} //-- setForce
/**
* Set the base directory.
*
* @param dir the base directory
**/
public void setBasedir(File dir) {
baseDir = dir;
} //-- setSourceDir
/**
* Set the destination directory into which the XSL result
* files should be copied to
@@ -243,7 +283,7 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger {
public void setDestdir(File dir) {
destDir = dir;
} //-- setDestDir
/**
* Set the desired file extension to be used for the target
* @param name the extension to use
@@ -251,24 +291,30 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger {
public void setExtension(String name) {
targetExtension = name;
} //-- setDestDir
/**
* 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;
}
/**
* 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);
}
/**
* 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) {
@@ -276,47 +322,71 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger {
}
return classpath.createPath();
}
/**
* 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();
}
}
/**
* 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) {
@@ -328,36 +398,46 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger {
return c;
}
}
/**
* Sets an out file
*
* @param outFile the output File instance.
*/
public void setOut(File outFile){
this.outFile = outFile;
}
/**
* Sets an input xml file to be styled
*
* @param inFile the input file
*/
public void setIn(File inFile){
this.inFile = inFile;
}
/**
* 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)
throws BuildException {

String fileExt=targetExtension;
File outFile=null;
File inFile=null;
String fileExt = targetExtension;
File outFile = null;
File inFile = null;
try {
long styleSheetLastModified = stylesheet.lastModified();
inFile = new File(baseDir,xmlFile);
inFile = new File(baseDir, xmlFile);

if (inFile.isDirectory()) {
log("Skipping " + inFile + " it is a directory.",
@@ -366,17 +446,18 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger {
}
int dotPos = xmlFile.lastIndexOf('.');
if(dotPos>0){
outFile = new File(destDir,xmlFile.substring(0,xmlFile.lastIndexOf('.'))+fileExt);
}else{
outFile = new File(destDir,xmlFile+fileExt);
if (dotPos > 0) {
outFile = new File(destDir,
xmlFile.substring(0, xmlFile.lastIndexOf('.')) + fileExt);
} else {
outFile = new File(destDir, xmlFile + fileExt);
}
if (force ||
inFile.lastModified() > outFile.lastModified() ||
styleSheetLastModified > outFile.lastModified()) {
ensureDirectoryFor( outFile );
log("Processing "+inFile+" to "+outFile);
log("Processing " + inFile + " to " + outFile);
configureLiaison(stylesheet);
liaison.transform(inFile, outFile);
}
@@ -388,45 +469,70 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger {
if (outFile != null) {
outFile.delete();
}
throw new BuildException(ex);
}
} //-- processXML

private void process(File inFile, File outFile, File stylesheet) throws BuildException {
try{
/**
* 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);
}
}catch (Exception ex) {
} catch (Exception ex) {
log("Failed to process " + inFile, Project.MSG_INFO);
if(outFile!=null) {
outFile.delete();
if (outFile != null) {
outFile.delete();
}
throw new BuildException(ex);
}
}

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()) {
throw new BuildException("Unable to create directory: "
+ directory.getAbsolutePath() );
+ directory.getAbsolutePath() );
}
}
}

/**
* 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
@@ -457,40 +563,74 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger {
}
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 {
private String name=null;
private String expression=null;

/** 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.");
if (name == null) {
throw new BuildException("Name attribute is missing.");
}
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.");
if (expression == null) {
throw new BuildException("Expression attribute is missing.");
}
return expression;
}
}
/**
* Set the output type to use for the transformation. Only "xml" (the
* default) is guaranteed to work for all parsers. Xalan2 also
@@ -500,27 +640,41 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger {
public void setOutputtype(String type) {
this.outputtype = type;
}
/**
* 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) {
return;
}
stylesheetLoaded = true;
try {
log( "Loading stylesheet " + stylesheet, Project.MSG_INFO);
liaison.setStylesheet( stylesheet );
for(Enumeration e = params.elements();e.hasMoreElements();) {
for (Enumeration e = params.elements(); e.hasMoreElements(); ) {
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);
}
}

} //-- XSLTProcess

+ 35
- 1
src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java View File

@@ -63,6 +63,12 @@ import org.apache.tools.ant.taskdefs.XSLTLiaison;
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.ErrorListener;
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)
@@ -95,6 +104,9 @@ public class TraXLiaison implements XSLTLiaison, ErrorListener, XSLTLoggerAware
private Transformer transformer = null;

private XSLTLogger logger;
/** possible resolver for publicIds */
private EntityResolver resolver;

public TraXLiaison() throws Exception {
tfactory = TransformerFactory.newInstance();
@@ -128,7 +140,23 @@ public class TraXLiaison implements XSLTLiaison, ErrorListener, XSLTLoggerAware
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 @@ public class TraXLiaison implements XSLTLiaison, ErrorListener, XSLTLoggerAware
logger.log(msg.toString());
}

/** Set the class to resolve entities during the transformation
*/
public void setEntityResolver(EntityResolver aResolver) throws Exception {
resolver = aResolver;
}
} //-- TraXLiaison

+ 97
- 0
src/main/org/apache/tools/ant/types/DTDLocation.java View File

@@ -0,0 +1,97 @@
/*
* 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;
}
}


+ 257
- 0
src/main/org/apache/tools/ant/types/XCatalog.java View File

@@ -0,0 +1,257 @@
/*
* 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$
*/
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;
}
}


+ 2
- 0
src/main/org/apache/tools/ant/types/defaults.properties View File

@@ -8,3 +8,5 @@ description=org.apache.tools.ant.types.Description
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


Loading…
Cancel
Save