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.taskdefs;
020:
021: import java.io.File;
022: import java.io.PrintStream;
023: import java.io.OutputStream;
024: import java.util.Iterator;
025:
026: import org.apache.tools.ant.Task;
027: import org.apache.tools.ant.Project;
028: import org.apache.tools.ant.BuildException;
029: import org.apache.tools.ant.taskdefs.condition.Condition;
030: import org.apache.tools.ant.types.FileSet;
031: import org.apache.tools.ant.types.Resource;
032: import org.apache.tools.ant.types.Comparison;
033: import org.apache.tools.ant.types.ResourceCollection;
034: import org.apache.tools.ant.types.EnumeratedAttribute;
035: import org.apache.tools.ant.types.resources.Resources;
036: import org.apache.tools.ant.types.resources.FileResource;
037: import org.apache.tools.ant.util.PropertyOutputStream;
038:
039: /**
040: * Gets lengths: of files/resources, byte size; of strings, length (optionally trimmed).
041: * The task is overloaded in this way for semantic reasons, much like Available.
042: * @since Ant 1.6.3
043: */
044: public class Length extends Task implements Condition {
045:
046: private static final String ALL = "all";
047: private static final String EACH = "each";
048: private static final String STRING = "string";
049:
050: private static final String LENGTH_REQUIRED = "Use of the Length condition requires that the length attribute be set.";
051:
052: private String property;
053: private String string;
054: private Boolean trim;
055: private String mode = ALL;
056: private Comparison when = Comparison.EQUAL;
057: private Long length;
058: private Resources resources;
059:
060: /**
061: * The property in which the length will be stored.
062: * @param property the <code>String</code> property key.
063: */
064: public synchronized void setProperty(String property) {
065: this .property = property;
066: }
067:
068: /**
069: * Set the single file for this task.
070: * @param file the <code>File</code> whose length to retrieve.
071: */
072: public synchronized void setFile(File file) {
073: add(new FileResource(file));
074: }
075:
076: /**
077: * Add a FileSet.
078: * @param fs the <code>FileSet</code> to add.
079: */
080: public synchronized void add(FileSet fs) {
081: add((ResourceCollection) fs);
082: }
083:
084: /**
085: * Add a ResourceCollection.
086: * @param c the <code>ResourceCollection</code> to add.
087: * @since Ant 1.7
088: */
089: public synchronized void add(ResourceCollection c) {
090: if (c == null) {
091: return;
092: }
093: resources = (resources == null) ? new Resources() : resources;
094: resources.add(c);
095: }
096:
097: /**
098: * Set the target count number for use as a Condition.
099: * @param ell the long length to compare with.
100: */
101: public synchronized void setLength(long ell) {
102: length = new Long(ell);
103: }
104:
105: /**
106: * Set the comparison for use as a Condition.
107: * @param w EnumeratedAttribute When.
108: * @see org.apache.tools.ant.types.Comparison
109: */
110: public synchronized void setWhen(When w) {
111: setWhen((Comparison) w);
112: }
113:
114: /**
115: * Set the comparison for use as a Condition.
116: * @param c Comparison.
117: * @see org.apache.tools.ant.types.Comparison
118: * @since Ant 1.7
119: */
120: public synchronized void setWhen(Comparison c) {
121: when = c;
122: }
123:
124: /**
125: * Set the execution mode for working with files.
126: * @param m the <code>FileMode</code> to use.
127: */
128: public synchronized void setMode(FileMode m) {
129: this .mode = m.getValue();
130: }
131:
132: /**
133: * Set the string whose length to get.
134: * @param string <code>String</code>.
135: */
136: public synchronized void setString(String string) {
137: this .string = string;
138: this .mode = STRING;
139: }
140:
141: /**
142: * Set whether to trim in string mode.
143: * @param trim <code>boolean</code>.
144: */
145: public synchronized void setTrim(boolean trim) {
146: this .trim = trim ? Boolean.TRUE : Boolean.FALSE;
147: }
148:
149: /**
150: * Learn whether strings will be trimmed.
151: * @return boolean trim setting.
152: */
153: public boolean getTrim() {
154: return trim != null && trim.booleanValue();
155: }
156:
157: /**
158: * Execute the length task.
159: */
160: public void execute() {
161: validate();
162: PrintStream ps = new PrintStream(
163: (property != null) ? (OutputStream) new PropertyOutputStream(
164: getProject(), property)
165: : (OutputStream) new LogOutputStream(this ,
166: Project.MSG_INFO));
167:
168: if (STRING.equals(mode)) {
169: ps.print(getLength(string, getTrim()));
170: ps.close();
171: } else if (EACH.equals(mode)) {
172: handleResources(new EachHandler(ps));
173: } else if (ALL.equals(mode)) {
174: handleResources(new AllHandler(ps));
175: }
176: }
177:
178: /**
179: * Fulfill the condition contract.
180: * @return true if the condition is true.
181: * @throws BuildException if an error occurs.
182: */
183: public boolean eval() {
184: validate();
185: if (length == null) {
186: throw new BuildException(LENGTH_REQUIRED);
187: }
188: Long ell = null;
189: if (STRING.equals(mode)) {
190: ell = new Long(getLength(string, getTrim()));
191: } else {
192: ConditionHandler h = new ConditionHandler();
193: handleResources(h);
194: ell = new Long(h.getLength());
195: }
196: return when.evaluate(ell.compareTo(length));
197: }
198:
199: private void validate() {
200: if (string != null) {
201: if (resources != null) {
202: throw new BuildException(
203: "the string length function"
204: + " is incompatible with the file/resource length function");
205: }
206: if (!(STRING.equals(mode))) {
207: throw new BuildException(
208: "the mode attribute is for use"
209: + " with the file/resource length function");
210: }
211: } else if (resources != null) {
212: if (!(EACH.equals(mode) || ALL.equals(mode))) {
213: throw new BuildException("invalid mode setting for"
214: + " file/resource length function: \"" + mode
215: + "\"");
216: } else if (trim != null) {
217: throw new BuildException(
218: "the trim attribute is"
219: + " for use with the string length function only");
220: }
221: } else {
222: throw new BuildException(
223: "you must set either the string attribute"
224: + " or specify one or more files using the file attribute or"
225: + " nested resource collections");
226: }
227: }
228:
229: private void handleResources(Handler h) {
230: for (Iterator i = resources.iterator(); i.hasNext();) {
231: Resource r = (Resource) i.next();
232: if (!r.isExists()) {
233: log(r + " does not exist", Project.MSG_ERR);
234: } else if (r.isDirectory()) {
235: log(r + " is a directory; length unspecified",
236: Project.MSG_ERR);
237: } else {
238: h.handle(r);
239: }
240: }
241: h.complete();
242: }
243:
244: private static long getLength(String s, boolean t) {
245: return (t ? s.trim() : s).length();
246: }
247:
248: /** EnumeratedAttribute operation mode */
249: public static class FileMode extends EnumeratedAttribute {
250: static final String[] MODES = new String[] { EACH, ALL };
251:
252: /**
253: * Return the possible values for FileMode.
254: * @return <code>String[]</code>.
255: */
256: public String[] getValues() {
257: return MODES;
258: }
259:
260: }
261:
262: /**
263: * EnumeratedAttribute for the when attribute.
264: */
265: public static class When extends Comparison {
266: //extend Comparison; retain for BC only
267: }
268:
269: private abstract class Handler {
270: private PrintStream ps;
271:
272: Handler(PrintStream ps) {
273: this .ps = ps;
274: }
275:
276: protected PrintStream getPs() {
277: return ps;
278: }
279:
280: protected abstract void handle(Resource r);
281:
282: void complete() {
283: ps.close();
284: }
285: }
286:
287: private class EachHandler extends Handler {
288: EachHandler(PrintStream ps) {
289: super (ps);
290: }
291:
292: protected void handle(Resource r) {
293: getPs().print(r.toString());
294: getPs().print(" : ");
295: //when writing to the log, we'll see what's happening:
296: long size = r.getSize();
297: if (size == Resource.UNKNOWN_SIZE) {
298: getPs().println("unknown");
299: } else {
300: getPs().println(size);
301: }
302: }
303: }
304:
305: private class AllHandler extends Handler {
306: private long accum = 0L;
307:
308: AllHandler(PrintStream ps) {
309: super (ps);
310: }
311:
312: protected long getAccum() {
313: return accum;
314: }
315:
316: protected synchronized void handle(Resource r) {
317: long size = r.getSize();
318: if (size == Resource.UNKNOWN_SIZE) {
319: log("Size unknown for " + r.toString(),
320: Project.MSG_WARN);
321: } else {
322: accum += size;
323: }
324: }
325:
326: void complete() {
327: getPs().print(accum);
328: super .complete();
329: }
330: }
331:
332: private class ConditionHandler extends AllHandler {
333: ConditionHandler() {
334: super (null);
335: }
336:
337: void complete() {
338: }
339:
340: long getLength() {
341: return getAccum();
342: }
343: }
344: }
|