3 import java_cup.runtime.ComplexSymbolFactory;
4 import java_cup.runtime.ScannerBuffer;
6 import java.util.Arrays;
7 import java.util.ArrayList;
8 import java.util.Collection;
9 import java.util.Collections;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Iterator;
13 import java.util.List;
17 import iotpolicy.parser.Lexer;
18 import iotpolicy.parser.Parser;
19 import iotpolicy.tree.ParseNode;
20 import iotpolicy.tree.ParseNodeVector;
21 import iotpolicy.tree.ParseTreeHandler;
22 import iotpolicy.tree.Declaration;
23 import iotpolicy.tree.DeclarationHandler;
24 import iotpolicy.tree.CapabilityDecl;
25 import iotpolicy.tree.InterfaceDecl;
26 import iotpolicy.tree.RequiresDecl;
28 import iotrmi.Java.IoTRMITypes;
31 /** Class IoTCompiler is the main interface/stub compiler for
32 * files generation. This class calls helper classes
33 * such as Parser, Lexer, InterfaceDecl, CapabilityDecl,
34 * RequiresDecl, ParseTreeHandler, etc.
36 * @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
40 public class IoTCompiler {
45 // Maps multiple interfaces to multiple objects of ParseTreeHandler
46 private Map<String,ParseTreeHandler> mapIntfacePTH;
47 private Map<String,DeclarationHandler> mapIntDeclHand;
48 private Map<String,Map<String,Set<String>>> mapInt2NewInts;
49 // Data structure to store our types (primitives and non-primitives) for compilation
50 private Map<String,String> mapPrimitives;
51 private Map<String,String> mapNonPrimitivesJava;
52 private Map<String,String> mapNonPrimitivesCplus;
53 // Other data structures
54 private Map<String,Integer> mapIntfaceObjId; // Maps interface name to object Id
55 private PrintWriter pw;
57 private String subdir;
62 private final static String OUTPUT_DIRECTORY = "output_files";
64 private enum ParamCategory {
66 PRIMITIVES, // All the primitive types, e.g. byte, short, int, long, etc.
67 NONPRIMITIVES, // Non-primitive types, e.g. Set, Map, List, etc.
68 USERDEFINED // Non-supported type by default; assumed as driver classes
74 public IoTCompiler() {
76 mapIntfacePTH = new HashMap<String,ParseTreeHandler>();
77 mapIntDeclHand = new HashMap<String,DeclarationHandler>();
78 mapInt2NewInts = new HashMap<String,Map<String,Set<String>>>();
79 mapIntfaceObjId = new HashMap<String,Integer>();
80 mapPrimitives = new HashMap<String,String>();
81 arraysToMap(mapPrimitives, IoTRMITypes.primitivesJava, IoTRMITypes.primitivesCplus);
82 mapNonPrimitivesJava = new HashMap<String,String>();
83 arraysToMap(mapNonPrimitivesJava, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitiveJavaLibs);
84 mapNonPrimitivesCplus = new HashMap<String,String>();
85 arraysToMap(mapNonPrimitivesCplus, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitivesCplus);
87 dir = OUTPUT_DIRECTORY;
93 * setDataStructures() sets parse tree and other data structures based on policy files.
95 * It also generates parse tree (ParseTreeHandler) and
96 * copies useful information from parse tree into
97 * InterfaceDecl, CapabilityDecl, and RequiresDecl
99 * Additionally, the data structure handles are
100 * returned from tree-parsing for further process.
103 public void setDataStructures(String origInt, ParseNode pnPol, ParseNode pnReq) {
105 ParseTreeHandler ptHandler = new ParseTreeHandler(origInt, pnPol, pnReq);
106 DeclarationHandler decHandler = new DeclarationHandler();
107 // Process ParseNode and generate Declaration objects
108 ptHandler.processInterfaceDecl();
109 InterfaceDecl intDecl = ptHandler.getInterfaceDecl();
110 decHandler.addInterfaceDecl(origInt, intDecl);
111 ptHandler.processCapabilityDecl();
112 CapabilityDecl capDecl = ptHandler.getCapabilityDecl();
113 decHandler.addCapabilityDecl(origInt, capDecl);
114 ptHandler.processRequiresDecl();
115 RequiresDecl reqDecl = ptHandler.getRequiresDecl();
116 decHandler.addRequiresDecl(origInt, reqDecl);
118 mapIntfacePTH.put(origInt, ptHandler);
119 mapIntDeclHand.put(origInt, decHandler);
120 // Set object Id counter to 0 for each interface
121 mapIntfaceObjId.put(origInt, new Integer(0));
122 //System.out.println("\nInterface: " + origInt + "\n\n");
127 * getMethodsForIntface() reads for methods in the data structure
129 * It is going to give list of methods for a certain interface
130 * based on the declaration of capabilities.
132 public void getMethodsForIntface(String origInt) {
134 ParseTreeHandler ptHandler = mapIntfacePTH.get(origInt);
135 Map<String,Set<String>> mapNewIntMethods = new HashMap<String,Set<String>>();
136 // Get set of new interfaces, e.g. CameraWithCaptureAndData
137 // Generate this new interface with all the methods it needs
138 // from different capabilities it declares
139 DeclarationHandler decHandler = mapIntDeclHand.get(origInt);
140 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(origInt);
141 Set<String> setIntfaces = reqDecl.getInterfaces();
142 for (String strInt : setIntfaces) {
144 // Initialize a set of methods
145 Set<String> setMethods = new HashSet<String>();
146 // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc.
147 List<String> listCapab = reqDecl.getCapabList(strInt);
148 for (String strCap : listCapab) {
150 // Get list of methods for each capability
151 CapabilityDecl capDecl = (CapabilityDecl) decHandler.getCapabilityDecl(origInt);
152 List<String> listCapabMeth = capDecl.getMethods(strCap);
153 for (String strMeth : listCapabMeth) {
155 // Add methods into setMethods
156 // This is to also handle redundancies (say two capabilities
157 // share the same methods)
158 setMethods.add(strMeth);
161 // Add interface and methods information into map
162 mapNewIntMethods.put(strInt, setMethods);
164 // Map the map of interface-methods to the original interface
165 mapInt2NewInts.put(origInt, mapNewIntMethods);
170 * HELPER: writeMethodJavaInterface() writes the method of the interface
172 private void writeMethodJavaInterface(Collection<String> methods, InterfaceDecl intDecl) {
174 for (String method : methods) {
176 List<String> methParams = intDecl.getMethodParams(method);
177 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
178 print("public " + intDecl.getMethodType(method) + " " +
179 intDecl.getMethodId(method) + "(");
180 for (int i = 0; i < methParams.size(); i++) {
181 // Check for params with driver class types and exchange it
182 // with its remote interface
183 String paramType = checkAndGetParamClass(methPrmTypes.get(i), false);
184 print(paramType + " " + methParams.get(i));
185 // Check if this is the last element (don't print a comma)
186 if (i != methParams.size() - 1) {
196 * generateJavaLocalInterface() writes the local interface and provides type-checking.
198 * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
199 * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
200 * The local interface has to be the input parameter for the stub and the stub
201 * interface has to be the input parameter for the local class.
203 public void generateJavaLocalInterfaces() throws IOException {
205 // Create a new directory
206 createDirectory(dir);
207 for (String intface : mapIntfacePTH.keySet()) {
208 // Open a new file to write into
209 FileWriter fw = new FileWriter(dir + "/" + intface + ".java");
210 pw = new PrintWriter(new BufferedWriter(fw));
211 // Pass in set of methods and get import classes
212 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
213 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
214 List<String> methods = intDecl.getMethods();
215 Set<String> importClasses = getImportClasses(methods, intDecl);
216 printImportStatements(importClasses);
217 // Write interface header
219 println("public interface " + intface + " {");
221 writeMethodJavaInterface(methods, intDecl);
224 System.out.println("IoTCompiler: Generated local interface " + intface + ".java...");
230 * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
232 public void generateJavaInterfaces() throws IOException {
234 // Create a new directory
235 String path = createDirectories(dir, subdir);
236 for (String intface : mapIntfacePTH.keySet()) {
238 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
239 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
241 // Open a new file to write into
242 String newIntface = intMeth.getKey();
243 FileWriter fw = new FileWriter(path + "/" + newIntface + ".java");
244 pw = new PrintWriter(new BufferedWriter(fw));
245 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
246 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
247 // Pass in set of methods and get import classes
248 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
249 printImportStatements(importClasses);
250 // Write interface header
252 println("public interface " + newIntface + " {");
254 writeMethodJavaInterface(intMeth.getValue(), intDecl);
257 System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
264 * HELPER: writePropertiesJavaStub() writes the properties of the stub class
266 private void writePropertiesJavaStub(String intface) {
268 println("private IoTRMICall rmiCall;");
269 //println("private IoTRMIObject rmiObj;");
270 println("private String address;");
271 println("private int[] ports;\n");
273 Integer objId = mapIntfaceObjId.get(intface);
274 println("private final static int objectId = " + objId + ";");
275 mapIntfaceObjId.put(intface, objId++);
281 * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
283 private void writeConstructorJavaStub(String intface) {
285 println("public " + intface + "(int _port, String _address, int _rev, int[] _ports) throws Exception {");
286 println("address = _address;");
287 println("ports = _ports;");
288 println("rmiCall = new IoTRMICall(_port, _address, _rev);");
294 * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class
296 private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
297 List<String> methPrmTypes, String method) {
299 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
300 String retType = intDecl.getMethodType(method);
301 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
302 // Generate array of parameter types
303 print("Class<?>[] paramCls = new Class<?>[] { ");
304 for (int i = 0; i < methParams.size(); i++) {
305 String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
306 print(getSimpleType(paramType) + ".class");
307 // Check if this is the last element (don't print a comma)
308 if (i != methParams.size() - 1) {
313 // Generate array of parameter objects
314 print("Object[] paramObj = new Object[] { ");
315 for (int i = 0; i < methParams.size(); i++) {
316 print(getSimpleIdentifier(methParams.get(i)));
317 // Check if this is the last element (don't print a comma)
318 if (i != methParams.size() - 1) {
323 // Check if this is "void"
324 if (retType.equals("void")) {
325 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
326 } else { // We do have a return value
327 // Check if the return value NONPRIMITIVES
328 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
329 String[] retGenValType = getTypeOfGeneric(retType);
330 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
331 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
332 println("return (" + retType + ")retObj;");
334 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
335 println("return (" + retType + ")retObj;");
342 * HELPER: writeMethodJavaStub() writes the method of the stub class
344 private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl) {
346 for (String method : methods) {
348 List<String> methParams = intDecl.getMethodParams(method);
349 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
350 print("public " + intDecl.getMethodType(method) + " " +
351 intDecl.getMethodId(method) + "(");
352 for (int i = 0; i < methParams.size(); i++) {
354 print(methPrmTypes.get(i) + " " + methParams.get(i));
355 // Check if this is the last element (don't print a comma)
356 if (i != methParams.size() - 1) {
361 // Now, write the body of stub!
362 writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
369 * generateJavaStubClasses() generate stubs based on the methods list in Java
371 public void generateJavaStubClasses() throws IOException {
373 // Create a new directory
374 String path = createDirectories(dir, subdir);
375 for (String intface : mapIntfacePTH.keySet()) {
377 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
378 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
380 // Open a new file to write into
381 String newIntface = intMeth.getKey();
382 String newStubClass = newIntface + "_Stub";
383 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
384 pw = new PrintWriter(new BufferedWriter(fw));
385 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
386 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
387 // Pass in set of methods and get import classes
388 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
389 List<String> stdImportClasses = getStandardJavaImportClasses();
390 List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
391 printImportStatements(allImportClasses); println("");
392 // Write interface header
393 println("public class " + newStubClass + " implements " + newIntface + " {\n");
395 writePropertiesJavaStub(intface);
397 writeConstructorJavaStub(newStubClass);
399 writeMethodJavaStub(intMeth.getValue(), intDecl);
402 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
409 * HELPER: writeMethodCplusInterface() writes the method of the interface
411 private void writeMethodCplusInterface(Collection<String> methods, InterfaceDecl intDecl) {
413 for (String method : methods) {
415 List<String> methParams = intDecl.getMethodParams(method);
416 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
417 print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
418 intDecl.getMethodId(method) + "(");
419 for (int i = 0; i < methParams.size(); i++) {
420 // Check for params with driver class types and exchange it
421 // with its remote interface
422 String paramType = checkAndGetParamClass(methPrmTypes.get(i), true);
423 paramType = checkAndGetCplusType(paramType);
424 // Check for arrays - translate into vector in C++
425 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
426 print(paramComplete);
427 // Check if this is the last element (don't print a comma)
428 if (i != methParams.size() - 1) {
438 * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking.
440 * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
441 * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
442 * The local interface has to be the input parameter for the stub and the stub
443 * interface has to be the input parameter for the local class.
445 public void generateCplusLocalInterfaces() throws IOException {
447 // Create a new directory
448 createDirectory(dir);
449 for (String intface : mapIntfacePTH.keySet()) {
450 // Open a new file to write into
451 FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
452 pw = new PrintWriter(new BufferedWriter(fw));
453 // Write file headers
454 println("#ifndef _" + intface.toUpperCase() + "_HPP__");
455 println("#define _" + intface.toUpperCase() + "_HPP__");
456 println("#include <iostream>");
457 // Pass in set of methods and get include classes
458 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
459 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
460 List<String> methods = intDecl.getMethods();
461 Set<String> includeClasses = getIncludeClasses(methods, intDecl);
462 printIncludeStatements(includeClasses); println("");
463 println("using namespace std;\n");
464 println("class " + intface); println("{");
467 writeMethodCplusInterface(methods, intDecl);
471 System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
477 * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
479 * For C++ we use virtual classe as interface
481 public void generateCPlusInterfaces() throws IOException {
483 // Create a new directory
484 String path = createDirectories(dir, subdir);
485 for (String intface : mapIntfacePTH.keySet()) {
487 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
488 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
490 // Open a new file to write into
491 String newIntface = intMeth.getKey();
492 FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp");
493 pw = new PrintWriter(new BufferedWriter(fw));
494 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
495 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
496 // Write file headers
497 println("#ifndef _" + newIntface.toUpperCase() + "_HPP__");
498 println("#define _" + newIntface.toUpperCase() + "_HPP__");
499 println("#include <iostream>");
500 // Pass in set of methods and get import classes
501 Set<String> includeClasses = getIncludeClasses(intMeth.getValue(), intDecl);
502 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
503 List<String> allIncludeClasses = getAllImportClasses(stdIncludeClasses, includeClasses);
504 printIncludeStatements(allIncludeClasses); println("");
505 println("using namespace std;\n");
506 println("class " + newIntface);
510 writeMethodCplusInterface(intMeth.getValue(), intDecl);
514 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
521 * HELPER: writeMethodCplusStub() writes the method of the stub
523 private void writeMethodCplusStub(Collection<String> methods, InterfaceDecl intDecl) {
525 for (String method : methods) {
527 List<String> methParams = intDecl.getMethodParams(method);
528 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
529 print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
530 intDecl.getMethodId(method) + "(");
531 for (int i = 0; i < methParams.size(); i++) {
532 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
533 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
534 print(methParamComplete);
535 // Check if this is the last element (don't print a comma)
536 if (i != methParams.size() - 1) {
541 writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method);
548 * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class
550 private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
551 List<String> methPrmTypes, String method) {
553 println("int numParam = " + methParams.size() + ";");
554 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
555 String retType = intDecl.getMethodType(method);
556 println("string retType = \"" + checkAndGetCplusType(retType) + "\";");
557 // Generate array of parameter types
558 print("string paramCls[] = { ");
559 for (int i = 0; i < methParams.size(); i++) {
560 String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
561 print("\"" + getSimpleType(paramType) + "\"");
562 // Check if this is the last element (don't print a comma)
563 if (i != methParams.size() - 1) {
568 // Generate array of parameter objects
569 print("void* paramObj[] = { ");
570 for (int i = 0; i < methParams.size(); i++) {
571 print("&" + checkAndGetCplusType(getSimpleIdentifier(methParams.get(i))));
572 // Check if this is the last element (don't print a comma)
573 if (i != methParams.size() - 1) {
578 // Check if this is "void"
579 if (retType.equals("void")) {
580 println("void* retObj = NULL;");
581 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
582 } else { // We do have a return value
583 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
584 println(checkAndGetCplusType(retType) + " retVal;");
586 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
587 println("void* retObj = &retVal;");
588 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
589 println("return retVal;");
595 * HELPER: writePropertiesCplusStub() writes the properties of the stub class
597 private void writePropertiesCplusStub(String intface) {
599 println("IoTRMICall\t\t\t*rmiCall;");
600 //println("IoTRMIObject\t\t\t*rmiObj;");
601 println("string\t\t\t\taddress;");
602 println("vector<int>\t\t\tports;\n");
604 Integer objId = mapIntfaceObjId.get(intface);
605 println("const static int\tobjectId = " + objId + ";");
606 mapIntfaceObjId.put(intface, objId++);
612 * HELPER: writeConstructorCplusStub() writes the constructor of the stub class
614 private void writeConstructorCplusStub(String newStubClass) {
616 println(newStubClass +
617 "(int _port, const char* _address, int _rev, bool* _bResult, vector<int> _ports) {");
618 println("address = _address;");
619 println("ports = _ports;");
620 println("rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);");
626 * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
628 private void writeDeconstructorCplusStub(String newStubClass) {
630 println("~" + newStubClass + "() {");
631 println("if (rmiCall != NULL) {");
632 println("delete rmiCall;");
633 println("rmiCall = NULL;");
637 // Check if this is callback!!! and print "delete rmiObj and vecCBObj"
642 * generateCPlusStubClasses() generate stubs based on the methods list in C++
644 public void generateCPlusStubClasses() throws IOException {
646 // Create a new directory
647 String path = createDirectories(dir, subdir);
648 for (String intface : mapIntfacePTH.keySet()) {
650 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
651 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
652 // Open a new file to write into
653 String newIntface = intMeth.getKey();
654 String newStubClass = newIntface + "_Stub";
655 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
656 pw = new PrintWriter(new BufferedWriter(fw));
657 // Write file headers
658 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
659 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
660 println("#include <iostream>");
661 println("#include \"" + newIntface + ".hpp\""); println("");
662 println("using namespace std;"); println("");
663 println("class " + newStubClass + " : public " + newIntface); println("{");
664 println("private:\n");
665 writePropertiesCplusStub(intface);
666 println("public:\n");
667 // Add default constructor and destructor
668 println(newStubClass + "() { }"); println("");
669 writeConstructorCplusStub(newStubClass);
670 writeDeconstructorCplusStub(newStubClass);
671 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
672 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
674 writeMethodCplusStub(intMeth.getValue(), intDecl);
675 print("}"); println(";");
678 System.out.println("IoTCompiler: Generated stub class " + newIntface + ".hpp...");
685 * generateInitializer() generate initializer based on type
687 public String generateCplusInitializer(String type) {
689 // Generate dummy returns for now
690 if (type.equals("short")||
691 type.equals("int") ||
692 type.equals("long") ||
693 type.equals("float")||
694 type.equals("double")) {
697 } else if ( type.equals("String") ||
698 type.equals("string")) {
701 } else if ( type.equals("char") ||
702 type.equals("byte")) {
705 } else if ( type.equals("boolean")) {
715 * generateReturnStmt() generate return statement based on methType
717 public String generateReturnStmt(String methType) {
719 // Generate dummy returns for now
720 if (methType.equals("short")||
721 methType.equals("int") ||
722 methType.equals("long") ||
723 methType.equals("float")||
724 methType.equals("double")) {
727 } else if ( methType.equals("String")) {
730 } else if ( methType.equals("char") ||
731 methType.equals("byte")) {
734 } else if ( methType.equals("boolean")) {
744 * setDirectory() sets a new directory for stub files
746 public void setDirectory(String _subdir) {
753 * printUsage() prints the usage of this compiler
755 public static void printUsage() {
757 System.out.println();
758 System.out.println("Sentinel interface and stub compiler version 1.0");
759 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
760 System.out.println("All rights reserved.");
761 System.out.println("Usage:");
762 System.out.println("\tjava IoTCompiler -help / --help / -h\n");
763 System.out.println("\t\tDisplay this help texts\n\n");
764 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>]");
765 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>] [options]\n");
766 System.out.println("\t\tTake one or more pairs of main-req policy files, and generate Java and/or C++ files\n");
767 System.out.println("Options:");
768 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
769 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
770 System.out.println();
775 * parseFile() prepares Lexer and Parser objects, then parses the file
777 public static ParseNode parseFile(String file) {
781 ComplexSymbolFactory csf = new ComplexSymbolFactory();
782 ScannerBuffer lexer =
783 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf));
784 Parser parse = new Parser(lexer,csf);
785 pn = (ParseNode) parse.parse().value;
786 } catch (Exception e) {
788 throw new Error("IoTCompiler: ERROR parsing policy file or wrong command line option: " + file);
799 boolean newline=true;
802 private void print(String str) {
807 for(int i=0; i<tab; i++)
817 * This function converts Java to C++ type for compilation
819 private String convertType(String jType) {
821 return mapPrimitives.get(jType);
825 private void println(String str) {
830 for(int i=0; i<tab; i++)
839 private void updatetabbing(String str) {
840 tablevel+=count(str,'{')-count(str,'}');
844 private int count(String str, char key) {
845 char[] array = str.toCharArray();
847 for(int i=0; i<array.length; i++) {
855 private void createDirectory(String dirName) {
857 File file = new File(dirName);
858 if (!file.exists()) {
860 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
862 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
865 System.out.println("IoTCompiler: Directory " + dirName + " exists...");
870 // Create a directory and possibly a sub directory
871 private String createDirectories(String dir, String subdir) {
874 createDirectory(path);
875 if (subdir != null) {
876 path = path + "/" + subdir;
877 createDirectory(path);
883 // Inserting array members into a Map object
884 // that maps arrKey to arrVal objects
885 private void arraysToMap(Map map, Object[] arrKey, Object[] arrVal) {
887 for(int i = 0; i < arrKey.length; i++) {
889 map.put(arrKey[i], arrVal[i]);
894 // Return parameter category, i.e. PRIMITIVES, NONPRIMITIVES, or USERDEFINED
895 private ParamCategory getParamCategory(String paramType) {
897 if (mapPrimitives.containsKey(paramType)) {
898 return ParamCategory.PRIMITIVES;
899 // We can either use mapNonPrimitivesJava or mapNonPrimitivesCplus here
900 } else if (mapNonPrimitivesJava.containsKey(getSimpleType(paramType))) {
901 return ParamCategory.NONPRIMITIVES;
903 return ParamCategory.USERDEFINED;
907 // Return full class name for non-primitives to generate Java import statements
908 // e.g. java.util.Set for Set, java.util.Map for Map
909 private String getNonPrimitiveJavaClass(String paramNonPrimitives) {
911 return mapNonPrimitivesJava.get(paramNonPrimitives);
915 // Return full class name for non-primitives to generate Cplus include statements
916 // e.g. #include <set> for Set, #include <map> for Map
917 private String getNonPrimitiveCplusClass(String paramNonPrimitives) {
919 return mapNonPrimitivesCplus.get(paramNonPrimitives);
923 // Get simple types, e.g. HashSet for HashSet<...>
924 // Basically strip off the "<...>"
925 private String getSimpleType(String paramType) {
927 // Check if this is generics
928 if(paramType.contains("<")) {
929 String[] type = paramType.split("<");
936 // Generate a set of standard classes for import statements
937 private List<String> getStandardJavaImportClasses() {
939 List<String> importClasses = new ArrayList<String>();
940 // Add the standard list first
941 importClasses.add("java.io.IOException");
942 importClasses.add("java.util.List");
943 importClasses.add("java.util.ArrayList");
944 importClasses.add("iotrmi.Java.IoTRMICall");
945 importClasses.add("iotrmi.Java.IoTRMIObject");
947 return importClasses;
951 // Generate a set of standard classes for import statements
952 private List<String> getStandardCplusIncludeClasses() {
954 List<String> importClasses = new ArrayList<String>();
955 // Add the standard list first
956 importClasses.add("<vector>");
957 importClasses.add("\"IoTRMICall.hpp\"");
958 importClasses.add("\"IoTRMIObject.hpp\"");
960 return importClasses;
964 // Generate a set of standard classes for import statements
965 private List<String> getAllImportClasses(Collection<String> stdImportClasses, Collection<String> importClasses) {
967 List<String> allImportClasses = new ArrayList<String>(stdImportClasses);
968 // Iterate over the list of import classes
969 for (String str : importClasses) {
970 if (!stdImportClasses.contains(str)) {
971 stdImportClasses.add(str);
975 return allImportClasses;
980 // Generate a set of classes for import statements
981 private Set<String> getImportClasses(Collection<String> methods, InterfaceDecl intDecl) {
983 Set<String> importClasses = new HashSet<String>();
984 for (String method : methods) {
985 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
986 for (String paramType : methPrmTypes) {
988 String simpleType = getSimpleType(paramType);
989 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
990 importClasses.add(getNonPrimitiveJavaClass(simpleType));
994 return importClasses;
998 // Generate a set of classes for include statements
999 private Set<String> getIncludeClasses(Collection<String> methods, InterfaceDecl intDecl) {
1001 Set<String> includeClasses = new HashSet<String>();
1002 for (String method : methods) {
1004 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1005 List<String> methParams = intDecl.getMethodParams(method);
1006 for (int i = 0; i < methPrmTypes.size(); i++) {
1008 String simpleType = getSimpleType(methPrmTypes.get(i));
1009 String param = methParams.get(i);
1010 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
1011 includeClasses.add("<" + getNonPrimitiveCplusClass(simpleType) + ">");
1012 } else if (getParamCategory(simpleType) == ParamCategory.USERDEFINED) {
1013 includeClasses.add("\"" + exchangeParamType(simpleType) + ".hpp\"");
1014 } else if (param.contains("[]")) {
1015 // Check if this is array for C++; translate into vector
1016 includeClasses.add("<vector>");
1020 return includeClasses;
1024 private void printImportStatements(Collection<String> importClasses) {
1026 for(String cls : importClasses) {
1027 println("import " + cls + ";");
1032 private void printIncludeStatements(Collection<String> includeClasses) {
1034 for(String cls : includeClasses) {
1035 println("#include " + cls);
1040 // Get the C++ version of a non-primitive type
1041 // e.g. set for Set and map for Map
1042 // Input nonPrimitiveType has to be generics in format
1043 private String[] getTypeOfGeneric(String nonPrimitiveType) {
1045 // Handle <, >, and , for 2-type generic/template
1046 String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(",");
1051 // This helper function strips off array declaration, e.g. D[] becomes D
1052 private String getSimpleIdentifier(String ident) {
1054 // Handle [ for array declaration
1055 String substr = ident;
1056 if (ident.contains("[]")) {
1057 substr = ident.split("\\[\\]")[0];
1063 private String checkAndGetCplusType(String paramType) {
1065 if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
1066 return convertType(paramType);
1067 } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) {
1069 // Check for generic/template format
1070 if (paramType.contains("<") && paramType.contains(">")) {
1072 String genericClass = getSimpleType(paramType);
1073 String[] genericType = getTypeOfGeneric(paramType);
1074 String cplusTemplate = null;
1075 if (genericType.length == 1) // Generic/template with one type
1076 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
1077 "<" + convertType(genericType[0]) + ">";
1078 else // Generic/template with two types
1079 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
1080 "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">";
1081 return cplusTemplate;
1083 return getNonPrimitiveCplusClass(paramType);
1085 // Just return it as is if it's not non-primitives
1090 // Detect array declaration, e.g. int A[],
1091 // then generate "int A[]" in C++ as "vector<int> A"
1092 private String checkAndGetCplusArray(String paramType, String param) {
1094 String paramComplete = null;
1095 // Check for array declaration
1096 if (param.contains("[]")) {
1097 paramComplete = "vector<" + paramType + "> " + param.replace("[]","");
1099 // Just return it as is if it's not an array
1100 paramComplete = paramType + " " + param;
1102 return paramComplete;
1106 // Detect array declaration, e.g. int A[],
1107 // then generate type "int[]"
1108 private String checkAndGetArray(String paramType, String param) {
1110 String paramTypeRet = null;
1111 // Check for array declaration
1112 if (param.contains("[]")) {
1113 paramTypeRet = paramType + "[]";
1115 // Just return it as is if it's not an array
1116 paramTypeRet = paramType;
1118 return paramTypeRet;
1122 // Get simple types, e.g. HashSet for HashSet<...>
1123 // Basically strip off the "<...>"
1124 private String checkAndGetParamClass(String paramType, boolean needPtr) {
1126 // Check if this is generics
1127 if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
1128 // If true then return with pointer (C++)
1130 return exchangeParamType(paramType) + "*";
1131 else // Java, so no pointer needed
1132 return exchangeParamType(paramType);
1138 // Returns the other interface for type-checking purposes for USERDEFINED
1139 // classes based on the information provided in multiple policy files
1140 // e.g. return CameraWithXXX instead of Camera
1141 private String exchangeParamType(String intface) {
1143 // Param type that's passed is the interface name we need to look for
1144 // in the map of interfaces, based on available policy files.
1145 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1146 if (decHandler != null) {
1147 // We've found the required interface policy files
1148 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(intface);
1149 Set<String> setExchInt = reqDecl.getInterfaces();
1150 if (setExchInt.size() == 1) {
1151 Iterator iter = setExchInt.iterator();
1152 return (String) iter.next();
1154 throw new Error("IoTCompiler: Ambiguous stub interfaces: " + setExchInt.toString() +
1155 ". Only one new interface can be declared if the object " + intface +
1156 " needs to be passed in as an input parameter!");
1159 // NULL value - this means policy files missing
1160 throw new Error("IoTCompiler: Parameter type lookup failed for " + intface +
1161 "... Please provide the necessary policy files for user-defined types." +
1162 " If this is an array please type the brackets after the variable name," +
1163 " e.g. \"String str[]\", not \"String[] str\"." +
1164 " If this is a Collections (Java) / STL (C++) type, this compiler only" +
1165 " supports List/ArrayList (Java) or list (C++).");
1170 public static void main(String[] args) throws Exception {
1172 // If there is no argument or just "--help" or "-h", then invoke printUsage()
1173 if ((args[0].equals("-help") ||
1174 args[0].equals("--help")||
1175 args[0].equals("-h")) ||
1176 (args.length == 0)) {
1178 IoTCompiler.printUsage();
1180 } else if (args.length > 1) {
1182 IoTCompiler comp = new IoTCompiler();
1185 // Parse main policy file
1186 ParseNode pnPol = IoTCompiler.parseFile(args[i]);
1187 // Parse "requires" policy file
1188 ParseNode pnReq = IoTCompiler.parseFile(args[i+1]);
1189 // Get interface name
1190 String intface = ParseTreeHandler.getOrigIntface(pnPol);
1191 comp.setDataStructures(intface, pnPol, pnReq);
1192 comp.getMethodsForIntface(intface);
1194 // 1) Check if this is the last option before "-java" or "-cplus"
1195 // 2) Check if this is really the last option (no "-java" or "-cplus")
1196 } while(!args[i].equals("-java") &&
1197 !args[i].equals("-cplus") &&
1200 // Generate everything if we don't see "-java" or "-cplus"
1201 if (i == args.length) {
1202 comp.generateJavaLocalInterfaces();
1203 comp.generateJavaInterfaces();
1204 comp.generateJavaStubClasses();
1205 comp.generateCplusLocalInterfaces();
1206 comp.generateCPlusInterfaces();
1207 comp.generateCPlusStubClasses();
1209 // Check other options
1210 while(i < args.length) {
1212 if (!args[i].equals("-java") &&
1213 !args[i].equals("-cplus")) {
1214 throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
1216 if (i + 1 < args.length) {
1217 comp.setDirectory(args[i+1]);
1219 throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
1221 if (args[i].equals("-java")) {
1222 comp.generateJavaLocalInterfaces();
1223 comp.generateJavaInterfaces();
1224 comp.generateJavaStubClasses();
1226 comp.generateCplusLocalInterfaces();
1227 comp.generateCPlusInterfaces();
1228 comp.generateCPlusStubClasses();
1235 // Need to at least have exactly 2 parameters, i.e. main policy file and requires file
1236 IoTCompiler.printUsage();
1237 throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");