1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609 |
- /* *******************************************************************
- * Copyright (c) 1999-2001 Xerox Corporation,
- * 2002 Palo Alto Research Center, Incorporated (PARC).
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Xerox/PARC initial implementation
- * ******************************************************************/
-
- package org.aspectj.util;
-
- import java.io.BufferedOutputStream;
- import java.io.BufferedReader;
- import java.io.ByteArrayOutputStream;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.File;
- import java.io.FileFilter;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.FileReader;
- import java.io.FileWriter;
- import java.io.FilenameFilter;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.io.PrintStream;
- import java.io.Reader;
- import java.io.StringReader;
- import java.io.Writer;
- import java.net.MalformedURLException;
- import java.net.URISyntaxException;
- import java.net.URL;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.zip.ZipEntry;
- import java.util.zip.ZipFile;
-
- /**
- * @author Andy Clement
- * @author Kris De Volder
- */
- public class FileUtil {
- /** default parent directory File when a file has a null parent */
- public static final File DEFAULT_PARENT = new File("."); // XXX user.dir?
-
- /** unmodifiable List of String source file suffixes (including leading ".") */
- public static final List<String> SOURCE_SUFFIXES = Collections.unmodifiableList(Arrays.asList(new String[] { ".java", ".aj" }));
-
- public static final FileFilter ZIP_FILTER = new FileFilter() {
- public boolean accept(File file) {
- return isZipFile(file);
- }
-
- public String toString() {
- return "ZIP_FILTER";
- }
- };
-
- // public static final FileFilter SOURCE_FILTER = new FileFilter() {
- // public boolean accept(File file) {
- // return hasSourceSuffix(file);
- // }
- //
- // public String toString() {
- // return "SOURCE_FILTER";
- // }
- // };
-
- final static int[] INT_RA = new int[0];
-
- /** accept all files */
- public static final FileFilter ALL = new FileFilter() {
- public boolean accept(File f) {
- return true;
- }
- };
- public static final FileFilter DIRS_AND_WRITABLE_CLASSES = new FileFilter() {
- public boolean accept(File file) {
- return ((null != file) && (file.isDirectory() || (file.canWrite() && file.getName().toLowerCase().endsWith(".class"))));
- }
- };
- private static final boolean PERMIT_CVS;
- static {
- String name = FileUtil.class.getName() + ".PERMIT_CVS";
- PERMIT_CVS = LangUtil.getBoolean(name, false);
- }
-
- /** @return true if file exists and is a zip file */
- public static boolean isZipFile(File file) {
- try {
- return (null != file) && new ZipFile(file) != null;
- } catch (IOException e) {
- return false;
- }
- }
-
- /** @return true if path ends with .zip or .jar */
- // public static boolean hasZipSuffix(String path) {
- // return ((null != path) && (0 != zipSuffixLength(path)));
- // }
- /** @return 0 if file has no zip/jar suffix or 4 otherwise */
- public static int zipSuffixLength(File file) {
- return (null == file ? 0 : zipSuffixLength(file.getPath()));
- }
-
- /** @return 0 if no zip/jar suffix or 4 otherwise */
- public static int zipSuffixLength(String path) {
- if ((null != path) && (4 < path.length())) {
- String test = path.substring(path.length() - 4).toLowerCase();
- if (".zip".equals(test) || ".jar".equals(test)) {
- return 4;
- }
- }
- return 0;
- }
-
- /** @return true if file path has a source suffix */
- public static boolean hasSourceSuffix(File file) {
- return ((null != file) && hasSourceSuffix(file.getPath()));
- }
-
- /** @return true if path ends with .java or .aj */
- public static boolean hasSourceSuffix(String path) {
- return ((null != path) && (0 != sourceSuffixLength(path)));
- }
-
- /**
- * @return 0 if file has no source suffix or the length of the suffix otherwise
- */
- public static int sourceSuffixLength(File file) {
- return (null == file ? 0 : sourceSuffixLength(file.getPath()));
- }
-
- /** @return 0 if no source suffix or the length of the suffix otherwise */
- public static int sourceSuffixLength(String path) {
- if (LangUtil.isEmpty(path)) {
- return 0;
- }
-
- for (String suffix : SOURCE_SUFFIXES) {
- if (path.endsWith(suffix) || path.toLowerCase().endsWith(suffix)) {
- return suffix.length();
- }
- }
- return 0;
- }
-
- /** @return true if this is a readable directory */
- public static boolean canReadDir(File dir) {
- return ((null != dir) && dir.canRead() && dir.isDirectory());
- }
-
- /** @return true if this is a readable file */
- public static boolean canReadFile(File file) {
- return ((null != file) && file.canRead() && file.isFile());
- }
-
- /** @return true if dir is a writable directory */
- public static boolean canWriteDir(File dir) {
- return ((null != dir) && dir.canWrite() && dir.isDirectory());
- }
-
- /** @return true if this is a writable file */
- public static boolean canWriteFile(File file) {
- return ((null != file) && file.canWrite() && file.isFile());
- }
-
- // /**
- // * @throws IllegalArgumentException unless file is readable and not a
- // * directory
- // */
- // public static void throwIaxUnlessCanReadFile(File file, String label) {
- // if (!canReadFile(file)) {
- // throw new IllegalArgumentException(label + " not readable file: " +
- // file);
- // }
- // }
-
- /**
- * @throws IllegalArgumentException unless dir is a readable directory
- */
- public static void throwIaxUnlessCanReadDir(File dir, String label) {
- if (!canReadDir(dir)) {
- throw new IllegalArgumentException(label + " not readable dir: " + dir);
- }
- }
-
- /**
- * @throws IllegalArgumentException unless file is readable and not a directory
- */
- public static void throwIaxUnlessCanWriteFile(File file, String label) {
- if (!canWriteFile(file)) {
- throw new IllegalArgumentException(label + " not writable file: " + file);
- }
- }
-
- /** @throws IllegalArgumentException unless dir is a readable directory */
- public static void throwIaxUnlessCanWriteDir(File dir, String label) {
- if (!canWriteDir(dir)) {
- throw new IllegalArgumentException(label + " not writable dir: " + dir);
- }
- }
-
- /** @return array same length as input, with String paths */
- public static String[] getPaths(File[] files) {
- if ((null == files) || (0 == files.length)) {
- return new String[0];
- }
- String[] result = new String[files.length];
- for (int i = 0; i < result.length; i++) {
- if (null != files[i]) {
- result[i] = files[i].getPath();
- }
- }
- return result;
- }
-
- /** @return array same length as input, with String paths */
- public static String[] getPaths(List<File> files) {
- final int size = (null == files ? 0 : files.size());
- if (0 == size) {
- return new String[0];
- }
- String[] result = new String[size];
- for (int i = 0; i < size; i++) {
- File file = files.get(i);
- if (null != file) {
- result[i] = file.getPath();
- }
- }
- return result;
- }
-
- /**
- * Extract the name of a class from the path to its file. If the basedir is null, then the class is assumed to be in the default
- * package unless the classFile has one of the top-level suffixes { com, org, java, javax } as a parent directory.
- *
- * @param basedir the File of the base directory (prefix of classFile)
- * @param classFile the File of the class to extract the name for
- * @throws IllegalArgumentException if classFile is null or does not end with ".class" or a non-null basedir is not a prefix of
- * classFile
- */
- public static String fileToClassName(File basedir, File classFile) {
- LangUtil.throwIaxIfNull(classFile, "classFile");
- String classFilePath = normalizedPath(classFile);
- if (!classFilePath.endsWith(".class")) {
- String m = classFile + " does not end with .class";
- throw new IllegalArgumentException(m);
- }
- classFilePath = classFilePath.substring(0, classFilePath.length() - 6);
- if (null != basedir) {
- String basePath = normalizedPath(basedir);
- if (!classFilePath.startsWith(basePath)) {
- String m = classFile + " does not start with " + basedir;
- throw new IllegalArgumentException(m);
- }
- classFilePath = classFilePath.substring(basePath.length() + 1);
- } else {
- final String[] suffixes = new String[] { "com", "org", "java", "javax" };
- boolean found = false;
- for (int i = 0; !found && (i < suffixes.length); i++) {
- int loc = classFilePath.indexOf(suffixes[i] + "/");
- if ((0 == loc) || ((-1 != loc) && ('/' == classFilePath.charAt(loc - 1)))) {
- classFilePath = classFilePath.substring(loc);
- found = true;
- }
- }
- if (!found) {
- int loc = classFilePath.lastIndexOf("/");
- if (-1 != loc) { // treat as default package
- classFilePath = classFilePath.substring(loc + 1);
- }
- }
- }
- return classFilePath.replace('/', '.');
- }
-
- /**
- * Normalize path for comparisons by rendering absolute, clipping basedir prefix, trimming and changing '\\' to '/'
- *
- * @param file the File with the path to normalize
- * @param basedir the File for the prefix of the file to normalize - ignored if null
- * @return "" if null or normalized path otherwise
- * @throws IllegalArgumentException if basedir is not a prefix of file
- */
- public static String normalizedPath(File file, File basedir) {
- String filePath = normalizedPath(file);
- if (null != basedir) {
- String basePath = normalizedPath(basedir);
- if (filePath.startsWith(basePath)) {
- filePath = filePath.substring(basePath.length());
- if (filePath.startsWith("/")) {
- filePath = filePath.substring(1);
- }
- }
- }
- return filePath;
- }
-
- /**
- * Render a set of files to String as a path by getting absolute paths of each and delimiting with infix.
- *
- * @param files the File[] to flatten - may be null or empty
- * @param infix the String delimiter internally between entries (if null, then use File.pathSeparator). (alias to
- * <code>flatten(getAbsolutePaths(files), infix)</code>
- * @return String with absolute paths to entries in order, delimited with infix
- */
- public static String flatten(File[] files, String infix) {
- if (LangUtil.isEmpty(files)) {
- return "";
- }
- return flatten(getPaths(files), infix);
- }
-
- /**
- * Flatten File[] to String.
- *
- * @param files the File[] of paths to flatten - null ignored
- * @param infix the String infix to use - null treated as File.pathSeparator
- */
- public static String flatten(String[] paths, String infix) {
- if (null == infix) {
- infix = File.pathSeparator;
- }
- StringBuffer result = new StringBuffer();
- boolean first = true;
- for (String path : paths) {
- if (null == path) {
- continue;
- }
- if (first) {
- first = false;
- }
- else {
- result.append(infix);
- }
- result.append(path);
- }
- return result.toString();
- }
-
- /**
- * Normalize path for comparisons by rendering absolute trimming and changing '\\' to '/'
- *
- * @return "" if null or normalized path otherwise
- */
- public static String normalizedPath(File file) {
- return (null == file ? "" : weakNormalize(file.getAbsolutePath()));
- }
-
- /**
- * Weakly normalize path for comparisons by trimming and changing '\\' to '/'
- */
- public static String weakNormalize(String path) {
- if (null != path) {
- path = path.replace('\\', '/').trim();
- }
- return path;
- }
-
- /**
- * Get best File for the first-readable path in input paths, treating entries prefixed "sp:" as system property keys. Safe to
- * call in static initializers.
- *
- * @param paths the String[] of paths to check.
- * @return null if not found, or valid File otherwise
- */
- public static File getBestFile(String[] paths) {
- if (null == paths) {
- return null;
- }
- File result = null;
- for (int i = 0; (null == result) && (i < paths.length); i++) {
- String path = paths[i];
- if (null == path) {
- continue;
- }
- if (path.startsWith("sp:")) {
- try {
- path = System.getProperty(path.substring(3));
- } catch (Throwable t) {
- path = null;
- }
- if (null == path) {
- continue;
- }
- }
- try {
- File f = new File(path);
- if (f.exists() && f.canRead()) {
- result = FileUtil.getBestFile(f);
- }
- } catch (Throwable t) {
- // swallow
- }
- }
- return result;
- }
-
- public static File getBestFile(String[] paths, boolean mustBeJar) {
- if (null == paths) {
- return null;
- }
- File result = null;
- for (int i = 0; (null == result) && (i < paths.length); i++) {
- String path = paths[i];
- if (null == path) {
- continue;
- }
- if (path.startsWith("sp:")) {
- try {
- path = System.getProperty(path.substring(3));
- } catch (Throwable t) {
- path = null;
- }
- if (null == path) {
- continue;
- }
- }
- try {
- File f = new File(path);
-
- if (f.exists() && f.canRead()) {
- if (mustBeJar && !f.isDirectory()) {
- result = FileUtil.getBestFile(f);
- }
- }
- } catch (Throwable t) {
- // swallow
- }
- }
- return result;
- }
-
- /**
- * Render as best file, canonical or absolute.
- *
- * @param file the File to get the best File for (not null)
- * @return File of the best-available path
- * @throws IllegalArgumentException if file is null
- */
- public static File getBestFile(File file) {
- LangUtil.throwIaxIfNull(file, "file");
- if (file.exists()) {
- try {
- return file.getCanonicalFile();
- } catch (IOException e) {
- return file.getAbsoluteFile();
- }
- } else {
- return file;
- }
- }
-
- /**
- * Render as best path, canonical or absolute.
- *
- * @param file the File to get the path for (not null)
- * @return String of the best-available path
- * @throws IllegalArgumentException if file is null
- */
- public static String getBestPath(File file) {
- LangUtil.throwIaxIfNull(file, "file");
- if (file.exists()) {
- try {
- return file.getCanonicalPath();
- } catch (IOException e) {
- return file.getAbsolutePath();
- }
- } else {
- return file.getPath();
- }
- }
-
- /** @return array same length as input, with String absolute paths */
- public static String[] getAbsolutePaths(File[] files) {
- if ((null == files) || (0 == files.length)) {
- return new String[0];
- }
- String[] result = new String[files.length];
- for (int i = 0; i < result.length; i++) {
- if (null != files[i]) {
- result[i] = files[i].getAbsolutePath();
- }
- }
- return result;
- }
-
- /**
- * Recursively delete the contents of dir, but not the dir itself
- *
- * @return the total number of files deleted
- */
- public static int deleteContents(File dir) {
- return deleteContents(dir, ALL);
- }
-
- /**
- * Recursively delete some contents of dir, but not the dir itself. This deletes any subdirectory which is empty after its files
- * are deleted.
- *
- * @return the total number of files deleted
- */
- public static int deleteContents(File dir, FileFilter filter) {
- return deleteContents(dir, filter, true);
- }
-
- /**
- * Recursively delete some contents of dir, but not the dir itself. If deleteEmptyDirs is true, this deletes any subdirectory
- * which is empty after its files are deleted.
- *
- * @param dir the File directory (if a file, the the file is deleted)
- * @return the total number of files deleted
- */
- public static int deleteContents(File dir, FileFilter filter,
- boolean deleteEmptyDirs) {
- if (null == dir) {
- throw new IllegalArgumentException("null dir");
- }
- if ((!dir.exists()) || (!dir.canWrite())) {
- return 0;
- }
- if (!dir.isDirectory()) {
- dir.delete();
- return 1;
- }
- String[] fromFiles = dir.list();
- if (fromFiles == null) {
- return 0;
- }
- int result = 0;
- for (String string : fromFiles) {
- File file = new File(dir, string);
- if ((null == filter) || filter.accept(file)) {
- if (file.isDirectory()) {
- result += deleteContents(file, filter, deleteEmptyDirs);
- String[] fileContent = file.list();
- if (deleteEmptyDirs && fileContent != null
- && 0 == fileContent.length) {
- file.delete();
- }
- }
- else {
- /* boolean ret = */
- file.delete();
- result++;
- }
- }
- }
- return result;
- }
-
- /**
- * Copy contents of fromDir into toDir
- *
- * @param fromDir must exist and be readable
- * @param toDir must exist or be creatable and be writable
- * @return the total number of files copied
- */
- public static int copyDir(File fromDir, File toDir) throws IOException {
- return copyDir(fromDir, toDir, null, null);
- }
-
- /**
- * Recursively copy files in fromDir (with any fromSuffix) to toDir, replacing fromSuffix with toSuffix if any. This silently
- * ignores dirs and files that are not readable but throw IOException for directories that are not writable. This does not clean
- * out the original contents of toDir. (subdirectories are not renamed per directory rules)
- *
- * @param fromSuffix select files with this suffix - select all if null or empty
- * @param toSuffix replace fromSuffix with toSuffix in the destination file name - ignored if null or empty, appended to name if
- * fromSuffix is null or empty
- * @return the total number of files copied
- */
- public static int copyDir(File fromDir, File toDir, final String fromSuffix, String toSuffix) throws IOException {
- return copyDir(fromDir, toDir, fromSuffix, toSuffix, (FileFilter) null);
- }
-
- // /**
- // * Recursively copy files in fromDir (with any fromSuffix) to toDir,
- // * replacing fromSuffix with toSuffix if any, and adding the destination
- // * file to any collector. This silently ignores dirs and files that are
- // not
- // * readable but throw IOException for directories that are not writable.
- // * This does not clean out the original contents of toDir. (subdirectories
- // * are not renamed per directory rules) This calls any delegate
- // * FilenameFilter to collect any selected file.
- // *
- // * @param fromSuffix select files with this suffix - select all if null or
- // * empty
- // * @param toSuffix replace fromSuffix with toSuffix in the destination
- // file
- // * name - ignored if null or empty, appended to name if
- // * fromSuffix is null or empty
- // * @param collector the List sink for destination files - ignored if null
- // * @return the total number of files copied
- // */
- // public static int copyDir(File fromDir, File toDir, final String
- // fromSuffix, final String toSuffix, final List collector)
- // throws IOException {
- // // int before = collector.size();
- // if (null == collector) {
- // return copyDir(fromDir, toDir, fromSuffix, toSuffix);
- // } else {
- // FileFilter collect = new FileFilter() {
- // public boolean accept(File pathname) {
- // return collector.add(pathname);
- // }
- // };
- // return copyDir(fromDir, toDir, fromSuffix, toSuffix, collect);
- // }
- // }
-
- /**
- * Recursively copy files in fromDir (with any fromSuffix) to toDir, replacing fromSuffix with toSuffix if any. This silently
- * ignores dirs and files that are not readable but throw IOException for directories that are not writable. This does not clean
- * out the original contents of toDir. (subdirectories are not renamed per directory rules) This calls any delegate
- * FilenameFilter to collect any selected file.
- *
- * @param fromSuffix select files with this suffix - select all if null or empty
- * @param toSuffix replace fromSuffix with toSuffix in the destination file name - ignored if null or empty, appended to name if
- * fromSuffix is null or empty
- * @return the total number of files copied
- */
- public static int copyDir(File fromDir, File toDir, final String fromSuffix, final String toSuffix, final FileFilter delegate)
- throws IOException {
-
- if ((null == fromDir) || (!fromDir.canRead())) {
- return 0;
- }
- final boolean haveSuffix = ((null != fromSuffix) && (0 < fromSuffix.length()));
- final int slen = (!haveSuffix ? 0 : fromSuffix.length());
-
- if (!toDir.exists()) {
- toDir.mkdirs();
- }
- final String[] fromFiles;
- if (!haveSuffix) {
- fromFiles = fromDir.list();
- } else {
- FilenameFilter filter = new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return (new File(dir, name).isDirectory() || (name.endsWith(fromSuffix)));
- }
- };
- fromFiles = fromDir.list(filter);
- }
- int result = 0;
- final int MAX = (null == fromFiles ? 0 : fromFiles.length);
- for (int i = 0; i < MAX; i++) {
- String filename = fromFiles[i];
- File fromFile = new File(fromDir, filename);
- if (fromFile.canRead()) {
- if (fromFile.isDirectory()) {
- result += copyDir(fromFile, new File(toDir, filename), fromSuffix, toSuffix, delegate);
- } else if (fromFile.isFile()) {
- if (haveSuffix) {
- filename = filename.substring(0, filename.length() - slen);
- }
- if (null != toSuffix) {
- filename = filename + toSuffix;
- }
- File targetFile = new File(toDir, filename);
- if ((null == delegate) || delegate.accept(targetFile)) {
- copyFile(fromFile, targetFile);
- }
- result++;
- }
- }
- }
- return result;
- }
-
- /**
- * Recursively list files in srcDir.
- *
- * @return ArrayList with String paths of File under srcDir (relative to srcDir)
- */
- public static String[] listFiles(File srcDir) {
- ArrayList<String> result = new ArrayList<String>();
- if ((null != srcDir) && srcDir.canRead()) {
- listFiles(srcDir, null, result);
- }
- return result.toArray(new String[0]);
- }
-
- public static final FileFilter aspectjSourceFileFilter = new FileFilter() {
- public boolean accept(File pathname) {
- String name = pathname.getName().toLowerCase();
- return name.endsWith(".java") || name.endsWith(".aj");
- }
- };
-
- /**
- * Recursively list files in srcDir.
- *
- * @return ArrayList with String paths of File under srcDir (relative to srcDir)
- */
- public static File[] listFiles(File srcDir, FileFilter fileFilter) {
- ArrayList<File> result = new ArrayList<File>();
- if ((null != srcDir) && srcDir.canRead()) {
- listFiles(srcDir, result, fileFilter);
- }
- return result.toArray(new File[result.size()]);
- }
-
- /**
- * Recursively list .class files in specified directory
- *
- * @return List of File objects
- */
- public static List<File> listClassFiles(File dir) {
- ArrayList<File> result = new ArrayList<File>();
- if ((null != dir) && dir.canRead()) {
- listClassFiles(dir, result);
- }
- return result;
- }
-
- /**
- * Convert String[] paths to File[] as offset of base directory
- *
- * @param basedir the non-null File base directory for File to create with paths
- * @param paths the String[] of paths to create
- * @return File[] with same length as paths
- */
- public static File[] getBaseDirFiles(File basedir, String[] paths) {
- return getBaseDirFiles(basedir, paths, (String[]) null);
- }
-
- /**
- * Convert String[] paths to File[] as offset of base directory
- *
- * @param basedir the non-null File base directory for File to create with paths
- * @param paths the String[] of paths to create
- * @param suffixes the String[] of suffixes to limit sources to - ignored if null
- * @return File[] with same length as paths
- */
- public static File[] getBaseDirFiles(File basedir, String[] paths, String[] suffixes) {
- LangUtil.throwIaxIfNull(basedir, "basedir");
- LangUtil.throwIaxIfNull(paths, "paths");
- File[] result = null;
- if (!LangUtil.isEmpty(suffixes)) {
- ArrayList<File> list = new ArrayList<File>();
- for (String path : paths) {
- for (String suffix : suffixes) {
- if (path.endsWith(suffix)) {
- list.add(new File(basedir, path));
- break;
- }
- }
- }
- result = list.toArray(new File[0]);
- } else {
- result = new File[paths.length];
- for (int i = 0; i < result.length; i++) {
- result[i] = newFile(basedir, paths[i]);
- }
- }
- return result;
- }
-
- /**
- * Create a new File, resolving paths ".." and "." specially.
- *
- * @param dir the File for the parent directory of the file
- * @param path the path in the parent directory (filename only?)
- * @return File for the new file.
- */
- private static File newFile(File dir, String path) {
- if (".".equals(path)) {
- return dir;
- } else if ("..".equals(path)) {
- File parentDir = dir.getParentFile();
- if (null != parentDir) {
- return parentDir;
- } else {
- return new File(dir, "..");
- }
- } else {
- return new File(dir, path);
- }
- }
-
- /**
- * Copy files from source dir into destination directory, creating any needed directories. This differs from copyDir in not
- * being recursive; each input with the source dir creates a full path. However, if the source is a directory, it is copied as
- * such.
- *
- * @param srcDir an existing, readable directory containing relativePaths files
- * @param relativePaths a set of paths relative to srcDir to readable File to copy
- * @param destDir an existing, writable directory to copy files to
- * @throws IllegalArgumentException if input invalid, IOException if operations fail
- */
- public static File[] copyFiles(File srcDir, String[] relativePaths, File destDir) throws IllegalArgumentException, IOException {
- final String[] paths = relativePaths;
- throwIaxUnlessCanReadDir(srcDir, "srcDir");
- throwIaxUnlessCanWriteDir(destDir, "destDir");
- LangUtil.throwIaxIfNull(paths, "relativePaths");
- File[] result = new File[paths.length];
- for (int i = 0; i < paths.length; i++) {
- String path = paths[i];
- LangUtil.throwIaxIfNull(path, "relativePaths-entry");
- File src = newFile(srcDir, paths[i]);
- File dest = newFile(destDir, path);
- File destParent = dest.getParentFile();
- if (!destParent.exists()) {
- destParent.mkdirs();
- }
- LangUtil.throwIaxIfFalse(canWriteDir(destParent), "dest-entry-parent");
- copyFile(src, dest); // both file-dir and dir-dir copies
- result[i] = dest;
- }
- return result;
- }
-
- /**
- * Copy fromFile to toFile, handling file-file, dir-dir, and file-dir copies.
- *
- * @param fromFile the File path of the file or directory to copy - must be readable
- * @param toFile the File path of the target file or directory - must be writable (will be created if it does not exist)
- */
- public static void copyFile(File fromFile, File toFile) throws IOException {
- LangUtil.throwIaxIfNull(fromFile, "fromFile");
- LangUtil.throwIaxIfNull(toFile, "toFile");
- LangUtil.throwIaxIfFalse(!toFile.equals(fromFile), "same file");
- if (toFile.isDirectory()) { // existing directory
- throwIaxUnlessCanWriteDir(toFile, "toFile");
- if (fromFile.isFile()) { // file-dir
- File targFile = new File(toFile, fromFile.getName());
- copyValidFiles(fromFile, targFile);
- } else if (fromFile.isDirectory()) { // dir-dir
- copyDir(fromFile, toFile);
- } else {
- LangUtil.throwIaxIfFalse(false, "not dir or file: " + fromFile);
- }
- } else if (toFile.isFile()) { // target file exists
- if (fromFile.isDirectory()) {
- LangUtil.throwIaxIfFalse(false, "can't copy to file dir: " + fromFile);
- }
- copyValidFiles(fromFile, toFile); // file-file
- } else { // target file is a non-existent path -- could be file or dir
- /* File toFileParent = */ensureParentWritable(toFile);
- if (fromFile.isFile()) {
- copyValidFiles(fromFile, toFile);
- } else if (fromFile.isDirectory()) {
- toFile.mkdirs();
- throwIaxUnlessCanWriteDir(toFile, "toFile");
- copyDir(fromFile, toFile);
- } else {
- LangUtil.throwIaxIfFalse(false, "not dir or file: " + fromFile);
- }
- }
- }
-
- /**
- * Ensure that the parent directory to path can be written. If the path has a null parent, DEFAULT_PARENT is tested. If the path
- * parent does not exist, this tries to create it.
- *
- * @param path the File path whose parent should be writable
- * @return the File path of the writable parent directory
- * @throws IllegalArgumentException if parent cannot be written or path is null.
- */
- public static File ensureParentWritable(File path) {
- LangUtil.throwIaxIfNull(path, "path");
- File pathParent = path.getParentFile();
- if (null == pathParent) {
- pathParent = DEFAULT_PARENT;
- }
- if (!pathParent.canWrite()) {
- pathParent.mkdirs();
- }
- throwIaxUnlessCanWriteDir(pathParent, "pathParent");
- return pathParent;
- }
-
- /**
- * Copy file to file.
- *
- * @param fromFile the File to copy (readable, non-null file)
- * @param toFile the File to copy to (non-null, parent dir exists)
- * @throws IOException
- */
- public static void copyValidFiles(File fromFile, File toFile) throws IOException {
- FileInputStream in = null;
- FileOutputStream out = null;
- try {
- in = new FileInputStream(fromFile);
- out = new FileOutputStream(toFile);
- copyStream(in, out);
- } finally {
- if (out != null) {
- out.close();
- }
- if (in != null) {
- in.close();
- }
- }
- }
-
- /** do line-based copying */
- @SuppressWarnings("deprecation")
- public static void copyStream(DataInputStream in, PrintStream out) throws IOException {
- LangUtil.throwIaxIfNull(in, "in");
- LangUtil.throwIaxIfNull(in, "out");
- String s;
- while (null != (s = in.readLine())) {
- out.println(s);
- }
- }
-
- public static void copyStream(InputStream in, OutputStream out) throws IOException {
- final int MAX = 4096;
- byte[] buf = new byte[MAX];
- for (int bytesRead = in.read(buf, 0, MAX); bytesRead != -1; bytesRead = in.read(buf, 0, MAX)) {
- out.write(buf, 0, bytesRead);
- }
- }
-
- public static void copyStream(Reader in, Writer out) throws IOException {
- final int MAX = 4096;
- char[] buf = new char[MAX];
- for (int bytesRead = in.read(buf, 0, MAX); bytesRead != -1; bytesRead = in.read(buf, 0, MAX)) {
- out.write(buf, 0, bytesRead);
- }
- }
-
- /**
- * Make a new child directory of parent
- *
- * @param parent a File for the parent (writable)
- * @param child a prefix for the child directory
- * @return a File dir that exists with parentDir as the parent file or null
- */
- public static File makeNewChildDir(File parent, String child) {
- if (null == parent || !parent.canWrite() || !parent.isDirectory()) {
- throw new IllegalArgumentException("bad parent: " + parent);
- } else if (null == child) {
- child = "makeNewChildDir";
- } else if (!isValidFileName(child)) {
- throw new IllegalArgumentException("bad child: " + child);
- }
- File result = new File(parent, child);
- int safety = 1000;
- for (String suffix = FileUtil.randomFileString(); ((0 < --safety) && result.exists()); suffix = FileUtil.randomFileString()) {
- result = new File(parent, child + suffix);
- }
- if (result.exists()) {
- System.err.println("exhausted files for child dir in " + parent);
- return null;
- }
- return ((result.mkdirs() && result.exists()) ? result : null);
- }
-
- /**
- * Make a new temporary directory in the same directory that the system uses for temporary files, or if that files, in the
- * current directory.
- *
- * @param name the preferred (simple) name of the directory - may be null.
- * @return File of an existing new temp dir, or null if unable to create
- */
- public static File getTempDir(String name) {
- if (null == name) {
- name = "FileUtil_getTempDir";
- } else if (!isValidFileName(name)) {
- throw new IllegalArgumentException(" invalid: " + name);
- }
- File result = null;
- File tempFile = null;
- try {
- tempFile = File.createTempFile("ignoreMe", ".txt");
- File tempParent = tempFile.getParentFile();
- result = makeNewChildDir(tempParent, name);
- } catch (IOException t) {
- result = makeNewChildDir(new File("."), name);
- } finally {
- if (null != tempFile) {
- tempFile.delete();
- }
- }
- return result;
- }
-
- public static URL[] getFileURLs(File[] files) {
- if ((null == files) || (0 == files.length)) {
- return new URL[0];
- }
- URL[] result = new URL[files.length]; // XXX dangerous non-copy...
- for (int i = 0; i < result.length; i++) {
- result[i] = getFileURL(files[i]);
- }
- return result;
- }
-
- /**
- * Get URL for a File. This appends "/" for directories. prints errors to System.err
- *
- * @param file the File to convert to URL (not null)
- */
- @SuppressWarnings("deprecation")
- public static URL getFileURL(File file) {
- LangUtil.throwIaxIfNull(file, "file");
- URL result = null;
- try {
- result = file.toURL();// TODO AV - was toURI.toURL that does not
- // works on Java 1.3
- if (null != result) {
- return result;
- }
- String url = "file:" + file.getAbsolutePath().replace('\\', '/');
- result = new URL(url + (file.isDirectory() ? "/" : ""));
- } catch (MalformedURLException e) {
- String m = "Util.makeURL(\"" + file.getPath() + "\" MUE " + e.getMessage();
- System.err.println(m);
- }
- return result;
- }
-
- /**
- * Write contents to file, returning null on success or error message otherwise. This tries to make any necessary parent
- * directories first.
- *
- * @param file the File to write (not null)
- * @param contents the String to write (use "" if null)
- * @return String null on no error, error otherwise
- */
- public static String writeAsString(File file, String contents) {
- LangUtil.throwIaxIfNull(file, "file");
- if (null == contents) {
- contents = "";
- }
- Writer out = null;
- try {
- File parentDir = file.getParentFile();
- if (!parentDir.exists() && !parentDir.mkdirs()) {
- return "unable to make parent dir for " + file;
- }
- Reader in = new StringReader(contents);
- out = new FileWriter(file);
- FileUtil.copyStream(in, out);
- return null;
- } catch (IOException e) {
- return LangUtil.unqualifiedClassName(e) + " writing " + file + ": " + e.getMessage();
- } finally {
- if (null != out) {
- try {
- out.close();
- } catch (IOException e) {
- } // ignored
- }
- }
- }
-
- /**
- * Reads a boolean array with our encoding
- */
- public static boolean[] readBooleanArray(DataInputStream s) throws IOException {
- int len = s.readInt();
- boolean[] ret = new boolean[len];
- for (int i = 0; i < len; i++) {
- ret[i] = s.readBoolean();
- }
- return ret;
- }
-
- /**
- * Writes a boolean array with our encoding
- */
- public static void writeBooleanArray(boolean[] a, DataOutputStream s) throws IOException {
- int len = a.length;
- s.writeInt(len);
- for (boolean b : a) {
- s.writeBoolean(b);
- }
- }
-
- /**
- * Reads an int array with our encoding
- */
- public static int[] readIntArray(DataInputStream s) throws IOException {
- int len = s.readInt();
- int[] ret = new int[len];
- for (int i = 0; i < len; i++) {
- ret[i] = s.readInt();
- }
- return ret;
- }
-
- /**
- * Writes an int array with our encoding
- */
- public static void writeIntArray(int[] a, DataOutputStream s) throws IOException {
- int len = a.length;
- s.writeInt(len);
- for (int j : a) {
- s.writeInt(j);
- }
- }
-
- /**
- * Reads an int array with our encoding
- */
- public static String[] readStringArray(DataInputStream s) throws IOException {
- int len = s.readInt();
- String[] ret = new String[len];
- for (int i = 0; i < len; i++) {
- ret[i] = s.readUTF();
- }
- return ret;
- }
-
- /**
- * Writes an int array with our encoding
- */
- public static void writeStringArray(String[] a, DataOutputStream s) throws IOException {
- if (a == null) {
- s.writeInt(0);
- return;
- }
- int len = a.length;
- s.writeInt(len);
- for (String value : a) {
- s.writeUTF(value);
- }
- }
-
- /**
- * Returns the contents of this file as a String
- */
- public static String readAsString(File file) throws IOException {
- BufferedReader r = new BufferedReader(new FileReader(file));
- StringBuffer b = new StringBuffer();
- while (true) {
- int ch = r.read();
- if (ch == -1) {
- break;
- }
- b.append((char) ch);
- }
- r.close();
- return b.toString();
- }
-
- // /**
- // * Returns the contents of this stream as a String
- // */
- // public static String readAsString(InputStream in) throws IOException {
- // BufferedReader r = new BufferedReader(new InputStreamReader(in));
- // StringBuffer b = new StringBuffer();
- // while (true) {
- // int ch = r.read();
- // if (ch == -1)
- // break;
- // b.append((char) ch);
- // }
- // in.close();
- // r.close();
- // return b.toString();
- // }
-
- /**
- * Returns the contents of this file as a byte[]
- */
- public static byte[] readAsByteArray(File file) throws IOException {
- FileInputStream in = new FileInputStream(file);
- byte[] ret = FileUtil.readAsByteArray(in);
- in.close();
- return ret;
- }
-
- /**
- * Reads this input stream and returns contents as a byte[]
- */
- public static byte[] readAsByteArray(InputStream inStream) throws IOException {
- int size = 1024;
- byte[] ba = new byte[size];
- int readSoFar = 0;
-
- while (true) {
- int nRead = inStream.read(ba, readSoFar, size - readSoFar);
- if (nRead == -1) {
- break;
- }
- readSoFar += nRead;
- if (readSoFar == size) {
- int newSize = size * 2;
- byte[] newBa = new byte[newSize];
- System.arraycopy(ba, 0, newBa, 0, size);
- ba = newBa;
- size = newSize;
- }
- }
-
- byte[] newBa = new byte[readSoFar];
- System.arraycopy(ba, 0, newBa, 0, readSoFar);
- return newBa;
- }
-
- final static String FILECHARS = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-
- /** @return semi-random String of length 6 usable as filename suffix */
- static String randomFileString() {
- final double FILECHARS_length = FILECHARS.length();
- final int LEN = 6;
- final char[] result = new char[LEN];
- int index = (int) (Math.random() * 6d);
- for (int i = 0; i < LEN; i++) {
- if (index >= LEN) {
- index = 0;
- }
- result[index++] = FILECHARS.charAt((int) (Math.random() * FILECHARS_length));
- }
- return new String(result);
- }
-
- public static InputStream getStreamFromZip(String zipFile, String name) {
- try {
- ZipFile zf = new ZipFile(zipFile);
- try {
- ZipEntry entry = zf.getEntry(name);
- return zf.getInputStream(entry);
- } finally {
- // ??? is it safe not to close this zf.close();
- }
- } catch (IOException ioe) {
- return null;
- }
- }
-
- //
- // public static void extractJar(String zipFile, String outDir) throws
- // IOException {
- // ZipInputStream zs = new ZipInputStream(new FileInputStream(zipFile));
- // ZipEntry entry;
- // while ((entry = zs.getNextEntry()) != null) {
- // if (entry.isDirectory())
- // continue;
- // byte[] in = readAsByteArray(zs);
- //
- // File outFile = new File(outDir + "/" + entry.getName());
- // // if (!outFile.getParentFile().exists())
- // // System.err.println("parent: " + outFile.getParentFile());
- // // System.err.println("parent: " + outFile.getParentFile());
- // outFile.getParentFile().mkdirs();
- // FileOutputStream os = new FileOutputStream(outFile);
- // os.write(in);
- // os.close();
- // zs.closeEntry();
- // }
- // zs.close();
- // }
-
- /**
- * Do line-based search for literal text in source files, returning file:line where found.
- *
- * @param sought the String text to seek in the file
- * @param sources the List of String paths to the source files
- * @param listAll if false, only list first match in file
- * @param errorSink the PrintStream to print any errors to (one per line) (use null to silently ignore errors)
- * @return List of String of the form file:line for each found entry (never null, might be empty)
- */
- // OPTIMIZE only used by tests? move it out
- public static List<String> lineSeek(String sought, List<String> sources, boolean listAll, PrintStream errorSink) {
- if (LangUtil.isEmpty(sought) || LangUtil.isEmpty(sources)) {
- return Collections.emptyList();
- }
- ArrayList<String> result = new ArrayList<String>();
- for (String path : sources) {
- String error = lineSeek(sought, path, listAll, result);
- if ((null != error) && (null != errorSink)) {
- errorSink.println(error);
- }
- }
- return result;
- }
-
- /**
- * Do line-based search for literal text in source file, returning line where found as a String in the form
- * {sourcePath}:line:column submitted to the collecting parameter sink. Any error is rendered to String and returned as the
- * result.
- *
- * @param sought the String text to seek in the file
- * @param sources the List of String paths to the source files
- * @param listAll if false, only list first match in file
- * @param List sink the List for String entries of the form {sourcePath}:line:column
- * @return String error if any, or add String entries to sink
- */
- public static String lineSeek(String sought, String sourcePath, boolean listAll, ArrayList<String> sink) {
- if (LangUtil.isEmpty(sought) || LangUtil.isEmpty(sourcePath)) {
- return "nothing sought";
- }
- if (LangUtil.isEmpty(sourcePath)) {
- return "no sourcePath";
- }
- final File file = new File(sourcePath);
- if (!file.canRead() || !file.isFile()) {
- return "sourcePath not a readable file";
- }
- int lineNum = 0;
- FileReader fin = null;
- try {
- fin = new FileReader(file);
- BufferedReader reader = new BufferedReader(fin);
- String line;
- while (null != (line = reader.readLine())) {
- lineNum++;
- int loc = line.indexOf(sought);
- if (-1 != loc) {
- sink.add(sourcePath + ":" + lineNum + ":" + loc);
- if (!listAll) {
- break;
- }
- }
- }
- } catch (IOException e) {
- return LangUtil.unqualifiedClassName(e) + " reading " + sourcePath + ":" + lineNum;
- } finally {
- try {
- if (null != fin) {
- fin.close();
- }
- } catch (IOException e) {
- } // ignore
- }
- return null;
- }
-
- public static BufferedOutputStream makeOutputStream(File file) throws FileNotFoundException {
- File parent = file.getParentFile();
- if (parent != null) {
- parent.mkdirs();
- }
- return new BufferedOutputStream(new FileOutputStream(file));
- }
-
- /**
- * Sleep until after the last last-modified stamp from the files.
- *
- * @param files the File[] of files to inspect for last modified times (this ignores null or empty files array and null or
- * non-existing components of files array)
- * @return true if succeeded without 100 interrupts
- */
- public static boolean sleepPastFinalModifiedTime(File[] files) {
- if ((null == files) || (0 == files.length)) {
- return true;
- }
- long delayUntil = System.currentTimeMillis();
- for (File file : files) {
- if ((null == file) || !file.exists()) {
- continue;
- }
- long nextModTime = file.lastModified();
- if (nextModTime > delayUntil) {
- delayUntil = nextModTime;
- }
- }
- return LangUtil.sleepUntil(++delayUntil);
- }
-
- private static void listClassFiles(final File baseDir, ArrayList<File> result) {
- File[] files = baseDir.listFiles();
- for (File f : files) {
- if (f.isDirectory()) {
- listClassFiles(f, result);
- }
- else {
- if (f.getName().endsWith(".class")) {
- result.add(f);
- }
- }
- }
- }
-
- private static void listFiles(final File baseDir, ArrayList<File> result, FileFilter filter) {
- File[] files = baseDir.listFiles();
- // hack https://bugs.eclipse.org/bugs/show_bug.cgi?id=48650
- final boolean skipCVS = (!PERMIT_CVS && (filter == aspectjSourceFileFilter));
- for (File f : files) {
- if (f.isDirectory()) {
- if (skipCVS) {
- String name = f.getName().toLowerCase();
- if ("cvs".equals(name) || "sccs".equals(name)) {
- continue;
- }
- }
- listFiles(f, result, filter);
- }
- else {
- if (filter.accept(f)) {
- result.add(f);
- }
- }
- }
- }
-
- /** @return true if input is not null and contains no path separator */
- private static boolean isValidFileName(String input) {
- return ((null != input) && (!input.contains(File.pathSeparator)));
- }
-
- private static void listFiles(final File baseDir, String dir, ArrayList<String> result) {
- final String dirPrefix = (null == dir ? "" : dir + "/");
- final File dirFile = (null == dir ? baseDir : new File(baseDir.getPath() + "/" + dir));
- final String[] files = dirFile.list();
- for (String file : files) {
- File f = new File(dirFile, file);
- String path = dirPrefix + file;
- if (f.isDirectory()) {
- listFiles(baseDir, path, result);
- }
- else {
- result.add(path);
- }
- }
- }
-
- private FileUtil() {
- }
-
- public static List<String> makeClasspath(URL[] urls) {
- List<String> ret = new LinkedList<String>();
- if (urls != null) {
- for (URL url : urls) {
- ret.add(toPathString(url));
- }
- }
- return ret;
- }
-
- private static String toPathString(URL url) {
- try {
- return url.toURI().getPath();
- } catch (URISyntaxException e) {
- System.err.println("Warning!! Malformed URL may cause problems: "+url); // TODO: Better way to report this?
- // In this case it was likely not using properly escaped
- // characters so we just use the 'bad' method that doesn't decode
- // special chars
- return url.getPath();
- }
- }
-
- /**
- * A pipe when run reads from an input stream to an output stream, optionally sleeping between reads.
- *
- * @see #copyStream(InputStream, OutputStream)
- */
- public static class Pipe implements Runnable {
- private final InputStream in;
- private final OutputStream out;
- private final long sleep;
- private ByteArrayOutputStream snoop;
- private long totalWritten;
- private Throwable thrown;
- private boolean halt;
- /**
- * Seem to be unable to detect erroroneous closing of System.out...
- */
- private final boolean closeInput;
- private final boolean closeOutput;
-
- /**
- * If true, then continue processing stream until no characters are returned when halting.
- */
- private boolean finishStream;
-
- private boolean done; // true after completing() completes
-
- /**
- * alias for <code>Pipe(in, out, 100l, false, false)</code>
- *
- * @param in the InputStream source to read
- * @param out the OutputStream sink to write
- */
- Pipe(InputStream in, OutputStream out) {
- this(in, out, 100l, false, false);
- }
-
- /**
- * @param in the InputStream source to read
- * @param out the OutputStream sink to write
- * @param tryClosingStreams if true, then try closing both streams when done
- * @param sleep milliseconds to delay between reads (pinned to 0..1 minute)
- */
- Pipe(InputStream in, OutputStream out, long sleep, boolean closeInput, boolean closeOutput) {
- LangUtil.throwIaxIfNull(in, "in");
- LangUtil.throwIaxIfNull(out, "out");
- this.in = in;
- this.out = out;
- this.closeInput = closeInput;
- this.closeOutput = closeOutput;
- this.sleep = Math.min(0l, Math.max(60l * 1000l, sleep));
- }
-
- public void setSnoop(ByteArrayOutputStream snoop) {
- this.snoop = snoop;
- }
-
- /**
- * Run the pipe. This halts on the first Throwable thrown or when a read returns -1 (for end-of-file) or on demand.
- */
- public void run() {
- totalWritten = 0;
- if (halt) {
- return;
- }
- try {
- final int MAX = 4096;
- byte[] buf = new byte[MAX];
- // TODO this blocks, hanging the harness
- int count = in.read(buf, 0, MAX);
- ByteArrayOutputStream mySnoop;
- while ((halt && finishStream && (0 < count)) || (!halt && (-1 != count))) {
- out.write(buf, 0, count);
- mySnoop = snoop;
- if (null != mySnoop) {
- mySnoop.write(buf, 0, count);
- }
- totalWritten += count;
- if (halt && !finishStream) {
- break;
- }
- if (!halt && (0 < sleep)) {
- Thread.sleep(sleep);
- }
- if (halt && !finishStream) {
- break;
- }
- count = in.read(buf, 0, MAX);
- }
- } catch (Throwable e) {
- thrown = e;
- } finally {
- halt = true;
- if (closeInput) {
- try {
- in.close();
- } catch (IOException e) {
- // ignore
- }
- }
- if (closeOutput) {
- try {
- out.close();
- } catch (IOException e) {
- // ignore
- }
- }
- done = true;
- completing(totalWritten, thrown);
- }
-
- }
-
- /**
- * Tell the pipe to halt the next time it gains control.
- *
- * @param wait if true, this waits synchronously until pipe is done
- * @param finishStream if true, then continue until a read from the input stream returns no bytes, then halt.
- * @return true if <code>run()</code> will return the next time it gains control
- */
- public boolean halt(boolean wait, boolean finishStream) {
- if (!halt) {
- halt = true;
- }
- if (wait) {
- while (!done) {
- synchronized (this) {
- notifyAll();
- }
- if (!done) {
- try {
- Thread.sleep(5l);
- } catch (InterruptedException e) {
- break;
- }
- }
- }
- }
- return halt;
- }
-
- /** @return the total number of bytes written */
- public long totalWritten() {
- return totalWritten;
- }
-
- /** @return any exception thrown when reading/writing */
- public Throwable getThrown() {
- return thrown;
- }
-
- /**
- * This is called when the pipe is completing. This implementation does nothing. Subclasses implement this to get notice.
- * Note that halt(true, true) might or might not have completed before this method is called.
- */
- protected void completing(long totalWritten, Throwable thrown) {
- }
- }
-
- }
|