001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.types.selectors;
020:
021: import java.io.File;
022:
023: import org.apache.tools.ant.types.Comparison;
024: import org.apache.tools.ant.types.EnumeratedAttribute;
025: import org.apache.tools.ant.types.Parameter;
026:
027: /**
028: * Selector that filters files based on their size.
029: *
030: * @since 1.5
031: */
032: public class SizeSelector extends BaseExtendSelector {
033:
034: /** Used for parameterized custom selector */
035: public static final String SIZE_KEY = "value";
036: /** Used for parameterized custom selector */
037: public static final String UNITS_KEY = "units";
038: /** Used for parameterized custom selector */
039: public static final String WHEN_KEY = "when";
040:
041: private long size = -1;
042: private long multiplier = 1;
043: private long sizelimit = -1;
044: private Comparison when = Comparison.EQUAL;
045:
046: /**
047: * Creates a new <code>SizeSelector</code> instance.
048: *
049: */
050: public SizeSelector() {
051: }
052:
053: /**
054: * Returns a <code>String</code> object representing the specified
055: * SizeSelector. This is "{sizeselector value: " + <"compare",
056: * "less", "more", "equal"> + "}".
057: * @return a string describing this object
058: */
059: public String toString() {
060: StringBuffer buf = new StringBuffer("{sizeselector value: ");
061: buf.append(sizelimit);
062: buf.append("compare: ").append(when.getValue());
063: buf.append("}");
064: return buf.toString();
065: }
066:
067: /**
068: * A size selector needs to know what size to base its selecting on.
069: * This will be further modified by the multiplier to get an
070: * actual size limit.
071: *
072: * @param size the size to select against expressed in units.
073: */
074: public void setValue(long size) {
075: this .size = size;
076: if (multiplier != 0 && size > -1) {
077: sizelimit = size * multiplier;
078: }
079: }
080:
081: /**
082: * Sets the units to use for the comparison. This is a little
083: * complicated because common usage has created standards that
084: * play havoc with capitalization rules. Thus, some people will
085: * use "K" for indicating 1000's, when the SI standard calls for
086: * "k". Others have tried to introduce "K" as a multiple of 1024,
087: * but that falls down when you reach "M", since "m" is already
088: * defined as 0.001.
089: * <p>
090: * To get around this complexity, a number of standards bodies
091: * have proposed the 2^10 standard, and at least one has adopted
092: * it. But we are still left with a populace that isn't clear on
093: * how capitalization should work.
094: * <p>
095: * We therefore ignore capitalization as much as possible.
096: * Completely mixed case is not possible, but all upper and lower
097: * forms are accepted for all long and short forms. Since we have
098: * no need to work with the 0.001 case, this practice works here.
099: * <p>
100: * This function translates all the long and short forms that a
101: * unit prefix can occur in and translates them into a single
102: * multiplier.
103: *
104: * @param units The units to compare the size to, using an
105: * EnumeratedAttribute.
106: */
107: public void setUnits(ByteUnits units) {
108: int i = units.getIndex();
109: multiplier = 0;
110: if (i > -1 && i < 4) {
111: multiplier = 1000;
112: } else if (i > 3 && i < 9) {
113: multiplier = 1024;
114: } else if (i > 8 && i < 13) {
115: multiplier = 1000000;
116: } else if (i > 12 && i < 18) {
117: multiplier = 1048576;
118: } else if (i > 17 && i < 22) {
119: multiplier = 1000000000L;
120: } else if (i > 21 && i < 27) {
121: multiplier = 1073741824L;
122: } else if (i > 26 && i < 31) {
123: multiplier = 1000000000000L;
124: } else if (i > 30 && i < 36) {
125: multiplier = 1099511627776L;
126: }
127: if (multiplier > 0 && size > -1) {
128: sizelimit = size * multiplier;
129: }
130: }
131:
132: /**
133: * This specifies when the file should be selected, whether it be
134: * when the file matches a particular size, when it is smaller,
135: * or whether it is larger.
136: *
137: * @param when The comparison to perform, an EnumeratedAttribute.
138: */
139: public void setWhen(SizeComparisons when) {
140: this .when = when;
141: }
142:
143: /**
144: * When using this as a custom selector, this method will be called.
145: * It translates each parameter into the appropriate setXXX() call.
146: *
147: * @param parameters the complete set of parameters for this selector.
148: */
149: public void setParameters(Parameter[] parameters) {
150: super .setParameters(parameters);
151: if (parameters != null) {
152: for (int i = 0; i < parameters.length; i++) {
153: String paramname = parameters[i].getName();
154: if (SIZE_KEY.equalsIgnoreCase(paramname)) {
155: try {
156: setValue(new Long(parameters[i].getValue())
157: .longValue());
158: } catch (NumberFormatException nfe) {
159: setError("Invalid size setting "
160: + parameters[i].getValue());
161: }
162: } else if (UNITS_KEY.equalsIgnoreCase(paramname)) {
163: ByteUnits units = new ByteUnits();
164: units.setValue(parameters[i].getValue());
165: setUnits(units);
166: } else if (WHEN_KEY.equalsIgnoreCase(paramname)) {
167: SizeComparisons scmp = new SizeComparisons();
168: scmp.setValue(parameters[i].getValue());
169: setWhen(scmp);
170: } else {
171: setError("Invalid parameter " + paramname);
172: }
173: }
174: }
175: }
176:
177: /**
178: * <p>Checks to make sure all settings are kosher. In this case, it
179: * means that the size attribute has been set (to a positive value),
180: * that the multiplier has a valid setting, and that the size limit
181: * is valid. Since the latter is a calculated value, this can only
182: * fail due to a programming error.
183: * </p>
184: * <p>If a problem is detected, the setError() method is called.
185: * </p>
186: */
187: public void verifySettings() {
188: if (size < 0) {
189: setError("The value attribute is required, and must be positive");
190: } else if (multiplier < 1) {
191: setError("Invalid Units supplied, must be K,Ki,M,Mi,G,Gi,T,or Ti");
192: } else if (sizelimit < 0) {
193: setError("Internal error: Code is not setting sizelimit correctly");
194: }
195: }
196:
197: /**
198: * The heart of the matter. This is where the selector gets to decide
199: * on the inclusion of a file in a particular fileset.
200: *
201: * @param basedir A java.io.File object for the base directory.
202: * @param filename The name of the file to check.
203: * @param file A File object for this filename.
204: * @return whether the file should be selected or not.
205: */
206: public boolean isSelected(File basedir, String filename, File file) {
207:
208: // throw BuildException on error
209: validate();
210:
211: // Directory size never selected for
212: if (file.isDirectory()) {
213: return true;
214: }
215: long diff = file.length() - sizelimit;
216: return when.evaluate(diff == 0 ? 0 : (int) (diff / Math
217: .abs(diff)));
218: }
219:
220: /**
221: * Enumerated attribute with the values for units.
222: * <p>
223: * This treats the standard SI units as representing powers of ten,
224: * as they should. If you want the powers of 2 that approximate
225: * the SI units, use the first two characters followed by a
226: * <code>bi</code>. So 1024 (2^10) becomes <code>kibi</code>,
227: * 1048576 (2^20) becomes <code>mebi</code>, 1073741824 (2^30)
228: * becomes <code>gibi</code>, and so on. The symbols are also
229: * accepted, and these are the first letter capitalized followed
230: * by an <code>i</code>. <code>Ki</code>, <code>Mi</code>,
231: * <code>Gi</code>, and so on. Capitalization variations on these
232: * are also accepted.
233: * <p>
234: * This binary prefix system is approved by the IEC and appears on
235: * its way for approval by other agencies, but it is not an SI
236: * standard. It disambiguates things for us, though.
237: */
238: public static class ByteUnits extends EnumeratedAttribute {
239: /**
240: * @return the values as an array of strings
241: */
242: public String[] getValues() {
243: return new String[] { "K", "k", "kilo", "KILO", "Ki", "KI",
244: "ki", "kibi", "KIBI", "M", "m", "mega", "MEGA",
245: "Mi", "MI", "mi", "mebi", "MEBI", "G", "g", "giga",
246: "GIGA", "Gi", "GI", "gi", "gibi", "GIBI", "T", "t",
247: "tera", "TERA",
248: /* You wish! */"Ti", "TI", "ti", "tebi", "TEBI" };
249: }
250: }
251:
252: /**
253: * Enumerated attribute with the values for size comparison.
254: */
255: public static class SizeComparisons extends Comparison {
256: }
257:
258: }
|