blob: 52e883da3dec04ecf42698518d0fe648fd4d5ad5 [file] [log] [blame]
/*
* 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.selectors;
import java.io.File;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.Parameter;
import org.apache.tools.ant.BuildException;
/**
* Selector that filters files based on their size.
*
* @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
* @since 1.5
*/
public class SizeSelector extends BaseExtendSelector {
private long size = -1;
private long multiplier = 1;
private long sizelimit = -1;
private int cmp = 2;
public final static String SIZE_KEY = "value";
public final static String UNITS_KEY = "units";
public final static String WHEN_KEY = "when";
public SizeSelector() {
}
public String toString() {
StringBuffer buf = new StringBuffer("{sizeselector value: ");
buf.append(sizelimit);
buf.append("compare: ");
if (cmp == 0) {
buf.append("less");
}
else if (cmp == 1) {
buf.append("more");
} else {
buf.append("equal");
}
buf.append("}");
return buf.toString();
}
/**
* A size selector needs to know what size to base its selecting on.
* This will be further modified by the multiplier to get an
* actual size limit.
*
* @param size the size to select against expressed in units
*/
public void setValue(long size) {
this.size = size;
if ((multiplier != 0) && (size > -1)) {
sizelimit = size * multiplier;
}
}
/**
* Sets the units to use for the comparison. This is a little
* complicated because common usage has created standards that
* play havoc with capitalization rules. Thus, some people will
* use "K" for indicating 1000's, when the SI standard calls for
* "k". Others have tried to introduce "K" as a multiple of 1024,
* but that falls down when you reach "M", since "m" is already
* defined as 0.001.
* <p>
* To get around this complexity, a number of standards bodies
* have proposed the 2^10 standard, and at least one has adopted
* it. But we are still left with a populace that isn't clear on
* how capitalization should work.
* <p>
* We therefore ignore capitalization as much as possible.
* Completely mixed case is not possible, but all upper and lower
* forms are accepted for all long and short forms. Since we have
* no need to work with the 0.001 case, this practice works here.
* <p>
* This function translates all the long and short forms that a
* unit prefix can occur in and translates them into a single
* multiplier.
*
* @param units The units to compare the size to, using an
* EnumeratedAttribute
*/
public void setUnits(ByteUnits units) {
int i = units.getIndex();
multiplier = 0;
if ((i > -1) && (i < 4)) {
multiplier = 1000;
}
else if ((i > 3) && (i < 9)) {
multiplier = 1024;
}
else if ((i > 8) && (i < 13)) {
multiplier = 1000000;
}
else if ((i > 12) && (i < 18)) {
multiplier = 1048576;
}
else if ((i > 17) && (i < 22)) {
multiplier = 1000000000L;
}
else if ((i > 21) && (i < 27)) {
multiplier = 1073741824L;
}
else if ((i > 26) && (i < 31)) {
multiplier = 1000000000000L;
}
else if ((i > 30) && (i < 36)) {
multiplier = 1099511627776L;
}
if ((multiplier > 0) && (size > -1)) {
sizelimit = size * multiplier;
}
}
/**
* This specifies when the file should be selected, whether it be
* when the file matches a particular size, when it is smaller,
* or whether it is larger.
*
* @param cmp The comparison to perform, an EnumeratedAttribute
*/
public void setWhen(SizeComparisons cmp) {
this.cmp = cmp.getIndex();
}
/**
* When using this as a custom selector, this method will be called.
* It translates each parameter into the appropriate setXXX() call.
*
* @param parameters the complete set of parameters for this selector
*/
public void setParameters(Parameter[] parameters) {
super.setParameters(parameters);
if (parameters != null) {
for (int i = 0; i < parameters.length; i++) {
String paramname = parameters[i].getName();
if (SIZE_KEY.equalsIgnoreCase(paramname)) {
try {
setValue(new Long(parameters[i].getValue()
).longValue());
} catch (NumberFormatException nfe) {
setError("Invalid size setting "
+ parameters[i].getValue());
}
}
else if (UNITS_KEY.equalsIgnoreCase(paramname)) {
ByteUnits units = new ByteUnits();
units.setValue(parameters[i].getValue());
setUnits(units);
}
else if (WHEN_KEY.equalsIgnoreCase(paramname)) {
SizeComparisons cmp = new SizeComparisons();
cmp.setValue(parameters[i].getValue());
setWhen(cmp);
}
else {
setError("Invalid parameter " + paramname);
}
}
}
}
/**
* <p>Checks to make sure all settings are kosher. In this case, it
* means that the size attribute has been set (to a positive value),
* that the multiplier has a valid setting, and that the size limit
* is valid. Since the latter is a calculated value, this can only
* fail due to a programming error.
* </p>
* <p>If a problem is detected, the setError() method is called.
* </p>
*/
public void verifySettings() {
if (size < 0) {
setError("The value attribute is required, and must be positive");
}
else if (multiplier < 1) {
setError("Invalid Units supplied, must be K,Ki,M,Mi,G,Gi,T,or Ti");
}
else if (sizelimit < 0) {
setError("Internal error: Code is not setting sizelimit correctly");
}
}
/**
* The heart of the matter. This is where the selector gets to decide
* on the inclusion of a file in a particular fileset.
*
* @param basedir A java.io.File object for the base directory
* @param filename The name of the file to check
* @param file A File object for this filename
* @return whether the file should be selected or not
*/
public boolean isSelected(File basedir, String filename, File file) {
// throw BuildException on error
validate();
// Directory size never selected for
if (file.isDirectory()) {
return true;
}
if (cmp == 0) {
return (file.length() < sizelimit);
}
else if (cmp == 1) {
return (file.length() > sizelimit);
}
else {
return (file.length() == sizelimit);
}
}
/**
* Enumerated attribute with the values for units.
* <p>
* This treats the standard SI units as representing powers of ten,
* as they should. If you want the powers of 2 that approximate
* the SI units, use the first two characters followed by a
* <code>bi</code>. So 1024 (2^10) becomes <code>kibi</code>,
* 1048576 (2^20) becomes <code>mebi</code>, 1073741824 (2^30)
* becomes <code>gibi</code>, and so on. The symbols are also
* accepted, and these are the first letter capitalized followed
* by an <code>i</code>. <code>Ki</code>, <code>Mi</code>,
* <code>Gi</code>, and so on. Capitalization variations on these
* are also accepted.
* <p>
* This binary prefix system is approved by the IEC and appears on
* its way for approval by other agencies, but it is not an SI
* standard. It disambiguates things for us, though.
*/
public static class ByteUnits extends EnumeratedAttribute {
public String[] getValues() {
return new String[] {"K", "k", "kilo", "KILO",
"Ki", "KI", "ki", "kibi", "KIBI",
"M", "m", "mega", "MEGA",
"Mi", "MI", "mi", "mebi", "MEBI",
"G", "g", "giga", "GIGA",
"Gi", "GI", "gi", "gibi", "GIBI",
"T", "t", "tera", "TERA",
/* You wish! */ "Ti", "TI", "ti", "tebi", "TEBI"
};
}
}
/**
* Enumerated attribute with the values for size comparison.
*/
public static class SizeComparisons extends EnumeratedAttribute {
public String[] getValues() {
return new String[] {"less", "more", "equal"};
}
}
}