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 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 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. USERDEFINED // Non-supported type by default; assumed as driver classes } /** * Class constructors */ public IoTCompiler() { mapIntfacePTH = new HashMap(); mapIntDeclHand = new HashMap(); mapInt2NewInts = new HashMap>>(); mapIntfaceObjId = 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 ptHandler.processInterfaceDecl(); InterfaceDecl intDecl = ptHandler.getInterfaceDecl(); decHandler.addInterfaceDecl(origInt, intDecl); ptHandler.processCapabilityDecl(); CapabilityDecl capDecl = ptHandler.getCapabilityDecl(); decHandler.addCapabilityDecl(origInt, capDecl); ptHandler.processRequiresDecl(); RequiresDecl reqDecl = ptHandler.getRequiresDecl(); decHandler.addRequiresDecl(origInt, reqDecl); mapIntfacePTH.put(origInt, ptHandler); mapIntDeclHand.put(origInt, decHandler); // Set object Id counter to 0 for each interface mapIntfaceObjId.put(origInt, new Integer(0)); //System.out.println("\nInterface: " + origInt + "\n\n"); } /** * 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: 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 = checkAndGetParamClass(methPrmTypes.get(i), false); print(paramType + " " + methParams.get(i)); // Check if this is the last element (don't print a comma) if (i != methParams.size() - 1) { print(", "); } } println(");"); } } /** * 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); printImportStatements(importClasses); // Write interface header println(""); println("public interface " + intface + " {"); // Write methods writeMethodJavaInterface(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 Set importClasses = getImportClasses(intMeth.getValue(), intDecl); printImportStatements(importClasses); // Write interface header println(""); println("public interface " + newIntface + " {"); // Write methods writeMethodJavaInterface(intMeth.getValue(), intDecl); println("}"); pw.close(); System.out.println("IoTCompiler: Generated interface " + newIntface + ".java..."); } } } /** * HELPER: writePropertiesJavaStub() writes the properties of the stub class */ private void writePropertiesJavaStub(String intface) { println("private IoTRMICall rmiCall;"); //println("private IoTRMIObject rmiObj;"); 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 + ";"); mapIntfaceObjId.put(intface, objId++); println("\n"); } /** * HELPER: writeConstructorJavaStub() writes the constructor of the stub class */ private void writeConstructorJavaStub(String intface) { println("public " + intface + "(int _port, String _address, int _rev, int[] _ports) throws Exception {"); println("address = _address;"); println("ports = _ports;"); println("rmiCall = new IoTRMICall(_port, _address, _rev);"); println("}\n"); } /** * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class */ private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method) { println("int methodId = " + intDecl.getMethodNumId(method) + ";"); String retType = intDecl.getMethodType(method); println("Class retType = " + getSimpleType(retType) + ".class;"); // Generate array of parameter types print("Class[] paramCls = new Class[] { "); for (int i = 0; i < methParams.size(); i++) { print(getSimpleType(methPrmTypes.get(i)) + ".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(getSimpleIdentifier(methParams.get(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 // 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 method of the stub class */ private void writeMethodJavaStub(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++) { 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! writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method); println("}\n"); } } /** * 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 importClasses = getImportClasses(intMeth.getValue(), intDecl); List stdImportClasses = getStandardJavaImportClasses(); List allImportClasses = getAllImportClasses(stdImportClasses, importClasses); printImportStatements(allImportClasses); println(""); // Write interface header println("public class " + newStubClass + " implements " + newIntface + " {\n"); // Write properties writePropertiesJavaStub(intface); // Write constructor writeConstructorJavaStub(newStubClass); // Write methods writeMethodJavaStub(intMeth.getValue(), intDecl); println("}"); pw.close(); System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java..."); } } } /** * 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 = checkAndGetParamClass(methPrmTypes.get(i), true); 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;"); } } /** * 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); printIncludeStatements(includeClasses); println(""); println("using namespace std;\n"); println("class " + intface); println("{"); println("public:"); // Write methods writeMethodCplusInterface(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); List stdIncludeClasses = getStandardCplusIncludeClasses(); List allIncludeClasses = getAllImportClasses(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 method of the stub */ private void writeMethodCplusStub(Collection methods, InterfaceDecl intDecl) { for (String method : methods) { List methParams = intDecl.getMethodParams(method); List methPrmTypes = intDecl.getMethodParamTypes(method); print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " + intDecl.getMethodId(method) + "("); for (int i = 0; i < methParams.size(); i++) { 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(") { "); writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method); println("}\n"); } } /** * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class */ private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List methParams, List methPrmTypes, String method) { println("int numParam = " + methParams.size() + ";"); println("int methodId = " + intDecl.getMethodNumId(method) + ";"); String retType = intDecl.getMethodType(method); println("string retType = \"" + checkAndGetCplusType(retType) + "\";"); // Generate array of parameter types print("string paramCls[] = { "); for (int i = 0; i < methParams.size(); i++) { print("\"" + checkAndGetCplusType(methPrmTypes.get(i)) + "\""); // 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("void* paramObj[] = { "); for (int i = 0; i < methParams.size(); i++) { print("&" + checkAndGetCplusType(getSimpleIdentifier(methParams.get(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 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: writePropertiesCplusStub() writes the properties of the stub class */ private void writePropertiesCplusStub(String intface) { println("IoTRMICall\t\t\t*rmiCall;"); //println("IoTRMIObject\t\t\t*rmiObj;"); println("string\t\t\t\taddress;"); println("vector\t\t\tports;\n"); // Get the object Id Integer objId = mapIntfaceObjId.get(intface); println("const static int\tobjectId = " + objId + ";"); mapIntfaceObjId.put(intface, objId++); println("\n"); } /** * HELPER: writeConstructorCplusStub() writes the constructor of the stub class */ private void writeConstructorCplusStub(String newStubClass) { 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);"); println("}\n"); } /** * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class */ private void writeDeconstructorCplusStub(String newStubClass) { println("~" + newStubClass + "() {"); println("if (rmiCall != NULL) {"); println("delete rmiCall;"); println("rmiCall = NULL;"); println("}"); println("}"); println(""); // Check if this is callback!!! and print "delete rmiObj and vecCBObj" } /** * 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 "); println("#include \"" + newIntface + ".hpp\""); println(""); println("using namespace std;"); println(""); println("class " + newStubClass + " : public " + newIntface); println("{"); println("private:\n"); writePropertiesCplusStub(intface); println("public:\n"); // Add default constructor and destructor println(newStubClass + "() { }"); println(""); writeConstructorCplusStub(newStubClass); writeDeconstructorCplusStub(newStubClass); DeclarationHandler decHandler = mapIntDeclHand.get(intface); InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface); // Write methods writeMethodCplusStub(intMeth.getValue(), intDecl); print("}"); println(";"); println("#endif"); pw.close(); System.out.println("IoTCompiler: Generated stub class " + newIntface + ".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"; } } /** * generateReturnStmt() generate return statement based on methType */ public String generateReturnStmt(String methType) { // Generate dummy returns for now if (methType.equals("short")|| methType.equals("int") || methType.equals("long") || methType.equals("float")|| methType.equals("double")) { return "1"; } else if ( methType.equals("String")) { return "\"a\""; } else if ( methType.equals("char") || methType.equals("byte")) { return "\'a\'"; } else if ( methType.equals("boolean")) { return "true"; } 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); } return pn; } /**================ * 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, #include for Map 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 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("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("\"IoTRMICall.hpp\""); importClasses.add("\"IoTRMIObject.hpp\""); return importClasses; } // Generate a set of standard classes for import statements private List getAllImportClasses(Collection stdImportClasses, Collection importClasses) { List allImportClasses = new ArrayList(stdImportClasses); // Iterate over the list of import classes for (String str : importClasses) { if (!stdImportClasses.contains(str)) { stdImportClasses.add(str); } } return allImportClasses; } // 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; } // Generate a set of classes for include statements private Set getIncludeClasses(Collection methods, InterfaceDecl intDecl) { 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) { includeClasses.add("\"" + exchangeParamType(simpleType) + ".hpp\""); } else if (param.contains("[]")) { // Check if this is array for C++; translate into vector includeClasses.add(""); } } } return includeClasses; } private void printImportStatements(Collection importClasses) { for(String cls : importClasses) { println("import " + cls + ";"); } } 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; } // 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; } 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 // Just return it as is if it's not non-primitives return paramType; } // 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; } // Get simple types, e.g. HashSet for HashSet<...> // Basically strip off the "<...>" private String checkAndGetParamClass(String paramType, boolean needPtr) { // Check if this is generics if(getParamCategory(paramType) == ParamCategory.USERDEFINED) { // If true then return with pointer (C++) if (needPtr) return exchangeParamType(paramType) + "*"; else // Java, so no pointer needed 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!"); } } 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++)."); } } 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.generateJavaLocalInterfaces(); comp.generateJavaInterfaces(); comp.generateJavaStubClasses(); comp.generateCplusLocalInterfaces(); comp.generateCPlusInterfaces(); comp.generateCPlusStubClasses(); } 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]); } else { if (i + 1 < args.length) { comp.setDirectory(args[i+1]); } else throw new Error("IoTCompiler: ERROR - please provide after option: " + args[i]); if (args[i].equals("-java")) { comp.generateJavaLocalInterfaces(); comp.generateJavaInterfaces(); comp.generateJavaStubClasses(); } else { comp.generateCplusLocalInterfaces(); comp.generateCPlusInterfaces(); comp.generateCPlusStubClasses(); } } 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!"); } } }