package iotpolicy; import java_cup.runtime.ComplexSymbolFactory; import java_cup.runtime.ScannerBuffer; import java.io.*; import java.util.Arrays; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import iotpolicy.parser.Lexer; import iotpolicy.parser.Parser; import iotpolicy.tree.ParseNode; import iotpolicy.tree.ParseNodeVector; import iotpolicy.tree.ParseTreeHandler; import iotpolicy.tree.Declaration; import iotpolicy.tree.DeclarationHandler; import iotpolicy.tree.CapabilityDecl; import iotpolicy.tree.InterfaceDecl; import iotpolicy.tree.RequiresDecl; import iotpolicy.tree.EnumDecl; import iotpolicy.tree.StructDecl; import iotrmi.Java.IoTRMITypes; /** Class IoTCompiler is the main interface/stub compiler for * files generation. This class calls helper classes * such as Parser, Lexer, InterfaceDecl, CapabilityDecl, * RequiresDecl, ParseTreeHandler, etc. * * @author Rahmadi Trimananda * @version 1.0 * @since 2016-09-22 */ public class IoTCompiler { /** * Class properties */ // Maps multiple interfaces to multiple objects of ParseTreeHandler private Map mapIntfacePTH; private Map mapIntDeclHand; private Map>> mapInt2NewInts; // Data structure to store our types (primitives and non-primitives) for compilation private Map mapPrimitives; private Map mapNonPrimitivesJava; private Map mapNonPrimitivesCplus; // Other data structures private Map mapIntfaceObjId; // Maps interface name to object Id private Map mapNewIntfaceObjId; // Maps new interface name to its object Id (keep track of stubs) private PrintWriter pw; private String dir; private String subdir; /** * Class constants */ private final static String OUTPUT_DIRECTORY = "output_files"; private enum ParamCategory { PRIMITIVES, // All the primitive types, e.g. byte, short, int, long, etc. NONPRIMITIVES, // Non-primitive types, e.g. Set, Map, List, etc. ENUM, // Enum type STRUCT, // Struct type USERDEFINED // Assumed as driver classes } /** * Class constructors */ public IoTCompiler() { mapIntfacePTH = new HashMap(); mapIntDeclHand = new HashMap(); mapInt2NewInts = new HashMap>>(); mapIntfaceObjId = new HashMap(); mapNewIntfaceObjId = new HashMap(); mapPrimitives = new HashMap(); arraysToMap(mapPrimitives, IoTRMITypes.primitivesJava, IoTRMITypes.primitivesCplus); mapNonPrimitivesJava = new HashMap(); arraysToMap(mapNonPrimitivesJava, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitiveJavaLibs); mapNonPrimitivesCplus = new HashMap(); arraysToMap(mapNonPrimitivesCplus, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitivesCplus); pw = null; dir = OUTPUT_DIRECTORY; subdir = null; } /** * setDataStructures() sets parse tree and other data structures based on policy files. *

* It also generates parse tree (ParseTreeHandler) and * copies useful information from parse tree into * InterfaceDecl, CapabilityDecl, and RequiresDecl * data structures. * Additionally, the data structure handles are * returned from tree-parsing for further process. */ public void setDataStructures(String origInt, ParseNode pnPol, ParseNode pnReq) { ParseTreeHandler ptHandler = new ParseTreeHandler(origInt, pnPol, pnReq); DeclarationHandler decHandler = new DeclarationHandler(); // Process ParseNode and generate Declaration objects // Interface ptHandler.processInterfaceDecl(); InterfaceDecl intDecl = ptHandler.getInterfaceDecl(); decHandler.addInterfaceDecl(origInt, intDecl); // Capabilities ptHandler.processCapabilityDecl(); CapabilityDecl capDecl = ptHandler.getCapabilityDecl(); decHandler.addCapabilityDecl(origInt, capDecl); // Requires ptHandler.processRequiresDecl(); RequiresDecl reqDecl = ptHandler.getRequiresDecl(); decHandler.addRequiresDecl(origInt, reqDecl); // Enumeration ptHandler.processEnumDecl(); EnumDecl enumDecl = ptHandler.getEnumDecl(); decHandler.addEnumDecl(origInt, enumDecl); // Struct ptHandler.processStructDecl(); StructDecl structDecl = ptHandler.getStructDecl(); decHandler.addStructDecl(origInt, structDecl); mapIntfacePTH.put(origInt, ptHandler); mapIntDeclHand.put(origInt, decHandler); // Set object Id counter to 0 for each interface mapIntfaceObjId.put(origInt, new Integer(0)); } /** * getMethodsForIntface() reads for methods in the data structure *

* It is going to give list of methods for a certain interface * based on the declaration of capabilities. */ public void getMethodsForIntface(String origInt) { ParseTreeHandler ptHandler = mapIntfacePTH.get(origInt); Map> mapNewIntMethods = new HashMap>(); // Get set of new interfaces, e.g. CameraWithCaptureAndData // Generate this new interface with all the methods it needs // from different capabilities it declares DeclarationHandler decHandler = mapIntDeclHand.get(origInt); RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(origInt); Set setIntfaces = reqDecl.getInterfaces(); for (String strInt : setIntfaces) { // Initialize a set of methods Set setMethods = new HashSet(); // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc. List listCapab = reqDecl.getCapabList(strInt); for (String strCap : listCapab) { // Get list of methods for each capability CapabilityDecl capDecl = (CapabilityDecl) decHandler.getCapabilityDecl(origInt); List listCapabMeth = capDecl.getMethods(strCap); for (String strMeth : listCapabMeth) { // Add methods into setMethods // This is to also handle redundancies (say two capabilities // share the same methods) setMethods.add(strMeth); } } // Add interface and methods information into map mapNewIntMethods.put(strInt, setMethods); } // Map the map of interface-methods to the original interface mapInt2NewInts.put(origInt, mapNewIntMethods); } /** * HELPER: writeMethodJavaLocalInterface() writes the method of the local interface */ private void writeMethodJavaLocalInterface(Collection methods, InterfaceDecl intDecl) { for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); print("public " + intDecl.getMethodType(method) + " " + intDecl.getMethodId(method) + "("); for (int i = 0; i < methParams.size(); i++) { // Check for params with driver class types and exchange it // with its remote interface String paramType = checkAndGetParamClass(methPrmTypes.get(i)); print(paramType + " " + methParams.get(i)); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(");"); } } /** * HELPER: writeMethodJavaInterface() writes the method of the interface */ private void writeMethodJavaInterface(Collection methods, InterfaceDecl intDecl) { for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); print("public " + intDecl.getMethodType(method) + " " + intDecl.getMethodId(method) + "("); for (int i = 0; i < methParams.size(); i++) { // Check for params with driver class types and exchange it // with its remote interface String paramType = methPrmTypes.get(i); print(paramType + " " + methParams.get(i)); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(");"); } } /** * HELPER: generateEnumJava() writes the enumeration declaration */ private void generateEnumJava() throws IOException { // Create a new directory createDirectory(dir); for (String intface : mapIntfacePTH.keySet()) { // Get the right EnumDecl DeclarationHandler decHandler = mapIntDeclHand.get(intface); EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface); Set enumTypes = enumDecl.getEnumDeclarations(); // Iterate over enum declarations for (String enType : enumTypes) { // Open a new file to write into FileWriter fw = new FileWriter(dir + "/" + enType + ".java"); pw = new PrintWriter(new BufferedWriter(fw)); println("public enum " + enType + " {"); List enumMembers = enumDecl.getMembers(enType); for (int i = 0; i < enumMembers.size(); i++) { String member = enumMembers.get(i); print(member); // Check if this is the last element (don't print a comma) if (i != enumMembers.size() - 1) println(","); else println(""); } println("}\n"); pw.close(); System.out.println("IoTCompiler: Generated enum class " + enType + ".java..."); } } } /** * HELPER: generateStructJava() writes the struct declaration */ private void generateStructJava() throws IOException { // Create a new directory createDirectory(dir); for (String intface : mapIntfacePTH.keySet()) { // Get the right StructDecl DeclarationHandler decHandler = mapIntDeclHand.get(intface); StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface); List structTypes = structDecl.getStructTypes(); // Iterate over enum declarations for (String stType : structTypes) { // Open a new file to write into FileWriter fw = new FileWriter(dir + "/" + stType + ".java"); pw = new PrintWriter(new BufferedWriter(fw)); println("public class " + stType + " {"); List structMemberTypes = structDecl.getMemberTypes(stType); List structMembers = structDecl.getMembers(stType); for (int i = 0; i < structMembers.size(); i++) { String memberType = structMemberTypes.get(i); String member = structMembers.get(i); println("public static " + memberType + " " + member + ";"); } println("}\n"); pw.close(); System.out.println("IoTCompiler: Generated struct class " + stType + ".java..."); } } } /** * generateJavaLocalInterface() writes the local interface and provides type-checking. *

* It needs to rewrite and exchange USERDEFINED types in input parameters of stub * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording. * The local interface has to be the input parameter for the stub and the stub * interface has to be the input parameter for the local class. */ public void generateJavaLocalInterfaces() throws IOException { // Create a new directory createDirectory(dir); for (String intface : mapIntfacePTH.keySet()) { // Open a new file to write into FileWriter fw = new FileWriter(dir + "/" + intface + ".java"); pw = new PrintWriter(new BufferedWriter(fw)); // Pass in set of methods and get import classes DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); List methods = intDecl.getMethods(); Set importClasses = getImportClasses(methods, intDecl); List stdImportClasses = getStandardJavaIntfaceImportClasses(); List allImportClasses = getAllLibClasses(stdImportClasses, importClasses); printImportStatements(allImportClasses); // Write interface header println(""); println("public interface " + intface + " {"); // Write methods writeMethodJavaLocalInterface(methods, intDecl); println("}"); pw.close(); System.out.println("IoTCompiler: Generated local interface " + intface + ".java..."); } } /** * generateJavaInterfaces() generate stub interfaces based on the methods list in Java */ public void generateJavaInterfaces() throws IOException { // Create a new directory String path = createDirectories(dir, subdir); for (String intface : mapIntfacePTH.keySet()) { Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { // Open a new file to write into String newIntface = intMeth.getKey(); FileWriter fw = new FileWriter(path + "/" + newIntface + ".java"); pw = new PrintWriter(new BufferedWriter(fw)); DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); // Pass in set of methods and get import classes List methods = intDecl.getMethods(); Set importClasses = getImportClasses(methods, intDecl); List stdImportClasses = getStandardJavaIntfaceImportClasses(); List allImportClasses = getAllLibClasses(stdImportClasses, importClasses); printImportStatements(allImportClasses); // Write interface header println(""); println("public interface " + newIntface + " {\n"); // Write methods writeMethodJavaInterface(methods, intDecl); println("}"); pw.close(); System.out.println("IoTCompiler: Generated interface " + newIntface + ".java..."); } } } /** * HELPER: writePropertiesJavaPermission() writes the permission in properties */ private void writePropertiesJavaPermission(String intface, InterfaceDecl intDecl) { Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { String newIntface = intMeth.getKey(); int newObjectId = getNewIntfaceObjectId(newIntface); println("private final static int object" + newObjectId + "Id = " + newObjectId + ";\t//" + newIntface); Set methodIds = intMeth.getValue(); print("private static Integer[] object" + newObjectId + "Permission = { "); int i = 0; for (String methodId : methodIds) { int methodNumId = intDecl.getMethodNumId(methodId); print(Integer.toString(methodNumId)); // Check if this is the last element (don't print a comma) if (i != methodIds.size() - 1) { print(", "); } i++; } println(" };"); println("private List set" + newObjectId + "Allowed;"); } } /** * HELPER: writePropertiesJavaStub() writes the properties of the stub class */ private void writePropertiesJavaStub(String intface, String newIntface, boolean callbackExist, Set callbackClasses) { println("private IoTRMICall rmiCall;"); println("private String address;"); println("private int[] ports;\n"); // Get the object Id Integer objId = mapIntfaceObjId.get(intface); println("private final static int objectId = " + objId + ";"); mapNewIntfaceObjId.put(newIntface, objId); mapIntfaceObjId.put(intface, objId++); if (callbackExist) { // We assume that each class only has one callback interface for now Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); println("// Callback properties"); println("private IoTRMIObject rmiObj;"); println("List<" + callbackType + "> listCallbackObj;"); println("private static int objIdCnt = 0;"); // Generate permission stuff for callback stubs DeclarationHandler decHandler = mapIntDeclHand.get(callbackType); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(callbackType); writePropertiesJavaPermission(callbackType, intDecl); } println("\n"); } /** * HELPER: writeConstructorJavaPermission() writes the permission in constructor */ private void writeConstructorJavaPermission(String intface) { Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { String newIntface = intMeth.getKey(); int newObjectId = getNewIntfaceObjectId(newIntface); println("set" + newObjectId + "Allowed = Arrays.asList(object" + newObjectId +"Permission);"); } } /** * HELPER: writeConstructorJavaStub() writes the constructor of the stub class */ private void writeConstructorJavaStub(String intface, String newStubClass, boolean callbackExist, Set callbackClasses) { println("public " + newStubClass + "(int _port, String _address, int _rev, int[] _ports) throws Exception {"); println("address = _address;"); println("ports = _ports;"); println("rmiCall = new IoTRMICall(_port, _address, _rev);"); if (callbackExist) { Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); writeConstructorJavaPermission(intface); println("listCallbackObj = new ArrayList<" + callbackType + ">();"); println("___initCallBack();"); } println("}\n"); } /** * HELPER: writeJavaMethodCallbackPermission() writes permission checks in stub for callbacks */ private void writeJavaMethodCallbackPermission(String intface) { println("int methodId = IoTRMIObject.getMethodId(method);"); // Get all the different stubs Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { String newIntface = intMeth.getKey(); int newObjectId = getNewIntfaceObjectId(newIntface); println("if (!set" + newObjectId + "Allowed.contains(methodId)) {"); println("throw new Error(\"Callback object for " + intface + " is not allowed to access method: \" + methodId);"); println("}"); } } /** * HELPER: writeInitCallbackJavaStub() writes callback initialization in stub */ private void writeInitCallbackJavaStub(String intface, InterfaceDecl intDecl) { println("public void ___initCallBack() {"); // Generate main thread for callbacks println("Thread thread = new Thread() {"); println("public void run() {"); println("try {"); println("rmiObj = new IoTRMIObject(ports[0]);"); println("while (true) {"); println("byte[] method = rmiObj.getMethodBytes();"); writeJavaMethodCallbackPermission(intface); println("int objId = IoTRMIObject.getObjectId(method);"); println(intface + "_CallbackSkeleton skel = (" + intface + "_CallbackSkeleton) listCallbackObj.get(objId);"); println("if (skel != null) {"); println("skel.invokeMethod(rmiObj);"); println("} else {"); println("throw new Error(\"" + intface + ": Object with Id \" + objId + \" not found!\");"); println("}"); println("}"); println("} catch (Exception ex) {"); println("ex.printStackTrace();"); println("throw new Error(\"Error instantiating class " + intface + "_CallbackSkeleton!\");"); println("}"); println("}"); println("};"); println("thread.start();\n"); // Generate info sending part String method = "___initCallBack()"; println("int methodId = " + intDecl.getHelperMethodNumId(method) + ";"); println("Class retType = void.class;"); println("Class[] paramCls = new Class[] { int.class, String.class, int.class };"); println("Object[] paramObj = new Object[] { ports[0], address, 0 };"); println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);"); println("}\n"); } /** * HELPER: checkAndWriteEnumTypeJavaStub() writes the enum type (convert from enum to int) */ private void checkAndWriteEnumTypeJavaStub(List methParams, List methPrmTypes) { // Iterate and find enum declarations for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isEnumClass(simpleType)) { // Check if this is enum type if (isArray(param)) { // An array println("int len" + i + " = " + param + ".length;"); println("int paramEnum" + i + "[] = new int[len];"); println("for (int i = 0; i < len" + i + "; i++) {"); println("paramEnum" + i + "[i] = " + param + "[i].ordinal();"); println("}"); } else if (isList(paramType)) { // A list println("int len" + i + " = " + param + ".size();"); println("int paramEnum" + i + "[] = new int[len];"); println("for (int i = 0; i < len" + i + "; i++) {"); println("paramEnum" + i + "[i] = " + param + ".get(i).ordinal();"); println("}"); } else { // Just one element println("int paramEnum" + i + "[] = new int[1];"); println("paramEnum" + i + "[0] = " + param + ".ordinal();"); } } } } /** * HELPER: checkAndWriteEnumRetTypeJavaStub() writes the enum return type (convert from enum to int) */ private void checkAndWriteEnumRetTypeJavaStub(String retType) { // Strips off array "[]" for return type String pureType = getSimpleArrayType(getSimpleType(retType)); // Take the inner type of generic if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) pureType = getTypeOfGeneric(retType)[0]; if (isEnumClass(pureType)) { // Check if this is enum type // Enum decoder println("int[] retEnum = (int[]) retObj;"); println(pureType + "[] enumVals = " + pureType + ".values();"); if (isArray(retType)) { // An array println("int retLen = retEnum.length;"); println(pureType + "[] enumRetVal = new " + pureType + "[retLen];"); println("for (int i = 0; i < retLen; i++) {"); println("enumRetVal[i] = enumVals[retEnum[i]];"); println("}"); } else if (isList(retType)) { // A list println("int retLen = retEnum.length;"); println("List<" + pureType + "> enumRetVal = new ArrayList<" + pureType + ">();"); println("for (int i = 0; i < retLen; i++) {"); println("enumRetVal.add(enumVals[retEnum[i]]);"); println("}"); } else { // Just one element println(pureType + " enumRetVal = enumVals[retEnum[0]];"); } println("return enumRetVal;"); } } /** * HELPER: checkAndWriteStructSetupJavaStub() writes the struct type setup */ private void checkAndWriteStructSetupJavaStub(List methParams, List methPrmTypes, InterfaceDecl intDecl, String method) { // Iterate and find struct declarations for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { // Check if this is enum type int methodNumId = intDecl.getMethodNumId(method); String helperMethod = methodNumId + "struct" + i; println("int methodIdStruct" + i + " = " + intDecl.getHelperMethodNumId(helperMethod) + ";"); println("Class retTypeStruct" + i + " = void.class;"); println("Class[] paramClsStruct" + i + " = new Class[] { int.class };"); if (isArray(param)) { // An array println("Object[] paramObjStruct" + i + " = new Object[] { " + getSimpleArrayType(param) + ".length };"); } else if (isList(paramType)) { // A list println("Object[] paramObjStruct" + i + " = new Object[] { " + getSimpleArrayType(param) + ".size() };"); } else { // Just one element println("Object[] paramObjStruct" + i + " = new Object[] { new Integer(1) };"); } println("rmiCall.remoteCall(objectId, methodIdStruct" + i + ", retTypeStruct" + i + ", null, paramClsStruct" + i + ", paramObjStruct" + i + ");\n"); } } } /** * HELPER: isStructPresent() checks presence of struct */ private boolean isStructPresent(List methParams, List methPrmTypes) { // Iterate and find enum declarations for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) return true; } return false; } /** * HELPER: writeLengthStructParamClassJavaStub() writes lengths of parameters */ private void writeLengthStructParamClassJavaStub(List methParams, List methPrmTypes) { // Iterate and find struct declarations - count number of params for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getGenericType(paramType); if (isStructClass(simpleType)) { int members = getNumOfMembers(simpleType); if (isArray(param)) { // An array String structLen = param + ".length"; print(members + "*" + structLen); } else if (isList(paramType)) { // A list String structLen = param + ".size()"; print(members + "*" + structLen); } else print(Integer.toString(members)); } else print("1"); if (i != methParams.size() - 1) { print("+"); } } } /** * HELPER: writeStructMembersJavaStub() writes parameters of struct */ private void writeStructMembersJavaStub(String simpleType, String paramType, String param) { // Get the struct declaration for this struct and generate initialization code StructDecl structDecl = getStructDecl(simpleType); List memTypes = structDecl.getMemberTypes(simpleType); List members = structDecl.getMembers(simpleType); if (isArray(param)) { // An array println("for(int i = 0; i < " + param + ".length; i++) {"); } else if (isList(paramType)) { // A list println("for(int i = 0; i < " + param + ".size(); i++) {"); } if (isArrayOrList(param, paramType)) { // An array or list for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;"); print("paramObj[pos++] = " + param + "[i]."); print(getSimpleIdentifier(members.get(i))); println(";"); } println("}"); } else { // Just one struct element for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;"); print("paramObj[pos++] = " + param + "."); print(getSimpleIdentifier(members.get(i))); println(";"); } } } /** * HELPER: writeStructParamClassJavaStub() writes parameters if struct is present */ private void writeStructParamClassJavaStub(List methParams, List methPrmTypes) { print("int paramLen = "); writeLengthStructParamClassJavaStub(methParams, methPrmTypes); println(";"); println("Object[] paramObj = new Object[paramLen];"); println("Class[] paramCls = new Class[paramLen];"); println("int pos = 0;"); // Iterate again over the parameters for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getGenericType(paramType); if (isStructClass(simpleType)) { writeStructMembersJavaStub(simpleType, paramType, param); } else { String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i)); println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;"); print("paramObj[pos++] = "); print(getEnumParam(methPrmTypes.get(i), getSimpleIdentifier(methParams.get(i)), i)); println(";"); } } } /** * HELPER: writeStructRetMembersJavaStub() writes parameters of struct for return statement */ private void writeStructRetMembersJavaStub(String simpleType, String retType) { // Get the struct declaration for this struct and generate initialization code StructDecl structDecl = getStructDecl(simpleType); List memTypes = structDecl.getMemberTypes(simpleType); List members = structDecl.getMembers(simpleType); if (isArrayOrList(retType, retType)) { // An array or list println("for(int i = 0; i < retLen; i++) {"); } if (isArray(retType)) { // An array for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); print("structRet[i]." + getSimpleIdentifier(members.get(i))); println(" = (" + getSimpleType(getEnumType(prmType)) + ") retObj[retObjPos++];"); } println("}"); } else if (isList(retType)) { // A list println(simpleType + " structRetMem = new " + simpleType + "();"); for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); print("structRetMem." + getSimpleIdentifier(members.get(i))); println(" = (" + getSimpleType(getEnumType(prmType)) + ") retObj[retObjPos++];"); } println("structRet.add(structRetMem);"); println("}"); } else { // Just one struct element for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); print("structRet." + getSimpleIdentifier(members.get(i))); println(" = (" + getSimpleType(getEnumType(prmType)) + ") retObj[retObjPos++];"); } } println("return structRet;"); } /** * HELPER: writeStructReturnJavaStub() writes parameters if struct is present for return statement */ private void writeStructReturnJavaStub(String simpleType, String retType) { // Handle the returned struct!!! println("Object retLenObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);"); // Minimum retLen is 1 if this is a single struct object println("int retLen = (int) retLenObj;"); int numMem = getNumOfMembers(simpleType); println("Class[] retCls = new Class[" + numMem + "*retLen];"); println("Class[] retClsVal = new Class[" + numMem + "*retLen];"); println("int retPos = 0;"); // Get the struct declaration for this struct and generate initialization code StructDecl structDecl = getStructDecl(simpleType); List memTypes = structDecl.getMemberTypes(simpleType); List members = structDecl.getMembers(simpleType); if (isArrayOrList(retType, retType)) { // An array or list println("for(int i = 0; i < retLen; i++) {"); for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;"); println("retClsVal[retPos++] = null;"); } println("}"); } else { // Just one struct element for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;"); println("retClsVal[retPos++] = null;"); } } println("Object[] retObj = rmiCall.getStructObjects(retCls, retClsVal);"); if (isArray(retType)) { // An array println(simpleType + "[] structRet = new " + simpleType + "[retLen];"); println("for(int i = 0; i < retLen; i++) {"); println("structRet[i] = new " + simpleType + "();"); println("}"); } else if (isList(retType)) { // A list println("List<" + simpleType + "> structRet = new ArrayList<" + simpleType + ">();"); } else println(simpleType + " structRet = new " + simpleType + "();"); println("int retObjPos = 0;"); writeStructRetMembersJavaStub(simpleType, retType); } /** * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class */ private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method) { checkAndWriteStructSetupJavaStub(methParams, methPrmTypes, intDecl, method); println("int methodId = " + intDecl.getMethodNumId(method) + ";"); String retType = intDecl.getMethodType(method); println("Class retType = " + getSimpleType(getStructType(getEnumType(retType))) + ".class;"); checkAndWriteEnumTypeJavaStub(methParams, methPrmTypes); // Generate array of parameter types if (isStructPresent(methParams, methPrmTypes)) { writeStructParamClassJavaStub(methParams, methPrmTypes); } else { print("Class[] paramCls = new Class[] { "); for (int i = 0; i < methParams.size(); i++) { String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i)); print(getSimpleType(getEnumType(paramType)) + ".class"); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(" };"); // Generate array of parameter objects print("Object[] paramObj = new Object[] { "); for (int i = 0; i < methParams.size(); i++) { print(getEnumParam(methPrmTypes.get(i), getSimpleIdentifier(methParams.get(i)), i)); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(" };"); } // Check if this is "void" if (retType.equals("void")) { println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);"); } else { // We do have a return value // Generate array of parameter types if (isStructClass(getGenericType(getSimpleArrayType(retType)))) { writeStructReturnJavaStub(getGenericType(getSimpleArrayType(retType)), retType); } else { // Check if the return value NONPRIMITIVES if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) { String[] retGenValType = getTypeOfGeneric(retType); println("Class retGenValType = " + retGenValType[0] + ".class;"); println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);"); println("return (" + retType + ")retObj;"); } else if (getParamCategory(retType) == ParamCategory.ENUM) { // This is an enum type println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);"); checkAndWriteEnumRetTypeJavaStub(retType); } else { println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);"); println("return (" + retType + ")retObj;"); } } } } /** * HELPER: returnGenericCallbackType() returns the callback type */ private String returnGenericCallbackType(String paramType) { if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) return getTypeOfGeneric(paramType)[0]; else return paramType; } /** * HELPER: checkCallbackType() checks the callback type */ private boolean checkCallbackType(String paramType, String callbackType) { String prmType = returnGenericCallbackType(paramType); return callbackType.equals(prmType); } /** * HELPER: writeCallbackMethodBodyJavaStub() writes the callback method of the stub class */ private void writeCallbackMethodBodyJavaStub(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method, String callbackType) { println("try {"); // Check if this is single object, array, or list of objects for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object String param = methParams.get(i); if (isArrayOrList(paramType, param)) { // Generate loop println("for (" + paramType + " cb : " + getSimpleIdentifier(param) + ") {"); println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);"); } else println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(" + getSimpleIdentifier(param) + ", objIdCnt++);"); println("listCallbackObj.add(skel);"); if (isArrayOrList(paramType, param)) println("}"); } } println("} catch (Exception ex) {"); println("ex.printStackTrace();"); println("throw new Error(\"Exception when generating skeleton objects!\");"); println("}\n"); println("int methodId = " + intDecl.getMethodNumId(method) + ";"); String retType = intDecl.getMethodType(method); println("Class retType = " + getSimpleType(getEnumType(retType)) + ".class;"); // Generate array of parameter types print("Class[] paramCls = new Class[] { "); for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object print("int.class"); } else { // Generate normal classes if it's not a callback object String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i)); print(getSimpleType(prmType) + ".class"); } if (i != methParams.size() - 1) // Check if this is the last element print(", "); } println(" };"); // Generate array of parameter objects print("Object[] paramObj = new Object[] { "); for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object //if (isArray(methPrmTypes.get(i), methParams.get(i))) if (isArray(methParams.get(i))) print(getSimpleIdentifier(methParams.get(i)) + ".length"); else if (isList(methPrmTypes.get(i))) print(getSimpleIdentifier(methParams.get(i)) + ".size()"); else print("new Integer(1)"); } else print(getSimpleIdentifier(methParams.get(i))); if (i != methParams.size() - 1) print(", "); } println(" };"); // Check if this is "void" if (retType.equals("void")) { println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);"); } else { // We do have a return value // Check if the return value NONPRIMITIVES if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) { String[] retGenValType = getTypeOfGeneric(retType); println("Class retGenValType = " + retGenValType[0] + ".class;"); println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);"); println("return (" + retType + ")retObj;"); } else { println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);"); println("return (" + retType + ")retObj;"); } } } /** * HELPER: writeMethodJavaStub() writes the methods of the stub class */ private void writeMethodJavaStub(Collection methods, InterfaceDecl intDecl, Set callbackClasses) { for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); print("public " + intDecl.getMethodType(method) + " " + intDecl.getMethodId(method) + "("); boolean isCallbackMethod = false; String callbackType = null; for (int i = 0; i < methParams.size(); i++) { String paramType = returnGenericCallbackType(methPrmTypes.get(i)); // Check if this has callback object if (callbackClasses.contains(paramType)) { isCallbackMethod = true; callbackType = paramType; // Even if there're 2 callback arguments, we expect them to be of the same interface } print(methPrmTypes.get(i) + " " + methParams.get(i)); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(") {"); // Now, write the body of stub! if (isCallbackMethod) writeCallbackMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method, callbackType); else writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method); println("}\n"); // Write the init callback helper method if (isCallbackMethod) writeInitCallbackJavaStub(callbackType, intDecl); } } /** * generateJavaStubClasses() generate stubs based on the methods list in Java */ public void generateJavaStubClasses() throws IOException { // Create a new directory String path = createDirectories(dir, subdir); for (String intface : mapIntfacePTH.keySet()) { Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { // Open a new file to write into String newIntface = intMeth.getKey(); String newStubClass = newIntface + "_Stub"; FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java"); pw = new PrintWriter(new BufferedWriter(fw)); DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); // Pass in set of methods and get import classes Set methods = intMeth.getValue(); Set importClasses = getImportClasses(methods, intDecl); List stdImportClasses = getStandardJavaImportClasses(); List allImportClasses = getAllLibClasses(stdImportClasses, importClasses); printImportStatements(allImportClasses); println(""); // Find out if there are callback objects Set callbackClasses = getCallbackClasses(methods, intDecl); boolean callbackExist = !callbackClasses.isEmpty(); // Write class header println("public class " + newStubClass + " implements " + newIntface + " {\n"); // Write properties writePropertiesJavaStub(intface, newIntface, callbackExist, callbackClasses); // Write constructor writeConstructorJavaStub(intface, newStubClass, callbackExist, callbackClasses); // Write methods writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses); println("}"); pw.close(); System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java..."); } } } /** * HELPER: writePropertiesJavaCallbackStub() writes the properties of the callback stub class */ private void writePropertiesJavaCallbackStub(String intface, String newIntface, boolean callbackExist, Set callbackClasses) { println("private IoTRMICall rmiCall;"); println("private String address;"); println("private int[] ports;\n"); // Get the object Id println("private static int objectId = 0;"); if (callbackExist) { // We assume that each class only has one callback interface for now Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); println("// Callback properties"); println("private IoTRMIObject rmiObj;"); println("List<" + callbackType + "> listCallbackObj;"); println("private static int objIdCnt = 0;"); // Generate permission stuff for callback stubs DeclarationHandler decHandler = mapIntDeclHand.get(callbackType); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(callbackType); writePropertiesJavaPermission(callbackType, intDecl); } println("\n"); } /** * HELPER: writeConstructorJavaCallbackStub() writes the constructor of the callback stub class */ private void writeConstructorJavaCallbackStub(String intface, String newStubClass, boolean callbackExist, Set callbackClasses) { // TODO: If we want callback in callback, then we need to add address and port initializations println("public " + newStubClass + "(IoTRMICall _rmiCall, int _objectId) throws Exception {"); println("objectId = _objectId;"); println("rmiCall = _rmiCall;"); if (callbackExist) { Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); writeConstructorJavaPermission(intface); println("listCallbackObj = new ArrayList<" + callbackType + ">();"); println("___initCallBack();"); println("// TODO: Add address and port initialization here if we want callback in callback!"); } println("}\n"); } /** * generateJavaCallbackStubClasses() generate callback stubs based on the methods list in Java *

* Callback stubs gets the IoTRMICall objects from outside of the class as contructor input * because all these stubs are populated by the class that takes in this object as a callback * object. In such a class, we only use one socket, hence one IoTRMICall, for all callback objects. */ public void generateJavaCallbackStubClasses() throws IOException { // Create a new directory String path = createDirectories(dir, subdir); for (String intface : mapIntfacePTH.keySet()) { Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { // Open a new file to write into String newIntface = intMeth.getKey(); String newStubClass = newIntface + "_CallbackStub"; FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java"); pw = new PrintWriter(new BufferedWriter(fw)); DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); // Pass in set of methods and get import classes Set methods = intMeth.getValue(); Set importClasses = getImportClasses(methods, intDecl); List stdImportClasses = getStandardJavaImportClasses(); List allImportClasses = getAllLibClasses(stdImportClasses, importClasses); printImportStatements(allImportClasses); println(""); // Find out if there are callback objects Set callbackClasses = getCallbackClasses(methods, intDecl); boolean callbackExist = !callbackClasses.isEmpty(); // Write class header println("public class " + newStubClass + " implements " + newIntface + " {\n"); // Write properties writePropertiesJavaCallbackStub(intface, newIntface, callbackExist, callbackClasses); // Write constructor writeConstructorJavaCallbackStub(intface, newStubClass, callbackExist, callbackClasses); // Write methods // TODO: perhaps need to generate callback for callback writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses); println("}"); pw.close(); System.out.println("IoTCompiler: Generated callback stub class " + newStubClass + ".java..."); } } } /** * HELPER: writePropertiesJavaSkeleton() writes the properties of the skeleton class */ private void writePropertiesJavaSkeleton(String intface, boolean callbackExist, InterfaceDecl intDecl) { println("private " + intface + " mainObj;"); //println("private int ports;"); println("private IoTRMIObject rmiObj;\n"); // Callback if (callbackExist) { println("private static int objIdCnt = 0;"); println("private IoTRMICall rmiCall;"); } writePropertiesJavaPermission(intface, intDecl); println("\n"); } /** * HELPER: writeConstructorJavaSkeleton() writes the constructor of the skeleton class */ private void writeConstructorJavaSkeleton(String newSkelClass, String intface) { println("public " + newSkelClass + "(" + intface + " _mainObj, int _port) throws Exception {"); println("mainObj = _mainObj;"); println("rmiObj = new IoTRMIObject(_port);"); // Generate permission control initialization writeConstructorJavaPermission(intface); println("___waitRequestInvokeMethod();"); println("}\n"); } /** * HELPER: writeStdMethodBodyJavaSkeleton() writes the standard method body in the skeleton class */ private void writeStdMethodBodyJavaSkeleton(List methParams, String methodId, String methodType) { if (methodType.equals("void")) print("mainObj." + methodId + "("); else print("return mainObj." + methodId + "("); for (int i = 0; i < methParams.size(); i++) { print(getSimpleIdentifier(methParams.get(i))); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(");"); } /** * HELPER: writeInitCallbackJavaSkeleton() writes the init callback method for skeleton class */ private void writeInitCallbackJavaSkeleton(boolean callbackSkeleton) { // This is a callback skeleton generation if (callbackSkeleton) println("public void ___regCB(IoTRMIObject rmiObj) throws IOException {"); else println("public void ___regCB() throws IOException {"); println("Object[] paramObj = rmiObj.getMethodParams(new Class[] { int.class, String.class, int.class },"); println("\tnew Class[] { null, null, null });"); println("rmiCall = new IoTRMICall((int) paramObj[0], (String) paramObj[1], (int) paramObj[2]);"); println("}\n"); } /** * HELPER: writeMethodJavaSkeleton() writes the method of the skeleton class */ private void writeMethodJavaSkeleton(Collection methods, InterfaceDecl intDecl, Set callbackClasses, boolean callbackSkeleton) { for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); String methodId = intDecl.getMethodId(method); print("public " + intDecl.getMethodType(method) + " " + methodId + "("); boolean isCallbackMethod = false; String callbackType = null; for (int i = 0; i < methParams.size(); i++) { String origParamType = methPrmTypes.get(i); String paramType = checkAndGetParamClass(origParamType); if (callbackClasses.contains(origParamType)) { // Check if this has callback object isCallbackMethod = true; callbackType = origParamType; } print(paramType + " " + methParams.get(i)); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(") {"); // Now, write the body of skeleton! writeStdMethodBodyJavaSkeleton(methParams, methodId, intDecl.getMethodType(method)); println("}\n"); if (isCallbackMethod) writeInitCallbackJavaSkeleton(callbackSkeleton); } } /** * HELPER: writeCallbackJavaStubGeneration() writes the callback stub generation part */ private Map writeCallbackJavaStubGeneration(List methParams, List methPrmTypes, String callbackType) { Map mapStubParam = new HashMap(); // Iterate over callback objects for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); //if (callbackType.equals(paramType)) { if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object println("try {"); String exchParamType = checkAndGetParamClass(paramType); // Print array if this is array or list if this is a list of callback objects if (isArray(param)) { println("int numStubs" + i + " = (int) paramObj[" + i + "];"); println(exchParamType + "[] stub" + i + " = new " + exchParamType + "[numStubs" + i + "];"); } else if (isList(paramType)) { println("int numStubs" + i + " = (int) paramObj[" + i + "];"); println("List<" + exchParamType + "> stub" + i + " = new ArrayList<" + exchParamType + ">();"); } else { println(exchParamType + " stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);"); println("objIdCnt++;"); } } // Generate a loop if needed if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object String exchParamType = checkAndGetParamClass(paramType); if (isArray(param)) { println("for (int objId = 0; objId < numStubs" + i + "; objId++) {"); println("stub" + i + "[objId] = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);"); println("objIdCnt++;"); println("}"); } else if (isList(paramType)) { println("for (int objId = 0; objId < numStubs" + i + "; objId++) {"); println("stub" + i + ".add(new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt));"); println("objIdCnt++;"); println("}"); } mapStubParam.put(i, "stub" + i); // List of all stub parameters } } return mapStubParam; } /** * HELPER: checkAndWriteEnumTypeJavaSkeleton() writes the enum type (convert from enum to int) */ private void checkAndWriteEnumTypeJavaSkeleton(List methParams, List methPrmTypes) { // Iterate and find enum declarations for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isEnumClass(simpleType)) { // Check if this is enum type println("int paramInt" + i + "[] = (int[]) paramObj[" + i + "];"); println(simpleType + "[] enumVals = " + simpleType + ".values();"); if (isArray(param)) { // An array println("int len" + i + " = paramInt" + i + ".length;"); println(simpleType + "[] paramEnum = new " + simpleType + "[len];"); println("for (int i = 0; i < len" + i + "; i++) {"); println("paramEnum[i] = enumVals[paramInt" + i + "[i]];"); println("}"); } else if (isList(paramType)) { // A list println("int len" + i + " = paramInt" + i + ".length;"); println("List<" + simpleType + "> paramEnum = new ArrayList<" + simpleType + ">();"); println("for (int i = 0; i < len" + i + "; i++) {"); println("paramEnum.add(enumVals[paramInt" + i + "[i]]);"); println("}"); } else { // Just one element println(simpleType + " paramEnum" + i + " = enumVals[paramInt" + i + "[0]];"); } } } } /** * HELPER: checkAndWriteEnumRetTypeJavaSkeleton() writes the enum return type (convert from enum to int) */ private void checkAndWriteEnumRetTypeJavaSkeleton(String retType, String methodId) { // Strips off array "[]" for return type String pureType = getSimpleArrayType(getSimpleType(retType)); // Take the inner type of generic if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) pureType = getTypeOfGeneric(retType)[0]; if (isEnumClass(pureType)) { // Check if this is enum type // Enum decoder if (isArray(retType)) { // An array print(pureType + "[] retEnum = " + methodId + "("); } else if (isList(retType)) { // A list print("List<" + pureType + "> retEnum = " + methodId + "("); } else { // Just one element print(pureType + " retEnum = " + methodId + "("); } } } /** * HELPER: checkAndWriteEnumRetConvJavaSkeleton() writes the enum return type (convert from enum to int) */ private void checkAndWriteEnumRetConvJavaSkeleton(String retType) { // Strips off array "[]" for return type String pureType = getSimpleArrayType(getSimpleType(retType)); // Take the inner type of generic if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) pureType = getTypeOfGeneric(retType)[0]; if (isEnumClass(pureType)) { // Check if this is enum type if (isArray(retType)) { // An array println("int retLen = retEnum.length;"); println("int[] retEnumVal = new int[retLen];"); println("for (int i = 0; i < retLen; i++) {"); println("retEnumVal[i] = retEnum[i].ordinal();"); println("}"); } else if (isList(retType)) { // A list println("int retLen = retEnum.size();"); println("List<" + pureType + "> retEnumVal = new ArrayList<" + pureType + ">();"); println("for (int i = 0; i < retLen; i++) {"); println("retEnumVal.add(retEnum[i].ordinal());"); println("}"); } else { // Just one element println("int[] retEnumVal = new int[1];"); println("retEnumVal[0] = retEnum.ordinal();"); } println("Object retObj = retEnumVal;"); } } /** * HELPER: writeLengthStructParamClassSkeleton() writes lengths of params */ private void writeLengthStructParamClassSkeleton(List methParams, List methPrmTypes, String method, InterfaceDecl intDecl) { // Iterate and find struct declarations - count number of params for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getGenericType(paramType); if (isStructClass(simpleType)) { int members = getNumOfMembers(simpleType); print(Integer.toString(members) + "*"); int methodNumId = intDecl.getMethodNumId(method); print("struct" + methodNumId + "Size" + i); } else print("1"); if (i != methParams.size() - 1) { print("+"); } } } /** * HELPER: writeStructMembersJavaSkeleton() writes member parameters of struct */ private void writeStructMembersJavaSkeleton(String simpleType, String paramType, String param, String method, InterfaceDecl intDecl, int iVar) { // Get the struct declaration for this struct and generate initialization code StructDecl structDecl = getStructDecl(simpleType); List memTypes = structDecl.getMemberTypes(simpleType); List members = structDecl.getMembers(simpleType); if (isArrayOrList(param, paramType)) { // An array or list int methodNumId = intDecl.getMethodNumId(method); String counter = "struct" + methodNumId + "Size" + iVar; println("for(int i = 0; i < " + counter + "; i++) {"); } println("int pos = 0;"); if (isArrayOrList(param, paramType)) { // An array or list println("for(int i = 0; i < retLen; i++) {"); for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;"); println("paramClsGen[pos++] = null;"); } println("}"); } else { // Just one struct element for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;"); println("paramClsGen[pos++] = null;"); } } } /** * HELPER: writeStructMembersInitJavaSkeleton() writes member parameters initialization of struct */ private void writeStructMembersInitJavaSkeleton(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method) { for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getGenericType(paramType); if (isStructClass(simpleType)) { int methodNumId = intDecl.getMethodNumId(method); String counter = "struct" + methodNumId + "Size" + i; // Declaration if (isArray(param)) { // An array println(simpleType + "[] paramStruct" + i + " = new " + simpleType + "[" + counter + "];"); println("for(int i = 0; i < " + counter + "; i++) {"); println("paramStruct" + i + "[i] = new " + simpleType + "();"); println("}"); } else if (isList(paramType)) { // A list println("List<" + simpleType + "> paramStruct" + i + " = new ArrayList<" + simpleType + ">();"); } else println(simpleType + " paramStruct" + i + " = new " + simpleType + "();"); println("int objPos = 0;"); // Initialize members StructDecl structDecl = getStructDecl(simpleType); List members = structDecl.getMembers(simpleType); List memTypes = structDecl.getMemberTypes(simpleType); if (isArrayOrList(param, paramType)) { // An array or list println("for(int i = 0; i < " + counter + "; i++) {"); } if (isArray(param)) { // An array for (int j = 0; j < members.size(); j++) { String prmType = checkAndGetArray(memTypes.get(j), members.get(j)); print("paramStruct" + i + "[i]." + getSimpleIdentifier(members.get(j))); println(" = (" + getSimpleType(getEnumType(prmType)) + ") paramObj[objPos++];"); } println("}"); } else if (isList(paramType)) { // A list println(simpleType + " paramStructMem = new " + simpleType + "();"); for (int j = 0; j < members.size(); j++) { String prmType = checkAndGetArray(memTypes.get(j), members.get(j)); print("paramStructMem." + getSimpleIdentifier(members.get(j))); println(" = (" + getSimpleType(getEnumType(prmType)) + ") paramObj[objPos++];"); } println("paramStruct" + i + ".add(paramStructMem);"); println("}"); } else { // Just one struct element for (int j = 0; j < members.size(); j++) { String prmType = checkAndGetArray(memTypes.get(j), members.get(j)); print("paramStruct" + i + "." + getSimpleIdentifier(members.get(j))); println(" = (" + getSimpleType(getEnumType(prmType)) + ") paramObj[objPos++];"); } } } else { // Take offsets of parameters println("int offset" + i +" = objPos;"); } } } /** * HELPER: writeStructReturnJavaSkeleton() writes struct for return statement */ private void writeStructReturnJavaSkeleton(String simpleType, String retType) { // Minimum retLen is 1 if this is a single struct object if (isArray(retType)) println("int retLen = retStruct.length;"); else if (isList(retType)) println("int retLen = retStruct.size();"); else // Just single struct object println("int retLen = 1;"); println("Object retLenObj = retLen;"); println("rmiObj.sendReturnObj(retLenObj);"); int numMem = getNumOfMembers(simpleType); println("Class[] retCls = new Class[" + numMem + "*retLen];"); println("Object[] retObj = new Object[" + numMem + "*retLen];"); println("int retPos = 0;"); // Get the struct declaration for this struct and generate initialization code StructDecl structDecl = getStructDecl(simpleType); List memTypes = structDecl.getMemberTypes(simpleType); List members = structDecl.getMembers(simpleType); if (isArrayOrList(retType, retType)) { // An array or list println("for(int i = 0; i < retLen; i++) {"); for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;"); print("retObj[retPos++] = retStruct[i]."); print(getEnumParam(memTypes.get(i), getSimpleIdentifier(members.get(i)), i)); println(";"); } println("}"); } else { // Just one struct element for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;"); print("retObj[retPos++] = retStruct."); print(getEnumParam(memTypes.get(i), getSimpleIdentifier(members.get(i)), i)); println(";"); } } } /** * HELPER: writeMethodHelperReturnJavaSkeleton() writes return statement part in skeleton */ private void writeMethodHelperReturnJavaSkeleton(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method, boolean isCallbackMethod, String callbackType, boolean isStructMethod) { checkAndWriteEnumTypeJavaSkeleton(methParams, methPrmTypes); Map mapStubParam = null; if (isCallbackMethod) mapStubParam = writeCallbackJavaStubGeneration(methParams, methPrmTypes, callbackType); // Check if this is "void" String retType = intDecl.getMethodType(method); if (retType.equals("void")) { print(intDecl.getMethodId(method) + "("); } else if (isEnumClass(getSimpleArrayType(getSimpleType(retType)))) { // Enum type checkAndWriteEnumRetTypeJavaSkeleton(retType, intDecl.getMethodId(method)); } else if (isStructClass(getSimpleArrayType(getSimpleType(retType)))) { // Struct type print(retType + " retStruct = " + intDecl.getMethodId(method) + "("); } else { // We do have a return value print("Object retObj = " + intDecl.getMethodId(method) + "("); } for (int i = 0; i < methParams.size(); i++) { if (isCallbackMethod) { print(mapStubParam.get(i)); // Get the callback parameter } else if (isEnumClass(getSimpleType(methPrmTypes.get(i)))) { // Enum class print(getEnumParam(methPrmTypes.get(i), methParams.get(i), i)); } else if (isStructClass(getSimpleType(methPrmTypes.get(i)))) { print("paramStruct" + i); } else { String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i)); if (isStructMethod) print("(" + prmType + ") paramObj[offset" + i + "]"); else print("(" + prmType + ") paramObj[" + i + "]"); } if (i != methParams.size() - 1) print(", "); } println(");"); if (!retType.equals("void")) { if (isEnumClass(getSimpleArrayType(getSimpleType(retType)))) { // Enum type checkAndWriteEnumRetConvJavaSkeleton(retType); println("rmiObj.sendReturnObj(retObj);"); } else if (isStructClass(getSimpleArrayType(getSimpleType(retType)))) { // Struct type writeStructReturnJavaSkeleton(getSimpleArrayType(getSimpleType(retType)), retType); println("rmiObj.sendReturnObj(retCls, retObj);"); } else println("rmiObj.sendReturnObj(retObj);"); } if (isCallbackMethod) { // Catch exception if this is callback println("} catch(Exception ex) {"); println("ex.printStackTrace();"); println("throw new Error(\"Exception from callback object instantiation!\");"); println("}"); } } /** * HELPER: writeMethodHelperStructJavaSkeleton() writes the struct in skeleton */ private void writeMethodHelperStructJavaSkeleton(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method, Set callbackClasses) { // Generate array of parameter objects boolean isCallbackMethod = false; String callbackType = null; print("int paramLen = "); writeLengthStructParamClassSkeleton(methParams, methPrmTypes, method, intDecl); println(";"); println("Class[] paramCls = new Class[paramLen];"); println("Class[] paramClsGen = new Class[paramLen];"); // Iterate again over the parameters for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getGenericType(paramType); if (isStructClass(simpleType)) { writeStructMembersJavaSkeleton(simpleType, paramType, param, method, intDecl, i); } else { String prmType = returnGenericCallbackType(methPrmTypes.get(i)); if (callbackClasses.contains(prmType)) { isCallbackMethod = true; callbackType = prmType; println("paramCls[pos] = int.class;"); println("paramClsGen[pos++] = null;"); } else { // Generate normal classes if it's not a callback object String paramTypeOth = checkAndGetArray(methPrmTypes.get(i), methParams.get(i)); println("paramCls[pos] = " + getSimpleType(getEnumType(paramTypeOth)) + ".class;"); print("paramClsGen[pos++] = "); String prmTypeOth = methPrmTypes.get(i); if (getParamCategory(prmTypeOth) == ParamCategory.NONPRIMITIVES) println(getTypeOfGeneric(prmType)[0] + ".class;"); else println("null;"); } } } println("Object[] paramObj = rmiObj.getMethodParams(paramCls, paramClsGen);"); writeStructMembersInitJavaSkeleton(intDecl, methParams, methPrmTypes, method); // Write the return value part writeMethodHelperReturnJavaSkeleton(intDecl, methParams, methPrmTypes, method, isCallbackMethod, callbackType, true); } /** * HELPER: writeStdMethodHelperBodyJavaSkeleton() writes the standard method body helper in the skeleton class */ private void writeStdMethodHelperBodyJavaSkeleton(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method, Set callbackClasses) { // Generate array of parameter objects boolean isCallbackMethod = false; String callbackType = null; print("Object[] paramObj = rmiObj.getMethodParams(new Class[] { "); for (int i = 0; i < methParams.size(); i++) { String paramType = returnGenericCallbackType(methPrmTypes.get(i)); if (callbackClasses.contains(paramType)) { isCallbackMethod = true; callbackType = paramType; print("int.class"); } else { // Generate normal classes if it's not a callback object String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i)); print(getSimpleType(getEnumType(prmType)) + ".class"); } if (i != methParams.size() - 1) print(", "); } println(" }, "); // Generate generic class if it's a generic type.. null otherwise print("new Class[] { "); for (int i = 0; i < methParams.size(); i++) { String prmType = methPrmTypes.get(i); if (getParamCategory(prmType) == ParamCategory.NONPRIMITIVES) print(getTypeOfGeneric(prmType)[0] + ".class"); else print("null"); if (i != methParams.size() - 1) print(", "); } println(" });"); // Write the return value part writeMethodHelperReturnJavaSkeleton(intDecl, methParams, methPrmTypes, method, isCallbackMethod, callbackType, false); } /** * HELPER: writeMethodHelperJavaSkeleton() writes the method helper of the skeleton class */ private void writeMethodHelperJavaSkeleton(Collection methods, InterfaceDecl intDecl, Set callbackClasses) { // Use this set to handle two same methodIds Set uniqueMethodIds = new HashSet(); for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); if (isStructPresent(methParams, methPrmTypes)) { // Treat struct differently String methodId = intDecl.getMethodId(method); print("public void ___"); String helperMethod = methodId; if (uniqueMethodIds.contains(methodId)) helperMethod = helperMethod + intDecl.getMethodNumId(method); else uniqueMethodIds.add(methodId); String retType = intDecl.getMethodType(method); print(helperMethod + "("); boolean begin = true; for (int i = 0; i < methParams.size(); i++) { // Print size variables String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { if (!begin) { // Generate comma for not the beginning variable print(", "); begin = false; } int methodNumId = intDecl.getMethodNumId(method); print("int struct" + methodNumId + "Size" + i); } } // Check if this is "void" if (retType.equals("void")) println(") {"); else println(") throws IOException {"); writeMethodHelperStructJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses); println("}\n"); } else { String methodId = intDecl.getMethodId(method); print("public void ___"); String helperMethod = methodId; if (uniqueMethodIds.contains(methodId)) helperMethod = helperMethod + intDecl.getMethodNumId(method); else uniqueMethodIds.add(methodId); // Check if this is "void" String retType = intDecl.getMethodType(method); if (retType.equals("void")) println(helperMethod + "() {"); else println(helperMethod + "() throws IOException {"); // Now, write the helper body of skeleton! writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses); println("}\n"); } } // Write method helper for structs writeMethodHelperStructSetupJavaSkeleton(methods, intDecl); } /** * HELPER: writeMethodHelperStructSetupJavaSkeleton() writes the method helper of struct setup in skeleton class */ private void writeMethodHelperStructSetupJavaSkeleton(Collection methods, InterfaceDecl intDecl) { // Use this set to handle two same methodIds for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); // Check for params with structs for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { int methodNumId = intDecl.getMethodNumId(method); print("public int ___"); String helperMethod = methodNumId + "struct" + i; println(helperMethod + "() {"); // Now, write the helper body of skeleton! println("Object[] paramObj = rmiObj.getMethodParams(new Class[] { int.class }, new Class[] { null });"); println("return (int) paramObj[0];"); println("}\n"); } } } } /** * HELPER: writeMethodHelperStructSetupJavaCallbackSkeleton() writes the method helper of struct setup in callback skeleton class */ private void writeMethodHelperStructSetupJavaCallbackSkeleton(Collection methods, InterfaceDecl intDecl) { // Use this set to handle two same methodIds for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); // Check for params with structs for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { int methodNumId = intDecl.getMethodNumId(method); print("public int ___"); String helperMethod = methodNumId + "struct" + i; println(helperMethod + "(IoTRMIObject rmiObj) {"); // Now, write the helper body of skeleton! println("Object[] paramObj = rmiObj.getMethodParams(new Class[] { int.class }, new Class[] { null });"); println("return (int) paramObj[0];"); println("}\n"); } } } } /** * HELPER: writeCountVarStructSkeleton() writes counter variable of struct for skeleton */ private void writeCountVarStructSkeleton(Collection methods, InterfaceDecl intDecl) { // Use this set to handle two same methodIds for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); // Check for params with structs for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { int methodNumId = intDecl.getMethodNumId(method); println("int struct" + methodNumId + "Size" + i + " = 0;"); } } } } /** * HELPER: writeInputCountVarStructSkeleton() writes input counter variable of struct for skeleton */ private boolean writeInputCountVarStructSkeleton(String method, InterfaceDecl intDecl) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); boolean structExist = false; // Check for params with structs for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); boolean begin = true; if (isStructClass(simpleType)) { structExist = true; if (!begin) { print(", "); begin = false; } int methodNumId = intDecl.getMethodNumId(method); print("struct" + methodNumId + "Size" + i); } } return structExist; } /** * HELPER: writeMethodCallStructSkeleton() writes method call for wait invoke in skeleton */ private void writeMethodCallStructSkeleton(Collection methods, InterfaceDecl intDecl) { // Use this set to handle two same methodIds for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); // Check for params with structs for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { int methodNumId = intDecl.getMethodNumId(method); print("case "); String helperMethod = methodNumId + "struct" + i; String tempVar = "struct" + methodNumId + "Size" + i; print(intDecl.getHelperMethodNumId(helperMethod) + ": "); print(tempVar + " = ___"); println(helperMethod + "(); break;"); } } } } /** * HELPER: writeMethodCallStructCallbackSkeleton() writes method call for wait invoke in skeleton */ private void writeMethodCallStructCallbackSkeleton(Collection methods, InterfaceDecl intDecl) { // Use this set to handle two same methodIds for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); // Check for params with structs for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { int methodNumId = intDecl.getMethodNumId(method); print("case "); String helperMethod = methodNumId + "struct" + i; String tempVar = "struct" + methodNumId + "Size" + i; print(intDecl.getHelperMethodNumId(helperMethod) + ": "); print(tempVar + " = ___"); println(helperMethod + "(rmiObj); break;"); } } } } /** * HELPER: writeJavaMethodPermission() writes permission checks in skeleton */ private void writeJavaMethodPermission(String intface) { // Get all the different stubs Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { String newIntface = intMeth.getKey(); int newObjectId = getNewIntfaceObjectId(newIntface); println("if (_objectId == object" + newObjectId + "Id) {"); println("if (!set" + newObjectId + "Allowed.contains(methodId)) {"); println("throw new Error(\"Object with object Id: \" + _objectId + \" is not allowed to access method: \" + methodId);"); println("}"); println("}"); println("else {"); println("throw new Error(\"Object Id: \" + _objectId + \" not recognized!\");"); println("}"); } } /** * HELPER: writeJavaWaitRequestInvokeMethod() writes the main loop of the skeleton class */ private void writeJavaWaitRequestInvokeMethod(Collection methods, InterfaceDecl intDecl, boolean callbackExist, String intface) { // Use this set to handle two same methodIds Set uniqueMethodIds = new HashSet(); println("private void ___waitRequestInvokeMethod() throws IOException {"); // Write variables here if we have callbacks or enums or structs writeCountVarStructSkeleton(methods, intDecl); println("while (true) {"); println("rmiObj.getMethodBytes();"); println("int _objectId = rmiObj.getObjectId();"); println("int methodId = rmiObj.getMethodId();"); // Generate permission check writeJavaMethodPermission(intface); println("switch (methodId) {"); // Print methods and method Ids for (String method : methods) { String methodId = intDecl.getMethodId(method); int methodNumId = intDecl.getMethodNumId(method); print("case " + methodNumId + ": ___"); String helperMethod = methodId; if (uniqueMethodIds.contains(methodId)) helperMethod = helperMethod + methodNumId; else uniqueMethodIds.add(methodId); print(helperMethod + "("); writeInputCountVarStructSkeleton(method, intDecl); println("); break;"); } String method = "___initCallBack()"; // Print case -9999 (callback handler) if callback exists if (callbackExist) { int methodId = intDecl.getHelperMethodNumId(method); println("case " + methodId + ": ___regCB(); break;"); } writeMethodCallStructSkeleton(methods, intDecl); println("default: "); println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");"); println("}"); println("}"); println("}\n"); } /** * generateJavaSkeletonClass() generate skeletons based on the methods list in Java */ public void generateJavaSkeletonClass() throws IOException { // Create a new directory String path = createDirectories(dir, subdir); for (String intface : mapIntfacePTH.keySet()) { // Open a new file to write into String newSkelClass = intface + "_Skeleton"; FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java"); pw = new PrintWriter(new BufferedWriter(fw)); // Pass in set of methods and get import classes DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); List methods = intDecl.getMethods(); Set importClasses = getImportClasses(methods, intDecl); List stdImportClasses = getStandardJavaImportClasses(); List allImportClasses = getAllLibClasses(stdImportClasses, importClasses); printImportStatements(allImportClasses); // Find out if there are callback objects Set callbackClasses = getCallbackClasses(methods, intDecl); boolean callbackExist = !callbackClasses.isEmpty(); // Write class header println(""); println("public class " + newSkelClass + " implements " + intface + " {\n"); // Write properties writePropertiesJavaSkeleton(intface, callbackExist, intDecl); // Write constructor writeConstructorJavaSkeleton(newSkelClass, intface); // Write methods writeMethodJavaSkeleton(methods, intDecl, callbackClasses, false); // Write method helper writeMethodHelperJavaSkeleton(methods, intDecl, callbackClasses); // Write waitRequestInvokeMethod() - main loop writeJavaWaitRequestInvokeMethod(methods, intDecl, callbackExist, intface); println("}"); pw.close(); System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".java..."); } } /** * HELPER: writePropertiesJavaCallbackSkeleton() writes the properties of the callback skeleton class */ private void writePropertiesJavaCallbackSkeleton(String intface, boolean callbackExist) { println("private " + intface + " mainObj;"); // For callback skeletons, this is its own object Id println("private static int objectId = 0;"); // Callback if (callbackExist) { println("private static int objIdCnt = 0;"); println("private IoTRMICall rmiCall;"); } println("\n"); } /** * HELPER: writeConstructorJavaCallbackSkeleton() writes the constructor of the skeleton class */ private void writeConstructorJavaCallbackSkeleton(String newSkelClass, String intface) { println("public " + newSkelClass + "(" + intface + " _mainObj, int _objectId) throws Exception {"); println("mainObj = _mainObj;"); println("objectId = _objectId;"); println("}\n"); } /** * HELPER: writeMethodHelperJavaCallbackSkeleton() writes the method helper of the callback skeleton class */ private void writeMethodHelperJavaCallbackSkeleton(Collection methods, InterfaceDecl intDecl, Set callbackClasses) { // Use this set to handle two same methodIds Set uniqueMethodIds = new HashSet(); for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); if (isStructPresent(methParams, methPrmTypes)) { // Treat struct differently String methodId = intDecl.getMethodId(method); print("public void ___"); String helperMethod = methodId; if (uniqueMethodIds.contains(methodId)) helperMethod = helperMethod + intDecl.getMethodNumId(method); else uniqueMethodIds.add(methodId); String retType = intDecl.getMethodType(method); print(helperMethod + "("); boolean begin = true; for (int i = 0; i < methParams.size(); i++) { // Print size variables String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { if (!begin) { // Generate comma for not the beginning variable print(", "); begin = false; } int methodNumId = intDecl.getMethodNumId(method); print("int struct" + methodNumId + "Size" + i); } } // Check if this is "void" if (retType.equals("void")) println(", IoTRMIObject rmiObj) {"); else println(", IoTRMIObject rmiObj) throws IOException {"); writeMethodHelperStructJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses); println("}\n"); } else { String methodId = intDecl.getMethodId(method); print("public void ___"); String helperMethod = methodId; if (uniqueMethodIds.contains(methodId)) helperMethod = helperMethod + intDecl.getMethodNumId(method); else uniqueMethodIds.add(methodId); // Check if this is "void" String retType = intDecl.getMethodType(method); if (retType.equals("void")) println(helperMethod + "(IoTRMIObject rmiObj) {"); else println(helperMethod + "(IoTRMIObject rmiObj) throws IOException {"); // Now, write the helper body of skeleton! writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses); println("}\n"); } } // Write method helper for structs writeMethodHelperStructSetupJavaCallbackSkeleton(methods, intDecl); } /** * HELPER: writeJavaCallbackWaitRequestInvokeMethod() writes the request invoke method of the callback skeleton class */ private void writeJavaCallbackWaitRequestInvokeMethod(Collection methods, InterfaceDecl intDecl, boolean callbackExist) { // Use this set to handle two same methodIds Set uniqueMethodIds = new HashSet(); println("public void invokeMethod(IoTRMIObject rmiObj) throws IOException {"); // Write variables here if we have callbacks or enums or structs writeCountVarStructSkeleton(methods, intDecl); // Write variables here if we have callbacks or enums or structs println("int methodId = rmiObj.getMethodId();"); // TODO: code the permission check here! println("switch (methodId) {"); // Print methods and method Ids for (String method : methods) { String methodId = intDecl.getMethodId(method); int methodNumId = intDecl.getMethodNumId(method); print("case " + methodNumId + ": ___"); String helperMethod = methodId; if (uniqueMethodIds.contains(methodId)) helperMethod = helperMethod + methodNumId; else uniqueMethodIds.add(methodId); print(helperMethod + "("); if (writeInputCountVarStructSkeleton(method, intDecl)) println(", rmiObj); break;"); else println("rmiObj); break;"); } String method = "___initCallBack()"; // Print case -9999 (callback handler) if callback exists if (callbackExist) { int methodId = intDecl.getHelperMethodNumId(method); println("case " + methodId + ": ___regCB(rmiObj); break;"); } writeMethodCallStructCallbackSkeleton(methods, intDecl); println("default: "); println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");"); println("}"); println("}\n"); } /** * generateJavaCallbackSkeletonClass() generate callback skeletons based on the methods list in Java */ public void generateJavaCallbackSkeletonClass() throws IOException { // Create a new directory String path = createDirectories(dir, subdir); for (String intface : mapIntfacePTH.keySet()) { // Open a new file to write into String newSkelClass = intface + "_CallbackSkeleton"; FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java"); pw = new PrintWriter(new BufferedWriter(fw)); // Pass in set of methods and get import classes DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); List methods = intDecl.getMethods(); Set importClasses = getImportClasses(methods, intDecl); List stdImportClasses = getStandardJavaImportClasses(); List allImportClasses = getAllLibClasses(stdImportClasses, importClasses); printImportStatements(allImportClasses); // Find out if there are callback objects Set callbackClasses = getCallbackClasses(methods, intDecl); boolean callbackExist = !callbackClasses.isEmpty(); // Write class header println(""); println("public class " + newSkelClass + " implements " + intface + " {\n"); // Write properties writePropertiesJavaCallbackSkeleton(intface, callbackExist); // Write constructor writeConstructorJavaCallbackSkeleton(newSkelClass, intface); // Write methods writeMethodJavaSkeleton(methods, intDecl, callbackClasses, true); // Write method helper writeMethodHelperJavaCallbackSkeleton(methods, intDecl, callbackClasses); // Write waitRequestInvokeMethod() - main loop writeJavaCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist); println("}"); pw.close(); System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".java..."); } } /** * HELPER: writeMethodCplusLocalInterface() writes the method of the local interface */ private void writeMethodCplusLocalInterface(Collection methods, InterfaceDecl intDecl) { for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " + intDecl.getMethodId(method) + "("); for (int i = 0; i < methParams.size(); i++) { // Check for params with driver class types and exchange it // with its remote interface String paramType = checkAndGetParamClass(methPrmTypes.get(i)); paramType = checkAndGetCplusType(paramType); // Check for arrays - translate into vector in C++ String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i)); print(paramComplete); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(") = 0;"); } } /** * HELPER: writeMethodCplusInterface() writes the method of the interface */ private void writeMethodCplusInterface(Collection methods, InterfaceDecl intDecl) { for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " + intDecl.getMethodId(method) + "("); for (int i = 0; i < methParams.size(); i++) { // Check for params with driver class types and exchange it // with its remote interface String paramType = methPrmTypes.get(i); paramType = checkAndGetCplusType(paramType); // Check for arrays - translate into vector in C++ String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i)); print(paramComplete); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(") = 0;"); } } /** * HELPER: generateEnumCplus() writes the enumeration declaration */ public void generateEnumCplus() throws IOException { // Create a new directory createDirectory(dir); for (String intface : mapIntfacePTH.keySet()) { // Get the right StructDecl DeclarationHandler decHandler = mapIntDeclHand.get(intface); EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface); Set enumTypes = enumDecl.getEnumDeclarations(); // Iterate over enum declarations for (String enType : enumTypes) { // Open a new file to write into FileWriter fw = new FileWriter(dir + "/" + enType + ".hpp"); pw = new PrintWriter(new BufferedWriter(fw)); // Write file headers println("#ifndef _" + enType.toUpperCase() + "_HPP__"); println("#define _" + enType.toUpperCase() + "_HPP__"); println("enum " + enType + " {"); List enumMembers = enumDecl.getMembers(enType); for (int i = 0; i < enumMembers.size(); i++) { String member = enumMembers.get(i); print(member); // Check if this is the last element (don't print a comma) if (i != enumMembers.size() - 1) println(","); else println(""); } println("};\n"); println("#endif"); pw.close(); System.out.println("IoTCompiler: Generated enum " + enType + ".hpp..."); } } } /** * HELPER: generateStructCplus() writes the struct declaration */ public void generateStructCplus() throws IOException { // Create a new directory createDirectory(dir); for (String intface : mapIntfacePTH.keySet()) { // Get the right StructDecl DeclarationHandler decHandler = mapIntDeclHand.get(intface); StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface); List structTypes = structDecl.getStructTypes(); // Iterate over enum declarations for (String stType : structTypes) { // Open a new file to write into FileWriter fw = new FileWriter(dir + "/" + stType + ".hpp"); pw = new PrintWriter(new BufferedWriter(fw)); // Write file headers println("#ifndef _" + stType.toUpperCase() + "_HPP__"); println("#define _" + stType.toUpperCase() + "_HPP__"); println("struct " + stType + " {"); List structMemberTypes = structDecl.getMemberTypes(stType); List structMembers = structDecl.getMembers(stType); for (int i = 0; i < structMembers.size(); i++) { String memberType = structMemberTypes.get(i); String member = structMembers.get(i); String structTypeC = checkAndGetCplusType(memberType); String structComplete = checkAndGetCplusArray(structTypeC, member); println(structComplete + ";"); } println("};\n"); println("#endif"); pw.close(); System.out.println("IoTCompiler: Generated struct " + stType + ".hpp..."); } } } /** * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking. *

* It needs to rewrite and exchange USERDEFINED types in input parameters of stub * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording. * The local interface has to be the input parameter for the stub and the stub * interface has to be the input parameter for the local class. */ public void generateCplusLocalInterfaces() throws IOException { // Create a new directory createDirectory(dir); for (String intface : mapIntfacePTH.keySet()) { // Open a new file to write into FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp"); pw = new PrintWriter(new BufferedWriter(fw)); // Write file headers println("#ifndef _" + intface.toUpperCase() + "_HPP__"); println("#define _" + intface.toUpperCase() + "_HPP__"); println("#include "); // Pass in set of methods and get include classes DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); List methods = intDecl.getMethods(); Set includeClasses = getIncludeClasses(methods, intDecl, intface, true); printIncludeStatements(includeClasses); println(""); println("using namespace std;\n"); //writeStructCplus(structDecl); println("class " + intface); println("{"); println("public:"); // Write methods writeMethodCplusLocalInterface(methods, intDecl); println("};"); println("#endif"); pw.close(); System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp..."); } } /** * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++ *

* For C++ we use virtual classe as interface */ public void generateCPlusInterfaces() throws IOException { // Create a new directory String path = createDirectories(dir, subdir); for (String intface : mapIntfacePTH.keySet()) { Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { // Open a new file to write into String newIntface = intMeth.getKey(); FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp"); pw = new PrintWriter(new BufferedWriter(fw)); DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); // Write file headers println("#ifndef _" + newIntface.toUpperCase() + "_HPP__"); println("#define _" + newIntface.toUpperCase() + "_HPP__"); println("#include "); // Pass in set of methods and get import classes Set includeClasses = getIncludeClasses(intMeth.getValue(), intDecl, intface, false); List stdIncludeClasses = getStandardCplusIncludeClasses(); List allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses); printIncludeStatements(allIncludeClasses); println(""); println("using namespace std;\n"); println("class " + newIntface); println("{"); println("public:"); // Write methods writeMethodCplusInterface(intMeth.getValue(), intDecl); println("};"); println("#endif"); pw.close(); System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp..."); } } } /** * HELPER: writeMethodCplusStub() writes the methods of the stub */ private void writeMethodCplusStub(Collection methods, InterfaceDecl intDecl, Set callbackClasses) { for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); //System.out.println("\n\nMethod return type: " + checkAndGetCplusType(intDecl.getMethodType(method)) + "\n\n"); print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " + intDecl.getMethodId(method) + "("); boolean isCallbackMethod = false; String callbackType = null; for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); // Check if this has callback object if (callbackClasses.contains(paramType)) { isCallbackMethod = true; callbackType = paramType; // Even if there're 2 callback arguments, we expect them to be of the same interface } String methPrmType = checkAndGetCplusType(methPrmTypes.get(i)); String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i)); print(methParamComplete); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(") { "); if (isCallbackMethod) writeCallbackMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method, callbackType); else writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method); println("}\n"); // Write the init callback helper method if (isCallbackMethod) { writeInitCallbackCplusStub(callbackType, intDecl); writeInitCallbackSendInfoCplusStub(intDecl); } } } /** * HELPER: writeCallbackMethodBodyCplusStub() writes the callback method of the stub class */ private void writeCallbackMethodBodyCplusStub(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method, String callbackType) { // Check if this is single object, array, or list of objects boolean isArrayOrList = false; String callbackParam = null; for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object String param = methParams.get(i); if (isArrayOrList(paramType, param)) { // Generate loop println("for (" + paramType + "* cb : " + getSimpleIdentifier(param) + ") {"); println(callbackType + "_CallbackSkeleton* skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);"); isArrayOrList = true; callbackParam = getSimpleIdentifier(param); } else println(callbackType + "_CallbackSkeleton* skel = new " + callbackType + "_CallbackSkeleton(" + getSimpleIdentifier(param) + ", objIdCnt++);"); println("vecCallbackObj.push_back(skel);"); if (isArrayOrList(paramType, param)) println("}"); } } println("int numParam = " + methParams.size() + ";"); println("int methodId = " + intDecl.getMethodNumId(method) + ";"); String retType = intDecl.getMethodType(method); //String retTypeC = checkAndGetCplusType(retType); //println("string retType = \"" + checkAndGetCplusArrayType(getStructType(getEnumType(retTypeC))) + "\";"); println("string retType = \"" + checkAndGetCplusRetClsType(getStructType(getEnumType(retType))) + "\";"); // Generate array of parameter types print("string paramCls[] = { "); for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object print("\"int\""); } else { // Generate normal classes if it's not a callback object //String paramTypeC = checkAndGetArray(methPrmTypes.get(i), methParams.get(i)); //String prmType = getSimpleType(getEnumType(paramTypeC)); String paramTypeC = checkAndGetCplusArgClsType(methPrmTypes.get(i), methParams.get(i)); String prmType = getEnumType(paramTypeC); print("\"" + prmType + "\""); } if (i != methParams.size() - 1) // Check if this is the last element print(", "); } println(" };"); print("int ___paramCB = "); if (isArrayOrList) println(callbackParam + ".size();"); else println("1;"); // Generate array of parameter objects print("void* paramObj[] = { "); for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object print("&___paramCB"); } else print(getSimpleIdentifier(methParams.get(i))); if (i != methParams.size() - 1) print(", "); } println(" };"); // Check if this is "void" if (retType.equals("void")) { println("void* retObj = NULL;"); println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);"); } else { // We do have a return value if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) println(checkAndGetCplusType(retType) + " retVal;"); else println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";"); println("void* retObj = &retVal;"); println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);"); println("return retVal;"); } } /** * HELPER: checkAndWriteEnumTypeCplusStub() writes the enum type (convert from enum to int) */ private void checkAndWriteEnumTypeCplusStub(List methParams, List methPrmTypes) { // Iterate and find enum declarations for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isEnumClass(simpleType)) { // Check if this is enum type if (isArrayOrList(paramType, param)) { // An array or vector println("int len" + i + " = " + param + ".size();"); println("vector paramEnum" + i + "(len);"); println("for (int i = 0; i < len" + i + "; i++) {"); println("paramEnum" + i + "[i] = (int) " + param + "[i];"); println("}"); } else { // Just one element println("vector paramEnum" + i + "(1);"); println("paramEnum" + i + "[0] = (int) " + param + ";"); } } } } /** * HELPER: checkAndWriteEnumRetTypeCplusStub() writes the enum return type (convert from enum to int) */ private void checkAndWriteEnumRetTypeCplusStub(String retType) { // Strips off array "[]" for return type String pureType = getSimpleArrayType(getSimpleType(retType)); // Take the inner type of generic if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) pureType = getTypeOfGeneric(retType)[0]; if (isEnumClass(pureType)) { // Check if this is enum type println("vector retEnumInt;"); println("void* retObj = &retEnumInt;"); println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);"); if (isArrayOrList(retType, retType)) { // An array or vector println("int retLen = retEnumInt.size();"); println("vector<" + pureType + "> retVal(retLen);"); println("for (int i = 0; i < retLen; i++) {"); println("retVal[i] = (" + pureType + ") retEnumInt[i];"); println("}"); } else { // Just one element println(pureType + " retVal = (" + pureType + ") retEnumInt[0];"); } println("return retVal;"); } } /** * HELPER: checkAndWriteStructSetupCplusStub() writes the struct type setup */ private void checkAndWriteStructSetupCplusStub(List methParams, List methPrmTypes, InterfaceDecl intDecl, String method) { // Iterate and find struct declarations for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { // Check if this is enum type println("int numParam" + i + " = 1;"); int methodNumId = intDecl.getMethodNumId(method); String helperMethod = methodNumId + "struct" + i; println("int methodIdStruct" + i + " = " + intDecl.getHelperMethodNumId(helperMethod) + ";"); println("string retTypeStruct" + i + " = \"void\";"); println("string paramClsStruct" + i + "[] = { \"int\" };"); print("int structLen" + i + " = "); if (isArrayOrList(param, paramType)) { // An array println(getSimpleArrayType(param) + ".size();"); } else { // Just one element println("1;"); } println("void* paramObjStruct" + i + "[] = { &structLen" + i + " };"); println("void* retStructLen" + i + " = NULL;"); println("rmiCall->remoteCall(objectId, methodIdStruct" + i + ", retTypeStruct" + i + ", paramClsStruct" + i + ", paramObjStruct" + i + ", numParam" + i + ", retStructLen" + i + ");\n"); } } } /** * HELPER: writeLengthStructParamClassCplusStub() writes lengths of params */ private void writeLengthStructParamClassCplusStub(List methParams, List methPrmTypes) { // Iterate and find struct declarations - count number of params for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getGenericType(paramType); if (isStructClass(simpleType)) { int members = getNumOfMembers(simpleType); if (isArrayOrList(param, paramType)) { // An array String structLen = param + ".size()"; print(members + "*" + structLen); } else print(Integer.toString(members)); } else print("1"); if (i != methParams.size() - 1) { print("+"); } } } /** * HELPER: writeStructMembersCplusStub() writes member parameters of struct */ private void writeStructMembersCplusStub(String simpleType, String paramType, String param) { // Get the struct declaration for this struct and generate initialization code StructDecl structDecl = getStructDecl(simpleType); List memTypes = structDecl.getMemberTypes(simpleType); List members = structDecl.getMembers(simpleType); if (isArrayOrList(param, paramType)) { // An array or list println("for(int i = 0; i < " + param + ".size(); i++) {"); } if (isArrayOrList(param, paramType)) { // An array or list for (int i = 0; i < members.size(); i++) { String prmTypeC = checkAndGetCplusType(memTypes.get(i)); String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i)); println("paramCls[pos] = \"" + getSimpleType(getEnumType(prmType)) + "\";"); print("paramObj[pos++] = &" + param + "[i]."); print(getSimpleIdentifier(members.get(i))); println(";"); } println("}"); } else { // Just one struct element for (int i = 0; i < members.size(); i++) { String prmTypeC = checkAndGetCplusType(memTypes.get(i)); String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i)); println("paramCls[pos] = \"" + getSimpleType(getEnumType(prmType)) + "\";"); print("paramObj[pos++] = &" + param + "."); print(getSimpleIdentifier(members.get(i))); println(";"); } } } /** * HELPER: writeStructParamClassCplusStub() writes member parameters of struct */ private void writeStructParamClassCplusStub(List methParams, List methPrmTypes) { print("int numParam = "); writeLengthStructParamClassCplusStub(methParams, methPrmTypes); println(";"); println("void* paramObj[numParam];"); println("string paramCls[numParam];"); println("int pos = 0;"); // Iterate again over the parameters for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getGenericType(paramType); if (isStructClass(simpleType)) { writeStructMembersCplusStub(simpleType, paramType, param); } else { String prmTypeC = checkAndGetCplusType(methPrmTypes.get(i)); String prmType = checkAndGetCplusArrayType(prmTypeC, methParams.get(i)); println("paramCls[pos] = \"" + getSimpleType(getEnumType(prmType)) + "\";"); print("paramObj[pos++] = &"); print(getEnumParam(methPrmTypes.get(i), getSimpleIdentifier(methParams.get(i)), i)); println(";"); } } } /** * HELPER: writeStructRetMembersCplusStub() writes member parameters of struct for return statement */ private void writeStructRetMembersCplusStub(String simpleType, String retType) { // Get the struct declaration for this struct and generate initialization code StructDecl structDecl = getStructDecl(simpleType); List memTypes = structDecl.getMemberTypes(simpleType); List members = structDecl.getMembers(simpleType); if (isArrayOrList(retType, retType)) { // An array or list println("for(int i = 0; i < retLen; i++) {"); } if (isArrayOrList(retType, retType)) { // An array or list for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); print("structRet[i]." + getSimpleIdentifier(members.get(i))); println(" = retParam" + i + "[i];"); } println("}"); } else { // Just one struct element for (int i = 0; i < members.size(); i++) { String prmType = checkAndGetArray(memTypes.get(i), members.get(i)); print("structRet." + getSimpleIdentifier(members.get(i))); println(" = retParam" + i + ";"); } } println("return structRet;"); } /** * HELPER: writeStructReturnCplusStub() writes member parameters of struct for return statement */ private void writeStructReturnCplusStub(String simpleType, String retType) { // Minimum retLen is 1 if this is a single struct object println("int retLen = 0;"); println("void* retLenObj = { &retLen };"); // Handle the returned struct!!! println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retLenObj);"); int numMem = getNumOfMembers(simpleType); println("int numRet = " + numMem + "*retLen;"); println("string retCls[numRet];"); println("void* retObj[numRet];"); StructDecl structDecl = getStructDecl(simpleType); List memTypes = structDecl.getMemberTypes(simpleType); List members = structDecl.getMembers(simpleType); // Set up variables if (isArrayOrList(retType, retType)) { // An array or list for (int i = 0; i < members.size(); i++) { String prmTypeC = checkAndGetCplusType(memTypes.get(i)); String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i)); println(getSimpleType(getEnumType(prmType)) + " retParam" + i + "[retLen];"); } } else { // Just one struct element for (int i = 0; i < members.size(); i++) { String prmTypeC = checkAndGetCplusType(memTypes.get(i)); String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i)); println(getSimpleType(getEnumType(prmType)) + " retParam" + i + ";"); } } println("int retPos = 0;"); // Get the struct declaration for this struct and generate initialization code if (isArrayOrList(retType, retType)) { // An array or list println("for(int i = 0; i < retLen; i++) {"); for (int i = 0; i < members.size(); i++) { String prmTypeC = checkAndGetCplusType(memTypes.get(i)); String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i)); println("retCls[retPos] = \"" + getSimpleType(getEnumType(prmType)) + "\";"); println("retObj[retPos++] = &retParam" + i + "[i];"); } println("}"); } else { // Just one struct element for (int i = 0; i < members.size(); i++) { String prmTypeC = checkAndGetCplusType(memTypes.get(i)); String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i)); println("retCls[retPos] = \"" + getSimpleType(getEnumType(prmType)) + "\";"); println("retObj[retPos++] = &retParam" + i + ";"); } } println("rmiCall->getStructObjects(retCls, numRet, retObj);"); if (isArrayOrList(retType, retType)) { // An array or list println("vector<" + simpleType + "> structRet(retLen);"); } else println(simpleType + " structRet;"); writeStructRetMembersCplusStub(simpleType, retType); } /** * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class */ private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method) { checkAndWriteStructSetupCplusStub(methParams, methPrmTypes, intDecl, method); println("int methodId = " + intDecl.getMethodNumId(method) + ";"); String retType = intDecl.getMethodType(method); //String retTypeC = checkAndGetCplusType(retType); //println("string retType = \"" + checkAndGetCplusArrayType(getStructType(getEnumType(retTypeC))) + "\";"); println("string retType = \"" + checkAndGetCplusRetClsType(getStructType(getEnumType(retType))) + "\";"); // Generate array of parameter types if (isStructPresent(methParams, methPrmTypes)) { writeStructParamClassCplusStub(methParams, methPrmTypes); } else { println("int numParam = " + methParams.size() + ";"); print("string paramCls[] = { "); for (int i = 0; i < methParams.size(); i++) { //String paramTypeC = checkAndGetArray(methPrmTypes.get(i), methParams.get(i)); //String prmType = getSimpleType(getEnumType(paramTypeC)); String paramTypeC = checkAndGetCplusArgClsType(methPrmTypes.get(i), methParams.get(i)); String prmType = getEnumType(paramTypeC); print("\"" + prmType + "\""); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(" };"); checkAndWriteEnumTypeCplusStub(methParams, methPrmTypes); // Generate array of parameter objects print("void* paramObj[] = { "); for (int i = 0; i < methParams.size(); i++) { print("&" + getEnumParam(methPrmTypes.get(i), getSimpleIdentifier(methParams.get(i)), i)); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(" };"); } // Check if this is "void" if (retType.equals("void")) { println("void* retObj = NULL;"); println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);"); } else { // We do have a return value // Generate array of parameter types if (isStructClass(getGenericType(getSimpleArrayType(retType)))) { writeStructReturnCplusStub(getGenericType(getSimpleArrayType(retType)), retType); } else { // Check if the return value NONPRIMITIVES if (getParamCategory(retType) == ParamCategory.ENUM) { checkAndWriteEnumRetTypeCplusStub(retType); } else { //if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) if (isArrayOrList(retType,retType)) println(checkAndGetCplusType(retType) + " retVal;"); else { println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";"); } println("void* retObj = &retVal;"); println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);"); println("return retVal;"); } } } } /** * HELPER: writePropertiesCplusStub() writes the properties of the stub class */ private void writePropertiesCplusPermission(String intface) { Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { String newIntface = intMeth.getKey(); int newObjectId = getNewIntfaceObjectId(newIntface); println("const static int object" + newObjectId + "Id = " + newObjectId + ";"); println("const static set set" + newObjectId + "Allowed;"); } } /** * HELPER: writePropertiesCplusStub() writes the properties of the stub class */ private void writePropertiesCplusStub(String intface, String newIntface, boolean callbackExist, Set callbackClasses) { println("IoTRMICall *rmiCall;"); //println("IoTRMIObject\t\t\t*rmiObj;"); println("string address;"); println("vector ports;\n"); // Get the object Id Integer objId = mapIntfaceObjId.get(intface); println("const static int objectId = " + objId + ";"); mapNewIntfaceObjId.put(newIntface, objId); mapIntfaceObjId.put(intface, objId++); if (callbackExist) { // We assume that each class only has one callback interface for now Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); println("// Callback properties"); println("IoTRMIObject *rmiObj;"); println("vector<" + callbackType + "*> vecCallbackObj;"); println("static int objIdCnt;"); // Generate permission stuff for callback stubs writePropertiesCplusPermission(callbackType); } println("\n"); } /** * HELPER: writeConstructorCplusStub() writes the constructor of the stub class */ private void writeConstructorCplusStub(String newStubClass, boolean callbackExist, Set callbackClasses) { println(newStubClass + "(int _port, const char* _address, int _rev, bool* _bResult, vector _ports) {"); println("address = _address;"); println("ports = _ports;"); println("rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);"); if (callbackExist) { println("objIdCnt = 0;"); Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); println("thread th1 (&" + newStubClass + "::___initCallBack, this);"); println("th1.detach();"); println("___regCB();"); } println("}\n"); } /** * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class */ private void writeDeconstructorCplusStub(String newStubClass, boolean callbackExist, Set callbackClasses) { println("~" + newStubClass + "() {"); println("if (rmiCall != NULL) {"); println("delete rmiCall;"); println("rmiCall = NULL;"); println("}"); if (callbackExist) { // We assume that each class only has one callback interface for now println("if (rmiObj != NULL) {"); println("delete rmiObj;"); println("rmiObj = NULL;"); println("}"); Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); println("for(" + callbackType + "* cb : vecCallbackObj) {"); println("delete cb;"); println("cb = NULL;"); println("}"); } println("}"); println(""); } /** * HELPER: writeCplusMethodCallbackPermission() writes permission checks in stub for callbacks */ private void writeCplusMethodCallbackPermission(String intface) { println("int methodId = IoTRMIObject::getMethodId(method);"); // Get all the different stubs Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { String newIntface = intMeth.getKey(); int newObjectId = getNewIntfaceObjectId(newIntface); println("if (set" + newObjectId + "Allowed.find(methodId) == set" + newObjectId + "Allowed.end()) {"); println("cerr << \"Callback object for " + intface + " is not allowed to access method: \" << methodId;"); println("exit(-1);"); println("}"); } } /** * HELPER: writeInitCallbackCplusStub() writes the initialization of callback */ private void writeInitCallbackCplusStub(String intface, InterfaceDecl intDecl) { println("void ___initCallBack() {"); println("bool bResult = false;"); println("rmiObj = new IoTRMIObject(ports[0], &bResult);"); println("while (true) {"); println("char* method = rmiObj->getMethodBytes();"); writeCplusMethodCallbackPermission(intface); println("int objId = IoTRMIObject::getObjectId(method);"); println("if (objId < vecCallbackObj.size()) { // Check if still within range"); println(intface + "_CallbackSkeleton* skel = dynamic_cast<" + intface + "_CallbackSkeleton*> (vecCallbackObj.at(objId));"); println("skel->invokeMethod(rmiObj);"); println("} else {"); println("cerr << \"Illegal object Id: \" << to_string(objId);"); // TODO: perhaps need to change this into "throw" to make it cleaner (allow stack unfolding) println("exit(-1);"); println("}"); println("}"); println("}\n"); } /** * HELPER: writeInitCallbackSendInfoCplusStub() writes the initialization (send info part) of callback */ private void writeInitCallbackSendInfoCplusStub(InterfaceDecl intDecl) { // Generate info sending part println("void ___regCB() {"); println("int numParam = 3;"); String method = "___initCallBack()"; println("int methodId = " + intDecl.getHelperMethodNumId(method) + ";"); println("string retType = \"void\";"); println("string paramCls[] = { \"int\", \"string\", \"int\" };"); println("int rev = 0;"); println("void* paramObj[] = { &ports[0], &address, &rev };"); println("void* retObj = NULL;"); println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);"); println("}\n"); } /** * generateCPlusStubClasses() generate stubs based on the methods list in C++ */ public void generateCPlusStubClasses() throws IOException { // Create a new directory String path = createDirectories(dir, subdir); for (String intface : mapIntfacePTH.keySet()) { Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { // Open a new file to write into String newIntface = intMeth.getKey(); String newStubClass = newIntface + "_Stub"; FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp"); pw = new PrintWriter(new BufferedWriter(fw)); // Write file headers println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__"); println("#define _" + newStubClass.toUpperCase() + "_HPP__"); println("#include "); // Find out if there are callback objects Set methods = intMeth.getValue(); DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); Set callbackClasses = getCallbackClasses(methods, intDecl); boolean callbackExist = !callbackClasses.isEmpty(); if (callbackExist) // Need thread library if this has callback println("#include "); println("#include \"" + newIntface + ".hpp\""); println(""); println("using namespace std;"); println(""); println("class " + newStubClass + " : public " + newIntface); println("{"); println("private:\n"); writePropertiesCplusStub(intface, newIntface, callbackExist, callbackClasses); println("public:\n"); // Add default constructor and destructor println(newStubClass + "() { }"); println(""); writeConstructorCplusStub(newStubClass, callbackExist, callbackClasses); writeDeconstructorCplusStub(newStubClass, callbackExist, callbackClasses); // Write methods writeMethodCplusStub(methods, intDecl, callbackClasses); print("}"); println(";"); if (callbackExist) writePermissionInitializationCplus(intface, newStubClass, intDecl); println("#endif"); pw.close(); System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".hpp..."); } } } /** * HELPER: writePropertiesCplusCallbackStub() writes the properties of the stub class */ private void writePropertiesCplusCallbackStub(String intface, String newIntface, boolean callbackExist, Set callbackClasses) { println("IoTRMICall *rmiCall;"); // Get the object Id println("static int objectId;"); if (callbackExist) { // We assume that each class only has one callback interface for now Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); println("// Callback properties"); println("IoTRMIObject *rmiObj;"); println("vector<" + callbackType + "*> vecCallbackObj;"); println("static int objIdCnt;"); // TODO: Need to initialize address and ports if we want to have callback-in-callback println("string address;"); println("vector ports;\n"); writePropertiesCplusPermission(callbackType); } println("\n"); } /** * HELPER: writeConstructorCplusCallbackStub() writes the constructor of the stub class */ private void writeConstructorCplusCallbackStub(String newStubClass, boolean callbackExist, Set callbackClasses) { println(newStubClass + "(IoTRMICall* _rmiCall, int _objectId) {"); println("objectId = _objectId;"); println("rmiCall = _rmiCall;"); if (callbackExist) { Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); println("thread th1 (&" + newStubClass + "::___initCallBack, this);"); println("th1.detach();"); println("___regCB();"); } println("}\n"); } /** * generateCPlusCallbackStubClasses() generate callback stubs based on the methods list in C++ */ public void generateCPlusCallbackStubClasses() throws IOException { // Create a new directory String path = createDirectories(dir, subdir); for (String intface : mapIntfacePTH.keySet()) { Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { // Open a new file to write into String newIntface = intMeth.getKey(); String newStubClass = newIntface + "_CallbackStub"; FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp"); pw = new PrintWriter(new BufferedWriter(fw)); // Find out if there are callback objects Set methods = intMeth.getValue(); DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); Set callbackClasses = getCallbackClasses(methods, intDecl); boolean callbackExist = !callbackClasses.isEmpty(); // Write file headers println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__"); println("#define _" + newStubClass.toUpperCase() + "_HPP__"); println("#include "); if (callbackExist) println("#include "); println("#include \"" + newIntface + ".hpp\""); println(""); println("using namespace std;"); println(""); println("class " + newStubClass + " : public " + newIntface); println("{"); println("private:\n"); writePropertiesCplusCallbackStub(intface, newIntface, callbackExist, callbackClasses); println("public:\n"); // Add default constructor and destructor println(newStubClass + "() { }"); println(""); writeConstructorCplusCallbackStub(newStubClass, callbackExist, callbackClasses); writeDeconstructorCplusStub(newStubClass, callbackExist, callbackClasses); // Write methods writeMethodCplusStub(methods, intDecl, callbackClasses); println("};"); if (callbackExist) writePermissionInitializationCplus(intface, newStubClass, intDecl); println("#endif"); pw.close(); System.out.println("IoTCompiler: Generated callback stub class " + newIntface + ".hpp..."); } } } /** * HELPER: writePropertiesCplusSkeleton() writes the properties of the skeleton class */ private void writePropertiesCplusSkeleton(String intface, boolean callbackExist, Set callbackClasses) { println(intface + " *mainObj;"); // Callback if (callbackExist) { Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); String exchangeType = checkAndGetParamClass(callbackType); println("// Callback properties"); println("static int objIdCnt;"); println("vector<" + exchangeType + "*> vecCallbackObj;"); println("IoTRMICall *rmiCall;"); } println("IoTRMIObject *rmiObj;\n"); // Keep track of object Ids of all stubs registered to this interface writePropertiesCplusPermission(intface); println("\n"); } /** * HELPER: writePermissionInitializationCplus() writes the initialization of permission set */ private void writePermissionInitializationCplus(String intface, String newSkelClass, InterfaceDecl intDecl) { // Keep track of object Ids of all stubs registered to this interface Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { String newIntface = intMeth.getKey(); int newObjectId = getNewIntfaceObjectId(newIntface); print("const set " + newSkelClass + "::set" + newObjectId + "Allowed {"); Set methodIds = intMeth.getValue(); int i = 0; for (String methodId : methodIds) { int methodNumId = intDecl.getMethodNumId(methodId); print(Integer.toString(methodNumId)); // Check if this is the last element (don't print a comma) if (i != methodIds.size() - 1) { print(", "); } i++; } println(" };"); } } /** * HELPER: writeConstructorCplusSkeleton() writes the constructor of the skeleton class */ private void writeConstructorCplusSkeleton(String newSkelClass, String intface, boolean callbackExist) { println(newSkelClass + "(" + intface + " *_mainObj, int _port) {"); println("bool _bResult = false;"); println("mainObj = _mainObj;"); println("rmiObj = new IoTRMIObject(_port, &_bResult);"); // Callback if (callbackExist) { println("objIdCnt = 0;"); } //println("set0Allowed = Arrays.asList(object0Permission);"); println("___waitRequestInvokeMethod();"); println("}\n"); } /** * HELPER: writeDeconstructorCplusSkeleton() writes the deconstructor of the skeleton class */ private void writeDeconstructorCplusSkeleton(String newSkelClass, boolean callbackExist, Set callbackClasses) { println("~" + newSkelClass + "() {"); println("if (rmiObj != NULL) {"); println("delete rmiObj;"); println("rmiObj = NULL;"); println("}"); if (callbackExist) { // We assume that each class only has one callback interface for now println("if (rmiCall != NULL) {"); println("delete rmiCall;"); println("rmiCall = NULL;"); println("}"); Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); String exchangeType = checkAndGetParamClass(callbackType); println("for(" + exchangeType + "* cb : vecCallbackObj) {"); println("delete cb;"); println("cb = NULL;"); println("}"); } println("}"); println(""); } /** * HELPER: writeStdMethodBodyCplusSkeleton() writes the standard method body in the skeleton class */ private void writeStdMethodBodyCplusSkeleton(List methParams, String methodId, String methodType) { if (methodType.equals("void")) print("mainObj->" + methodId + "("); else print("return mainObj->" + methodId + "("); for (int i = 0; i < methParams.size(); i++) { print(getSimpleIdentifier(methParams.get(i))); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(");"); } /** * HELPER: writeInitCallbackCplusSkeleton() writes the init callback method for skeleton class */ private void writeInitCallbackCplusSkeleton(boolean callbackSkeleton) { // This is a callback skeleton generation if (callbackSkeleton) println("void ___regCB(IoTRMIObject* rmiObj) {"); else println("void ___regCB() {"); println("int numParam = 3;"); println("int param1 = 0;"); println("string param2 = \"\";"); println("int param3 = 0;"); println("void* paramObj[] = { ¶m1, ¶m2, ¶m3 };"); println("bool bResult = false;"); println("rmiCall = new IoTRMICall(param1, param2.c_str(), param3, &bResult);"); println("}\n"); } /** * HELPER: writeMethodCplusSkeleton() writes the method of the skeleton class */ private void writeMethodCplusSkeleton(Collection methods, InterfaceDecl intDecl, Set callbackClasses, boolean callbackSkeleton) { for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); String methodId = intDecl.getMethodId(method); String methodType = checkAndGetCplusType(intDecl.getMethodType(method)); print(methodType + " " + methodId + "("); boolean isCallbackMethod = false; String callbackType = null; for (int i = 0; i < methParams.size(); i++) { String origParamType = methPrmTypes.get(i); if (callbackClasses.contains(origParamType)) { // Check if this has callback object isCallbackMethod = true; callbackType = origParamType; } String paramType = checkAndGetParamClass(methPrmTypes.get(i)); String methPrmType = checkAndGetCplusType(paramType); String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i)); print(methParamComplete); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(") {"); // Now, write the body of skeleton! writeStdMethodBodyCplusSkeleton(methParams, methodId, intDecl.getMethodType(method)); println("}\n"); if (isCallbackMethod) writeInitCallbackCplusSkeleton(callbackSkeleton); } } /** * HELPER: writeCallbackCplusNumStubs() writes the numStubs variable */ private void writeCallbackCplusNumStubs(List methParams, List methPrmTypes, String callbackType) { for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); //if (callbackType.equals(paramType)) { if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object String exchParamType = checkAndGetParamClass(paramType); // Print array if this is array or list if this is a list of callback objects println("int numStubs" + i + " = 0;"); } } } /** * HELPER: writeCallbackCplusStubGeneration() writes the callback stub generation part */ private void writeCallbackCplusStubGeneration(List methParams, List methPrmTypes, String callbackType) { // Iterate over callback objects for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); // Generate a loop if needed if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object String exchParamType = checkAndGetParamClass(paramType); if (isArrayOrList(paramType, param)) { println("vector<" + exchParamType + "> stub;"); println("for (int objId = 0; objId < numStubs" + i + "; objId++) {"); println(exchParamType + "* cb" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);"); println("stub" + i + ".push_back(cb);"); println("vecCallbackObj.push_back(cb);"); println("objIdCnt++;"); println("}"); } else { println(exchParamType + "* stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);"); println("vecCallbackObj.push_back(stub" + i + ");"); println("objIdCnt++;"); } } } } /** * HELPER: checkAndWriteEnumTypeCplusSkeleton() writes the enum type (convert from enum to int) */ private void checkAndWriteEnumTypeCplusSkeleton(List methParams, List methPrmTypes) { // Iterate and find enum declarations for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isEnumClass(simpleType)) { // Check if this is enum type if (isArrayOrList(paramType, param)) { // An array println("int len" + i + " = paramEnumInt" + i + ".size();"); println("vector<" + simpleType + "> paramEnum" + i + "(len" + i + ");"); println("for (int i=0; i < len" + i + "; i++) {"); println("paramEnum" + i + "[i] = (" + simpleType + ") paramEnumInt" + i + "[i];"); println("}"); } else { // Just one element println(simpleType + " paramEnum" + i + ";"); println("paramEnum" + i + " = (" + simpleType + ") paramEnumInt" + i + "[0];"); } } } } /** * HELPER: checkAndWriteEnumRetTypeCplusSkeleton() writes the enum return type (convert from enum to int) */ private void checkAndWriteEnumRetTypeCplusSkeleton(String retType) { // Strips off array "[]" for return type String pureType = getSimpleArrayType(getSimpleType(retType)); // Take the inner type of generic if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) pureType = getTypeOfGeneric(retType)[0]; if (isEnumClass(pureType)) { // Check if this is enum type // Enum decoder if (isArrayOrList(retType, retType)) { // An array println("int retLen = retEnum.size();"); println("vector retEnumInt(retLen);"); println("for (int i=0; i < retLen; i++) {"); println("retEnumInt[i] = (int) retEnum[i];"); println("}"); } else { // Just one element println("vector retEnumInt(1);"); println("retEnumInt[0] = (int) retEnum;"); } } } /** * HELPER: writeMethodHelperReturnCplusSkeleton() writes the return statement part in skeleton */ private void writeMethodInputParameters(List methParams, List methPrmTypes, Set callbackClasses, String methodId) { print(methodId + "("); for (int i = 0; i < methParams.size(); i++) { String paramType = returnGenericCallbackType(methPrmTypes.get(i)); if (callbackClasses.contains(paramType)) print("stub" + i); else if (isEnumClass(getSimpleType(paramType))) // Check if this is enum type print("paramEnum" + i); else if (isStructClass(getSimpleType(paramType))) // Struct type print("paramStruct" + i); else print(getSimpleIdentifier(methParams.get(i))); if (i != methParams.size() - 1) { print(", "); } } println(");"); } /** * HELPER: writeMethodHelperReturnCplusSkeleton() writes the return statement part in skeleton */ private void writeMethodHelperReturnCplusSkeleton(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method, boolean isCallbackMethod, String callbackType, String methodId, Set callbackClasses) { println("rmiObj->getMethodParams(paramCls, numParam, paramObj);"); if (isCallbackMethod) writeCallbackCplusStubGeneration(methParams, methPrmTypes, callbackType); checkAndWriteEnumTypeCplusSkeleton(methParams, methPrmTypes); writeStructMembersInitCplusSkeleton(intDecl, methParams, methPrmTypes, method); // Check if this is "void" String retType = intDecl.getMethodType(method); // Check if this is "void" if (retType.equals("void")) { writeMethodInputParameters(methParams, methPrmTypes, callbackClasses, methodId); } else { // We do have a return value if (isEnumClass(getSimpleArrayType(getSimpleType(retType)))) // Enum type print(checkAndGetCplusType(retType) + " retEnum = "); else if (isStructClass(getSimpleArrayType(getSimpleType(retType)))) // Struct type print(checkAndGetCplusType(retType) + " retStruct = "); else print(checkAndGetCplusType(retType) + " retVal = "); writeMethodInputParameters(methParams, methPrmTypes, callbackClasses, methodId); checkAndWriteEnumRetTypeCplusSkeleton(retType); if (isStructClass(getSimpleArrayType(getSimpleType(retType)))) // Struct type writeStructReturnCplusSkeleton(getSimpleArrayType(getSimpleType(retType)), retType); if (isEnumClass(getSimpleArrayType(getSimpleType(retType)))) // Enum type println("void* retObj = &retEnumInt;"); else if (!isStructClass(getSimpleArrayType(getSimpleType(retType)))) // Struct type println("void* retObj = &retVal;"); String retTypeC = checkAndGetCplusType(retType); if (isStructClass(getSimpleArrayType(getSimpleType(retType)))) // Struct type println("rmiObj->sendReturnObj(retObj, retCls, numRetObj);"); else println("rmiObj->sendReturnObj(retObj, \"" + checkAndGetCplusRetClsType(getEnumType(retType)) + "\");"); } } /** * HELPER: writeStdMethodHelperBodyCplusSkeleton() writes the standard method body helper in the skeleton class */ private void writeStdMethodHelperBodyCplusSkeleton(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method, String methodId, Set callbackClasses) { // Generate array of parameter types boolean isCallbackMethod = false; String callbackType = null; print("string paramCls[] = { "); for (int i = 0; i < methParams.size(); i++) { String paramType = returnGenericCallbackType(methPrmTypes.get(i)); if (callbackClasses.contains(paramType)) { isCallbackMethod = true; callbackType = paramType; print("\"int\""); } else { // Generate normal classes if it's not a callback object //String paramTypeC = checkAndGetArray(methPrmTypes.get(i), methParams.get(i)); //String prmType = getSimpleType(getEnumType(paramTypeC)); String paramTypeC = checkAndGetCplusArgClsType(methPrmTypes.get(i), methParams.get(i)); String prmType = getEnumType(paramTypeC); print("\"" + prmType + "\""); } if (i != methParams.size() - 1) { print(", "); } } println(" };"); println("int numParam = " + methParams.size() + ";"); if (isCallbackMethod) writeCallbackCplusNumStubs(methParams, methPrmTypes, callbackType); // Generate parameters for (int i = 0; i < methParams.size(); i++) { String paramType = returnGenericCallbackType(methPrmTypes.get(i)); if (!callbackClasses.contains(paramType)) { String methPrmType = checkAndGetCplusType(methPrmTypes.get(i)); if (isEnumClass(getSimpleType(methPrmType))) { // Check if this is enum type println("vector paramEnumInt" + i + ";"); } else { String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i)); println(methParamComplete + ";"); } } } // Generate array of parameter objects print("void* paramObj[] = { "); for (int i = 0; i < methParams.size(); i++) { String paramType = returnGenericCallbackType(methPrmTypes.get(i)); if (callbackClasses.contains(paramType)) print("&numStubs" + i); else if (isEnumClass(getSimpleType(paramType))) // Check if this is enum type print("¶mEnumInt" + i); else print("&" + getSimpleIdentifier(methParams.get(i))); if (i != methParams.size() - 1) { print(", "); } } println(" };"); // Write the return value part writeMethodHelperReturnCplusSkeleton(intDecl, methParams, methPrmTypes, method, isCallbackMethod, callbackType, methodId, callbackClasses); } /** * HELPER: writeStructMembersCplusSkeleton() writes member parameters of struct */ private void writeStructMembersCplusSkeleton(String simpleType, String paramType, String param, String method, InterfaceDecl intDecl, int iVar) { // Get the struct declaration for this struct and generate initialization code StructDecl structDecl = getStructDecl(simpleType); List memTypes = structDecl.getMemberTypes(simpleType); List members = structDecl.getMembers(simpleType); int methodNumId = intDecl.getMethodNumId(method); String counter = "struct" + methodNumId + "Size" + iVar; if (isArrayOrList(param, paramType)) { // An array or list println("for(int i = 0; i < " + counter + "; i++) {"); } // Set up variables if (isArrayOrList(param, paramType)) { // An array or list for (int i = 0; i < members.size(); i++) { String prmTypeC = checkAndGetCplusType(memTypes.get(i)); String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i)); println(getSimpleType(getEnumType(prmType)) + " param" + i + "[" + counter + "];"); } } else { // Just one struct element for (int i = 0; i < members.size(); i++) { String prmTypeC = checkAndGetCplusType(memTypes.get(i)); String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i)); println(getSimpleType(getEnumType(prmType)) + " param" + i + ";"); } } println("int pos = 0;"); if (isArrayOrList(param, paramType)) { // An array or list println("for(int i = 0; i < retLen; i++) {"); for (int i = 0; i < members.size(); i++) { String prmTypeC = checkAndGetCplusType(memTypes.get(i)); String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i)); println("paramCls[pos] = \"" + getSimpleType(getEnumType(prmType)) + "\";"); println("paramObj[pos++] = ¶m" + i + "[i];"); } println("}"); } else { // Just one struct element for (int i = 0; i < members.size(); i++) { String prmTypeC = checkAndGetCplusType(memTypes.get(i)); String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i)); println("paramCls[pos] = \"" + getSimpleType(getEnumType(prmType)) + "\";"); println("paramObj[pos++] = ¶m" + i + ";"); } } } /** * HELPER: writeStructMembersInitCplusSkeleton() writes member parameters initialization of struct */ private void writeStructMembersInitCplusSkeleton(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method) { for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getGenericType(paramType); if (isStructClass(simpleType)) { int methodNumId = intDecl.getMethodNumId(method); String counter = "struct" + methodNumId + "Size" + i; // Declaration if (isArrayOrList(param, paramType)) { // An array or list println("vector<" + simpleType + "> paramStruct" + i + ";"); } else println(simpleType + " paramStruct" + i + ";"); // Initialize members StructDecl structDecl = getStructDecl(simpleType); List members = structDecl.getMembers(simpleType); List memTypes = structDecl.getMemberTypes(simpleType); if (isArrayOrList(param, paramType)) { // An array or list println("for(int i = 0; i < " + counter + "; i++) {"); for (int j = 0; j < members.size(); j++) { print("paramStruct" + i + "[i]." + getSimpleIdentifier(members.get(j))); println(" = param" + j + "[i];"); } println("}"); } else { // Just one struct element for (int j = 0; j < members.size(); j++) { print("paramStruct" + i + "." + getSimpleIdentifier(members.get(j))); println(" = param" + j + ";"); } } } } } /** * HELPER: writeStructReturnCplusSkeleton() writes parameters of struct for return statement */ private void writeStructReturnCplusSkeleton(String simpleType, String retType) { // Minimum retLen is 1 if this is a single struct object if (isArrayOrList(retType, retType)) println("int retLen = retStruct.size();"); else // Just single struct object println("int retLen = 1;"); println("void* retLenObj = &retLen;"); println("rmiObj->sendReturnObj(retLenObj, \"int\");"); int numMem = getNumOfMembers(simpleType); println("int numRetObj = " + numMem + "*retLen;"); println("string retCls[numRetObj];"); println("void* retObj[numRetObj];"); println("int retPos = 0;"); // Get the struct declaration for this struct and generate initialization code StructDecl structDecl = getStructDecl(simpleType); List memTypes = structDecl.getMemberTypes(simpleType); List members = structDecl.getMembers(simpleType); if (isArrayOrList(retType, retType)) { // An array or list println("for(int i = 0; i < retLen; i++) {"); for (int i = 0; i < members.size(); i++) { String paramTypeC = checkAndGetCplusType(memTypes.get(i)); String prmType = checkAndGetCplusArrayType(paramTypeC, members.get(i)); println("retCls[retPos] = \"" + getSimpleType(getEnumType(prmType)) + "\";"); print("retObj[retPos++] = &retStruct[i]."); print(getEnumParam(memTypes.get(i), getSimpleIdentifier(members.get(i)), i)); println(";"); } println("}"); } else { // Just one struct element for (int i = 0; i < members.size(); i++) { String paramTypeC = checkAndGetCplusType(memTypes.get(i)); String prmType = checkAndGetCplusArrayType(paramTypeC, members.get(i)); println("retCls[retPos] = \"" + getSimpleType(getEnumType(prmType)) + "\";"); print("retObj[retPos++] = &retStruct."); print(getEnumParam(memTypes.get(i), getSimpleIdentifier(members.get(i)), i)); println(";"); } } } /** * HELPER: writeMethodHelperStructCplusSkeleton() writes the struct in skeleton */ private void writeMethodHelperStructCplusSkeleton(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method, String methodId, Set callbackClasses) { // Generate array of parameter objects boolean isCallbackMethod = false; String callbackType = null; print("int numParam = "); writeLengthStructParamClassSkeleton(methParams, methPrmTypes, method, intDecl); println(";"); println("string paramCls[numParam];"); println("void* paramObj[numParam];"); // Iterate again over the parameters for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getGenericType(paramType); if (isStructClass(simpleType)) { writeStructMembersCplusSkeleton(simpleType, paramType, param, method, intDecl, i); } else { String prmType = returnGenericCallbackType(methPrmTypes.get(i)); if (callbackClasses.contains(prmType)) { isCallbackMethod = true; callbackType = paramType; writeCallbackCplusNumStubs(methParams, methPrmTypes, callbackType); println("paramCls[pos] = \"int\";"); println("paramObj[pos++] = &numStubs" + i + ";"); } else { // Generate normal classes if it's not a callback object String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i)); String prmTypeC = checkAndGetCplusArrayType(paramTypeC, methParams.get(i)); if (isEnumClass(getSimpleType(paramTypeC))) { // Check if this is enum type println("vector paramEnumInt" + i + ";"); } else { String methParamComplete = checkAndGetCplusArray(paramTypeC, methParams.get(i)); println(methParamComplete + ";"); } println("paramCls[pos] = \"" + getEnumType(prmTypeC) + "\";"); if (isEnumClass(getSimpleType(paramType))) // Check if this is enum type println("paramObj[pos++] = ¶mEnumInt" + i); else println("paramObj[pos++] = &" + getSimpleIdentifier(methParams.get(i)) + ";"); } } } // Write the return value part writeMethodHelperReturnCplusSkeleton(intDecl, methParams, methPrmTypes, method, isCallbackMethod, callbackType, methodId, callbackClasses); } /** * HELPER: writeMethodHelperCplusSkeleton() writes the method helper of the skeleton class */ private void writeMethodHelperCplusSkeleton(Collection methods, InterfaceDecl intDecl, Set callbackClasses) { // Use this set to handle two same methodIds Set uniqueMethodIds = new HashSet(); for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); if (isStructPresent(methParams, methPrmTypes)) { // Treat struct differently String methodId = intDecl.getMethodId(method); print("void ___"); String helperMethod = methodId; if (uniqueMethodIds.contains(methodId)) helperMethod = helperMethod + intDecl.getMethodNumId(method); else uniqueMethodIds.add(methodId); String retType = intDecl.getMethodType(method); print(helperMethod + "("); boolean begin = true; for (int i = 0; i < methParams.size(); i++) { // Print size variables String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { if (!begin) { // Generate comma for not the beginning variable print(", "); begin = false; } int methodNumId = intDecl.getMethodNumId(method); print("int struct" + methodNumId + "Size" + i); } } println(") {"); writeMethodHelperStructCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses); println("}\n"); } else { String methodId = intDecl.getMethodId(method); print("void ___"); String helperMethod = methodId; if (uniqueMethodIds.contains(methodId)) helperMethod = helperMethod + intDecl.getMethodNumId(method); else uniqueMethodIds.add(methodId); // Check if this is "void" String retType = intDecl.getMethodType(method); println(helperMethod + "() {"); // Now, write the helper body of skeleton! writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses); println("}\n"); } } // Write method helper for structs writeMethodHelperStructSetupCplusSkeleton(methods, intDecl); } /** * HELPER: writeMethodHelperStructSetupCplusSkeleton() writes the method helper of struct in skeleton class */ private void writeMethodHelperStructSetupCplusSkeleton(Collection methods, InterfaceDecl intDecl) { // Use this set to handle two same methodIds for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); // Check for params with structs for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { int methodNumId = intDecl.getMethodNumId(method); print("int ___"); String helperMethod = methodNumId + "struct" + i; println(helperMethod + "() {"); // Now, write the helper body of skeleton! println("string paramCls[] = { \"int\" };"); println("int numParam = 1;"); println("int param0 = 0;"); println("void* paramObj[] = { ¶m0 };"); println("rmiObj->getMethodParams(paramCls, numParam, paramObj);"); println("return param0;"); println("}\n"); } } } } /** * HELPER: writeMethodHelperStructSetupCplusCallbackSkeleton() writes the method helper of struct in skeleton class */ private void writeMethodHelperStructSetupCplusCallbackSkeleton(Collection methods, InterfaceDecl intDecl) { // Use this set to handle two same methodIds for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); // Check for params with structs for (int i = 0; i < methParams.size(); i++) { String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { int methodNumId = intDecl.getMethodNumId(method); print("int ___"); String helperMethod = methodNumId + "struct" + i; println(helperMethod + "(IoTRMIObject* rmiObj) {"); // Now, write the helper body of skeleton! println("string paramCls[] = { \"int\" };"); println("int numParam = 1;"); println("int param0 = 0;"); println("void* paramObj[] = { ¶m0 };"); println("rmiObj->getMethodParams(paramCls, numParam, paramObj);"); println("return param0;"); println("}\n"); } } } } /** * HELPER: writeCplusMethodPermission() writes permission checks in skeleton */ private void writeCplusMethodPermission(String intface) { // Get all the different stubs Map> mapNewIntMethods = mapInt2NewInts.get(intface); for (Map.Entry> intMeth : mapNewIntMethods.entrySet()) { String newIntface = intMeth.getKey(); int newObjectId = getNewIntfaceObjectId(newIntface); println("if (_objectId == object" + newObjectId + "Id) {"); println("if (set" + newObjectId + "Allowed.find(methodId) == set" + newObjectId + "Allowed.end()) {"); println("cerr << \"Object with object Id: \" << _objectId << \" is not allowed to access method: \" << methodId << endl;"); println("exit(-1);"); println("}"); println("}"); println("else {"); println("cerr << \"Object Id: \" << _objectId << \" not recognized!\" << endl;"); println("exit(-1);"); println("}"); } } /** * HELPER: writeCplusWaitRequestInvokeMethod() writes the main loop of the skeleton class */ private void writeCplusWaitRequestInvokeMethod(Collection methods, InterfaceDecl intDecl, boolean callbackExist, String intface) { // Use this set to handle two same methodIds Set uniqueMethodIds = new HashSet(); println("void ___waitRequestInvokeMethod() {"); // Write variables here if we have callbacks or enums or structs writeCountVarStructSkeleton(methods, intDecl); println("while (true) {"); println("rmiObj->getMethodBytes();"); println("int _objectId = rmiObj->getObjectId();"); println("int methodId = rmiObj->getMethodId();"); // Generate permission check writeCplusMethodPermission(intface); println("switch (methodId) {"); // Print methods and method Ids for (String method : methods) { String methodId = intDecl.getMethodId(method); int methodNumId = intDecl.getMethodNumId(method); print("case " + methodNumId + ": ___"); String helperMethod = methodId; if (uniqueMethodIds.contains(methodId)) helperMethod = helperMethod + methodNumId; else uniqueMethodIds.add(methodId); print(helperMethod + "("); writeInputCountVarStructSkeleton(method, intDecl); println("); break;"); } String method = "___initCallBack()"; // Print case -9999 (callback handler) if callback exists if (callbackExist) { int methodId = intDecl.getHelperMethodNumId(method); println("case " + methodId + ": ___regCB(); break;"); } writeMethodCallStructSkeleton(methods, intDecl); println("default: "); println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;"); println("throw exception();"); println("}"); println("}"); println("}\n"); } /** * generateCplusSkeletonClass() generate skeletons based on the methods list in C++ */ public void generateCplusSkeletonClass() throws IOException { // Create a new directory String path = createDirectories(dir, subdir); for (String intface : mapIntfacePTH.keySet()) { // Open a new file to write into String newSkelClass = intface + "_Skeleton"; FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp"); pw = new PrintWriter(new BufferedWriter(fw)); // Write file headers println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__"); println("#define _" + newSkelClass.toUpperCase() + "_HPP__"); println("#include "); println("#include \"" + intface + ".hpp\"\n"); // Pass in set of methods and get import classes DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); List methods = intDecl.getMethods(); Set includeClasses = getIncludeClasses(methods, intDecl, intface, true); List stdIncludeClasses = getStandardCplusIncludeClasses(); List allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses); printIncludeStatements(allIncludeClasses); println(""); println("using namespace std;\n"); // Find out if there are callback objects Set callbackClasses = getCallbackClasses(methods, intDecl); boolean callbackExist = !callbackClasses.isEmpty(); // Write class header println("class " + newSkelClass + " : public " + intface); println("{"); println("private:\n"); // Write properties writePropertiesCplusSkeleton(intface, callbackExist, callbackClasses); println("public:\n"); // Write constructor writeConstructorCplusSkeleton(newSkelClass, intface, callbackExist); // Write deconstructor writeDeconstructorCplusSkeleton(newSkelClass, callbackExist, callbackClasses); // Write methods writeMethodCplusSkeleton(methods, intDecl, callbackClasses, false); // Write method helper writeMethodHelperCplusSkeleton(methods, intDecl, callbackClasses); // Write waitRequestInvokeMethod() - main loop writeCplusWaitRequestInvokeMethod(methods, intDecl, callbackExist, intface); println("};"); writePermissionInitializationCplus(intface, newSkelClass, intDecl); println("#endif"); pw.close(); System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".hpp..."); } } /** * HELPER: writePropertiesCplusCallbackSkeleton() writes the properties of the callback skeleton class */ private void writePropertiesCplusCallbackSkeleton(String intface, boolean callbackExist, Set callbackClasses) { println(intface + " *mainObj;"); // Keep track of object Ids of all stubs registered to this interface println("static int objectId;"); // Callback if (callbackExist) { Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); String exchangeType = checkAndGetParamClass(callbackType); println("// Callback properties"); println("IoTRMICall* rmiCall;"); println("vector<" + exchangeType + "*> vecCallbackObj;"); println("static int objIdCnt;"); } println("\n"); } /** * HELPER: writeConstructorCplusCallbackSkeleton() writes the constructor of the skeleton class */ private void writeConstructorCplusCallbackSkeleton(String newSkelClass, String intface, boolean callbackExist) { println(newSkelClass + "(" + intface + " *_mainObj, int _objectId) {"); println("mainObj = _mainObj;"); println("objectId = _objectId;"); // Callback if (callbackExist) { println("objIdCnt = 0;"); } println("}\n"); } /** * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class */ private void writeDeconstructorCplusCallbackSkeleton(String newStubClass, boolean callbackExist, Set callbackClasses) { println("~" + newStubClass + "() {"); if (callbackExist) { // We assume that each class only has one callback interface for now println("if (rmiCall != NULL) {"); println("delete rmiCall;"); println("rmiCall = NULL;"); println("}"); Iterator it = callbackClasses.iterator(); String callbackType = (String) it.next(); String exchangeType = checkAndGetParamClass(callbackType); println("for(" + exchangeType + "* cb : vecCallbackObj) {"); println("delete cb;"); println("cb = NULL;"); println("}"); } println("}"); println(""); } /** * HELPER: writeMethodHelperCplusCallbackSkeleton() writes the method helper of callback skeleton class */ private void writeMethodHelperCplusCallbackSkeleton(Collection methods, InterfaceDecl intDecl, Set callbackClasses) { // Use this set to handle two same methodIds Set uniqueMethodIds = new HashSet(); for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); if (isStructPresent(methParams, methPrmTypes)) { // Treat struct differently String methodId = intDecl.getMethodId(method); print("void ___"); String helperMethod = methodId; if (uniqueMethodIds.contains(methodId)) helperMethod = helperMethod + intDecl.getMethodNumId(method); else uniqueMethodIds.add(methodId); String retType = intDecl.getMethodType(method); print(helperMethod + "("); boolean begin = true; for (int i = 0; i < methParams.size(); i++) { // Print size variables String paramType = methPrmTypes.get(i); String param = methParams.get(i); String simpleType = getSimpleType(paramType); if (isStructClass(simpleType)) { if (!begin) { // Generate comma for not the beginning variable print(", "); begin = false; } int methodNumId = intDecl.getMethodNumId(method); print("int struct" + methodNumId + "Size" + i); } } println(", IoTRMIObject* rmiObj) {"); writeMethodHelperStructCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses); println("}\n"); } else { String methodId = intDecl.getMethodId(method); print("void ___"); String helperMethod = methodId; if (uniqueMethodIds.contains(methodId)) helperMethod = helperMethod + intDecl.getMethodNumId(method); else uniqueMethodIds.add(methodId); // Check if this is "void" String retType = intDecl.getMethodType(method); println(helperMethod + "(IoTRMIObject* rmiObj) {"); // Now, write the helper body of skeleton! writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses); println("}\n"); } } // Write method helper for structs writeMethodHelperStructSetupCplusCallbackSkeleton(methods, intDecl); } /** * HELPER: writeCplusCallbackWaitRequestInvokeMethod() writes the request invoke method of the skeleton callback class */ private void writeCplusCallbackWaitRequestInvokeMethod(Collection methods, InterfaceDecl intDecl, boolean callbackExist) { // Use this set to handle two same methodIds Set uniqueMethodIds = new HashSet(); println("void invokeMethod(IoTRMIObject* rmiObj) {"); // Write variables here if we have callbacks or enums or structs writeCountVarStructSkeleton(methods, intDecl); // Write variables here if we have callbacks or enums or structs println("int methodId = rmiObj->getMethodId();"); // TODO: code the permission check here! println("switch (methodId) {"); // Print methods and method Ids for (String method : methods) { String methodId = intDecl.getMethodId(method); int methodNumId = intDecl.getMethodNumId(method); print("case " + methodNumId + ": ___"); String helperMethod = methodId; if (uniqueMethodIds.contains(methodId)) helperMethod = helperMethod + methodNumId; else uniqueMethodIds.add(methodId); print(helperMethod + "("); if (writeInputCountVarStructSkeleton(method, intDecl)) println(", rmiObj); break;"); else println("rmiObj); break;"); } String method = "___initCallBack()"; // Print case -9999 (callback handler) if callback exists if (callbackExist) { int methodId = intDecl.getHelperMethodNumId(method); println("case " + methodId + ": ___regCB(rmiObj); break;"); } writeMethodCallStructCallbackSkeleton(methods, intDecl); println("default: "); println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;"); println("throw exception();"); println("}"); println("}\n"); } /** * generateCplusCallbackSkeletonClass() generate callback skeletons based on the methods list in C++ */ public void generateCplusCallbackSkeletonClass() throws IOException { // Create a new directory String path = createDirectories(dir, subdir); for (String intface : mapIntfacePTH.keySet()) { // Open a new file to write into String newSkelClass = intface + "_CallbackSkeleton"; FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp"); pw = new PrintWriter(new BufferedWriter(fw)); // Write file headers println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__"); println("#define _" + newSkelClass.toUpperCase() + "_HPP__"); println("#include "); println("#include \"" + intface + ".hpp\"\n"); // Pass in set of methods and get import classes DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); List methods = intDecl.getMethods(); Set includeClasses = getIncludeClasses(methods, intDecl, intface, true); List stdIncludeClasses = getStandardCplusIncludeClasses(); List allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses); printIncludeStatements(allIncludeClasses); println(""); // Find out if there are callback objects Set callbackClasses = getCallbackClasses(methods, intDecl); boolean callbackExist = !callbackClasses.isEmpty(); println("using namespace std;\n"); // Write class header println("class " + newSkelClass + " : public " + intface); println("{"); println("private:\n"); // Write properties writePropertiesCplusCallbackSkeleton(intface, callbackExist, callbackClasses); println("public:\n"); // Write constructor writeConstructorCplusCallbackSkeleton(newSkelClass, intface, callbackExist); // Write deconstructor writeDeconstructorCplusCallbackSkeleton(newSkelClass, callbackExist, callbackClasses); // Write methods writeMethodCplusSkeleton(methods, intDecl, callbackClasses, true); // Write method helper writeMethodHelperCplusCallbackSkeleton(methods, intDecl, callbackClasses); // Write waitRequestInvokeMethod() - main loop writeCplusCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist); println("};"); println("#endif"); pw.close(); System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".hpp..."); } } /** * generateInitializer() generate initializer based on type */ public String generateCplusInitializer(String type) { // Generate dummy returns for now if (type.equals("short")|| type.equals("int") || type.equals("long") || type.equals("float")|| type.equals("double")) { return "0"; } else if ( type.equals("String") || type.equals("string")) { return "\"\""; } else if ( type.equals("char") || type.equals("byte")) { return "\' \'"; } else if ( type.equals("boolean")) { return "false"; } else { return "NULL"; } } /** * setDirectory() sets a new directory for stub files */ public void setDirectory(String _subdir) { subdir = _subdir; } /** * printUsage() prints the usage of this compiler */ public static void printUsage() { System.out.println(); System.out.println("Sentinel interface and stub compiler version 1.0"); System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group."); System.out.println("All rights reserved."); System.out.println("Usage:"); System.out.println("\tjava IoTCompiler -help / --help / -h\n"); System.out.println("\t\tDisplay this help texts\n\n"); System.out.println("\tjava IoTCompiler [ ]"); System.out.println("\tjava IoTCompiler [ ] [options]\n"); System.out.println("\t\tTake one or more pairs of main-req policy files, and generate Java and/or C++ files\n"); System.out.println("Options:"); System.out.println("\t-java\t\tGenerate Java stub files"); System.out.println("\t-cplus\t\tGenerate C++ stub files"); System.out.println(); } /** * parseFile() prepares Lexer and Parser objects, then parses the file */ public static ParseNode parseFile(String file) { ParseNode pn = null; try { ComplexSymbolFactory csf = new ComplexSymbolFactory(); ScannerBuffer lexer = new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf)); Parser parse = new Parser(lexer,csf); pn = (ParseNode) parse.parse().value; } catch (Exception e) { e.printStackTrace(); throw new Error("IoTCompiler: ERROR parsing policy file or wrong command line option: " + file + "\n"); } return pn; } /**================ * Basic helper functions **================ */ boolean newline=true; int tablevel=0; private void print(String str) { if (newline) { int tab=tablevel; if (str.equals("}")) tab--; for(int i=0; i for Set private String getNonPrimitiveCplusClass(String paramNonPrimitives) { return mapNonPrimitivesCplus.get(paramNonPrimitives); } // Get simple types, e.g. HashSet for HashSet<...> // Basically strip off the "<...>" private String getSimpleType(String paramType) { // Check if this is generics if(paramType.contains("<")) { String[] type = paramType.split("<"); return type[0]; } else return paramType; } // Generate a set of standard classes for import statements private List getStandardJavaIntfaceImportClasses() { List importClasses = new ArrayList(); // Add the standard list first importClasses.add("java.util.List"); importClasses.add("java.util.ArrayList"); return importClasses; } // Generate a set of standard classes for import statements private List getStandardJavaImportClasses() { List importClasses = new ArrayList(); // Add the standard list first importClasses.add("java.io.IOException"); importClasses.add("java.util.List"); importClasses.add("java.util.ArrayList"); importClasses.add("java.util.Arrays"); importClasses.add("iotrmi.Java.IoTRMICall"); importClasses.add("iotrmi.Java.IoTRMIObject"); return importClasses; } // Generate a set of standard classes for import statements private List getStandardCplusIncludeClasses() { List importClasses = new ArrayList(); // Add the standard list first importClasses.add(""); importClasses.add(""); importClasses.add("\"IoTRMICall.hpp\""); importClasses.add("\"IoTRMIObject.hpp\""); return importClasses; } // Combine all classes for import statements private List getAllLibClasses(Collection stdLibClasses, Collection libClasses) { List allLibClasses = new ArrayList(stdLibClasses); // Iterate over the list of import classes for (String str : libClasses) { if (!allLibClasses.contains(str)) { allLibClasses.add(str); } } return allLibClasses; } // Generate a set of classes for import statements private Set getImportClasses(Collection methods, InterfaceDecl intDecl) { Set importClasses = new HashSet(); for (String method : methods) { List methPrmTypes = intDecl.getMethodParamTypes(method); for (String paramType : methPrmTypes) { String simpleType = getSimpleType(paramType); if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) { importClasses.add(getNonPrimitiveJavaClass(simpleType)); } } } return importClasses; } // Handle and return the correct enum declaration // In Java, if we declare enum in Camera interface, then it becomes "Camera." private String getEnumParamDecl(String type, InterfaceDecl intDecl) { // Strips off array "[]" for return type String pureType = getSimpleArrayType(type); // Take the inner type of generic if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) pureType = getTypeOfGeneric(type)[0]; if (isEnumClass(pureType)) { String enumType = intDecl.getInterface() + "." + type; return enumType; } else return type; } // Handle and return the correct type private String getEnumParam(String type, String param, int i) { // Strips off array "[]" for return type String pureType = getSimpleArrayType(type); // Take the inner type of generic if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) pureType = getTypeOfGeneric(type)[0]; if (isEnumClass(pureType)) { String enumParam = "paramEnum" + i; return enumParam; } else return param; } // Handle and return the correct enum declaration translate into int[] private String getEnumType(String type) { // Strips off array "[]" for return type String pureType = getSimpleArrayType(type); // Take the inner type of generic if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) pureType = getTypeOfGeneric(type)[0]; if (isEnumClass(pureType)) { String enumType = "int[]"; return enumType; } else return type; } // Handle and return the correct struct declaration private String getStructType(String type) { // Strips off array "[]" for return type String pureType = getSimpleArrayType(type); // Take the inner type of generic if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) pureType = getTypeOfGeneric(type)[0]; if (isStructClass(pureType)) { String structType = "int"; return structType; } else return type; } // Check if this an enum declaration private boolean isEnumClass(String type) { // Just iterate over the set of interfaces for (String intface : mapIntfacePTH.keySet()) { DeclarationHandler decHandler = mapIntDeclHand.get(intface); EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface); Set setEnumDecl = enumDecl.getEnumDeclarations(); if (setEnumDecl.contains(type)) return true; } return false; } // Check if this an struct declaration private boolean isStructClass(String type) { // Just iterate over the set of interfaces for (String intface : mapIntfacePTH.keySet()) { DeclarationHandler decHandler = mapIntDeclHand.get(intface); StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface); List listStructDecl = structDecl.getStructTypes(); if (listStructDecl.contains(type)) return true; } return false; } // Return a struct declaration private StructDecl getStructDecl(String type) { // Just iterate over the set of interfaces for (String intface : mapIntfacePTH.keySet()) { DeclarationHandler decHandler = mapIntDeclHand.get(intface); StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface); List listStructDecl = structDecl.getStructTypes(); if (listStructDecl.contains(type)) return structDecl; } return null; } // Return number of members (-1 if not found) private int getNumOfMembers(String type) { // Just iterate over the set of interfaces for (String intface : mapIntfacePTH.keySet()) { DeclarationHandler decHandler = mapIntDeclHand.get(intface); StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface); List listStructDecl = structDecl.getStructTypes(); if (listStructDecl.contains(type)) return structDecl.getNumOfMembers(type); } return -1; } // Generate a set of classes for include statements private Set getIncludeClasses(Collection methods, InterfaceDecl intDecl, String intface, boolean needExchange) { Set includeClasses = new HashSet(); for (String method : methods) { List methPrmTypes = intDecl.getMethodParamTypes(method); List methParams = intDecl.getMethodParams(method); for (int i = 0; i < methPrmTypes.size(); i++) { String simpleType = getSimpleType(methPrmTypes.get(i)); String param = methParams.get(i); if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) { includeClasses.add("<" + getNonPrimitiveCplusClass(simpleType) + ">"); } else if (getParamCategory(simpleType) == ParamCategory.USERDEFINED) { // For original interface, we need it exchanged... not for stub interfaces if (needExchange) { includeClasses.add("\"" + exchangeParamType(simpleType) + ".hpp\""); includeClasses.add("\"" + exchangeParamType(simpleType) + "_CallbackStub.hpp\""); } else { includeClasses.add("\"" + simpleType + ".hpp\""); includeClasses.add("\"" + simpleType + "_CallbackSkeleton.hpp\""); } } else if (getParamCategory(getSimpleArrayType(simpleType)) == ParamCategory.ENUM) { includeClasses.add("\"" + simpleType + ".hpp\""); } else if (getParamCategory(getSimpleArrayType(simpleType)) == ParamCategory.STRUCT) { includeClasses.add("\"" + simpleType + ".hpp\""); } else if (param.contains("[]")) { // Check if this is array for C++; translate into vector includeClasses.add(""); } } } return includeClasses; } // Generate a set of callback classes private Set getCallbackClasses(Collection methods, InterfaceDecl intDecl) { Set callbackClasses = new HashSet(); for (String method : methods) { List methPrmTypes = intDecl.getMethodParamTypes(method); List methParams = intDecl.getMethodParams(method); for (int i = 0; i < methPrmTypes.size(); i++) { String type = methPrmTypes.get(i); if (getParamCategory(type) == ParamCategory.USERDEFINED) { callbackClasses.add(type); } else if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) { // Can be a List<...> of callback objects ... String genericType = getTypeOfGeneric(type)[0]; if (getParamCategory(type) == ParamCategory.USERDEFINED) { callbackClasses.add(type); } } } } return callbackClasses; } // Print import statements into file private void printImportStatements(Collection importClasses) { for(String cls : importClasses) { println("import " + cls + ";"); } } // Print include statements into file private void printIncludeStatements(Collection includeClasses) { for(String cls : includeClasses) { println("#include " + cls); } } // Get the C++ version of a non-primitive type // e.g. set for Set and map for Map // Input nonPrimitiveType has to be generics in format private String[] getTypeOfGeneric(String nonPrimitiveType) { // Handle <, >, and , for 2-type generic/template String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(","); return substr; } // Gets generic type inside "<" and ">" private String getGenericType(String type) { // Handle <, >, and , for 2-type generic/template if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) { String[] substr = type.split("<")[1].split(">")[0].split(","); return substr[0]; } else return type; } // This helper function strips off array declaration, e.g. int[] becomes int private String getSimpleArrayType(String type) { // Handle [ for array declaration String substr = type; if (type.contains("[]")) { substr = type.split("\\[\\]")[0]; } return substr; } // This helper function strips off array declaration, e.g. D[] becomes D private String getSimpleIdentifier(String ident) { // Handle [ for array declaration String substr = ident; if (ident.contains("[]")) { substr = ident.split("\\[\\]")[0]; } return substr; } // Checks and gets type in C++ private String checkAndGetCplusType(String paramType) { if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) { return convertType(paramType); } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) { // Check for generic/template format if (paramType.contains("<") && paramType.contains(">")) { String genericClass = getSimpleType(paramType); String[] genericType = getTypeOfGeneric(paramType); String cplusTemplate = null; if (genericType.length == 1) // Generic/template with one type cplusTemplate = getNonPrimitiveCplusClass(genericClass) + "<" + convertType(genericType[0]) + ">"; else // Generic/template with two types cplusTemplate = getNonPrimitiveCplusClass(genericClass) + "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">"; return cplusTemplate; } else return getNonPrimitiveCplusClass(paramType); } else if(paramType.contains("[]")) { // Array type (used for return type only) String cArray = "vector<" + convertType(getSimpleArrayType(paramType)) + ">"; return cArray; } else if(getParamCategory(paramType) == ParamCategory.USERDEFINED) { return paramType + "*"; } else // Just return it as is if it's not non-primitives return paramType; //return checkAndGetParamClass(paramType, true); } // Detect array declaration, e.g. int A[], // then generate "int A[]" in C++ as "vector A" private String checkAndGetCplusArray(String paramType, String param) { String paramComplete = null; // Check for array declaration if (param.contains("[]")) { paramComplete = "vector<" + paramType + "> " + param.replace("[]",""); } else // Just return it as is if it's not an array paramComplete = paramType + " " + param; return paramComplete; } // Detect array declaration, e.g. int A[], // then generate "int A[]" in C++ as "vector A" // This method just returns the type private String checkAndGetCplusArrayType(String paramType) { String paramTypeRet = null; // Check for array declaration if (paramType.contains("[]")) { String type = paramType.split("\\[\\]")[0]; paramTypeRet = checkAndGetCplusType(type) + "[]"; } else if (paramType.contains("vector")) { // Just return it as is if it's not an array String type = paramType.split("<")[1].split(">")[0]; paramTypeRet = checkAndGetCplusType(type) + "[]"; } else paramTypeRet = paramType; return paramTypeRet; } // Detect array declaration, e.g. int A[], // then generate "int A[]" in C++ as "vector A" // This method just returns the type private String checkAndGetCplusArrayType(String paramType, String param) { String paramTypeRet = null; // Check for array declaration if (param.contains("[]")) { paramTypeRet = checkAndGetCplusType(paramType) + "[]"; } else if (paramType.contains("vector")) { // Just return it as is if it's not an array String type = paramType.split("<")[1].split(">")[0]; paramTypeRet = checkAndGetCplusType(type) + "[]"; } else paramTypeRet = paramType; return paramTypeRet; } // Return the class type for class resolution (for return value) // - Check and return C++ array class, e.g. int A[] into int* // - Check and return C++ vector class, e.g. List A into vector private String checkAndGetCplusRetClsType(String paramType) { String paramTypeRet = null; // Check for array declaration if (paramType.contains("[]")) { String type = paramType.split("\\[\\]")[0]; paramTypeRet = getSimpleArrayType(type) + "*"; } else if (paramType.contains("<") && paramType.contains(">")) { // Just return it as is if it's not an array String type = paramType.split("<")[1].split(">")[0]; paramTypeRet = "vector<" + getGenericType(type) + ">"; } else paramTypeRet = paramType; return paramTypeRet; } // Return the class type for class resolution (for method arguments) // - Check and return C++ array class, e.g. int A[] into int* // - Check and return C++ vector class, e.g. List A into vector private String checkAndGetCplusArgClsType(String paramType, String param) { String paramTypeRet = null; // Check for array declaration if (param.contains("[]")) { paramTypeRet = getSimpleArrayType(paramType) + "*"; } else if (paramType.contains("<") && paramType.contains(">")) { // Just return it as is if it's not an array String type = paramType.split("<")[1].split(">")[0]; paramTypeRet = "vector<" + getGenericType(type) + ">"; } else paramTypeRet = paramType; return paramTypeRet; } // Detect array declaration, e.g. int A[], // then generate type "int[]" private String checkAndGetArray(String paramType, String param) { String paramTypeRet = null; // Check for array declaration if (param.contains("[]")) { paramTypeRet = paramType + "[]"; } else // Just return it as is if it's not an array paramTypeRet = paramType; return paramTypeRet; } // Is array or list? private boolean isArrayOrList(String paramType, String param) { // Check for array declaration if (isArray(param)) return true; else if (isList(paramType)) return true; else return false; } // Is array? // For return type we use retType as input parameter private boolean isArray(String param) { // Check for array declaration if (param.contains("[]")) return true; else return false; } // Is list? private boolean isList(String paramType) { // Check for array declaration if (paramType.contains("List")) return true; else return false; } // Get the right type for a callback object private String checkAndGetParamClass(String paramType) { // Check if this is generics if(getParamCategory(paramType) == ParamCategory.USERDEFINED) { return exchangeParamType(paramType); } else return paramType; } // Returns the other interface for type-checking purposes for USERDEFINED // classes based on the information provided in multiple policy files // e.g. return CameraWithXXX instead of Camera private String exchangeParamType(String intface) { // Param type that's passed is the interface name we need to look for // in the map of interfaces, based on available policy files. DeclarationHandler decHandler = mapIntDeclHand.get(intface); if (decHandler != null) { // We've found the required interface policy files RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(intface); Set setExchInt = reqDecl.getInterfaces(); if (setExchInt.size() == 1) { Iterator iter = setExchInt.iterator(); return (String) iter.next(); } else { throw new Error("IoTCompiler: Ambiguous stub interfaces: " + setExchInt.toString() + ". Only one new interface can be declared if the object " + intface + " needs to be passed in as an input parameter!\n"); } } else { // NULL value - this means policy files missing throw new Error("IoTCompiler: Parameter type lookup failed for " + intface + "... Please provide the necessary policy files for user-defined types." + " If this is an array please type the brackets after the variable name," + " e.g. \"String str[]\", not \"String[] str\"." + " If this is a Collections (Java) / STL (C++) type, this compiler only" + " supports List/ArrayList (Java) or list (C++).\n"); } } public static void main(String[] args) throws Exception { // If there is no argument or just "--help" or "-h", then invoke printUsage() if ((args[0].equals("-help") || args[0].equals("--help")|| args[0].equals("-h")) || (args.length == 0)) { IoTCompiler.printUsage(); } else if (args.length > 1) { IoTCompiler comp = new IoTCompiler(); int i = 0; do { // Parse main policy file ParseNode pnPol = IoTCompiler.parseFile(args[i]); // Parse "requires" policy file ParseNode pnReq = IoTCompiler.parseFile(args[i+1]); // Get interface name String intface = ParseTreeHandler.getOrigIntface(pnPol); comp.setDataStructures(intface, pnPol, pnReq); comp.getMethodsForIntface(intface); i = i + 2; // 1) Check if this is the last option before "-java" or "-cplus" // 2) Check if this is really the last option (no "-java" or "-cplus") } while(!args[i].equals("-java") && !args[i].equals("-cplus") && (i < args.length)); // Generate everything if we don't see "-java" or "-cplus" if (i == args.length) { comp.generateEnumJava(); comp.generateStructJava(); comp.generateJavaLocalInterfaces(); comp.generateJavaInterfaces(); comp.generateJavaStubClasses(); comp.generateJavaCallbackStubClasses(); comp.generateJavaSkeletonClass(); comp.generateJavaCallbackSkeletonClass(); comp.generateEnumCplus(); comp.generateStructCplus(); comp.generateCplusLocalInterfaces(); comp.generateCPlusInterfaces(); comp.generateCPlusStubClasses(); comp.generateCPlusCallbackStubClasses(); comp.generateCplusSkeletonClass(); comp.generateCplusCallbackSkeletonClass(); } else { // Check other options while(i < args.length) { // Error checking if (!args[i].equals("-java") && !args[i].equals("-cplus")) { throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i] + "\n"); } else { if (i + 1 < args.length) { comp.setDirectory(args[i+1]); } else throw new Error("IoTCompiler: ERROR - please provide after option: " + args[i] + "\n"); if (args[i].equals("-java")) { comp.generateEnumJava(); comp.generateStructJava(); comp.generateJavaLocalInterfaces(); comp.generateJavaInterfaces(); comp.generateJavaStubClasses(); comp.generateJavaCallbackStubClasses(); comp.generateJavaSkeletonClass(); comp.generateJavaCallbackSkeletonClass(); } else { comp.generateEnumCplus(); comp.generateStructCplus(); comp.generateCplusLocalInterfaces(); comp.generateCPlusInterfaces(); comp.generateCPlusStubClasses(); comp.generateCPlusCallbackStubClasses(); comp.generateCplusSkeletonClass(); comp.generateCplusCallbackSkeletonClass(); } } i = i + 2; } } } else { // Need to at least have exactly 2 parameters, i.e. main policy file and requires file IoTCompiler.printUsage(); throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!\n"); } } }