/** * Given the name of an interface <engineInterface> that a user wants to use for an engine, as * well as the name of a class <vmClass> that represents the vm, this does the following: * * <p>1. Checks that the given vm supports the interface. 2. Builds an engine and returns it. */ public static FluidEngine buildEngine(String engineInterface, String vmClass) { // get class for <engineInterface> Class cEngine = null; try { cEngine = Class.forName(engineInterface); } catch (Exception e) { System.err.println("Could not find engine interface " + cEngine); e.printStackTrace(); System.exit(1); } // get class for <vmClass> Class cVM = null; try { cVM = Class.forName(vmClass); } catch (Exception e) { System.err.println("Could not find VM " + cEngine); e.printStackTrace(); System.exit(1); } // make a VM VM vm = null; try { vm = (VM) cVM.newInstance(); } catch (Exception e) { System.err.println("Could not instantiate VM " + cEngine); e.printStackTrace(); System.exit(1); } // check that the VM implements the interface VMUtils.checkInterface(cVM, cEngine); // build a version of the engine interface that calls back to // this basic engine for all its native methods BasicEngine result = buildCallbackEngine(engineInterface, cEngine); // do the setup for the resulting engine result.setup(vm); return result; }
/** * Given class of the interface for a fluid engine, build a concrete instance of that interface * that calls back into a Basic Engine for all methods in the interface. */ private static BasicEngine buildCallbackEngine(String engineInterface, Class cEngine) { // build up list of callbacks for <engineInterface> StringBuffer decls = new StringBuffer(); Method[] engineMethods = cEngine.getMethods(); for (int i = 0; i < engineMethods.length; i++) { Method meth = engineMethods[i]; // skip methods that aren't declared in the interface if (meth.getDeclaringClass() != cEngine) { continue; } decls.append( " public " + Utils.asTypeDecl(meth.getReturnType()) + " " + meth.getName() + "("); Class[] params = meth.getParameterTypes(); for (int j = 0; j < params.length; j++) { decls.append(Utils.asTypeDecl(params[j]) + " p" + j); if (j != params.length - 1) { decls.append(", "); } } decls.append(") {\n"); decls.append( " return (" + Utils.asTypeDecl(meth.getReturnType()) + ")super.callNative(\"" + meth.getName() + "\", new Object[] {"); for (int j = 0; j < params.length; j++) { decls.append("p" + j); if (j != params.length - 1) { decls.append(", "); } } decls.append("} );\n"); decls.append(" }\n\n"); } // write template file String engineName = "BasicEngine_" + engineInterface; String fileName = engineName + ".java"; try { String contents = Utils.readFile("lava/engine/basic/BasicEngineTemplate.java").toString(); // remove package name contents = Utils.replaceAll(contents, "package lava.engine.basic;", ""); // for class decl contents = Utils.replaceAll( contents, "extends BasicEngine", "extends BasicEngine implements " + engineInterface); // for constructor contents = Utils.replaceAll(contents, "BasicEngineTemplate", engineName); // for methods contents = Utils.replaceAll(contents, "// INSERT METHODS HERE", decls.toString()); Utils.writeFile(fileName, contents); } catch (IOException e) { e.printStackTrace(); System.exit(1); } // compile the file try { Process jProcess = Runtime.getRuntime().exec("jikes " + fileName, null, null); jProcess.waitFor(); } catch (Exception e) { System.err.println("Error compiling auto-generated file " + fileName); e.printStackTrace(); System.exit(1); } // instantiate the class BasicEngine result = null; try { result = (BasicEngine) Class.forName(engineName).newInstance(); // cleanup the files we made new File(engineName + ".java").delete(); new File(engineName + ".class").delete(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } return result; }