blob: f57c59858d89c02bb3a4b65e984fd4f4d240dc6c [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001-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;
// java io classes
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
// java util classes
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;
// ant classes
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
/**
* A set of filters to be applied to something.
*
* A filter set may have begintoken and endtokens defined.
*
* @author <A href="mailto:gholam@xtra.co.nz"> Michael McCallum </A>
*/
public class FilterSet extends DataType implements Cloneable {
/**
* Individual filter component of filterset
*
* @author Michael McCallum
*/
public static class Filter {
/** Token which will be replaced in the filter operation */
String token;
/** The value which will replace the token in the filtering operation */
String value;
/**
* Constructor for the Filter object
*
* @param token The token which will be replaced when filtering
* @param value The value which will replace the token when filtering
*/
public Filter(String token, String value) {
this.token = token;
this.value = value;
}
/**
* No argument conmstructor
*/
public Filter() {
}
/**
* Sets the Token attribute of the Filter object
*
* @param token The new Token value
*/
public void setToken( String token ) {
this.token = token;
}
/**
* Sets the Value attribute of the Filter object
*
* @param value The new Value value
*/
public void setValue( String value ) {
this.value = value;
}
/**
* Gets the Token attribute of the Filter object
*
* @return The Token value
*/
public String getToken() {
return token;
}
/**
* Gets the Value attribute of the Filter object
*
* @return The Value value
*/
public String getValue() {
return value;
}
}
/**
* The filtersfile nested element.
*
* @author Michael McCallum
*/
public class FiltersFile {
/**
* Constructor for the Filter object
*/
public FiltersFile() {
}
/**
* Sets the file from which filters will be read.
*
* @param file the file from which filters will be read.
*/
public void setFile(File file) {
readFiltersFromFile(file);
}
}
/** The default token start string */
public final static String DEFAULT_TOKEN_START = "@";
/** The default token end string */
public final static String DEFAULT_TOKEN_END = "@";
private String startOfToken = DEFAULT_TOKEN_START;
private String endOfToken = DEFAULT_TOKEN_END;
/**
* List of ordered filters and filter files.
*/
private Vector filters = new Vector();
public FilterSet() {
}
/**
* Create a Filterset from another filterset
*
* @param filterset the filterset upon which this filterset will be based.
*/
protected FilterSet(FilterSet filterset) {
super();
this.filters = (Vector)filterset.getFilters().clone();
}
protected Vector getFilters() {
if (isReference()) {
return getRef().getFilters();
}
return filters;
}
protected FilterSet getRef() {
return (FilterSet)getCheckedRef(FilterSet.class, "filterset");
}
/**
* Gets the filter hash of the FilterSet.
*
* @return The hash of the tokens and values for quick lookup.
*/
public Hashtable getFilterHash() {
int filterSize = getFilters().size();
Hashtable filterHash = new Hashtable(filterSize);
for (Enumeration e = getFilters().elements(); e.hasMoreElements();) {
Filter filter = (Filter) e.nextElement();
filterHash.put(filter.getToken(), filter.getValue());
}
return filterHash;
}
/**
* set the file containing the filters for this filterset.
*
* @param filtersFile sets the filter fil to read filters for this filter set from.
* @exception BuildException if there is a problem reading the filters
*/
public void setFiltersfile(File filtersFile) throws BuildException {
if (isReference()) {
throw tooManyAttributes();
}
readFiltersFromFile(filtersFile);
}
/**
* The string used to id the beginning of a token.
*
* @param startOfToken The new Begintoken value
*/
public void setBeginToken(String startOfToken) {
if (isReference()) {
throw tooManyAttributes();
}
if (startOfToken == null || "".equals(startOfToken)) {
throw new BuildException("beginToken must not be empty");
}
this.startOfToken = startOfToken;
}
public String getBeginToken() {
if (isReference()) {
return getRef().getBeginToken();
}
return startOfToken;
}
/**
* The string used to id the end of a token.
*
* @param endOfToken The new Endtoken value
*/
public void setEndToken( String endOfToken ) {
if (isReference()) {
throw tooManyAttributes();
}
if (endOfToken == null || "".equals(endOfToken)) {
throw new BuildException("endToken must not be empty");
}
this.endOfToken = endOfToken;
}
public String getEndToken() {
if (isReference()) {
return getRef().getEndToken();
}
return endOfToken;
}
/**
* Read the filters from the given file.
*
* @param filtersFile the file from which filters are read
* @exception BuildException Throw a build exception when unable to read the
* file.
*/
public void readFiltersFromFile(File filtersFile) throws BuildException {
if (isReference()) {
throw tooManyAttributes();
}
if (filtersFile.isFile()) {
log("Reading filters from " + filtersFile, Project.MSG_VERBOSE );
FileInputStream in = null;
try {
Properties props = new Properties();
in = new FileInputStream(filtersFile);
props.load(in);
Enumeration enum = props.propertyNames();
Vector filters = getFilters();
while (enum.hasMoreElements()) {
String strPropName = (String) enum.nextElement();
String strValue = props.getProperty(strPropName);
filters.addElement(new Filter(strPropName, strValue));
}
}
catch (Exception e) {
throw new BuildException( "Could not read filters from file: " + filtersFile );
}
finally {
if ( in != null ) {
try {
in.close();
}
catch (IOException ioex) {
}
}
}
}
else {
throw new BuildException( "Must specify a file not a directory in the filtersfile attribute:" + filtersFile );
}
}
/**
* Does replacement on the given string with token matching.
* This uses the defined begintoken and endtoken values which default to @ for both.
*
* @param line The line to process the tokens in.
* @return The string with the tokens replaced.
*/
public String replaceTokens(String line) {
String beginToken = getBeginToken();
String endToken = getEndToken();
int index = line.indexOf(beginToken);
if (index > -1) {
Hashtable tokens = getFilterHash();
try {
StringBuffer b = new StringBuffer();
int i = 0;
String token = null;
String value = null;
do {
int endIndex = line.indexOf(endToken, index + beginToken.length() + 1 );
if (endIndex == -1) {
break;
}
token = line.substring(index + beginToken.length(), endIndex );
b.append(line.substring(i, index));
if (tokens.containsKey(token)) {
value = (String)tokens.get(token);
log( "Replacing: " + beginToken + token + endToken + " -> " + value, Project.MSG_VERBOSE );
b.append(value);
i = index + beginToken.length() + token.length() + endToken.length();
}
else {
// just append beginToken and search further
b.append(beginToken);
i = index + beginToken.length();
}
} while ((index = line.indexOf( beginToken, i )) > -1 );
b.append(line.substring(i));
return b.toString();
}
catch (StringIndexOutOfBoundsException e) {
return line;
}
}
else {
return line;
}
}
/**
* Create a new filter
*
* @param the filter to be added
*/
public void addFilter(Filter filter) {
if (isReference()) {
throw noChildrenAllowed();
}
filters.addElement(filter);
}
/**
* Create a new FiltersFile
*
* @return The filter that was created.
*/
public FiltersFile createFiltersfile() {
if (isReference()) {
throw noChildrenAllowed();
}
return new FiltersFile();
}
/**
* Add a new filter made from the given token and value.
*
* @param token The token for the new filter.
* @param value The value for the new filter.
*/
public void addFilter(String token, String value) {
if (isReference()) {
throw noChildrenAllowed();
}
filters.addElement(new Filter(token, value));
}
/**
* Add a Filterset to this filter set
*
* @param filterSet the filterset to be added to this filterset
*/
public void addFilterSet(FilterSet filterSet) {
if (isReference()) {
throw noChildrenAllowed();
}
for (Enumeration e = filterSet.getFilters().elements(); e.hasMoreElements();) {
filters.addElement(e.nextElement());
}
}
/**
* Test to see if this filter set it empty.
*
* @return Return true if there are filter in this set otherwise false.
*/
public boolean hasFilters() {
return getFilters().size() > 0;
}
public Object clone() throws BuildException {
if (isReference()) {
return new FilterSet(getRef());
} else {
return new FilterSet(this);
}
}
}