/*
* Copyright 2016 Nabarun Mondal
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.noga.njexl.lang;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
/**
* Helper class to test GC / reference interactions.
* Dynamically creates a class by compiling generated source Java code and
* load it through a dedicated class loader.
*/
public class ClassCreator {
private final JexlEngine jexl;
private final File base;
private File packageDir = null;
private int seed = 0;
private String className = null;
private String sourceName = null;
private ClassLoader loader = null;
public static final boolean canRun = comSunToolsJavacMain();
/**
* Check if we can invoke Sun's java compiler.
* @return true if it is possible, false otherwise
*/
private static boolean comSunToolsJavacMain() {
try {
Class<?> javac = ClassCreatorTest.class.getClassLoader().loadClass("com.sun.tools.javac.Main");
return javac != null;
} catch (Exception xany) {
return false;
}
}
public ClassCreator(JexlEngine theJexl, File theBase) throws Exception {
jexl = theJexl;
base = theBase;
}
public void clear() {
seed = 0;
packageDir = null;
className = null;
sourceName = null;
packageDir = null;
loader = null;
}
public void setSeed(int s) {
seed = s;
className = "foo" + s;
sourceName = className + ".java";
packageDir = new File(base, seed + "/org/apache/commons/jexl2/generated");
packageDir.mkdirs();
loader = null;
}
public String getClassName() {
return "noga.commons.njexl.generated." + className;
}
public Class<?> getClassInstance() throws Exception {
return getClassLoader().loadClass("noga.commons.njexl.generated." + className);
}
public ClassLoader getClassLoader() throws Exception {
if (loader == null) {
URL classpath = (new File(base, Integer.toString(seed))).toURI().toURL();
loader = new URLClassLoader(new URL[]{classpath}, null);
}
return loader;
}
public Class<?> createClass() throws Exception {
// generate, compile & validate
generate();
Class<?> clazz = compile();
if (clazz == null) {
throw new Exception("failed to compile foo" + seed);
}
Object v = validate(clazz);
if (v instanceof Integer && ((Integer) v).intValue() == seed) {
return clazz;
}
throw new Exception("failed to validate foo" + seed);
}
void generate() throws Exception {
FileWriter aWriter = new FileWriter(new File(packageDir, sourceName), false);
aWriter.write("package noga.commons.njexl.generated;");
aWriter.write("public class " + className + "{\n");
aWriter.write("private int value =");
aWriter.write(Integer.toString(seed));
aWriter.write(";\n");
aWriter.write(" public void setValue(int v) {");
aWriter.write(" value = v;");
aWriter.write(" }\n");
aWriter.write(" public int getValue() {");
aWriter.write(" return value;");
aWriter.write(" }\n");
aWriter.write(" }\n");
aWriter.flush();
aWriter.close();
}
Class<?> compile() throws Exception {
String source = packageDir.getPath() + "/" + sourceName;
Class<?> javac = getClassLoader().loadClass("com.sun.tools.javac.Main");
if (javac == null) {
return null;
}
Integer r = (Integer) jexl.invokeMethod(javac, "compile", source);
if (r.intValue() >= 0) {
return getClassLoader().loadClass("noga.commons.njexl.generated." + className);
}
return null;
}
Object validate(Class<?> clazz) throws Exception {
Class<?> params[] = {};
Object paramsObj[] = {};
Object iClass = clazz.newInstance();
Method thisMethod = clazz.getDeclaredMethod("getValue", params);
return thisMethod.invoke(iClass, paramsObj);
}
}