blob: 080a69b24ce5530ad01861197db4ddf037ce22a9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2014 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
* Nina Rinskaya
* Fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=172820.
*******************************************************************************/
package org.eclipse.jdt.core.tests.util;
import java.io.*;
import java.net.ServerSocket;
import java.util.*;
import java.util.zip.*;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.tests.compiler.regression.Requestor;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
import org.eclipse.jdt.internal.compiler.IProblemFactory;
import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
import org.eclipse.jdt.internal.compiler.batch.FileSystem;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
@SuppressWarnings({ "unchecked", "rawtypes" })
public class Util {
// Trace for delete operation
/*
* Maximum time wasted repeating delete operations while running JDT/Core tests.
*/
private static int DELETE_MAX_TIME = 0;
/**
* Trace deletion operations while running JDT/Core tests.
*/
public static boolean DELETE_DEBUG = false;
/**
* Maximum of time in ms to wait in deletion operation while running JDT/Core tests.
* Default is 10 seconds. This number cannot exceed 1 minute (ie. 60000).
* <br>
* To avoid too many loops while waiting, the ten first ones are done waiting
* 10ms before repeating, the ten loops after are done waiting 100ms and
* the other loops are done waiting 1s...
*/
public static int DELETE_MAX_WAIT = 10000;
private static final boolean DEBUG = false;
/**
* Initially, output directory was located in System.getProperty("java.io.tmpdir")+"\comptest".
* To allow user to run several compiler tests at the same time, main output directory
* is now located in a sub-directory of "comptest" which name is "run."+<code>System.currentMilliseconds</code>.
*
* @see #DELAY_BEFORE_CLEAN_PREVIOUS
*/
private final static String OUTPUT_DIRECTORY;
/**
* Let user specify the delay in hours before output directories are removed from file system
* while starting a new test run. Default value is 2 hours.
* <p>
* Note that this value may be a float and so have time less than one hour.
* If value is 0 or negative, then all previous run directories will be removed...
*
* @see #OUTPUT_DIRECTORY
*/
private final static String DELAY_BEFORE_CLEAN_PREVIOUS = System.getProperty("delay");
/*
* Static initializer to clean directories created while running previous test suites.
*/
static {
// Get delay for cleaning sub-directories
long millisecondsPerHour = 1000L * 3600L;
long delay = millisecondsPerHour * 2; // default is to keep previous run directories for 2 hours
try {
if (DELAY_BEFORE_CLEAN_PREVIOUS != null) {
float hours = Float.parseFloat(DELAY_BEFORE_CLEAN_PREVIOUS);
delay = (int) (millisecondsPerHour * hours);
}
}
catch (NumberFormatException nfe) {
// use default
}
// Get output directory root from system properties
String container = System.getProperty("jdt.test.output_directory");
if (container == null){
container = System.getProperty("java.io.tmpdir");
}
if (container == null) {
container = "."; // use current directory
}
// Get file for root directory
if (Character.isLowerCase(container.charAt(0)) && container.charAt(1) == ':') {
container = Character.toUpperCase(container.charAt(0)) + container.substring(1);
}
File dir = new File(new File(container), "comptest");
// If root directory already exists, clean it
if (dir.exists()) {
long now = System.currentTimeMillis();
if ((now - dir.lastModified()) > delay) {
// remove all directory content
flushDirectoryContent(dir);
} else {
// remove only old sub-dirs
File[] testDirs = dir.listFiles();
for (int i=0,l=testDirs.length; i<l; i++) {
if (testDirs[i].isDirectory()) {
if ((now - testDirs[i].lastModified()) > delay) {
delete(testDirs[i]);
}
}
}
}
}
// Computed test run directory name based on current time
File dateDir = new File(dir, "run."+System.currentTimeMillis());
String pathDir = null;
try {
pathDir = dateDir.getCanonicalPath();
} catch (IOException e) {
pathDir = dateDir.getAbsolutePath();
}
OUTPUT_DIRECTORY = pathDir;
}
public static void appendProblem(StringBuffer problems, IProblem problem, char[] source, int problemCount) {
problems.append(problemCount + (problem.isError() ? ". ERROR" : ". WARNING"));
problems.append(" in " + new String(problem.getOriginatingFileName()));
if (source != null) {
problems.append(((DefaultProblem)problem).errorReportSource(source));
}
problems.append("\n");
problems.append(problem.getMessage());
problems.append("\n");
}
public static CompilationUnit[] compilationUnits(String[] testFiles) {
int length = testFiles.length / 2;
CompilationUnit[] result = new CompilationUnit[length];
int index = 0;
for (int i = 0; i < length; i++) {
result[i] = new CompilationUnit(testFiles[index + 1].toCharArray(), testFiles[index], null);
index += 2;
}
return result;
}
public static void compile(String[] pathsAndContents, Map options, String outputPath) {
compile(pathsAndContents, options, null, outputPath);
}
public static void compile(String[] pathsAndContents, Map options, String[] classpath, String outputPath) {
IProblemFactory problemFactory = new DefaultProblemFactory(Locale.getDefault());
Requestor requestor =
new Requestor(
false,
null /*no custom requestor*/,
false, /* show category */
false /* show warning token*/);
requestor.outputPath = outputPath.endsWith(File.separator) ? outputPath : outputPath + File.separator;
String[] classLibs = getJavaClassLibs();
if (classpath != null) {
int length = classpath.length;
int classLibsLength = classLibs.length;
System.arraycopy(classpath, 0, classpath = new String[length + classLibsLength], 0, length);
System.arraycopy(classLibs, 0, classpath, length, classLibsLength);
} else {
classpath = classLibs;
}
INameEnvironment nameEnvironment = new FileSystem(classpath, new String[] {}, null);
IErrorHandlingPolicy errorHandlingPolicy =
new IErrorHandlingPolicy() {
public boolean proceedOnErrors() {
return true;
}
public boolean stopOnFirstError() {
return false;
}
public boolean ignoreAllErrors() {
return false;
}
};
CompilerOptions compilerOptions = new CompilerOptions(options);
compilerOptions.performMethodsFullRecovery = false;
compilerOptions.performStatementsRecovery = false;
Compiler batchCompiler =
new Compiler(
nameEnvironment,
errorHandlingPolicy,
compilerOptions,
requestor,
problemFactory);
batchCompiler.options.produceReferenceInfo = true;
batchCompiler.compile(compilationUnits(pathsAndContents)); // compile all files together
// cleanup
nameEnvironment.cleanup();
if (requestor.hasErrors)
System.err.print(requestor.problemLog); // problem log empty if no problems
}
public static String[] concatWithClassLibs(String[] classpaths, boolean inFront) {
String[] classLibs = getJavaClassLibs();
if (classpaths == null) return classLibs;
final int classLibsLength = classLibs.length;
final int classpathsLength = classpaths.length;
String[] defaultClassPaths = new String[classLibsLength + classpathsLength];
if (inFront) {
System.arraycopy(classLibs, 0, defaultClassPaths, classpathsLength, classLibsLength);
System.arraycopy(classpaths, 0, defaultClassPaths, 0, classpathsLength);
} else {
System.arraycopy(classLibs, 0, defaultClassPaths, 0, classLibsLength);
System.arraycopy(classpaths, 0, defaultClassPaths, classLibsLength, classpathsLength);
}
for (int i = 0; i < classpathsLength; i++) {
File file = new File(classpaths[i]);
if (!file.exists()) {
file.mkdirs();
}
}
return defaultClassPaths;
}
public static String[] concatWithClassLibs(String classpath, boolean inFront) {
String[] classLibs = getJavaClassLibs();
final int length = classLibs.length;
File dir = new File(classpath);
if (!dir.exists())
dir.mkdirs();
String[] defaultClassPaths = new String[length + 1];
if (inFront) {
System.arraycopy(classLibs, 0, defaultClassPaths, 1, length);
defaultClassPaths[0] = classpath;
} else {
System.arraycopy(classLibs, 0, defaultClassPaths, 0, length);
defaultClassPaths[length] = classpath;
}
return defaultClassPaths;
}
public static String convertToIndependantLineDelimiter(String source) {
if (source == null) return "";
if (source.indexOf('\n') == -1 && source.indexOf('\r') == -1) return source;
StringBuffer buffer = new StringBuffer();
for (int i = 0, length = source.length(); i < length; i++) {
char car = source.charAt(i);
if (car == '\r') {
buffer.append('\n');
if (i < length-1 && source.charAt(i+1) == '\n') {
i++; // skip \n after \r
}
} else {
buffer.append(car);
}
}
return buffer.toString();
}
/**
* Copy the given source (a file or a directory that must exists) to the given destination (a directory that must exists).
*/
public static void copy(String sourcePath, String destPath) {
sourcePath = toNativePath(sourcePath);
destPath = toNativePath(destPath);
File source = new File(sourcePath);
if (!source.exists()) return;
File dest = new File(destPath);
if (!dest.exists()) return;
if (source.isDirectory()) {
String[] files = source.list();
if (files != null) {
for (int i = 0; i < files.length; i++) {
String file = files[i];
File sourceFile = new File(source, file);
if (sourceFile.isDirectory()) {
File destSubDir = new File(dest, file);
destSubDir.mkdir();
copy(sourceFile.getPath(), destSubDir.getPath());
} else {
copy(sourceFile.getPath(), dest.getPath());
}
}
}
} else {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream(source);
File destFile = new File(dest, source.getName());
if (destFile.exists()) {
if (!Util.delete(destFile)) {
throw new IOException(destFile + " is in use");
}
}
out = new FileOutputStream(destFile);
int bufferLength = 1024;
byte[] buffer = new byte[bufferLength];
int read = 0;
while (read != -1) {
read = in.read(buffer, 0, bufferLength);
if (read != -1) {
out.write(buffer, 0, read);
}
}
} catch (IOException e) {
throw new Error(e.toString());
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
}
}
}
}
}
public static void createFile(String path, String contents) throws IOException {
FileOutputStream output = new FileOutputStream(path);
try {
output.write(contents.getBytes());
} finally {
output.close();
}
}
public static void createClassFolder(String[] pathsAndContents, String folderPath, String compliance) throws IOException {
File classesDir = new File(folderPath);
flushDirectoryContent(classesDir);
compile(pathsAndContents, getCompileOptions(compliance), folderPath);
}
public static void createEmptyJar(String jarPath, String compliance) throws IOException {
org.eclipse.jdt.core.tests.util.Util.createJar(
null,
new String[] {
"META-INF/MANIFEST.MF",
"Manifest-Version: 1.0\n",
},
jarPath,
null,
compliance);
}
public static void createJar(String[] pathsAndContents, Map options, String jarPath) throws IOException {
createJar(pathsAndContents, null, options, null, jarPath);
}
public static void createJar(String[] pathsAndContents, String[] extraPathsAndContents, Map options, String[] classpath, String jarPath) throws IOException {
String classesPath = getOutputDirectory() + File.separator + "classes";
File classesDir = new File(classesPath);
flushDirectoryContent(classesDir);
if (pathsAndContents != null) {
compile(pathsAndContents, options, classpath, classesPath);
}
if (extraPathsAndContents != null) {
for (int i = 0, l = extraPathsAndContents == null ? 0 : extraPathsAndContents.length; i < l; /* inc in loop */) {
File outputFile = new File(classesPath, extraPathsAndContents[i++]);
outputFile.getParentFile().mkdirs();
Util.writeToFile(extraPathsAndContents[i++], outputFile.getAbsolutePath());
}
}
zip(classesDir, jarPath);
}
public static void createJar(String[] javaPathsAndContents, String jarPath, String compliance) throws IOException {
createJar(javaPathsAndContents, null, jarPath, compliance);
}
public static void createJar(String[] javaPathsAndContents, String[] extraPathsAndContents, String jarPath, String compliance) throws IOException {
createJar(javaPathsAndContents, extraPathsAndContents, jarPath, null/*no classpath*/, compliance);
}
public static void createJar(String[] javaPathsAndContents, String[] extraPathsAndContents, String jarPath, String[] classpath, String compliance) throws IOException {
createJar(javaPathsAndContents, extraPathsAndContents, getCompileOptions(compliance), classpath, jarPath);
}
public static void createJar(String[] javaPathsAndContents, String[] extraPathsAndContents, String jarPath, String[] classpath, String compliance, Map options) throws IOException {
Map compileOptions = getCompileOptions(compliance);
if (options != null) {
compileOptions.putAll(options);
}
createJar(javaPathsAndContents, extraPathsAndContents, compileOptions, classpath, jarPath);
}
public static void createSourceZip(String[] pathsAndContents, String zipPath) throws IOException {
String sourcesPath = getOutputDirectory() + File.separator + "sources";
createSourceDir(pathsAndContents, sourcesPath);
zip(new File(sourcesPath), zipPath);
}
public static void createSourceDir(String[] pathsAndContents, String sourcesPath) throws IOException {
flushDirectoryContent(new File(sourcesPath));
for (int i = 0, length = pathsAndContents.length; i < length; i+=2) {
String sourcePath = sourcesPath + File.separator + pathsAndContents[i];
File sourceFile = new File(sourcePath);
sourceFile.getParentFile().mkdirs();
createFile(sourcePath, pathsAndContents[i+1]);
}
}
/**
* Delete a file or directory and insure that the file is no longer present
* on file system. In case of directory, delete all the hierarchy underneath.
*
* @param file The file or directory to delete
* @return true iff the file was really delete, false otherwise
*/
public static boolean delete(File file) {
// flush all directory content
if (file.isDirectory()) {
flushDirectoryContent(file);
}
// remove file
file.delete();
if (isFileDeleted(file)) {
return true;
}
return waitUntilFileDeleted(file);
}
/**
* Delete a file or directory and insure that the file is no longer present
* on file system. In case of directory, delete all the hierarchy underneath.
*
* @param resource The resource to delete
* @return true iff the file was really delete, false otherwise
*/
public static IStatus delete(IResource resource) {
IStatus status = null;
try {
resource.delete(true, null);
if (isResourceDeleted(resource)) {
return Status.OK_STATUS;
}
} catch (CoreException e) {
status = e.getStatus();
}
boolean deleted = waitUntilResourceDeleted(resource);
if (deleted) {
return Status.OK_STATUS;
}
if (status != null) {
return status;
}
return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, "Cannot delete resource "+resource);
}
/**
* Delete a file or directory and insure that the file is no longer present
* on file system. In case of directory, delete all the hierarchy underneath.
*
* @param path The path of the file or directory to delete
* @return true iff the file was really delete, false otherwise
*/
public static boolean delete(String path) {
return delete(new File(path));
}
/**
* Generate a display string from the given String.
* @param inputString the given input string
*
* Example of use: [org.eclipse.jdt.core.tests.util.Util.displayString("abc\ndef\tghi")]
*/
public static String displayString(String inputString){
return displayString(inputString, 0);
}
/**
* Generate a display string from the given String.
* It converts:
* <ul>
* <li>\t to \t</li>
* <li>\r to \\r</li>
* <li>\n to \n</li>
* <li>\b to \\b</li>
* <li>\f to \\f</li>
* <li>\" to \\\"</li>
* <li>\' to \\'</li>
* <li>\\ to \\\\</li>
* <li>All other characters are unchanged.</li>
* </ul>
* This method doesn't convert \r\n to \n.
* <p>
* Example of use:
* <o>
* <li>
* <pre>
* input string = "abc\ndef\tghi",
* indent = 3
* result = "\"\t\t\tabc\\n" +
* "\t\t\tdef\tghi\""
* </pre>
* </li>
* <li>
* <pre>
* input string = "abc\ndef\tghi\n",
* indent = 3
* result = "\"\t\t\tabc\\n" +
* "\t\t\tdef\tghi\\n\""
* </pre>
* </li>
* <li>
* <pre>
* input string = "abc\r\ndef\tghi\r\n",
* indent = 3
* result = "\"\t\t\tabc\\r\\n" +
* "\t\t\tdef\tghi\\r\\n\""
* </pre>
* </li>
* </ol>
* </p>
*
* @param inputString the given input string
* @param indent number of tabs are added at the begining of each line.
*
* @return the displayed string
*/
public static String displayString(String inputString, int indent) {
return displayString(inputString, indent, false);
}
public static String displayString(String inputString, int indent, boolean shift) {
if (inputString == null)
return "null";
int length = inputString.length();
StringBuffer buffer = new StringBuffer(length);
java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(inputString, "\n\r", true);
for (int i = 0; i < indent; i++) buffer.append("\t");
if (shift) indent++;
buffer.append("\"");
while (tokenizer.hasMoreTokens()){
String token = tokenizer.nextToken();
if (token.equals("\r")) {
buffer.append("\\r");
if (tokenizer.hasMoreTokens()) {
token = tokenizer.nextToken();
if (token.equals("\n")) {
buffer.append("\\n");
if (tokenizer.hasMoreTokens()) {
buffer.append("\" + \n");
for (int i = 0; i < indent; i++) buffer.append("\t");
buffer.append("\"");
}
continue;
}
buffer.append("\" + \n");
for (int i = 0; i < indent; i++) buffer.append("\t");
buffer.append("\"");
} else {
continue;
}
} else if (token.equals("\n")) {
buffer.append("\\n");
if (tokenizer.hasMoreTokens()) {
buffer.append("\" + \n");
for (int i = 0; i < indent; i++) buffer.append("\t");
buffer.append("\"");
}
continue;
}
StringBuffer tokenBuffer = new StringBuffer();
for (int i = 0; i < token.length(); i++){
char c = token.charAt(i);
switch (c) {
case '\r' :
tokenBuffer.append("\\r");
break;
case '\n' :
tokenBuffer.append("\\n");
break;
case '\b' :
tokenBuffer.append("\\b");
break;
case '\t' :
tokenBuffer.append("\t");
break;
case '\f' :
tokenBuffer.append("\\f");
break;
case '\"' :
tokenBuffer.append("\\\"");
break;
case '\'' :
tokenBuffer.append("\\'");
break;
case '\\' :
tokenBuffer.append("\\\\");
break;
default :
tokenBuffer.append(c);
}
}
buffer.append(tokenBuffer.toString());
}
buffer.append("\"");
return buffer.toString();
}
/**
* Reads the content of the given source file.
* Returns null if enable to read given source file.
*
* Example of use: [org.eclipse.jdt.core.tests.util.Util.fileContent("c:/temp/X.java")]
*/
public static String fileContent(String sourceFilePath) {
File sourceFile = new File(sourceFilePath);
if (!sourceFile.exists()) {
if (DEBUG) System.out.println("File " + sourceFilePath + " does not exists.");
return null;
}
if (!sourceFile.isFile()) {
if (DEBUG) System.out.println(sourceFilePath + " is not a file.");
return null;
}
StringBuffer sourceContentBuffer = new StringBuffer();
FileInputStream input = null;
try {
input = new FileInputStream(sourceFile);
} catch (FileNotFoundException e) {
return null;
}
try {
int read;
do {
read = input.read();
if (read != -1) {
sourceContentBuffer.append((char)read);
}
} while (read != -1);
input.close();
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
try {
input.close();
} catch (IOException e2) {
}
}
return sourceContentBuffer.toString();
}
/**
* Reads the content of the given source file and converts it to a display string.
*
* Example of use: [org.eclipse.jdt.core.tests.util.Util.fileContentToDisplayString("c:/temp/X.java", 0)]
*/
public static String fileContentToDisplayString(String sourceFilePath, int indent, boolean independantLineDelimiter) {
String sourceString = fileContent(sourceFilePath);
if (independantLineDelimiter) {
sourceString = convertToIndependantLineDelimiter(sourceString);
}
return displayString(sourceString, indent);
}
/**
* Reads the content of the given source file, converts it to a display string.
* If the destination file path is not null, writes the result to this file.
* Otherwise writes it to the console.
*
* Example of use: [org.eclipse.jdt.core.tests.util.Util.fileContentToDisplayString("c:/temp/X.java", 0, null)]
*/
public static void fileContentToDisplayString(String sourceFilePath, int indent, String destinationFilePath, boolean independantLineDelimiter) {
String displayString = fileContentToDisplayString(sourceFilePath, indent, independantLineDelimiter);
if (destinationFilePath == null) {
System.out.println(displayString);
return;
}
writeToFile(displayString, destinationFilePath);
}
/**
* Flush content of a given directory (leaving it empty),
* no-op if not a directory.
*/
public static void flushDirectoryContent(File dir) {
File[] files = dir.listFiles();
if (files == null) return;
for (int i = 0, max = files.length; i < max; i++) {
delete(files[i]);
}
}
private static Map getCompileOptions(String compliance) {
Map options = new HashMap();
options.put(CompilerOptions.OPTION_Compliance, compliance);
options.put(CompilerOptions.OPTION_Source, compliance);
options.put(CompilerOptions.OPTION_TargetPlatform, compliance);
// Ignore options with new defaults (since bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=76530)
options.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.IGNORE);
options.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.IGNORE);
options.put(CompilerOptions.OPTION_ReportFieldHiding, CompilerOptions.IGNORE);
options.put(CompilerOptions.OPTION_ReportLocalVariableHiding, CompilerOptions.IGNORE);
options.put(CompilerOptions.OPTION_ReportTypeParameterHiding, CompilerOptions.IGNORE);
options.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE);
options.put(CompilerOptions.OPTION_ReportRawTypeReference, CompilerOptions.IGNORE);
return options;
}
/**
* Returns the next available port number on the local host.
*/
public static int getFreePort() {
ServerSocket socket = null;
try {
socket = new ServerSocket(0);
return socket.getLocalPort();
} catch (IOException e) {
// ignore
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// ignore
}
}
}
return -1;
}
/**
* Search the user hard-drive for a Java class library.
* Returns null if none could be found.
*/
public static String[] getJavaClassLibs() {
String javaVersion = System.getProperty("java.version");
if (javaVersion.length() > 3) {
javaVersion = javaVersion.substring(0, 3);
}
long jdkLevel = CompilerOptions.versionToJdkLevel(javaVersion);
if (jdkLevel >= ClassFileConstants.JDK9) {
String jreDir = getJREDirectory();
return new String[] {
toNativePath(jreDir + "/jrt-fs.jar")
};
}
// check bootclasspath properties for Sun, JRockit and Harmony VMs
String bootclasspathProperty = System.getProperty("sun.boot.class.path"); //$NON-NLS-1$
if ((bootclasspathProperty == null) || (bootclasspathProperty.length() == 0)) {
// IBM J9 VMs
bootclasspathProperty = System.getProperty("vm.boot.class.path"); //$NON-NLS-1$
if ((bootclasspathProperty == null) || (bootclasspathProperty.length() == 0)) {
// Harmony using IBM VME
bootclasspathProperty = System.getProperty("org.apache.harmony.boot.class.path"); //$NON-NLS-1$
}
}
String[] jars = null;
if ((bootclasspathProperty != null) && (bootclasspathProperty.length() != 0)) {
StringTokenizer tokenizer = new StringTokenizer(bootclasspathProperty, File.pathSeparator);
final int size = tokenizer.countTokens();
jars = new String[size];
int i = 0;
while (tokenizer.hasMoreTokens()) {
final String fileName = toNativePath(tokenizer.nextToken());
if (new File(fileName).exists()) {
jars[i] = fileName;
i++;
}
}
if (size != i) {
// resize
System.arraycopy(jars, 0, (jars = new String[i]), 0, i);
}
} else {
String jreDir = getJREDirectory();
final String osName = System.getProperty("os.name");
if (jreDir == null) {
return new String[] {};
}
if (osName.startsWith("Mac")) {
return new String[] {
toNativePath(jreDir + "/../Classes/classes.jar")
};
}
final String vmName = System.getProperty("java.vm.name");
if ("J9".equals(vmName)) {
return new String[] {
toNativePath(jreDir + "/lib/jclMax/classes.zip")
};
}
String[] jarsNames = null;
ArrayList paths = new ArrayList();
if ("DRLVM".equals(vmName)) {
FilenameFilter jarFilter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".jar") & !name.endsWith("-src.jar");
}
};
jarsNames = new File(jreDir + "/lib/boot/").list(jarFilter);
addJarEntries(jreDir + "/lib/boot/", jarsNames, paths);
} else {
jarsNames = new String[] {
"/lib/vm.jar",
"/lib/rt.jar",
"/lib/core.jar",
"/lib/security.jar",
"/lib/xml.jar",
"/lib/graphics.jar"
};
addJarEntries(jreDir, jarsNames, paths);
}
jars = new String[paths.size()];
paths.toArray(jars);
}
return jars;
}
private static void addJarEntries(String jreDir, String[] jarNames, ArrayList paths) {
for (int i = 0, max = jarNames.length; i < max; i++) {
final String currentName = jreDir + jarNames[i];
File f = new File(currentName);
if (f.exists()) {
paths.add(toNativePath(currentName));
}
}
}
public static String getJavaClassLibsAsString() {
String[] classLibs = getJavaClassLibs();
StringBuffer buffer = new StringBuffer();
for (int i = 0, max = classLibs.length; i < max; i++) {
buffer
.append(classLibs[i])
.append(File.pathSeparatorChar);
}
return buffer.toString();
}
/**
* Returns the JRE directory this tests are running on.
* Returns null if none could be found.
*
* Example of use: [org.eclipse.jdt.core.tests.util.Util.getJREDirectory()]
*/
public static String getJREDirectory() {
return System.getProperty("java.home");
}
/**
* Search the user hard-drive for a possible output directory.
* Returns null if none could be found.
*
* Example of use: [org.eclipse.jdt.core.tests.util.Util.getOutputDirectory()]
*/
public static String getOutputDirectory() {
return OUTPUT_DIRECTORY;
}
/**
* Returns the parent's child file matching the given file or null if not found.
*
* @param file The searched file in parent
* @return The parent's child matching the given file or null if not found.
*/
private static File getParentChildFile(File file) {
File parent = file.getParentFile();
if (parent == null || !parent.exists()) return null;
File[] files = parent.listFiles();
int length = files==null ? 0 : files.length;
if (length > 0) {
for (int i=0; i<length; i++) {
if (files[i] == file) {
return files[i];
} else if (files[i].equals(file)) {
return files[i];
} else if (files[i].getPath().equals(file.getPath())) {
return files[i];
}
}
}
return null;
}
/**
* Returns parent's child resource matching the given resource or null if not found.
*
* @param resource The searched file in parent
* @return The parent's child matching the given file or null if not found.
*/
private static IResource getParentChildResource(IResource resource) {
IContainer parent = resource.getParent();
if (parent == null || !parent.exists()) return null;
try {
IResource[] members = parent.members();
int length = members ==null ? 0 : members.length;
if (length > 0) {
for (int i=0; i<length; i++) {
if (members[i] == resource) {
return members[i];
} else if (members[i].equals(resource)) {
return members[i];
} else if (members[i].getFullPath().equals(resource.getFullPath())) {
return members[i];
}
}
}
}
catch (CoreException ce) {
// skip
}
return null;
}
/**
* Returns the test name from stack elements info.
*
* @return The name of the test currently running
*/
private static String getTestName() {
StackTraceElement[] elements = new Exception().getStackTrace();
int idx = 0, length=elements.length;
while (idx<length && !elements[idx++].getClassName().startsWith("org.eclipse.jdt")) {
// loop until JDT/Core class appears in the stack
}
if (idx<length) {
StackTraceElement testElement = null;
while (idx<length && elements[idx].getClassName().startsWith("org.eclipse.jdt")) {
testElement = elements[idx++];
}
if (testElement != null) {
return testElement.getClassName() + " - " + testElement.getMethodName();
}
}
return "?";
}
public static String indentString(String inputString, int indent) {
if (inputString == null)
return "";
int length = inputString.length();
StringBuffer buffer = new StringBuffer(length);
java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(inputString, "\n\r", true);
StringBuffer indentStr = new StringBuffer(indent);
for (int i = 0; i < indent; i++) indentStr.append("\t");
buffer.append(indentStr);
while (tokenizer.hasMoreTokens()){
String token = tokenizer.nextToken();
buffer.append(token);
if (token.equals("\r") || token.equals("\n")) {
buffer.append(indentStr);
}
}
return buffer.toString();
}
/**
* Returns whether a file is really deleted or not.
* Does not only rely on {@link File#exists()} method but also
* look if it's not in its parent children {@link #getParentChildFile(File)}.
*
* @param file The file to test if deleted
* @return true if the file does not exist and was not found in its parent children.
*/
public static boolean isFileDeleted(File file) {
return !file.exists() && getParentChildFile(file) == null;
}
public static boolean isMacOS() {
return System.getProperty("os.name").indexOf("Mac") != -1;
}
/**
* Returns whether a resource is really deleted or not.
* Does not only rely on {@link IResource#isAccessible()} method but also
* look if it's not in its parent children {@link #getParentChildResource(IResource)}.
*
* @param resource The resource to test if deleted
* @return true if the resource is not accessible and was not found in its parent children.
*/
public static boolean isResourceDeleted(IResource resource) {
return !resource.isAccessible() && getParentChildResource(resource) == null;
}
/**
* Print given file information with specified indentation.
* These information are:<ul>
* <li>read {@link File#canRead()}</li>
* <li>write {@link File#canWrite()}</li>
* <li>exists {@link File#exists()}</li>
* <li>is file {@link File#isFile()}</li>
* <li>is directory {@link File#isDirectory()}</li>
* <li>is hidden {@link File#isHidden()}</li>
* </ul>
* May recurse several level in parents hierarchy.
* May also display children, but then will not recusre in parent
* hierarchy to avoid infinite loop...
*
* @param file The file to display information
* @param indent Number of tab to print before the information
* @param recurse Display also information on <code>recurse</code>th parents in hierarchy.
* If negative then display children information instead.
*/
private static void printFileInfo(File file, int indent, int recurse) {
String tab = "";
for (int i=0; i<indent; i++) tab+="\t";
System.out.print(tab+"- "+file.getName()+" file info: ");
String sep = "";
if (file.canRead()) {
System.out.print("read");
sep = ", ";
}
if (file.canWrite()) {
System.out.print(sep+"write");
sep = ", ";
}
if (file.exists()) {
System.out.print(sep+"exist");
sep = ", ";
}
if (file.isDirectory()) {
System.out.print(sep+"dir");
sep = ", ";
}
if (file.isFile()) {
System.out.print(sep+"file");
sep = ", ";
}
if (file.isHidden()) {
System.out.print(sep+"hidden");
sep = ", ";
}
System.out.println();
File[] files = file.listFiles();
int length = files==null ? 0 : files.length;
if (length > 0) {
boolean children = recurse < 0;
System.out.print(tab+" + children: ");
if (children) System.out.println();
for (int i=0; i<length; i++) {
if (children) { // display children
printFileInfo(files[i], indent+2, -1);
} else {
if (i>0) System.out.print(", ");
System.out.print(files[i].getName());
if (files[i].isDirectory()) System.out.print("[dir]");
else if (files[i].isFile()) System.out.print("[file]");
else System.out.print("[?]");
}
}
if (!children) System.out.println();
}
if (recurse > 0) {
File parent = file.getParentFile();
if (parent != null) printFileInfo(parent, indent+1, recurse-1);
}
}
/**
* Print stack trace with only JDT/Core elements.
*
* @param exception Exception of the stack trace. May be null, then a fake exception is used.
* @param indent Number of tab to display before the stack elements to display.
*/
private static void printJdtCoreStackTrace(Exception exception, int indent) {
String tab = "";
for (int i=0; i<indent; i++) tab+="\t";
StackTraceElement[] elements = (exception==null?new Exception():exception).getStackTrace();
int idx = 0, length=elements.length;
while (idx<length && !elements[idx++].getClassName().startsWith("org.eclipse.jdt")) {
// loop until JDT/Core class appears in the stack
}
if (idx<length) {
System.out.print(tab+"- stack trace");
if (exception == null)
System.out.println(":");
else
System.out.println(" for exception "+exception+":");
while (idx<length && elements[idx].getClassName().startsWith("org.eclipse.jdt")) {
StackTraceElement testElement = elements[idx++];
System.out.println(tab+" -> "+testElement);
}
} else {
exception.printStackTrace(System.out);
}
}
/**
* Makes the given path a path using native path separators as returned by File.getPath()
* and trimming any extra slash.
*/
public static String toNativePath(String path) {
String nativePath = path.replace('\\', File.separatorChar).replace('/', File.separatorChar);
return
nativePath.endsWith("/") || nativePath.endsWith("\\") ?
nativePath.substring(0, nativePath.length() - 1) :
nativePath;
}
public static String toString(String[] strings, boolean addExtraNewLine) {
if (strings == null) return "null";
StringBuffer buffer = new StringBuffer();
for (int i = 0, length = strings.length; i < length; i++){
buffer.append(strings[i]);
if (addExtraNewLine || i < length - 1)
buffer.append("\n");
}
return buffer.toString();
}
/**
* Unzip the contents of the given zip in the given directory (create it if it doesn't exist)
*/
public static void unzip(String zipPath, String destDirPath) throws IOException {
InputStream zipIn = new FileInputStream(zipPath);
byte[] buf = new byte[8192];
File destDir = new File(destDirPath);
ZipInputStream zis = new ZipInputStream(zipIn);
FileOutputStream fos = null;
try {
ZipEntry zEntry;
while ((zEntry = zis.getNextEntry()) != null) {
// if it is empty directory, create it
if (zEntry.isDirectory()) {
new File(destDir, zEntry.getName()).mkdirs();
continue;
}
// if it is a file, extract it
String filePath = zEntry.getName();
int lastSeparator = filePath.lastIndexOf("/"); //$NON-NLS-1$
String fileDir = ""; //$NON-NLS-1$
if (lastSeparator >= 0) {
fileDir = filePath.substring(0, lastSeparator);
}
//create directory for a file
new File(destDir, fileDir).mkdirs();
//write file
File outFile = new File(destDir, filePath);
fos = new FileOutputStream(outFile);
int n = 0;
while ((n = zis.read(buf)) >= 0) {
fos.write(buf, 0, n);
}
fos.close();
}
} catch (IOException ioe) {
if (fos != null) {
try {
fos.close();
} catch (IOException ioe2) {
}
}
} finally {
try {
zipIn.close();
if (zis != null)
zis.close();
} catch (IOException ioe) {
}
}
}
public static void waitAtLeast(int time) {
long start = System.currentTimeMillis();
do {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
}
} while ((System.currentTimeMillis() - start) < time);
}
/**
* Wait until the file is _really_ deleted on file system.
*
* @param file Deleted file
* @return true if the file was finally deleted, false otherwise
*/
private static boolean waitUntilFileDeleted(File file) {
if (DELETE_DEBUG) {
System.out.println();
System.out.println("WARNING in test: "+getTestName());
System.out.println(" - problems occured while deleting "+file);
printJdtCoreStackTrace(null, 1);
printFileInfo(file.getParentFile(), 1, -1); // display parent with its children
System.out.print(" - wait for ("+DELETE_MAX_WAIT+"ms max): ");
}
int count = 0;
int delay = 10; // ms
int maxRetry = DELETE_MAX_WAIT / delay;
int time = 0;
while (count < maxRetry) {
try {
count++;
Thread.sleep(delay);
time += delay;
if (time > DELETE_MAX_TIME) DELETE_MAX_TIME = time;
if (DELETE_DEBUG) System.out.print('.');
if (file.exists()) {
if (file.delete()) {
// SUCCESS
if (DELETE_DEBUG) {
System.out.println();
System.out.println(" => file really removed after "+time+"ms (max="+DELETE_MAX_TIME+"ms)");
System.out.println();
}
return true;
}
}
if (isFileDeleted(file)) {
// SUCCESS
if (DELETE_DEBUG) {
System.out.println();
System.out.println(" => file disappeared after "+time+"ms (max="+DELETE_MAX_TIME+"ms)");
System.out.println();
}
return true;
}
// Increment waiting delay exponentially
if (count >= 10 && delay <= 100) {
count = 1;
delay *= 10;
maxRetry = DELETE_MAX_WAIT / delay;
if ((DELETE_MAX_WAIT%delay) != 0) {
maxRetry++;
}
}
}
catch (InterruptedException ie) {
break; // end loop
}
}
if (!DELETE_DEBUG) {
System.out.println();
System.out.println("WARNING in test: "+getTestName());
System.out.println(" - problems occured while deleting "+file);
printJdtCoreStackTrace(null, 1);
printFileInfo(file.getParentFile(), 1, -1); // display parent with its children
}
System.out.println();
System.out.println(" !!! ERROR: "+file+" was never deleted even after having waited "+DELETE_MAX_TIME+"ms!!!");
System.out.println();
return false;
}
/**
* Wait until a resource is _really_ deleted on file system.
*
* @param resource Deleted resource
* @return true if the file was finally deleted, false otherwise
*/
public static boolean waitUntilResourceDeleted(IResource resource) {
IPath location = resource.getLocation();
if (location == null) {
System.out.println();
System.out.println(" !!! ERROR: "+resource+" getLocation() returned null!!!");
System.out.println();
return false;
}
File file = location.toFile();
if (DELETE_DEBUG) {
System.out.println();
System.out.println("WARNING in test: "+getTestName());
System.out.println(" - problems occured while deleting resource "+resource);
printJdtCoreStackTrace(null, 1);
printFileInfo(file.getParentFile(), 1, -1); // display parent with its children
System.out.print(" - wait for ("+DELETE_MAX_WAIT+"ms max): ");
}
int count = 0;
int delay = 10; // ms
int maxRetry = DELETE_MAX_WAIT / delay;
int time = 0;
while (count < maxRetry) {
try {
count++;
Thread.sleep(delay);
time += delay;
if (time > DELETE_MAX_TIME) DELETE_MAX_TIME = time;
if (DELETE_DEBUG) System.out.print('.');
if (resource.isAccessible()) {
try {
resource.delete(true, null);
if (isResourceDeleted(resource) && isFileDeleted(file)) {
// SUCCESS
if (DELETE_DEBUG) {
System.out.println();
System.out.println(" => resource really removed after "+time+"ms (max="+DELETE_MAX_TIME+"ms)");
System.out.println();
}
return true;
}
}
catch (CoreException e) {
// skip
}
}
if (isResourceDeleted(resource) && isFileDeleted(file)) {
// SUCCESS
if (DELETE_DEBUG) {
System.out.println();
System.out.println(" => resource disappeared after "+time+"ms (max="+DELETE_MAX_TIME+"ms)");
System.out.println();
}
return true;
}
// Increment waiting delay exponentially
if (count >= 10 && delay <= 100) {
count = 1;
delay *= 10;
maxRetry = DELETE_MAX_WAIT / delay;
if ((DELETE_MAX_WAIT%delay) != 0) {
maxRetry++;
}
}
}
catch (InterruptedException ie) {
break; // end loop
}
}
if (!DELETE_DEBUG) {
System.out.println();
System.out.println("WARNING in test: "+getTestName());
System.out.println(" - problems occured while deleting resource "+resource);
printJdtCoreStackTrace(null, 1);
printFileInfo(file.getParentFile(), 1, -1); // display parent with its children
}
System.out.println();
System.out.println(" !!! ERROR: "+resource+" was never deleted even after having waited "+DELETE_MAX_TIME+"ms!!!");
System.out.println();
return false;
}
public static void writeToFile(String contents, String destinationFilePath) {
File destFile = new File(destinationFilePath);
FileOutputStream output = null;
PrintWriter writer = null;
try {
output = new FileOutputStream(destFile);
writer = new PrintWriter(output);
writer.print(contents);
writer.flush();
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
if (writer != null) {
writer.close();
}
}
}
public static void zip(File rootDir, String zipPath) throws IOException {
ZipOutputStream zip = null;
try {
File zipFile = new File(zipPath);
if (zipFile.exists()) {
if (!delete(zipFile))
throw new IOException("Could not delete " + zipPath);
// ensure the new zip file has a different timestamp than the previous one
int timeToWait = 1000; // some platform (like Linux) have a 1s granularity)
waitAtLeast(timeToWait);
} else {
zipFile.getParentFile().mkdirs();
}
zip = new ZipOutputStream(new FileOutputStream(zipFile));
zip(rootDir, zip, rootDir.getPath().length()+1); // 1 for last slash
} finally {
if (zip != null) {
zip.close();
}
}
}
private static void zip(File dir, ZipOutputStream zip, int rootPathLength) throws IOException {
File[] files = dir.listFiles();
if (files != null) {
for (int i = 0, length = files.length; i < length; i++) {
File file = files[i];
if (file.isFile()) {
String path = file.getPath();
path = path.substring(rootPathLength);
ZipEntry entry = new ZipEntry(path.replace('\\', '/'));
zip.putNextEntry(entry);
zip.write(org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(file));
zip.closeEntry();
} else {
zip(file, zip, rootPathLength);
}
}
}
}
/**
* Zips the given files into the given jar. All the files are kept at the root of the zip.
*/
public static void zipFiles(File[] files, String zipPath) throws IOException {
File zipFile = new File(zipPath);
if (zipFile.exists()) {
if (!delete(zipFile))
throw new IOException("Could not delete " + zipPath);
// ensure the new zip file has a different timestamp than the previous one
int timeToWait = 1000; // some platform (like Linux) have a 1s granularity)
waitAtLeast(timeToWait);
} else {
zipFile.getParentFile().mkdirs();
}
ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(zipFile));
try {
for (int i = 0, length = files.length; i < length; i++) {
File file = files[i];
ZipEntry entry = new ZipEntry(file.getName());
zip.putNextEntry(entry);
zip.write(org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(file));
zip.closeEntry();
}
} finally {
zip.close();
}
}
/**
* Returns the compilation errors / warnings for the given CompilationResult.
*
* @param compilationResult the compilation result
* @param showCategory
* @param showWarningToken
* @return String the problem log
*/
public static String getProblemLog(CompilationResult compilationResult, boolean showCategory, boolean showWarningToken) {
StringBuffer buffer = new StringBuffer(100);
if (compilationResult.hasProblems() || compilationResult.hasTasks()) {
CategorizedProblem[] problems = compilationResult.getAllProblems();
int count = problems.length;
int problemCount = 0;
char[] unitSource = compilationResult.compilationUnit.getContents();
for (int i = 0; i < count; i++) {
DefaultProblem problem = (DefaultProblem) problems[i];
if (problem != null) {
if (problemCount == 0)
buffer.append("----------\n");
problemCount++;
buffer.append(problemCount + (problem.isError() ? ". ERROR" : ". WARNING"));
buffer.append(" in " + new String(problem.getOriginatingFileName()).replace('/', '\\'));
try {
buffer.append(problem.errorReportSource(unitSource));
buffer.append("\n");
if (showCategory) {
String category = problem.getInternalCategoryMessage();
if (category != null) {
buffer.append("[@cat:").append(category).append("] ");
}
}
if (showWarningToken) {
int irritant = ProblemReporter.getIrritant(problem.getID());
if (irritant != 0) {
String warningToken = CompilerOptions.warningTokenFromIrritant(irritant);
if (warningToken != null) {
buffer.append("[@sup:").append(warningToken).append("] ");
}
}
}
buffer.append(problem.getMessage());
buffer.append("\n");
} catch (Exception e) {
}
buffer.append("----------\n");
}
}
}
return buffer.toString();
}
public static long getMajorMinorVMVersion() {
String classFileVersion = System.getProperty("java.class.version"); //$NON-NLS-1$
if (classFileVersion != null) {
String[] versionParts = classFileVersion.split("\\."); //$NON-NLS-1$
if (versionParts.length >= 2) {
int majorVersion = -1;
try {
majorVersion = Integer.parseInt(versionParts[0]);
} catch (NumberFormatException e) {
// ignore
}
int minorVersion = -1;
try {
minorVersion = Integer.parseInt(versionParts[1]);
} catch (NumberFormatException e) {
// ignore
}
if (minorVersion != -1 && majorVersion != -1) {
return ((long) majorVersion << 16) + minorVersion;
}
}
}
return -1;
}
}