/* * Copyright 2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.tools.ant.taskdefs; import java.io.File; import java.io.PrintStream; import java.io.OutputStream; import java.io.ByteArrayOutputStream; import java.util.Vector; import java.util.HashSet; import org.apache.tools.ant.Task; import org.apache.tools.ant.Project; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.util.FileUtils; /** * Gets lengths: of files, byte size; of strings, length (optionally trimmed). * The task is overloaded in this way for semantic reasons, much like Available. * @since Ant 1.7 */ public class Length extends Task { private static final String ALL = "all"; private static final String EACH = "each"; private static final String STRING = "string"; private String property; private String string; private Boolean trim; private Vector filesets; private String mode = ALL; /** * The property in which the length will be stored. * @param property the String property key. */ public synchronized void setProperty(String property) { this.property = property; } /** * Set the single file for this task. * @param file the File whose length to retrieve. */ public synchronized void setFile(File file) { FileSet fs = new FileSet(); fs.setFile(file); add(fs); } /** * Add a FileSet. * @param fs the FileSet to add. */ public synchronized void add(FileSet fs) { filesets = (filesets == null) ? new Vector() : filesets; filesets.add(fs); } /** * Set the execution mode for working with files. * @param m the FileMode to use. */ public synchronized void setMode(FileMode m) { this.mode = m.getValue(); } /** * Set the string whose length to get. * @param string String. */ public synchronized void setString(String string) { this.string = string; this.mode = STRING; } /** * Set whether to trim in string mode. * @param trim boolean. */ public synchronized void setTrim(boolean trim) { this.trim = trim ? Boolean.TRUE : Boolean.FALSE; } /** * Execute the length task. */ public void execute() { validate(); PrintStream ps = new PrintStream((property != null) ? (OutputStream) new PropertyOutputStream() : (OutputStream) new LogOutputStream(this, Project.MSG_INFO)); if (STRING.equals(mode)) { ps.print(((trim != null && trim.booleanValue()) ? string.trim() : string).length()); ps.close(); } else if (EACH.equals(mode)) { handleFilesets(new EachHandler(ps)); } else if (ALL.equals(mode)) { handleFilesets(new AllHandler(ps)); } } private void validate() { if (string != null) { if (filesets != null && filesets.size() > 0) { throw new BuildException("the string length function" + " is incompatible with the file length function"); } if (!(STRING.equals(mode))) { throw new BuildException("the mode attribute is for use" + " with the file length function"); } } else if (filesets != null && filesets.size() > 0) { if (!(EACH.equals(mode) || ALL.equals(mode))) { throw new BuildException("invalid mode setting for" + " file length function: \"" + mode + "\""); } else if (trim != null) { throw new BuildException("the trim attribute is" + " for use with the string length function only"); } } else { throw new BuildException("you must set either the string attribute" + " or specify one or more files using the file attribute or" + " nested filesets"); } } private void handleFilesets(Handler h) { HashSet included = new HashSet(filesets.size()); for (int i = 0; i < filesets.size(); i++) { FileSet fs = (FileSet) (filesets.get(i)); DirectoryScanner ds = fs.getDirectoryScanner(getProject()); String[] f = ds.getIncludedFiles(); for (int j = 0; j < f.length; j++) { Resource r = ds.getResource(f[j]); if (!r.isExists()) { log(r.getName() + " does not exist", Project.MSG_ERR); } else if (r.isDirectory()) { log(r.getName() + " is a directory; length unspecified", Project.MSG_ERR); } else { //clone the Resource and alter path File basedir = ds.getBasedir(); if (basedir != null) { r = (Resource) (r.clone()); r.setName(FileUtils.getFileUtils().resolveFile( basedir, r.getName()).getAbsolutePath()); } if (included.add(r.getName())) { h.handle(r); } } } } included.clear(); included = null; h.complete(); } /** EnumeratedAttribute operation mode */ public static class FileMode extends EnumeratedAttribute { static final String[] MODES = new String[] {EACH, ALL}; /** * Return the possible values for FileMode. * @return String[]. */ public String[] getValues() { return MODES; } } private class PropertyOutputStream extends ByteArrayOutputStream { public void close() { getProject().setNewProperty( property, new String(toByteArray()).trim()); } } private abstract class Handler { PrintStream ps; Handler(PrintStream ps) { this.ps = ps; } protected abstract void handle(Resource r); void complete() { ps.close(); } } private class EachHandler extends Handler { EachHandler(PrintStream ps) { super(ps); } protected void handle(Resource r) { ps.print(r.getName()); ps.print(" : "); //when writing to the log, we'll see what's happening: long size = r.getSize(); if (size == Resource.UNKNOWN_SIZE) { ps.println("unknown"); } else { ps.println(size); } } } private class AllHandler extends Handler { long length = 0L; AllHandler(PrintStream ps) { super(ps); } protected synchronized void handle(Resource r) { long size = r.getSize(); if (size == Resource.UNKNOWN_SIZE) { log("Size unknown for " + r.getName(), Project.MSG_WARN); } else { length += size; } } void complete() { ps.print(length); super.complete(); } } }