/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package launchers;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import org.visage.api.VisageScriptEngine;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.PrintStream;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
/**
* This class primarily calls into visagert, visagec and visagedoc to ensure
* that a conformant version strings are returned for:
* a. System properties.
* b. tools visage, visagec, and visagedoc.
*/
public class Utils {
private static File distDir = null;
static File javaExe = null;
static File visageExe = null;
static File visagewExe = null;
static File visagecExe = null;
static File visagedocExe = null;
static boolean debug = false;
static File workingDir = null;
static JavaCompiler javaCompiler = null;
private static VisageScriptEngine engine = null;
static final boolean isWindows =
System.getProperty("os.name").startsWith("Windows");
static final FileFilter CLASS_FILTER = new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".class");
}
};
static final FileFilter JAR_FILTER = new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".jar");
}
};
static final FileFilter VISAGE_FILTER = new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".visage");
}
};
static final FileFilter JAVA_FILTER = new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".java");
}
};
static void init() throws IOException {
if (Utils.javaExe == null) {
Utils.javaExe = Utils.getJavaExe();
}
if (visageExe == null) {
visageExe = getVisageDistExe("visage");
}
if (visagewExe == null) {
visagewExe = getVisageDistExe("visagew");
}
if (visagecExe == null) {
visagecExe = getVisageDistExe("visagec");
}
if (visagedocExe == null) {
visagedocExe = getVisageDistExe("visagedoc");
}
if (engine == null) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine scrEng = manager.getEngineByName("visage");
if (scrEng instanceof VisageScriptEngine) {
engine = (VisageScriptEngine) scrEng;
} else {
throw new AssertionError("scrEng not instance of VisageSciptEngine");
}
}
if (workingDir == null) {
workingDir = Utils.getTempDirectory();
}
if (!workingDir.exists()) {
workingDir.mkdirs();
}
javaCompiler = ToolProvider.getSystemJavaCompiler();
}
static void reset() {
if (!debug) {
if (workingDir != null && workingDir.exists()) {
try {
Utils.recursiveDelete(workingDir);
} catch (IOException ioe) { /*oh well!*/ }
}
}
}
static void deleteAllFiles() {
deleteJavaFiles();
deleteVisageFiles();
deleteClassFiles();
deleteJarFiles();
}
static void deleteJavaFiles() {
deleteFiles(JAVA_FILTER);
}
static void deleteVisageFiles() {
deleteFiles(VISAGE_FILTER);
}
static void deleteClassFiles() {
deleteFiles(CLASS_FILTER);
}
static void deleteJarFiles() {
deleteFiles(JAR_FILTER);
}
static void deleteFiles(FileFilter filter) {
File[] files = workingDir.listFiles(filter);
for (File f : files) {
f.delete();
}
}
/*
* get the path to where the dist directory lives, we use javac.jar
* and script-api.jar to get the lib path, the parent of which is the
* basedir.
*/
static File getDistDir() throws FileNotFoundException, IOException {
if (distDir != null) {
return distDir;
}
String javaClasspaths[] =
System.getProperty("java.class.path", "").split(File.pathSeparator);
for (String x : javaClasspaths) {
if (x.endsWith("javac.jar")) {
String path = x.substring(0, x.indexOf("lib" +
File.separator + "javac.jar"));
distDir = new File(path, "dist").getAbsoluteFile();
return distDir;
} else if (x.endsWith("script-api.jar")) {
String path = x.substring(0, x.indexOf("lib" +
File.separator + "script-api.jar"));
distDir = new File(path, "dist").getAbsoluteFile();
return distDir;
}
}
throw new IOException("dist dir path could not be determined");
}
/**
* Recursively deletes everything under dir
*/
static void recursiveDelete(File dir) throws IOException {
if (dir.isFile()) {
dir.delete();
} else if (dir.isDirectory()) {
File[] entries = dir.listFiles();
for (int i = 0; i < entries.length; i++) {
if (entries[i].isDirectory()) {
recursiveDelete(entries[i]);
}
entries[i].delete();
}
dir.delete();
}
}
/*
* Gets a temporary clean directory for use
*/
static File getTempDirectory() throws IOException {
File tmpDir = File.createTempFile("versionTest", ".tmp");
if (tmpDir.exists()) {
recursiveDelete(tmpDir);
}
tmpDir.mkdirs();
return tmpDir;
}
/*
* gets the path to the java.exe
*/
static File getJavaExe() {
String javaHome = System.getProperty("java.home");
File jFile = new File(new File(javaHome, "bin"), "java");
if (isWindows) {
jFile = new File(jFile.toString() + ".exe");
}
return jFile;
}
/*
* returns the path to a visage executable, do not
* use .exe extension the method will take care of
* it.
*/
static File getVisageDistExe(String exename) throws IOException {
File exe = new File(new File(getDistDir(), "bin"),
(isWindows) ? exename + ".exe" : exename);
if (!exe.exists()) {
return null;
}
return exe;
}
/*
* Check to see if the expected pattern was obtained, if the expectedString
* is null, simply check if something was returned.
*/
static boolean checkExec(List<String> cmds, String expectedString, boolean match) {
List<String> outputList = doExec(cmds);
if (expectedString == null) {
if (outputList != null) {
return true;
}
} else if (match) {
if (outputList.get(0).matches(expectedString)) {
return true;
}
} else {
if (outputList.get(0).equals(expectedString)) {
return true;
}
}
// oh oh, something went wrong, print diagnostics to aid debugging
System.err.println("Command line:");
for (String x : cmds) {
System.err.print(" " + x);
}
System.err.println("");
System.err.println("Process output:");
for (String x : outputList) {
System.err.println(" " + x);
}
System.err.println("Expected string " + (match ? "match:" : "equals:") +
": " + expectedString);
return false;
}
static boolean verifyArguments(List<String> output, String[] expectedArgs) {
if (expectedArgs.length != output.size()) {
return false;
}
for (int i = 0; i < expectedArgs.length; i++) {
if (!expectedArgs[i].equals(output.get(i))) {
return false;
}
}
return true;
}
static boolean checkExec(List<String> cmds, String... expectedArgs)
throws IOException {
if (!verifyArguments(getArgumentsFromVisage(cmds), expectedArgs)) {
return false;
}
if (!verifyArguments(getArgumentsFromJava(cmds), expectedArgs)) {
return false;
}
if (isWindows) {
if (!verifyArguments(getArgumentsFromJavawVisage(cmds), expectedArgs)) {
return false;
}
if (!verifyArguments(getArgumentsFromJavawJava(cmds), expectedArgs)) {
return false;
}
}
return true;
}
static List<String> doExec(List<String> cmds) {
return doExec(cmds, null, false);
}
/*
* execs a cmd and returns a List representation of the output,
* if a testoutput file is provide that file is read for the programs
* output instead of stdout and stderr.
*/
static List<String> doExec(List<String> cmds, File testOutput,
boolean ignoreExitValue) {
if (debug) {
System.out.println("CWD: " + workingDir);
System.out.println("----Execution args----");
for (String x : cmds) {
System.out.println(x);
}
}
List<String> outputList = new ArrayList<String>();
ProcessBuilder pb = new ProcessBuilder(cmds);
pb = pb.directory(workingDir);
FileReader fr = null;
BufferedReader rdr = null;
try {
pb.redirectErrorStream(true);
Process p = pb.start();
rdr = new BufferedReader(new InputStreamReader(p.getInputStream()));
// note: its a good idea to read the whole stream, half baked
// reads can cause undesired side-effects.
String in = rdr.readLine();
if (debug) {
System.out.println("---output---");
}
while (in != null) {
if (debug) {
System.out.println(in);
}
outputList.add(in);
in = rdr.readLine();
}
p.waitFor();
p.destroy();
if (ignoreExitValue == false && p.exitValue() != 0) {
System.out.println("Error: Unexpected exit value " +
p.exitValue());
return null;
}
if (testOutput != null) {
fr = new FileReader(testOutput);
rdr = new BufferedReader(fr);
outputList.clear();
if (debug) {
System.out.println("---file output---");
}
in = rdr.readLine();
while (in != null) {
if (debug) {
System.out.println(in);
}
outputList.add(in);
in = rdr.readLine();
}
}
return outputList;
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex.getMessage());
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException ioe) {
throw new RuntimeException("Error while closing file " + ioe);
}
}
}
}
/*
* emit our Visage code
*/
static String emitVersionVisage(boolean fullversion) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.print("java.lang.System.out.print(Visage.getProperty(\"");
pw.print((fullversion) ? "visage.runtime.version" : "visage.version");
pw.println("\"));");
pw.println("java.lang.System.out.flush();");
return sw.toString();
}
/*
* Create and compile an Visage file, to get the version string.
* Note: we could use the ScriptEngine, however we would like to make
* sure the launchers (visage and visagec) works!.
*/
static String getVersionPropFromVisage(boolean isFullVersion) throws IOException {
String filename = "Version";
FileWriter fw = new FileWriter(new File(workingDir, filename + ".visage"));
PrintWriter pw = new PrintWriter(fw);
try {
pw.println(emitVersionVisage(isFullVersion));
} finally {
if (pw != null) {
pw.close();
}
if (fw != null) {
fw.close();
}
}
ArrayList<String> cmdsList = new ArrayList<String>();
cmdsList.add(visagecExe.toString());
cmdsList.add(filename + ".visage");
doExec(cmdsList);
cmdsList.clear();
cmdsList.add(visageExe.toString());
cmdsList.add(filename);
List<String> output = doExec(cmdsList);
return output.get(0);
}
/*
* emit our Visage code to print out the arguments, if it is
* javaw launcher then we write to a file.
*/
private static String emitArgsTestVisage(File outFile) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println("public function run(args: String[]) : Void {");
if (outFile != null) {
pw.println("var ps = new java.io.PrintStream(\"" +
outFile.getName() + "\");");
pw.println("java.lang.System.setOut(ps);");
}
pw.println("for (i in args) {");
pw.println("Visage.println(i);");
pw.println("}");
if (outFile != null) {
pw.println("ps.close();");
}
pw.println("}");
return sw.toString();
}
/*
* emit our Java code to print out the arguments, if it is
* javaw launcher we write to a file.
*/
private static String emitArgsTestJava(String classname, File outFile) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println("public class " + classname + " {");
pw.println("public static void main(String[] args) throws Exception {");
if (outFile != null) {
pw.println("java.io.PrintStream ps = new java.io.PrintStream(\"" +
outFile.getName() + "\");");
pw.println("System.setOut(ps);");
}
pw.println("for (String x : args) {");
pw.println("System.out.println(x);");
pw.println("}");
if (outFile != null) {
pw.println("ps.close();");
}
pw.println("}");
pw.println("}");
return sw.toString();
}
static String emitPropsTestJava(String classname, File outFile) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
if (outFile != null) {
pw.println("var ps = new java.io.PrintStream(\"" +
outFile.getName() + "\");");
pw.println("java.lang.System.setOut(ps);");
}
pw.println("Visage.println(\"SYSTEM-PROPERTIES-START\");");
pw.println("Visage.println(java.lang.System.getProperties());");
pw.println("Visage.println(\"SYSTEM-PROPERTIES-END\");");
if (outFile != null) {
pw.println("ps.close();");
}
return sw.toString();
}
/* NOTE:
* usage args = "-cp" | "-classpath", "jar-file", "main-class", "app-args....."
* OR
* usage args = "-jar", "jar-file", "app-args....."
*/
private static List<String> getArgumentsFromLauncher(List<String> cmdsList,
boolean useVisage, boolean usevisagew) throws IOException {
File testOutput = null ;
if (usevisagew) {
testOutput = new File(workingDir, "output.log");
if (testOutput.exists()) {
if (!testOutput.delete()) {
throw new RuntimeException("Could not delete file " +
testOutput.getAbsolutePath());
}
}
}
if (useVisage) {
createVisageJar(new File(workingDir, cmdsList.get(1)), testOutput);
} else {
createJavaJar(new File(workingDir, cmdsList.get(1)), testOutput);
}
ArrayList<String> execList = new ArrayList<String>();
execList.add(0, (usevisagew)
? visagewExe.toString()
: visageExe.toString()
);
execList.addAll(cmdsList);
return doExec(execList, testOutput, false);
}
private static List<String> getArgumentsFromVisage(List<String> cmdsList)
throws IOException {
return getArgumentsFromLauncher(cmdsList, true, false);
}
private static List<String> getArgumentsFromJava(List<String> cmdsList)
throws IOException {
return getArgumentsFromLauncher(cmdsList, false, false);
}
private static List<String> getArgumentsFromJavawVisage(List<String> cmdsList)
throws IOException {
return getArgumentsFromLauncher(cmdsList, true, true);
}
private static List<String> getArgumentsFromJavawJava(List<String> cmdsList)
throws IOException {
return getArgumentsFromLauncher(cmdsList, false, true);
}
private static void createVisageJar(File jarFilename, File testOutput) throws IOException {
createJar(true, jarFilename, testOutput);
}
private static void createJavaJar(File jarFilename, File testOutput) throws IOException {
createJar(false, jarFilename, testOutput);
}
static void createVisageJar(File jarFilename, String testSrc) throws IOException {
String filename = null;
String jarfilename = jarFilename.getName();
if (!jarfilename.endsWith(".jar")) {
throw new RuntimeException("jarFilename: does not end with .jar");
} else {
filename = jarfilename.substring(0, jarfilename.indexOf(".jar"));
}
// delete any stray files lying around
deleteAllFiles();
PrintStream ps = new PrintStream(new FileOutputStream(
new File(workingDir, filename + ".visage")));
ps.println(testSrc);
ps.close();
ArrayList<String> cmdsList = new ArrayList<String>();
cmdsList.add(visagecExe.toString());
cmdsList.add(filename + ".visage");
List<String> visagecList = doExec(cmdsList);
if (visagecList == null) {
throw new RuntimeException("Visage compilation failed " + filename + ".java");
}
String jarArgs[] = {
(debug) ? "cvfe" : "cfe",
jarFilename.getAbsolutePath(),
filename,
"-C",
workingDir.getAbsolutePath(),
"."
};
sun.tools.jar.Main jarTool =
new sun.tools.jar.Main(System.out, System.err, "JarCreator");
if (!jarTool.run(jarArgs)) {
throw new RuntimeException("jar creation failed " + jarFilename);
}
// delete left over class files
deleteClassFiles();
}
private static void createJar(boolean isVisage, File jarFilename, File testOutput) throws IOException {
String filename = null;
String jarfilename = jarFilename.getName();
if (!jarfilename.endsWith(".jar")) {
throw new RuntimeException("jarFilename: does not end with .jar");
} else {
filename = jarfilename.substring(0, jarfilename.indexOf(".jar"));
}
// delete any stray files lying around
deleteAllFiles();
if (isVisage) {
PrintStream ps = new PrintStream(new FileOutputStream(
new File(workingDir, filename + ".visage")));
ps.println(emitArgsTestVisage(testOutput));
ps.close();
ArrayList<String> cmdsList = new ArrayList<String>();
cmdsList.add(visagecExe.toString());
cmdsList.add(filename + ".visage");
List<String> visagecList = doExec(cmdsList);
if (visagecList == null) {
throw new RuntimeException("Visage compilation failed " + filename + ".java");
}
} else {
File javaFile = new File(workingDir, filename + ".java");
PrintStream ps = new PrintStream(new FileOutputStream(javaFile));
ps.println(emitArgsTestJava(filename, testOutput));
ps.close();
String compileArgs[] = {
"-d",
workingDir.getAbsolutePath(),
javaFile.getAbsolutePath()
};
if (javaCompiler.run(null, null, null, compileArgs) != 0) {
throw new RuntimeException("Java compilation failed " + filename + ".java");
}
}
String jarArgs[] = {
(debug) ? "cvfe" : "cfe",
jarFilename.getAbsolutePath(),
filename,
"-C",
workingDir.getAbsolutePath(),
"."
};
sun.tools.jar.Main jarTool =
new sun.tools.jar.Main(System.out, System.err, "JarCreator");
if (!jarTool.run(jarArgs)) {
throw new RuntimeException("jar creation failed " + jarFilename);
}
// delete left over class files
deleteClassFiles();
}
/*
* creates a file in the test working directory
*/
static void createFile(String outfileName, String contents) throws IOException {
PrintStream ps = new PrintStream(new FileOutputStream(
new File(workingDir, outfileName)));
ps.print(contents);
ps.close();
}
}