/*
* RapidMiner
*
* Copyright (C) 2001-2008 by Rapid-I and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapid-i.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.tools;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.Reader;
import java.io.StreamTokenizer;
import java.net.URL;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import com.rapidminer.RapidMiner;
import com.rapidminer.gui.MainFrame;
import com.rapidminer.gui.RapidMinerGUI;
import com.rapidminer.operator.Operator;
import com.rapidminer.operator.OperatorException;
import com.rapidminer.operator.UserError;
import com.rapidminer.tools.plugin.Plugin;
/**
* Tools for RapidMiner.
*
* @author Simon Fischer, Ingo Mierswa
* @version $Id: Tools.java,v 1.25 2008/05/25 12:08:44 ingomierswa Exp $
*/
public class Tools {
/** The line separator depending on the operating system. */
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
/** Number smaller than this value are consideres as zero. */
private static final double IS_ZERO = 1E-6;
/** Number of post-comma digits needed to distinguish between display of numbers as integers or doubles. */
private static final double IS_DISPLAY_ZERO = 1E-8;
/** Used for formatting values in the {@link #formatTime(Date)} method. */
private static final DateFormat TIME_FORMAT = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.US);
/** Used for formatting values in the {@link #formatDate(Date)} method. */
private static final DateFormat DATE_FORMAT = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
/** Used for formatting values in the {@link #formatDateTime(Date)} method. */
private static final DateFormat DATE_TIME_FORMAT = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.US);
/** Used for formatting values in the {@link #formatNumber(double)} method. */
private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(Locale.US);
/** Used for formatting values in the {@link #formatPercent(double)} method. */
private static final NumberFormat PERCENT_FORMAT = NumberFormat.getPercentInstance(Locale.US);
/** Used for determining the symbols used in decimal formats. */
private static final DecimalFormatSymbols FORMAT_SYMBOLS = new DecimalFormatSymbols(Locale.US);
private static final LinkedList<ResourceSource> ALL_RESOURCES = new LinkedList<ResourceSource>();
public static final String RESOURCE_PREFIX = "com/rapidminer/resources/";
static {
ALL_RESOURCES.add(new ResourceSource(Tools.class.getClassLoader()));
}
/**
* Returns a formatted string of the given number (percent format with two
* fraction digits).
*/
public static String formatPercent(double value) {
if (Double.isNaN(value))
return "?";
String percentDigitsString = System.getProperty(RapidMiner.PROPERTY_RAPIDMINER_GENERAL_FRACTIONDIGITS_PERCENT);
int percentDigits = 2;
try {
if (percentDigitsString != null)
percentDigits = Integer.parseInt(percentDigitsString);
} catch (NumberFormatException e) {
LogService.getGlobal().log("Bad integer for property 'rapidminer.gui.fractiondigits.percent', using default number if digits (2).", LogService.WARNING);
}
PERCENT_FORMAT.setMaximumFractionDigits(percentDigits);
PERCENT_FORMAT.setMinimumFractionDigits(percentDigits);
return PERCENT_FORMAT.format(value);
}
/**
* Returns a formatted string of the given number (number format with
* usually three fraction digits).
*/
public static String formatNumber(double value) {
if (Double.isNaN(value))
return "?";
int numberDigits = 3;
try {
String numberDigitsString = System.getProperty(RapidMiner.PROPERTY_RAPIDMINER_GENERAL_FRACTIONDIGITS_NUMBERS);
numberDigits = Integer.parseInt(numberDigitsString);
} catch (NumberFormatException e) {}
NUMBER_FORMAT.setMaximumFractionDigits(numberDigits);
NUMBER_FORMAT.setMinimumFractionDigits(numberDigits);
return NUMBER_FORMAT.format(value);
}
/**
* Returns a formatted string of the given number (uses the property
* rapidminer.gui.fractiondigits.numbers if the given number of digits is
* smaller than 0 (usually 3)).
*/
public static String formatNumber(double value, int numberOfDigits) {
if (Double.isNaN(value))
return "?";
int numberDigits = numberOfDigits;
if (numberDigits < 0) {
try {
String numberDigitsString = System.getProperty(RapidMiner.PROPERTY_RAPIDMINER_GENERAL_FRACTIONDIGITS_NUMBERS);
numberDigits = Integer.parseInt(numberDigitsString);
} catch (NumberFormatException e) {
numberDigits = 3;
}
}
NUMBER_FORMAT.setMaximumFractionDigits(numberDigits);
NUMBER_FORMAT.setMinimumFractionDigits(numberDigits);
return NUMBER_FORMAT.format(value);
}
/** Returns a number string with no fraction digits if possible. Otherwise the default
* number of digits will be returned. */
public static String formatIntegerIfPossible(double value) {
int numberDigits = 3;
try {
String numberDigitsString = System.getProperty(RapidMiner.PROPERTY_RAPIDMINER_GENERAL_FRACTIONDIGITS_NUMBERS);
numberDigits = Integer.parseInt(numberDigitsString);
} catch (NumberFormatException e) {}
return formatIntegerIfPossible(value, numberDigits);
}
/** Returns a number string with no fraction digits if possible. Otherwise the given
* number of digits will be returned. */
public static String formatIntegerIfPossible(double value, int numberOfDigits) {
if (Double.isNaN(value))
return "?";
if (Double.isInfinite(value)) {
if (value < 0)
return "-" + FORMAT_SYMBOLS.getInfinity();
else
return FORMAT_SYMBOLS.getInfinity();
}
long longValue = Math.round(value);
if (Math.abs(longValue - value) < IS_DISPLAY_ZERO) {
return longValue + "";
} else {
return formatNumber(value, numberOfDigits);
}
}
/** Format date as a short time string. */
public static String formatTime(Date date) {
return TIME_FORMAT.format(date);
}
/** Format date as a short time string. */
public static String formatDate(Date date) {
return DATE_FORMAT.format(date);
}
/** Format date as a short time string. */
public static String formatDateTime(Date date) {
return DATE_TIME_FORMAT.format(date);
}
/** Returns the name for an ordinal number. */
public static String ordinalNumber(int n) {
if ((n % 10 == 1) && (n % 100 != 11)) {
return n + "st";
}
if ((n % 10 == 2) && (n % 100 != 12)) {
return n + "nd";
}
if ((n % 10 == 3) && (n % 100 != 13)) {
return n + "rd";
}
return n + "th";
}
/** Returns true if the difference between both numbers is smaller than IS_ZERO. */
public static boolean isEqual(double d1, double d2) {
return Math.abs(d1 - d2) < IS_ZERO;
}
/** Returns {@link #isEqual(double, double)} for d and 0. */
public static boolean isZero(double d) {
return isEqual(d, 0.0d);
}
/** Returns no {@link #isEqual(double, double)}. */
public static boolean isNotEqual(double d1, double d2) {
return !isEqual(d1, d2);
}
/** Returns true if the d1 is greater than d2 and they are not equal. */
public static boolean isGreater(double d1, double d2) {
return (d1 > d2) && isNotEqual(d1, d2);
}
/** Returns true if the d1 is greater than d1 or both are equal. */
public static boolean isGreaterEqual(double d1, double d2) {
return (d1 > d2) || isEqual(d1, d2);
}
/** Returns true if the d1 is less than d2 and they are not equal. */
public static boolean isLess(double d1, double d2) {
return !isGreaterEqual(d1, d2);
}
/** Returns true if the d1 is less than d1 or both are equal. */
public static boolean isLessEqual(double d1, double d2) {
return !isGreater(d1, d2);
}
// ====================================
/** Returns the correct line separator for the current operating system. */
public static String getLineSeparator() {
return LINE_SEPARATOR;
}
/** Returns the correct line separator for the current operating system concatenated
* for the given number of times. */
public static String getLineSeparators(int number) {
if (number < 0)
number = 0;
StringBuffer result = new StringBuffer();
for (int i = 0; i < number; i++)
result.append(LINE_SEPARATOR);
return result.toString();
}
/** Replaces all possible line feed character combinations by "\n". This
* might be important for GUI purposes like tool tip texts which do not support
* carriage return combinations. */
public static String transformAllLineSeparators(String text) {
Pattern crlf = Pattern.compile("(\r\n|\r|\n|\n\r)");
Matcher m = crlf.matcher(text);
if (m.find()) {
text = m.replaceAll("\n");
}
return text;
}
/** Removes all possible line feed character combinations. This
* might be important for GUI purposes like tool tip texts which do not support
* carriage return combinations. */
public static String removeAllLineSeparators(String text) {
Pattern crlf = Pattern.compile("(\r\n|\r|\n|\n\r)");
Matcher m = crlf.matcher(text);
if (m.find()) {
text = m.replaceAll(" ");
}
return text;
}
/**
* Returns the class name of the given class without the package
* information.
*/
public static String classNameWOPackage(Class c) {
return c.getName().substring(c.getName().lastIndexOf(".") + 1);
}
// ====================================
/**
* Reads the output of the reader and delivers it as string.
*/
public static String readOutput(BufferedReader in) throws IOException {
StringBuffer output = new StringBuffer();
String line = null;
while ((line = in.readLine()) != null) {
output.append(line);
output.append(Tools.getLineSeparator());
}
return output.toString();
}
/**
* Creates a file relative to the given parent if name is not an absolute
* file name. Returns null if name is null.
*/
public static File getFile(File parent, String name) {
if (name == null)
return null;
File file = new File(name);
if (file.isAbsolute())
return file;
else
return new File(parent, name);
}
/** This method checks if the given file is a Zip file containing one entry (in case of file extension .zip).
* If this is the case, a reader based on a ZipInputStream for this entry is returned.
* Otherwise, this method checks if the file has the extension .gz. If this applies, a gzipped
* stream reader is returned. Otherwise, this method just returns a BufferedReader
* for the given file (file was not zipped at all). */
public static BufferedReader getReader(File file, Charset encoding) throws IOException {
// handle zip files if necessary
if (file.getAbsolutePath().endsWith(".zip")) {
ZipFile zipFile = new ZipFile(file);
if (zipFile.size() == 0) {
throw new IOException("Input of Zip file failed: the file archive does not contain any entries.");
}
if (zipFile.size() > 1) {
throw new IOException("Input of Zip file failed: the file archive contains more than one entry.");
}
Enumeration<? extends ZipEntry> entries = zipFile.entries();
InputStream zipIn = zipFile.getInputStream(entries.nextElement());
return new BufferedReader(new InputStreamReader(zipIn, encoding));
} else if (file.getAbsolutePath().endsWith(".gz")) {
return new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(file)), encoding));
} else {
//return new BufferedReader(new FileReader(file));
return new BufferedReader(new InputStreamReader(new FileInputStream(file), encoding));
}
}
/** This method tries to identify the encoding if a GUI is running and a process
* is defined. In this case, the encoding is taken from the process.
* Otherwise, the method tries to identify the encoding via the property
* {@link RapidMiner#PROPERTY_RAPIDMINER_GENERAL_DEFAULT_ENCODING}. If this is not
* possible, this method just returns the default system encoding. */
public static Charset getDefaultEncoding() {
Charset result = null;
// try GUI setting
MainFrame mainFrame = RapidMinerGUI.getMainFrame();
if (mainFrame != null) {
com.rapidminer.Process process = mainFrame.getProcess();
if (process != null) {
Operator rootOperator = process.getRootOperator();
if (rootOperator != null) {
result = rootOperator.getEncoding();
}
}
}
// try property setting
if (result == null) {
String encoding = System.getProperty(RapidMiner.PROPERTY_RAPIDMINER_GENERAL_DEFAULT_ENCODING);
if ((encoding != null) && (encoding.trim().length() > 0)) {
if (RapidMiner.SYSTEM_ENCODING_NAME.equals(encoding)) {
result = Charset.defaultCharset();
} else {
result = Charset.forName(encoding);
}
}
}
// still not found? try default charset
if (result == null) {
result = Charset.defaultCharset();
}
return result;
}
/**
* Creates a directory including parent directories.
*
* @return true, if operation was successful.
*/
public static boolean mkdir(File dir) {
if (dir == null)
return true;
if (dir.exists())
return true;
File parent = dir.getParentFile();
if (parent == null) {
return true;
} else if (!parent.exists()) {
if (!mkdir(parent))
return false;
}
return dir.mkdir();
}
/** Returns the relative path of the first file resolved against the second. */
public static String getRelativePath(File firstFile, File secondFile) throws IOException {
String canonicalFirstPath = firstFile.getCanonicalPath();
String canonicalSecondPath = secondFile.getCanonicalPath();
int minLength = Math.min(canonicalFirstPath.length(), canonicalSecondPath.length());
int index = 0;
for (index = 0; index < minLength; index++) {
if (canonicalFirstPath.charAt(index) != canonicalSecondPath.charAt(index)) {
break;
}
}
String relPath = canonicalFirstPath;
int lastSeparatorIndex = canonicalFirstPath.substring(0, index).lastIndexOf(File.separator);
if (lastSeparatorIndex != -1) {
String absRest = canonicalSecondPath.substring(lastSeparatorIndex + 1);
StringBuffer relPathBuffer = new StringBuffer();
while (absRest.indexOf(File.separator) >= 0) {
relPathBuffer.append(".." + File.separator);
absRest = absRest.substring(absRest.indexOf(File.separator) + 1);
}
relPathBuffer.append(canonicalFirstPath.substring(lastSeparatorIndex + 1));
relPath = relPathBuffer.toString();
}
return relPath;
}
/**
* Waits for process to die and writes log messages. Terminates if exit
* value is not 0.
*/
public static void waitForProcess(Operator operator, Process process, String name) throws OperatorException {
try {
LogService.getGlobal().log("Waiting for process '" + name + "' to die.", LogService.MINIMUM);
int value = process.waitFor();
if (value == 0) {
LogService.getGlobal().log("Process '" + name + "' terminated successfully.", LogService.STATUS);
} else {
throw new UserError(operator, 306, new Object[] { name, value });
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted waiting for process '" + name + "' to die.", e);
}
}
/**
* Sends a mail to the given address, using the specified subject and
* contents. Subject must contain no whitespace!
*/
public static void sendEmail(String address, String subject, String content) {
try {
// subject = subject.replaceAll("\\s", "_"); // replace whitespace
String command = System.getProperty(RapidMiner.PROPERTY_RAPIDMINER_TOOLS_SENDMAIL_COMMAND);
if (command != null) {
// command = command.replaceAll("\\$A", address);
// command = command.replaceAll("\\$S", subject);
LogService.getGlobal().log("Executing '" + command + "'", LogService.MINIMUM);
Process sendmail = Runtime.getRuntime().exec(new String[] { command, address });
PrintStream out = null;
try {
out = new PrintStream(sendmail.getOutputStream());
out.println("Subject: " + subject);
out.println("From: RapidMiner");
out.println("To: " + address);
out.println();
out.println(content);
} catch (Exception e) {
throw e;
} finally {
if (out != null)
out.close();
}
waitForProcess(null, sendmail, command);
}
} catch (Throwable e) {
LogService.getGlobal().log("Cannot send mail to " + address + ": " + e.getMessage(), LogService.ERROR);
}
}
/** Adds a new resource source. Might be used by plugins etc. */
public static void addResourceSource(ResourceSource source) {
ALL_RESOURCES.add(source);
}
/** Adds a new resource source before the others. Might be used by plugins etc. */
public static void prependResourceSource(ResourceSource source) {
ALL_RESOURCES.addFirst(source);
}
public static URL getResource(ClassLoader loader, String name) {
return getResource(loader, RESOURCE_PREFIX, name);
}
public static URL getResource(ClassLoader loader, String prefix, String name) {
return loader.getResource(prefix + name);
}
/** Returns the desired resource. Tries first to find a resource in the core RapidMiner resources
* directory. If no resource with the given name is found, it is tried to load with help of
* the ResourceSource which might have been added by plugins. Please note that resource names
* are only allowed to use '/' as separator instead of File.separator! */
public static URL getResource(String name) {
Iterator<ResourceSource> i = ALL_RESOURCES.iterator();
while (i.hasNext()) {
ResourceSource source = i.next();
URL url = source.getResource(name);
if (url != null) {
return url;
}
}
URL resourceURL = getResource(Tools.class.getClassLoader(), name);
if (resourceURL != null) {
return resourceURL;
} else {
return null;
}
}
public static String readTextFile(File file) throws IOException {
return readTextFile(new FileReader(file));
}
public static String readTextFile(Reader r) throws IOException {
StringBuffer contents = new StringBuffer();
BufferedReader reader = new BufferedReader(r);
String line = "";
while ((line = reader.readLine()) != null) {
contents.append(line + Tools.getLineSeparator());
}
reader.close();
return contents.toString();
}
public static final String[] TRUE_STRINGS = { "true", "on", "yes", "y" };
public static final String[] FALSE_STRINGS = { "false", "off", "no", "n" };
public static boolean booleanValue(String string, boolean deflt) {
if (string == null)
return deflt;
string = string.toLowerCase().trim();
for (int i = 0; i < TRUE_STRINGS.length; i++) {
if (TRUE_STRINGS[i].equals(string)) {
return true;
}
}
for (int i = 0; i < FALSE_STRINGS.length; i++) {
if (FALSE_STRINGS[i].equals(string)) {
return false;
}
}
return deflt;
}
public static File findSourceFile(StackTraceElement e) {
try {
Class clazz = Class.forName(e.getClassName());
while (clazz.getDeclaringClass() != null)
clazz = clazz.getDeclaringClass();
String filename = clazz.getName().replace('.', File.separatorChar);
return ParameterService.getSourceFile(filename + ".java");
} catch (Throwable t) {}
String filename = e.getClassName().replace('.', File.separatorChar);
return ParameterService.getSourceFile(filename + ".java");
}
public static Process launchFileEditor(File file, int line) throws IOException {
String editor = System.getProperty(RapidMiner.PROPERTY_RAPIDMINER_TOOLS_EDITOR);
if (editor == null)
throw new IOException("Property 'rapidminer.tools.editor' undefined.");
editor = editor.replaceAll("%f", file.getAbsolutePath());
editor = editor.replaceAll("%l", line + "");
return Runtime.getRuntime().exec(editor);
}
/** Replaces angle brackets by html entities. */
public static String escapeXML(String string) {
if (string == null)
return "null";
string = string.replaceAll("&", "&");
string = string.replaceAll("\"", """);
string = string.replaceAll("'", "'");
string = string.replaceAll("<", "<");
string = string.replaceAll(">", ">");
string = transformAllLineSeparators(string);
string = string.replaceAll("\n", "
");
string = string.replaceAll("\t", " ");
return string;
}
public static void findImplementationsInJar(JarFile jar, Class superClass, List<String> implementations) {
findImplementationsInJar(Tools.class.getClassLoader(), jar, superClass, implementations);
}
public static void findImplementationsInJar(ClassLoader loader, JarFile jar, Class<?> superClass, List<String> implementations) {
Enumeration<JarEntry> e = jar.entries();
while (e.hasMoreElements()) {
JarEntry entry = e.nextElement();
String name = entry.getName();
int dotClass = name.lastIndexOf(".class");
if (dotClass < 0)
continue;
name = name.substring(0, dotClass);
name = name.replaceAll("/", "\\.");
try {
Class<?> c = loader.loadClass(name);
if (superClass.isAssignableFrom(c)) {
if (!java.lang.reflect.Modifier.isAbstract(c.getModifiers())) {
implementations.add(name);
}
}
} catch (Throwable t) {}
}
}
public static Class classForName(String className) throws ClassNotFoundException {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {}
try {
return ClassLoader.getSystemClassLoader().loadClass(className);
} catch (ClassNotFoundException e) {}
Iterator i = Plugin.getAllPlugins().iterator();
while (i.hasNext()) {
Plugin p = (Plugin) i.next();
try {
return p.getClassLoader().loadClass(className);
} catch (ClassNotFoundException e) {
// TODO: do nothing?
}
}
throw new ClassNotFoundException(className);
}
/**
* This method merges quoted splits, e.g. if a string line should be splitted by comma and
* commas inside of a quoted string should not be used as splitting point.
*
* @param line the original line
* @param splittedTokens the tokens as they were originally splitted
* @param quoteString the string which should be used as quote indicator, e.g. " or '
* @return the array of strings where the given quoteString was regarded
* @throws IOException if an open quote was not ended
*/
public static String[] mergeQuotedSplits(String line, String[] splittedTokens, String quoteString) throws IOException {
int[] tokenStarts = new int[splittedTokens.length];
int currentCounter = 0;
int currentIndex = 0;
for (String currentToken : splittedTokens) {
tokenStarts[currentIndex] = line.indexOf(currentToken, currentCounter);
currentCounter = tokenStarts[currentIndex] + currentToken.length() + 1;
currentIndex++;
}
List<String> tokens = new LinkedList<String>();
int start = -1;
int end = -1;
for (int i = 0; i < splittedTokens.length; i++) {
if (splittedTokens[i].trim().startsWith(quoteString)) {
start = i;
}
if (start >= 0) {
StringBuffer current = new StringBuffer();
while ((end < 0) && (i < splittedTokens.length)) {
if (splittedTokens[i].endsWith(quoteString)) {
end = i;
break;
}
i++;
}
if (end < 0)
throw new IOException("Error during reading: open quote \" is not ended!");
String lastToken = null;
for (int a = start; a <= end; a++) {
String nextToken = splittedTokens[a];
if (nextToken.length() == 0)
continue;
if (a == start) {
nextToken = nextToken.substring(quoteString.length());
}
if (a == end) {
nextToken = nextToken.substring(0, nextToken.length() - quoteString.length());
}
// add correct separator
if (lastToken != null) {
//int lastIndex = line.indexOf(lastToken, totalCounter - lastToken.length()) + lastToken.length();
int lastIndex = tokenStarts[a-1] + lastToken.length();
int thisIndex = tokenStarts[a];
if (lastIndex >= 0 && thisIndex >= lastIndex) {
String separator = line.substring(lastIndex, thisIndex);
current.append(separator);
}
}
current.append(nextToken);
lastToken = splittedTokens[a];
}
tokens.add(current.toString());
start = -1;
end = -1;
} else {
tokens.add(splittedTokens[i]);
}
}
String[] quoted = new String[tokens.size()];
tokens.toArray(quoted);
return quoted;
}
/** Delivers the next token and skip empty lines. */
public static void getFirstToken(StreamTokenizer tokenizer) throws IOException {
// skip empty lines
while (tokenizer.nextToken() == StreamTokenizer.TT_EOL) {};
if ((tokenizer.ttype == '\'') || (tokenizer.ttype == '"')) {
tokenizer.ttype = StreamTokenizer.TT_WORD;
} else if ((tokenizer.ttype == StreamTokenizer.TT_WORD) && (tokenizer.sval.equals("?"))) {
tokenizer.ttype = '?';
}
}
/** Delivers the next token and checks if its the end of line. */
public static void getLastToken(StreamTokenizer tokenizer, boolean endOfFileOk) throws IOException {
if ((tokenizer.nextToken() != StreamTokenizer.TT_EOL) && ((tokenizer.ttype != StreamTokenizer.TT_EOF) || !endOfFileOk)) {
throw new IOException("expected the end of the line " + tokenizer.lineno());
}
}
/** Delivers the next token and checks for an unexpected end of line or file. */
public static void getNextToken(StreamTokenizer tokenizer) throws IOException {
if (tokenizer.nextToken() == StreamTokenizer.TT_EOL) {
throw new IOException("unexpected end of line " + tokenizer.lineno());
}
if (tokenizer.ttype == StreamTokenizer.TT_EOF) {
throw new IOException("unexpected end of file in line " + tokenizer.lineno());
} else if ((tokenizer.ttype == '\'') || (tokenizer.ttype == '"')) {
tokenizer.ttype = StreamTokenizer.TT_WORD;
} else if ((tokenizer.ttype == StreamTokenizer.TT_WORD) &&
(tokenizer.sval.equals("?"))){
tokenizer.ttype = '?';
}
}
/** Skips all tokens before next end of line (EOL). */
public static void waitForEOL(StreamTokenizer tokenizer) throws IOException {
// skip everything until EOL
while (tokenizer.nextToken() != StreamTokenizer.TT_EOL) {};
tokenizer.pushBack();
}
public static void delete(File file) {
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File child : files) {
delete(child);
}
boolean result = file.delete();
if (!result)
LogService.getGlobal().logWarning("Unable to delete file " + file);
} else {
boolean result = file.delete();
if (!result)
LogService.getGlobal().logWarning("Unable to delete file " + file);
}
}
public static void copy(File srcPath, File dstPath) throws IOException {
if (srcPath.isDirectory()) {
if (!dstPath.exists()) {
boolean result = dstPath.mkdir();
if (!result)
throw new IOException("Unable to create directoy: " + dstPath);
}
String[] files = srcPath.list();
for (int i = 0; i < files.length; i++) {
copy(new File(srcPath, files[i]), new File(dstPath, files[i]));
}
} else {
if (srcPath.exists()) {
FileChannel in = null;
FileChannel out = null;
try {
in = new FileInputStream(srcPath).getChannel();
out = new FileOutputStream(dstPath).getChannel();
long size = in.size();
MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, 0, size);
out.write(buf);
} finally {
if (in != null)
in.close();
if (out != null)
out.close();
}
}
}
}
}