package com.mindprod.example;
import com.mindprod.hunkio.HunkIO;
import com.sun.tools.javac.Main;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import static java.lang.System.out;
/**
* interface that our on-the-fly compiled classes must implement.
*/
interface Calculator
{
/**
* do some sort of calculation on two doubles.
*
* @param a first parameter
* @param b second parameter
*
* @return result of custom calculation
*/
@SuppressWarnings({ "SameParameterValue" })
public double calc( double a, double b );
/**
* get timestamp when compiled.
*
* @return the timestamp when the program was compiled.
*/
public Date whenCompiled();
}
/**
* Demonstrate generating Java source code on the fly, compiling item and executing item.
* <p/>
* ^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V<br>
* V E R Y _ I M P O R T A N T !<br>
* You MUST have F:\Program Files\java\jdk_1.7.0\lib\tools.jar from the JDK
* or similar on the path both to compile and run com.sun.tools.javac.Main.<br>
* The current directory when you execute MUST be E:\com\mindprod\example <br>
* E:\ MUST be on the classpath.<br>
* ^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V^V<br>
*
* @author Roedy Green, Canadian Mind Products
* @version 1.0 2006-02-04
* @since 2006-02-04
*/
public final class TestOnTheFly
{
/**
* Compile from within this JVM without spawning javac.exe or a separate JVM com.sun.tools.javac.Main lives in
* tools.jar Make sure J:\Program Files\Java\jdk1.7.0\lib\tools.jar is on the classpath. It won't be by default.
* <p/>
* THE JAVAC.MAIN TECHNIQUE USED IN THIS PROGRAM IS BOTH UNDOCUMENTED AND DEPRECATED!!!
* Normally you would use javax.tools.JavaCompiler instead, the way TestJavaCompiler does as
* described in http://mindprod.com/jgloss/javacompiler.html
*
* @param className name of the class to compile.
* @param programText source code text.
*
* @return status of the compile.
* @throws java.io.IOException on I/O failure.
* @see TestJavaCompiler
*/
@SuppressWarnings({ "SameParameterValue" })
private static int compile( String className,
String programText ) throws IOException
{
HunkIO.writeEntireFile( new File( className + ".java" ),
programText,
HunkIO.ISO88591 );
String[] optionsAndSources =
{ "-source", "1.5", "-target", "1.5", className + ".java" };
PrintWriter listing = new PrintWriter( System.out, false );
return Main.compile( optionsAndSources, listing );
}
/**
* Generate source for sample Java program on the fly.
*
* @param className name of class you want to generate
* @param expression a an expression involving a and/or b you want to calculate.
*
* @return text of an on-the-fly composed Java class.
*/
@SuppressWarnings({ "SameParameterValue" })
private static String composeAProgram( String className,
String expression )
{
final StringBuilder sb = new StringBuilder( 1000 );
sb.append( "package com.mindprod.example;import static java.lang.System.out;import static java.lang.System.err;\n" );
sb.append( "import java.util.Date;\n" );
sb.append( "public final class " );
sb.append( className );
sb.append( " implements Calculator\n" );
sb.append( "{\n" );
sb.append( "public double calc( double a, double b )\n" );
sb.append( " {\n" );
sb.append( " return " );
sb.append( expression );
sb.append( ";\n" );
sb.append( " }\n" );
sb.append( "public Date whenCompiled()\n" );
sb.append( " {\n" );
sb.append( " return new Date(" );
sb.append( System.currentTimeMillis() );
sb.append( "L);\n" );
sb.append( " }\n" );
sb.append( "}\n" );
return sb.toString();
}
/**
* Generate a program on the fly, compile it, and execute it.
*
* @param args not used
*
* @throws java.io.IOException on I/O failure.
* @throws ClassNotFoundException If can't find generated class files to execute.
* @throws IllegalAccessException if try to illegally access files.
* @throws InstantiationException if can't create instance of new class.
*/
public static void main( String[] args ) throws
IOException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException
{
String programText =
composeAProgram( "Hypotenuse", "Math.sqrt( a*a + b*b )" );
out.println( programText );
int status = compile( "Hypotenuse", programText );
out.println( "status of compile: " + status );
Calculator calculator =
( Calculator ) Class.forName( "com.mindprod.example.Hypotenuse" )
.newInstance();
out.println( "Hypotenuse.calc( 3, 4 ) is : "
+ calculator.calc( 3.0, 4.0 ) );
out.println( "compiled on: " + calculator.whenCompiled() );
}
}