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;
27 import iotpolicy.tree.EnumDecl;
28 import iotpolicy.tree.StructDecl;
30 import iotrmi.Java.IoTRMITypes;
33 /** Class IoTCompiler is the main interface/stub compiler for
34 * files generation. This class calls helper classes
35 * such as Parser, Lexer, InterfaceDecl, CapabilityDecl,
36 * RequiresDecl, ParseTreeHandler, etc.
38 * @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
42 public class IoTCompiler {
47 // Maps multiple interfaces to multiple objects of ParseTreeHandler
48 private Map<String,ParseTreeHandler> mapIntfacePTH;
49 private Map<String,DeclarationHandler> mapIntDeclHand;
50 private Map<String,Map<String,Set<String>>> mapInt2NewInts;
51 // Data structure to store our types (primitives and non-primitives) for compilation
52 private Map<String,String> mapPrimitives;
53 private Map<String,String> mapNonPrimitivesJava;
54 private Map<String,String> mapNonPrimitivesCplus;
55 // Other data structures
56 private Map<String,Integer> mapIntfaceObjId; // Maps interface name to object Id
57 private Map<String,Integer> mapNewIntfaceObjId; // Maps new interface name to its object Id (keep track of stubs)
58 private PrintWriter pw;
60 private String subdir;
65 private final static String OUTPUT_DIRECTORY = "output_files";
67 private enum ParamCategory {
69 PRIMITIVES, // All the primitive types, e.g. byte, short, int, long, etc.
70 NONPRIMITIVES, // Non-primitive types, e.g. Set, Map, List, etc.
71 USERDEFINED // Non-supported type by default; assumed as driver classes
77 public IoTCompiler() {
79 mapIntfacePTH = new HashMap<String,ParseTreeHandler>();
80 mapIntDeclHand = new HashMap<String,DeclarationHandler>();
81 mapInt2NewInts = new HashMap<String,Map<String,Set<String>>>();
82 mapIntfaceObjId = new HashMap<String,Integer>();
83 mapNewIntfaceObjId = new HashMap<String,Integer>();
84 mapPrimitives = new HashMap<String,String>();
85 arraysToMap(mapPrimitives, IoTRMITypes.primitivesJava, IoTRMITypes.primitivesCplus);
86 mapNonPrimitivesJava = new HashMap<String,String>();
87 arraysToMap(mapNonPrimitivesJava, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitiveJavaLibs);
88 mapNonPrimitivesCplus = new HashMap<String,String>();
89 arraysToMap(mapNonPrimitivesCplus, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitivesCplus);
91 dir = OUTPUT_DIRECTORY;
97 * setDataStructures() sets parse tree and other data structures based on policy files.
99 * It also generates parse tree (ParseTreeHandler) and
100 * copies useful information from parse tree into
101 * InterfaceDecl, CapabilityDecl, and RequiresDecl
103 * Additionally, the data structure handles are
104 * returned from tree-parsing for further process.
107 public void setDataStructures(String origInt, ParseNode pnPol, ParseNode pnReq) {
109 ParseTreeHandler ptHandler = new ParseTreeHandler(origInt, pnPol, pnReq);
110 DeclarationHandler decHandler = new DeclarationHandler();
111 // Process ParseNode and generate Declaration objects
113 ptHandler.processInterfaceDecl();
114 InterfaceDecl intDecl = ptHandler.getInterfaceDecl();
115 decHandler.addInterfaceDecl(origInt, intDecl);
117 ptHandler.processCapabilityDecl();
118 CapabilityDecl capDecl = ptHandler.getCapabilityDecl();
119 decHandler.addCapabilityDecl(origInt, capDecl);
121 ptHandler.processRequiresDecl();
122 RequiresDecl reqDecl = ptHandler.getRequiresDecl();
123 decHandler.addRequiresDecl(origInt, reqDecl);
125 ptHandler.processEnumDecl();
126 EnumDecl enumDecl = ptHandler.getEnumDecl();
127 decHandler.addEnumDecl(origInt, enumDecl);
129 ptHandler.processStructDecl();
130 StructDecl structDecl = ptHandler.getStructDecl();
131 decHandler.addStructDecl(origInt, structDecl);
133 mapIntfacePTH.put(origInt, ptHandler);
134 mapIntDeclHand.put(origInt, decHandler);
135 // Set object Id counter to 0 for each interface
136 mapIntfaceObjId.put(origInt, new Integer(0));
141 * getMethodsForIntface() reads for methods in the data structure
143 * It is going to give list of methods for a certain interface
144 * based on the declaration of capabilities.
146 public void getMethodsForIntface(String origInt) {
148 ParseTreeHandler ptHandler = mapIntfacePTH.get(origInt);
149 Map<String,Set<String>> mapNewIntMethods = new HashMap<String,Set<String>>();
150 // Get set of new interfaces, e.g. CameraWithCaptureAndData
151 // Generate this new interface with all the methods it needs
152 // from different capabilities it declares
153 DeclarationHandler decHandler = mapIntDeclHand.get(origInt);
154 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(origInt);
155 Set<String> setIntfaces = reqDecl.getInterfaces();
156 for (String strInt : setIntfaces) {
158 // Initialize a set of methods
159 Set<String> setMethods = new HashSet<String>();
160 // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc.
161 List<String> listCapab = reqDecl.getCapabList(strInt);
162 for (String strCap : listCapab) {
164 // Get list of methods for each capability
165 CapabilityDecl capDecl = (CapabilityDecl) decHandler.getCapabilityDecl(origInt);
166 List<String> listCapabMeth = capDecl.getMethods(strCap);
167 for (String strMeth : listCapabMeth) {
169 // Add methods into setMethods
170 // This is to also handle redundancies (say two capabilities
171 // share the same methods)
172 setMethods.add(strMeth);
175 // Add interface and methods information into map
176 mapNewIntMethods.put(strInt, setMethods);
178 // Map the map of interface-methods to the original interface
179 mapInt2NewInts.put(origInt, mapNewIntMethods);
184 * HELPER: writeMethodJavaLocalInterface() writes the method of the interface
186 private void writeMethodJavaLocalInterface(Collection<String> methods, InterfaceDecl intDecl) {
188 for (String method : methods) {
190 List<String> methParams = intDecl.getMethodParams(method);
191 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
192 print("public " + intDecl.getMethodType(method) + " " +
193 intDecl.getMethodId(method) + "(");
194 for (int i = 0; i < methParams.size(); i++) {
195 // Check for params with driver class types and exchange it
196 // with its remote interface
197 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
198 print(paramType + " " + methParams.get(i));
199 // Check if this is the last element (don't print a comma)
200 if (i != methParams.size() - 1) {
210 * HELPER: writeMethodJavaInterface() writes the method of the interface
212 private void writeMethodJavaInterface(Collection<String> methods, InterfaceDecl intDecl) {
214 for (String method : methods) {
216 List<String> methParams = intDecl.getMethodParams(method);
217 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
218 print("public " + intDecl.getMethodType(method) + " " +
219 intDecl.getMethodId(method) + "(");
220 for (int i = 0; i < methParams.size(); i++) {
221 // Check for params with driver class types and exchange it
222 // with its remote interface
223 String paramType = methPrmTypes.get(i);
224 print(paramType + " " + methParams.get(i));
225 // Check if this is the last element (don't print a comma)
226 if (i != methParams.size() - 1) {
236 * HELPER: writeEnumJava() writes the enumeration declaration
238 private void writeEnumJava(EnumDecl enumDecl) {
240 Set<String> enumTypes = enumDecl.getEnumDeclarations();
241 // Iterate over enum declarations
242 for (String enType : enumTypes) {
244 println("public enum " + enType + " {");
245 List<String> enumMembers = enumDecl.getMembers(enType);
246 for (int i = 0; i < enumMembers.size(); i++) {
248 String member = enumMembers.get(i);
250 // Check if this is the last element (don't print a comma)
251 if (i != enumMembers.size() - 1)
262 * HELPER: writeStructJava() writes the struct declaration
264 private void writeStructJava(StructDecl structDecl) {
266 List<String> structTypes = structDecl.getStructTypes();
267 // Iterate over enum declarations
268 for (String stType : structTypes) {
270 println("public class " + stType + " {");
271 List<String> structMemberTypes = structDecl.getMemberTypes(stType);
272 List<String> structMembers = structDecl.getMembers(stType);
273 for (int i = 0; i < structMembers.size(); i++) {
275 String memberType = structMemberTypes.get(i);
276 String member = structMembers.get(i);
277 println("public static " + memberType + " " + member + ";");
285 * generateJavaLocalInterface() writes the local interface and provides type-checking.
287 * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
288 * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
289 * The local interface has to be the input parameter for the stub and the stub
290 * interface has to be the input parameter for the local class.
292 public void generateJavaLocalInterfaces() throws IOException {
294 // Create a new directory
295 createDirectory(dir);
296 for (String intface : mapIntfacePTH.keySet()) {
297 // Open a new file to write into
298 FileWriter fw = new FileWriter(dir + "/" + intface + ".java");
299 pw = new PrintWriter(new BufferedWriter(fw));
300 // Pass in set of methods and get import classes
301 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
302 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
303 List<String> methods = intDecl.getMethods();
304 Set<String> importClasses = getImportClasses(methods, intDecl);
305 printImportStatements(importClasses);
306 // Write interface header
308 println("public interface " + intface + " {");
309 // Write enum if any...
310 EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface);
311 writeEnumJava(enumDecl);
312 // Write struct if any...
313 StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
314 writeStructJava(structDecl);
316 writeMethodJavaLocalInterface(methods, intDecl);
319 System.out.println("IoTCompiler: Generated local interface " + intface + ".java...");
325 * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
327 public void generateJavaInterfaces() throws IOException {
329 // Create a new directory
330 String path = createDirectories(dir, subdir);
331 for (String intface : mapIntfacePTH.keySet()) {
333 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
334 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
336 // Open a new file to write into
337 String newIntface = intMeth.getKey();
338 FileWriter fw = new FileWriter(path + "/" + newIntface + ".java");
339 pw = new PrintWriter(new BufferedWriter(fw));
340 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
341 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
342 // Pass in set of methods and get import classes
343 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
344 printImportStatements(importClasses);
345 // Write interface header
347 println("public interface " + newIntface + " {\n");
349 writeMethodJavaInterface(intMeth.getValue(), intDecl);
352 System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
359 * HELPER: writePropertiesJavaStub() writes the properties of the stub class
361 private void writePropertiesJavaStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
363 println("private IoTRMICall rmiCall;");
364 println("private String address;");
365 println("private int[] ports;\n");
367 Integer objId = mapIntfaceObjId.get(intface);
368 println("private final static int objectId = " + objId + ";");
369 mapNewIntfaceObjId.put(newIntface, objId);
370 mapIntfaceObjId.put(intface, objId++);
372 // We assume that each class only has one callback interface for now
373 Iterator it = callbackClasses.iterator();
374 String callbackType = (String) it.next();
375 println("// Callback properties");
376 println("private IoTRMIObject rmiObj;");
377 println("List<" + callbackType + "> listCallbackObj;");
378 println("private static int objIdCnt = 0;");
385 * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
387 private void writeConstructorJavaStub(String intface, boolean callbackExist, Set<String> callbackClasses) {
389 println("public " + intface + "(int _port, String _address, int _rev, int[] _ports) throws Exception {");
390 println("address = _address;");
391 println("ports = _ports;");
392 println("rmiCall = new IoTRMICall(_port, _address, _rev);");
394 Iterator it = callbackClasses.iterator();
395 String callbackType = (String) it.next();
396 println("listCallbackObj = new ArrayList<" + callbackType + ">();");
397 println("___initCallBack();");
404 * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
406 private void writeInitCallbackJavaStub(String intface, InterfaceDecl intDecl) {
408 println("public void ___initCallBack() {");
409 // Generate main thread for callbacks
410 println("Thread thread = new Thread() {");
411 println("public void run() {");
413 println("rmiObj = new IoTRMIObject(ports[0]);");
414 println("while (true) {");
415 println("byte[] method = rmiObj.getMethodBytes();");
416 println("int objId = IoTRMIObject.getObjectId(method);");
417 println(intface + "_CallbackSkeleton skel = (" + intface + "_CallbackSkeleton) listCallbackObj.get(objId);");
418 println("if (skel != null) {");
419 println("skel.invokeMethod(rmiObj);");
421 println("throw new Error(\"" + intface + ": Object with Id \" + objId + \" not found!\");");
424 println("} catch (Exception ex) {");
425 println("ex.printStackTrace();");
426 println("throw new Error(\"Error instantiating class " + intface + "_CallbackSkeleton!\");");
430 println("thread.start();\n");
431 // Generate info sending part
432 String method = "___initCallBack()";
433 println("int methodId = " + intDecl.getHelperMethodNumId(method) + ";");
434 println("Class<?> retType = void.class;");
435 println("Class<?>[] paramCls = new Class<?>[] { int.class, String.class, int.class };");
436 println("Object[] paramObj = new Object[] { ports[0], address, 0 };");
437 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
443 * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class
445 private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
446 List<String> methPrmTypes, String method) {
448 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
449 String retType = intDecl.getMethodType(method);
450 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
451 // Generate array of parameter types
452 print("Class<?>[] paramCls = new Class<?>[] { ");
453 for (int i = 0; i < methParams.size(); i++) {
454 String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
455 print(getSimpleType(paramType) + ".class");
456 // Check if this is the last element (don't print a comma)
457 if (i != methParams.size() - 1) {
462 // Generate array of parameter objects
463 print("Object[] paramObj = new Object[] { ");
464 for (int i = 0; i < methParams.size(); i++) {
465 print(getSimpleIdentifier(methParams.get(i)));
466 // Check if this is the last element (don't print a comma)
467 if (i != methParams.size() - 1) {
472 // Check if this is "void"
473 if (retType.equals("void")) {
474 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
475 } else { // We do have a return value
476 // Check if the return value NONPRIMITIVES
477 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
478 String[] retGenValType = getTypeOfGeneric(retType);
479 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
480 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
481 println("return (" + retType + ")retObj;");
483 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
484 println("return (" + retType + ")retObj;");
491 * HELPER: returnGenericCallbackType() returns the callback type
493 private String returnGenericCallbackType(String paramType) {
495 if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES)
496 return getTypeOfGeneric(paramType)[0];
503 * HELPER: checkCallbackType() checks the callback type
505 private boolean checkCallbackType(String paramType, String callbackType) {
507 String prmType = returnGenericCallbackType(paramType);
508 return callbackType.equals(prmType);
513 * HELPER: writeCallbackMethodBodyJavaStub() writes the callback method of the stub class
515 private void writeCallbackMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
516 List<String> methPrmTypes, String method, String callbackType) {
519 // Check if this is single object, array, or list of objects
520 for (int i = 0; i < methParams.size(); i++) {
522 String paramType = methPrmTypes.get(i);
523 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
524 String param = methParams.get(i);
525 if (isArrayOrList(paramType, param)) { // Generate loop
526 println("for (" + paramType + " cb : " + getSimpleIdentifier(param) + ") {");
527 println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);");
529 println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(" +
530 getSimpleIdentifier(param) + ", objIdCnt++);");
531 println("listCallbackObj.add(skel);");
532 if (isArrayOrList(paramType, param))
536 println("} catch (Exception ex) {");
537 println("ex.printStackTrace();");
538 println("throw new Error(\"Exception when generating skeleton objects!\");");
540 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
541 String retType = intDecl.getMethodType(method);
542 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
543 // Generate array of parameter types
544 print("Class<?>[] paramCls = new Class<?>[] { ");
545 for (int i = 0; i < methParams.size(); i++) {
546 String paramType = methPrmTypes.get(i);
547 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
549 } else { // Generate normal classes if it's not a callback object
550 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
551 print(getSimpleType(prmType) + ".class");
553 if (i != methParams.size() - 1) // Check if this is the last element
557 // Generate array of parameter objects
558 print("Object[] paramObj = new Object[] { ");
559 for (int i = 0; i < methParams.size(); i++) {
560 String paramType = methPrmTypes.get(i);
561 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
562 if (isArray(methPrmTypes.get(i), methParams.get(i)))
563 print(getSimpleIdentifier(methParams.get(i)) + ".length");
564 else if (isList(methPrmTypes.get(i), methParams.get(i)))
565 print(getSimpleIdentifier(methParams.get(i)) + ".size()");
567 print("new Integer(1)");
569 print(getSimpleIdentifier(methParams.get(i)));
570 if (i != methParams.size() - 1)
574 // Check if this is "void"
575 if (retType.equals("void")) {
576 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
577 } else { // We do have a return value
578 // Check if the return value NONPRIMITIVES
579 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
580 String[] retGenValType = getTypeOfGeneric(retType);
581 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
582 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
583 println("return (" + retType + ")retObj;");
585 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
586 println("return (" + retType + ")retObj;");
593 * HELPER: writeMethodJavaStub() writes the method of the stub class
595 private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
597 for (String method : methods) {
599 List<String> methParams = intDecl.getMethodParams(method);
600 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
601 print("public " + intDecl.getMethodType(method) + " " +
602 intDecl.getMethodId(method) + "(");
603 boolean isCallbackMethod = false;
604 String callbackType = null;
605 for (int i = 0; i < methParams.size(); i++) {
607 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
608 // Check if this has callback object
609 if (callbackClasses.contains(paramType)) {
610 isCallbackMethod = true;
611 callbackType = paramType;
612 // Even if there're 2 callback arguments, we expect them to be of the same interface
614 print(methPrmTypes.get(i) + " " + methParams.get(i));
615 // Check if this is the last element (don't print a comma)
616 if (i != methParams.size() - 1) {
621 // Now, write the body of stub!
622 if (isCallbackMethod)
623 writeCallbackMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method, callbackType);
625 writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
627 // Write the init callback helper method
628 if (isCallbackMethod)
629 writeInitCallbackJavaStub(callbackType, intDecl);
635 * generateJavaStubClasses() generate stubs based on the methods list in Java
637 public void generateJavaStubClasses() throws IOException {
639 // Create a new directory
640 String path = createDirectories(dir, subdir);
641 for (String intface : mapIntfacePTH.keySet()) {
643 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
644 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
646 // Open a new file to write into
647 String newIntface = intMeth.getKey();
648 String newStubClass = newIntface + "_Stub";
649 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
650 pw = new PrintWriter(new BufferedWriter(fw));
651 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
652 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
653 // Pass in set of methods and get import classes
654 Set<String> methods = intMeth.getValue();
655 Set<String> importClasses = getImportClasses(methods, intDecl);
656 List<String> stdImportClasses = getStandardJavaImportClasses();
657 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
658 printImportStatements(allImportClasses); println("");
659 // Find out if there are callback objects
660 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
661 boolean callbackExist = !callbackClasses.isEmpty();
662 // Write class header
663 println("public class " + newStubClass + " implements " + newIntface + " {\n");
665 writePropertiesJavaStub(intface, newIntface, callbackExist, callbackClasses);
667 writeConstructorJavaStub(newStubClass, callbackExist, callbackClasses);
669 writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses);
672 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
679 * HELPER: writePropertiesJavaCallbackStub() writes the properties of the callback stub class
681 private void writePropertiesJavaCallbackStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
683 println("private IoTRMICall rmiCall;");
684 println("private String address;");
685 println("private int[] ports;\n");
687 println("private static int objectId = 0;");
689 // We assume that each class only has one callback interface for now
690 Iterator it = callbackClasses.iterator();
691 String callbackType = (String) it.next();
692 println("// Callback properties");
693 println("private IoTRMIObject rmiObj;");
694 println("List<" + callbackType + "> listCallbackObj;");
695 println("private static int objIdCnt = 0;");
702 * HELPER: writeConstructorJavaCallbackStub() writes the constructor of the callback stub class
704 private void writeConstructorJavaCallbackStub(String intface, boolean callbackExist, Set<String> callbackClasses) {
706 // TODO: If we want callback in callback, then we need to add address and port initializations
707 println("public " + intface + "(IoTRMICall _rmiCall, int _objectId) throws Exception {");
708 println("objectId = _objectId;");
709 println("rmiCall = _rmiCall;");
711 Iterator it = callbackClasses.iterator();
712 String callbackType = (String) it.next();
713 println("listCallbackObj = new ArrayList<" + callbackType + ">();");
714 println("___initCallBack();");
715 println("// TODO: Add address and port initialization here if we want callback in callback!");
722 * generateJavaCallbackStubClasses() generate callback stubs based on the methods list in Java
724 * Callback stubs gets the IoTRMICall objects from outside of the class as contructor input
725 * because all these stubs are populated by the class that takes in this object as a callback
726 * object. In such a class, we only use one socket, hence one IoTRMICall, for all callback objects.
728 public void generateJavaCallbackStubClasses() throws IOException {
730 // Create a new directory
731 String path = createDirectories(dir, subdir);
732 for (String intface : mapIntfacePTH.keySet()) {
734 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
735 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
737 // Open a new file to write into
738 String newIntface = intMeth.getKey();
739 String newStubClass = newIntface + "_CallbackStub";
740 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
741 pw = new PrintWriter(new BufferedWriter(fw));
742 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
743 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
744 // Pass in set of methods and get import classes
745 Set<String> methods = intMeth.getValue();
746 Set<String> importClasses = getImportClasses(methods, intDecl);
747 List<String> stdImportClasses = getStandardJavaImportClasses();
748 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
749 printImportStatements(allImportClasses); println("");
750 // Find out if there are callback objects
751 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
752 boolean callbackExist = !callbackClasses.isEmpty();
753 // Write class header
754 println("public class " + newStubClass + " implements " + newIntface + " {\n");
756 writePropertiesJavaCallbackStub(intface, newIntface, callbackExist, callbackClasses);
758 writeConstructorJavaCallbackStub(newStubClass, callbackExist, callbackClasses);
760 // TODO: perhaps need to generate callback for callback
761 writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses);
764 System.out.println("IoTCompiler: Generated callback stub class " + newStubClass + ".java...");
771 * HELPER: writePropertiesJavaSkeleton() writes the properties of the skeleton class
773 private void writePropertiesJavaSkeleton(String intface, boolean callbackExist) {
775 println("private " + intface + " mainObj;");
776 //println("private int ports;");
777 println("private IoTRMIObject rmiObj;\n");
780 println("private static int objIdCnt = 0;");
781 println("private IoTRMICall rmiCall;");
783 // Keep track of object Ids of all stubs registered to this interface
784 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
785 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
786 String newIntface = intMeth.getKey();
787 int newObjectId = mapNewIntfaceObjId.get(newIntface);
788 println("private final static int object" + newObjectId + "Id = " +
789 newObjectId + ";\t//" + newIntface);
796 * HELPER: writeConstructorJavaSkeleton() writes the constructor of the skeleton class
798 private void writeConstructorJavaSkeleton(String newSkelClass, String intface) {
800 println("public " + newSkelClass + "(" + intface + " _mainObj, int _port) throws Exception {");
801 println("mainObj = _mainObj;");
802 println("rmiObj = new IoTRMIObject(_port);");
803 //println("set0Allowed = Arrays.asList(object0Permission);");
804 println("___waitRequestInvokeMethod();");
810 * HELPER: writeStdMethodBodyJavaSkeleton() writes the standard method body in the skeleton class
812 private void writeStdMethodBodyJavaSkeleton(List<String> methParams, String methodId, String methodType) {
814 if (methodType.equals("void"))
815 print("mainObj." + methodId + "(");
817 print("return mainObj." + methodId + "(");
818 for (int i = 0; i < methParams.size(); i++) {
820 print(getSimpleIdentifier(methParams.get(i)));
821 // Check if this is the last element (don't print a comma)
822 if (i != methParams.size() - 1) {
831 * HELPER: writeInitCallbackJavaSkeleton() writes the init callback method for skeleton class
833 private void writeInitCallbackJavaSkeleton(boolean callbackSkeleton) {
835 // This is a callback skeleton generation
836 if (callbackSkeleton)
837 println("public void ___regCB(IoTRMIObject rmiObj) throws IOException {");
839 println("public void ___regCB() throws IOException {");
840 println("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class, String.class, int.class },");
841 println("\tnew Class<?>[] { null, null, null });");
842 println("rmiCall = new IoTRMICall((int) paramObj[0], (String) paramObj[1], (int) paramObj[2]);");
848 * HELPER: writeMethodJavaSkeleton() writes the method of the skeleton class
850 private void writeMethodJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses,
851 boolean callbackSkeleton) {
853 for (String method : methods) {
855 List<String> methParams = intDecl.getMethodParams(method);
856 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
857 String methodId = intDecl.getMethodId(method);
858 print("public " + intDecl.getMethodType(method) + " " + methodId + "(");
859 boolean isCallbackMethod = false;
860 String callbackType = null;
861 for (int i = 0; i < methParams.size(); i++) {
863 String origParamType = methPrmTypes.get(i);
864 String paramType = checkAndGetParamClass(origParamType);
865 if (callbackClasses.contains(origParamType)) { // Check if this has callback object
866 isCallbackMethod = true;
867 callbackType = origParamType;
869 print(paramType + " " + methParams.get(i));
870 // Check if this is the last element (don't print a comma)
871 if (i != methParams.size() - 1) {
876 // Now, write the body of skeleton!
877 writeStdMethodBodyJavaSkeleton(methParams, methodId, intDecl.getMethodType(method));
879 if (isCallbackMethod)
880 writeInitCallbackJavaSkeleton(callbackSkeleton);
886 * HELPER: writeCallbackJavaStubGeneration() writes the callback stub generation part
888 private Map<Integer,String> writeCallbackJavaStubGeneration(List<String> methParams, List<String> methPrmTypes, String callbackType) {
890 Map<Integer,String> mapStubParam = new HashMap<Integer,String>();
891 // Iterate over callback objects
892 for (int i = 0; i < methParams.size(); i++) {
893 String paramType = methPrmTypes.get(i);
894 String param = methParams.get(i);
895 //if (callbackType.equals(paramType)) {
896 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
898 String exchParamType = checkAndGetParamClass(paramType);
899 // Print array if this is array or list if this is a list of callback objects
900 if (isArray(paramType, param)) {
901 println("int numStubs" + i + " = (int) paramObj[" + i + "];");
902 println(exchParamType + "[] stub" + i + " = new " + exchParamType + "[numStubs" + i + "];");
903 } else if (isList(paramType, param)) {
904 println("int numStubs" + i + " = (int) paramObj[" + i + "];");
905 println("List<" + exchParamType + "> stub" + i + " = new ArrayList<" + exchParamType + ">();");
907 println(exchParamType + " stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
908 println("objIdCnt++;");
911 // Generate a loop if needed
912 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
913 String exchParamType = checkAndGetParamClass(paramType);
914 if (isArray(paramType, param)) {
915 println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
916 println("stub" + i + "[objId] = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
917 println("objIdCnt++;");
919 } else if (isList(paramType, param)) {
920 println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
921 println("stub" + i + ".add(new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt));");
922 println("objIdCnt++;");
925 mapStubParam.put(i, "stub" + i); // List of all stub parameters
933 * HELPER: writeStdMethodHelperBodyJavaSkeleton() writes the standard method body helper in the skeleton class
935 private void writeStdMethodHelperBodyJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
936 List<String> methPrmTypes, String method, Set<String> callbackClasses) {
937 // Generate array of parameter objects
938 boolean isCallbackMethod = false;
939 String callbackType = null;
940 print("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { ");
941 for (int i = 0; i < methParams.size(); i++) {
943 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
944 if (callbackClasses.contains(paramType)) {
945 isCallbackMethod = true;
946 callbackType = paramType;
948 } else { // Generate normal classes if it's not a callback object
949 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
950 print(getSimpleType(prmType) + ".class");
952 if (i != methParams.size() - 1)
956 // Generate generic class if it's a generic type.. null otherwise
957 print("new Class<?>[] { ");
958 for (int i = 0; i < methParams.size(); i++) {
959 String prmType = methPrmTypes.get(i);
960 if (getParamCategory(prmType) == ParamCategory.NONPRIMITIVES)
961 print(getTypeOfGeneric(prmType)[0] + ".class");
964 if (i != methParams.size() - 1)
968 Map<Integer,String> mapStubParam = null;
969 if (isCallbackMethod)
970 mapStubParam = writeCallbackJavaStubGeneration(methParams, methPrmTypes, callbackType);
971 // Check if this is "void"
972 String retType = intDecl.getMethodType(method);
973 if (retType.equals("void")) {
974 print(intDecl.getMethodId(method) + "(");
975 } else { // We do have a return value
976 print("Object retObj = " + intDecl.getMethodId(method) + "(");
978 for (int i = 0; i < methParams.size(); i++) {
980 if (isCallbackMethod) {
981 print(mapStubParam.get(i)); // Get the callback parameter
983 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
984 print("(" + prmType + ") paramObj[" + i + "]");
986 if (i != methParams.size() - 1)
990 if (!retType.equals("void"))
991 println("rmiObj.sendReturnObj(retObj);");
992 if (isCallbackMethod) { // Catch exception if this is callback
993 println("} catch(Exception ex) {");
994 println("ex.printStackTrace();");
995 println("throw new Error(\"Exception from callback object instantiation!\");");
1002 * HELPER: writeMethodHelperJavaSkeleton() writes the method helper of the skeleton class
1004 private void writeMethodHelperJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1006 // Use this set to handle two same methodIds
1007 Set<String> uniqueMethodIds = new HashSet<String>();
1008 for (String method : methods) {
1010 List<String> methParams = intDecl.getMethodParams(method);
1011 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1012 String methodId = intDecl.getMethodId(method);
1013 print("public void ___");
1014 String helperMethod = methodId;
1015 if (uniqueMethodIds.contains(methodId))
1016 helperMethod = helperMethod + intDecl.getMethodNumId(method);
1018 uniqueMethodIds.add(methodId);
1019 // Check if this is "void"
1020 String retType = intDecl.getMethodType(method);
1021 if (retType.equals("void"))
1022 println(helperMethod + "() {");
1024 println(helperMethod + "() throws IOException {");
1025 // Now, write the helper body of skeleton!
1026 writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
1033 * HELPER: writeJavaWaitRequestInvokeMethod() writes the main loop of the skeleton class
1035 private void writeJavaWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist) {
1037 // Use this set to handle two same methodIds
1038 Set<String> uniqueMethodIds = new HashSet<String>();
1039 println("private void ___waitRequestInvokeMethod() throws IOException {");
1040 // Write variables here if we have callbacks or enums or structs
1041 println("while (true) {");
1042 println("rmiObj.getMethodBytes();");
1043 println("int _objectId = rmiObj.getObjectId();");
1044 println("int methodId = rmiObj.getMethodId();");
1045 // TODO: code the permission check here!
1046 println("switch (methodId) {");
1047 // Print methods and method Ids
1048 for (String method : methods) {
1049 String methodId = intDecl.getMethodId(method);
1050 int methodNumId = intDecl.getMethodNumId(method);
1051 print("case " + methodNumId + ": ___");
1052 String helperMethod = methodId;
1053 if (uniqueMethodIds.contains(methodId))
1054 helperMethod = helperMethod + methodNumId;
1056 uniqueMethodIds.add(methodId);
1057 println(helperMethod + "(); break;");
1059 String method = "___initCallBack()";
1060 // Print case -9999 (callback handler) if callback exists
1061 if (callbackExist) {
1062 int methodId = intDecl.getHelperMethodNumId(method);
1063 println("case " + methodId + ": ___regCB(); break;");
1065 println("default: ");
1066 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
1074 * generateJavaSkeletonClass() generate skeletons based on the methods list in Java
1076 public void generateJavaSkeletonClass() throws IOException {
1078 // Create a new directory
1079 String path = createDirectories(dir, subdir);
1080 for (String intface : mapIntfacePTH.keySet()) {
1081 // Open a new file to write into
1082 String newSkelClass = intface + "_Skeleton";
1083 FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
1084 pw = new PrintWriter(new BufferedWriter(fw));
1085 // Pass in set of methods and get import classes
1086 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1087 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1088 List<String> methods = intDecl.getMethods();
1089 Set<String> importClasses = getImportClasses(methods, intDecl);
1090 List<String> stdImportClasses = getStandardJavaImportClasses();
1091 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
1092 printImportStatements(allImportClasses);
1093 // Find out if there are callback objects
1094 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1095 boolean callbackExist = !callbackClasses.isEmpty();
1096 // Write class header
1098 println("public class " + newSkelClass + " implements " + intface + " {\n");
1100 writePropertiesJavaSkeleton(intface, callbackExist);
1101 // Write constructor
1102 writeConstructorJavaSkeleton(newSkelClass, intface);
1104 writeMethodJavaSkeleton(methods, intDecl, callbackClasses, false);
1105 // Write method helper
1106 writeMethodHelperJavaSkeleton(methods, intDecl, callbackClasses);
1107 // Write waitRequestInvokeMethod() - main loop
1108 writeJavaWaitRequestInvokeMethod(methods, intDecl, callbackExist);
1111 System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".java...");
1117 * HELPER: writePropertiesJavaCallbackSkeleton() writes the properties of the callback skeleton class
1119 private void writePropertiesJavaCallbackSkeleton(String intface, boolean callbackExist) {
1121 println("private " + intface + " mainObj;");
1122 // For callback skeletons, this is its own object Id
1123 println("private static int objectId = 0;");
1125 if (callbackExist) {
1126 println("private static int objIdCnt = 0;");
1127 println("private IoTRMICall rmiCall;");
1134 * HELPER: writeConstructorJavaCallbackSkeleton() writes the constructor of the skeleton class
1136 private void writeConstructorJavaCallbackSkeleton(String newSkelClass, String intface) {
1138 println("public " + newSkelClass + "(" + intface + " _mainObj, int _objectId) throws Exception {");
1139 println("mainObj = _mainObj;");
1140 println("objectId = _objectId;");
1146 * HELPER: writeMethodHelperJavaCallbackSkeleton() writes the method helper of the callback skeleton class
1148 private void writeMethodHelperJavaCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1150 // Use this set to handle two same methodIds
1151 Set<String> uniqueMethodIds = new HashSet<String>();
1152 for (String method : methods) {
1154 List<String> methParams = intDecl.getMethodParams(method);
1155 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1156 String methodId = intDecl.getMethodId(method);
1157 print("public void ___");
1158 String helperMethod = methodId;
1159 if (uniqueMethodIds.contains(methodId))
1160 helperMethod = helperMethod + intDecl.getMethodNumId(method);
1162 uniqueMethodIds.add(methodId);
1163 // Check if this is "void"
1164 String retType = intDecl.getMethodType(method);
1165 if (retType.equals("void"))
1166 println(helperMethod + "(IoTRMIObject rmiObj) {");
1168 println(helperMethod + "(IoTRMIObject rmiObj) throws IOException {");
1169 // Now, write the helper body of skeleton!
1170 writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
1177 * HELPER: writeJavaCallbackWaitRequestInvokeMethod() writes the main loop of the skeleton class
1179 private void writeJavaCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist) {
1181 // Use this set to handle two same methodIds
1182 Set<String> uniqueMethodIds = new HashSet<String>();
1183 println("public void invokeMethod(IoTRMIObject rmiObj) throws IOException {");
1184 // Write variables here if we have callbacks or enums or structs
1185 println("int methodId = rmiObj.getMethodId();");
1186 // TODO: code the permission check here!
1187 println("switch (methodId) {");
1188 // Print methods and method Ids
1189 for (String method : methods) {
1190 String methodId = intDecl.getMethodId(method);
1191 int methodNumId = intDecl.getMethodNumId(method);
1192 print("case " + methodNumId + ": ___");
1193 String helperMethod = methodId;
1194 if (uniqueMethodIds.contains(methodId))
1195 helperMethod = helperMethod + methodNumId;
1197 uniqueMethodIds.add(methodId);
1198 println(helperMethod + "(rmiObj); break;");
1200 String method = "___initCallBack()";
1201 // Print case -9999 (callback handler) if callback exists
1202 if (callbackExist) {
1203 int methodId = intDecl.getHelperMethodNumId(method);
1204 println("case " + methodId + ": ___regCB(rmiObj); break;");
1206 println("default: ");
1207 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
1214 * generateJavaCallbackSkeletonClass() generate callback skeletons based on the methods list in Java
1216 public void generateJavaCallbackSkeletonClass() throws IOException {
1218 // Create a new directory
1219 String path = createDirectories(dir, subdir);
1220 for (String intface : mapIntfacePTH.keySet()) {
1221 // Open a new file to write into
1222 String newSkelClass = intface + "_CallbackSkeleton";
1223 FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
1224 pw = new PrintWriter(new BufferedWriter(fw));
1225 // Pass in set of methods and get import classes
1226 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1227 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1228 List<String> methods = intDecl.getMethods();
1229 Set<String> importClasses = getImportClasses(methods, intDecl);
1230 List<String> stdImportClasses = getStandardJavaImportClasses();
1231 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
1232 printImportStatements(allImportClasses);
1233 // Find out if there are callback objects
1234 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1235 boolean callbackExist = !callbackClasses.isEmpty();
1236 // Write class header
1238 println("public class " + newSkelClass + " implements " + intface + " {\n");
1240 writePropertiesJavaCallbackSkeleton(intface, callbackExist);
1241 // Write constructor
1242 writeConstructorJavaCallbackSkeleton(newSkelClass, intface);
1244 writeMethodJavaSkeleton(methods, intDecl, callbackClasses, true);
1245 // Write method helper
1246 writeMethodHelperJavaCallbackSkeleton(methods, intDecl, callbackClasses);
1247 // Write waitRequestInvokeMethod() - main loop
1248 writeJavaCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist);
1251 System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".java...");
1257 * HELPER: writeMethodCplusLocalInterface() writes the method of the interface
1259 private void writeMethodCplusLocalInterface(Collection<String> methods, InterfaceDecl intDecl) {
1261 for (String method : methods) {
1263 List<String> methParams = intDecl.getMethodParams(method);
1264 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1265 print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
1266 intDecl.getMethodId(method) + "(");
1267 for (int i = 0; i < methParams.size(); i++) {
1268 // Check for params with driver class types and exchange it
1269 // with its remote interface
1270 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
1271 paramType = checkAndGetCplusType(paramType);
1272 // Check for arrays - translate into vector in C++
1273 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
1274 print(paramComplete);
1275 // Check if this is the last element (don't print a comma)
1276 if (i != methParams.size() - 1) {
1286 * HELPER: writeMethodCplusInterface() writes the method of the interface
1288 private void writeMethodCplusInterface(Collection<String> methods, InterfaceDecl intDecl) {
1290 for (String method : methods) {
1292 List<String> methParams = intDecl.getMethodParams(method);
1293 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1294 print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
1295 intDecl.getMethodId(method) + "(");
1296 for (int i = 0; i < methParams.size(); i++) {
1297 // Check for params with driver class types and exchange it
1298 // with its remote interface
1299 String paramType = methPrmTypes.get(i);
1300 paramType = checkAndGetCplusType(paramType);
1301 // Check for arrays - translate into vector in C++
1302 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
1303 print(paramComplete);
1304 // Check if this is the last element (don't print a comma)
1305 if (i != methParams.size() - 1) {
1315 * HELPER: writeEnumCplus() writes the enumeration declaration
1317 private void writeEnumCplus(EnumDecl enumDecl) {
1319 Set<String> enumTypes = enumDecl.getEnumDeclarations();
1320 // Iterate over enum declarations
1321 for (String enType : enumTypes) {
1323 println("enum " + enType + " {");
1324 List<String> enumMembers = enumDecl.getMembers(enType);
1325 for (int i = 0; i < enumMembers.size(); i++) {
1327 String member = enumMembers.get(i);
1329 // Check if this is the last element (don't print a comma)
1330 if (i != enumMembers.size() - 1)
1341 * HELPER: writeStructCplus() writes the struct declaration
1343 private void writeStructCplus(StructDecl structDecl) {
1345 List<String> structTypes = structDecl.getStructTypes();
1346 // Iterate over enum declarations
1347 for (String stType : structTypes) {
1349 println("struct " + stType + " {");
1350 List<String> structMemberTypes = structDecl.getMemberTypes(stType);
1351 List<String> structMembers = structDecl.getMembers(stType);
1352 for (int i = 0; i < structMembers.size(); i++) {
1354 String memberType = structMemberTypes.get(i);
1355 String member = structMembers.get(i);
1356 String structTypeC = checkAndGetCplusType(memberType);
1357 String structComplete = checkAndGetCplusArray(structTypeC, member);
1358 println(structComplete + ";");
1366 * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking.
1368 * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
1369 * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
1370 * The local interface has to be the input parameter for the stub and the stub
1371 * interface has to be the input parameter for the local class.
1373 public void generateCplusLocalInterfaces() throws IOException {
1375 // Create a new directory
1376 createDirectory(dir);
1377 for (String intface : mapIntfacePTH.keySet()) {
1378 // Open a new file to write into
1379 FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
1380 pw = new PrintWriter(new BufferedWriter(fw));
1381 // Write file headers
1382 println("#ifndef _" + intface.toUpperCase() + "_HPP__");
1383 println("#define _" + intface.toUpperCase() + "_HPP__");
1384 println("#include <iostream>");
1385 // Pass in set of methods and get include classes
1386 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1387 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1388 List<String> methods = intDecl.getMethods();
1389 Set<String> includeClasses = getIncludeClasses(methods, intDecl, true);
1390 printIncludeStatements(includeClasses); println("");
1391 println("using namespace std;\n");
1392 // Write enum if any...
1393 EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface);
1394 writeEnumCplus(enumDecl);
1395 // Write struct if any...
1396 StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
1397 writeStructCplus(structDecl);
1398 println("class " + intface); println("{");
1401 writeMethodCplusLocalInterface(methods, intDecl);
1405 System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
1411 * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
1413 * For C++ we use virtual classe as interface
1415 public void generateCPlusInterfaces() throws IOException {
1417 // Create a new directory
1418 String path = createDirectories(dir, subdir);
1419 for (String intface : mapIntfacePTH.keySet()) {
1421 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1422 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1424 // Open a new file to write into
1425 String newIntface = intMeth.getKey();
1426 FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp");
1427 pw = new PrintWriter(new BufferedWriter(fw));
1428 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1429 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1430 // Write file headers
1431 println("#ifndef _" + newIntface.toUpperCase() + "_HPP__");
1432 println("#define _" + newIntface.toUpperCase() + "_HPP__");
1433 println("#include <iostream>");
1434 // Pass in set of methods and get import classes
1435 Set<String> includeClasses = getIncludeClasses(intMeth.getValue(), intDecl, false);
1436 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
1437 List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
1438 printIncludeStatements(allIncludeClasses); println("");
1439 println("using namespace std;\n");
1440 println("class " + newIntface);
1444 writeMethodCplusInterface(intMeth.getValue(), intDecl);
1448 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
1455 * HELPER: writeMethodCplusStub() writes the method of the stub
1457 private void writeMethodCplusStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1459 for (String method : methods) {
1461 List<String> methParams = intDecl.getMethodParams(method);
1462 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1463 print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
1464 intDecl.getMethodId(method) + "(");
1465 boolean isCallbackMethod = false;
1466 String callbackType = null;
1467 for (int i = 0; i < methParams.size(); i++) {
1469 String paramType = methPrmTypes.get(i);
1470 // Check if this has callback object
1471 if (callbackClasses.contains(paramType)) {
1472 isCallbackMethod = true;
1473 callbackType = paramType;
1474 // Even if there're 2 callback arguments, we expect them to be of the same interface
1476 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
1477 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
1478 print(methParamComplete);
1479 // Check if this is the last element (don't print a comma)
1480 if (i != methParams.size() - 1) {
1485 if (isCallbackMethod)
1486 writeCallbackMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method, callbackType);
1488 writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method);
1490 // Write the init callback helper method
1491 if (isCallbackMethod) {
1492 writeInitCallbackCplusStub(callbackType, intDecl);
1493 writeInitCallbackSendInfoCplusStub(intDecl);
1500 * HELPER: writeCallbackMethodBodyCplusStub() writes the callback method of the stub class
1502 private void writeCallbackMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
1503 List<String> methPrmTypes, String method, String callbackType) {
1505 // Check if this is single object, array, or list of objects
1506 boolean isArrayOrList = false;
1507 String callbackParam = null;
1508 for (int i = 0; i < methParams.size(); i++) {
1510 String paramType = methPrmTypes.get(i);
1511 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1512 String param = methParams.get(i);
1513 if (isArrayOrList(paramType, param)) { // Generate loop
1514 println("for (" + paramType + "* cb : " + getSimpleIdentifier(param) + ") {");
1515 println(callbackType + "_CallbackSkeleton* skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);");
1516 isArrayOrList = true;
1517 callbackParam = getSimpleIdentifier(param);
1519 println(callbackType + "_CallbackSkeleton* skel = new " + callbackType + "_CallbackSkeleton(" +
1520 getSimpleIdentifier(param) + ", objIdCnt++);");
1521 println("vecCallbackObj.push_back(skel);");
1522 if (isArrayOrList(paramType, param))
1526 println("int numParam = " + methParams.size() + ";");
1527 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
1528 String retType = intDecl.getMethodType(method);
1529 String retTypeC = checkAndGetCplusType(retType);
1530 println("string retType = \"" + checkAndGetCplusArrayType(retTypeC) + "\";");
1531 // Generate array of parameter types
1532 print("string paramCls[] = { ");
1533 for (int i = 0; i < methParams.size(); i++) {
1534 String paramType = methPrmTypes.get(i);
1535 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1537 } else { // Generate normal classes if it's not a callback object
1538 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
1539 String prmType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
1540 print("\"" + prmType + "\"");
1542 if (i != methParams.size() - 1) // Check if this is the last element
1546 print("int ___paramCB = ");
1548 println(callbackParam + ".size();");
1551 // Generate array of parameter objects
1552 print("void* paramObj[] = { ");
1553 for (int i = 0; i < methParams.size(); i++) {
1554 String paramType = methPrmTypes.get(i);
1555 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1556 print("&___paramCB");
1558 print(getSimpleIdentifier(methParams.get(i)));
1559 if (i != methParams.size() - 1)
1563 // Check if this is "void"
1564 if (retType.equals("void")) {
1565 println("void* retObj = NULL;");
1566 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1567 } else { // We do have a return value
1568 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
1569 println(checkAndGetCplusType(retType) + " retVal;");
1571 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
1572 println("void* retObj = &retVal;");
1573 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1574 println("return retVal;");
1580 * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class
1582 private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
1583 List<String> methPrmTypes, String method) {
1585 println("int numParam = " + methParams.size() + ";");
1586 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
1587 String retType = intDecl.getMethodType(method);
1588 String retTypeC = checkAndGetCplusType(retType);
1589 println("string retType = \"" + checkAndGetCplusArrayType(retTypeC) + "\";");
1590 // Generate array of parameter types
1591 print("string paramCls[] = { ");
1592 for (int i = 0; i < methParams.size(); i++) {
1593 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
1594 String paramType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
1595 print("\"" + paramType + "\"");
1596 // Check if this is the last element (don't print a comma)
1597 if (i != methParams.size() - 1) {
1602 // Generate array of parameter objects
1603 print("void* paramObj[] = { ");
1604 for (int i = 0; i < methParams.size(); i++) {
1605 print("&" + getSimpleIdentifier(methParams.get(i)));
1606 // Check if this is the last element (don't print a comma)
1607 if (i != methParams.size() - 1) {
1612 // Check if this is "void"
1613 if (retType.equals("void")) {
1614 println("void* retObj = NULL;");
1615 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1616 } else { // We do have a return value
1617 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
1618 println(checkAndGetCplusType(retType) + " retVal;");
1620 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
1621 println("void* retObj = &retVal;");
1622 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1623 println("return retVal;");
1629 * HELPER: writePropertiesCplusStub() writes the properties of the stub class
1631 private void writePropertiesCplusStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
1633 println("IoTRMICall *rmiCall;");
1634 //println("IoTRMIObject\t\t\t*rmiObj;");
1635 println("string address;");
1636 println("vector<int> ports;\n");
1637 // Get the object Id
1638 Integer objId = mapIntfaceObjId.get(intface);
1639 println("const static int objectId = " + objId + ";");
1640 mapNewIntfaceObjId.put(newIntface, objId);
1641 mapIntfaceObjId.put(intface, objId++);
1642 if (callbackExist) {
1643 // We assume that each class only has one callback interface for now
1644 Iterator it = callbackClasses.iterator();
1645 String callbackType = (String) it.next();
1646 println("// Callback properties");
1647 println("IoTRMIObject *rmiObj;");
1648 println("vector<" + callbackType + "*> vecCallbackObj;");
1649 println("static int objIdCnt;");
1656 * HELPER: writeConstructorCplusStub() writes the constructor of the stub class
1658 private void writeConstructorCplusStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1660 println(newStubClass +
1661 "(int _port, const char* _address, int _rev, bool* _bResult, vector<int> _ports) {");
1662 println("address = _address;");
1663 println("ports = _ports;");
1664 println("rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);");
1665 if (callbackExist) {
1666 println("objIdCnt = 0;");
1667 Iterator it = callbackClasses.iterator();
1668 String callbackType = (String) it.next();
1669 println("thread th1 (&" + newStubClass + "::___initCallBack, this);");
1670 println("th1.detach();");
1671 println("___regCB();");
1678 * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
1680 private void writeDeconstructorCplusStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1682 println("~" + newStubClass + "() {");
1683 println("if (rmiCall != NULL) {");
1684 println("delete rmiCall;");
1685 println("rmiCall = NULL;");
1687 if (callbackExist) {
1688 // We assume that each class only has one callback interface for now
1689 println("if (rmiObj != NULL) {");
1690 println("delete rmiObj;");
1691 println("rmiObj = NULL;");
1693 Iterator it = callbackClasses.iterator();
1694 String callbackType = (String) it.next();
1695 println("for(" + callbackType + "* cb : vecCallbackObj) {");
1696 println("delete cb;");
1697 println("cb = NULL;");
1706 * HELPER: writeInitCallbackCplusStub() writes the constructor of the stub class
1708 private void writeInitCallbackCplusStub(String intface, InterfaceDecl intDecl) {
1710 println("void ___initCallBack() {");
1711 println("bool bResult = false;");
1712 println("rmiObj = new IoTRMIObject(ports[0], &bResult);");
1713 println("while (true) {");
1714 println("char* method = rmiObj->getMethodBytes();");
1715 println("int methodId = IoTRMIObject::getMethodId(method);");
1716 println("int objId = IoTRMIObject::getObjectId(method);");
1717 println("if (objId < vecCallbackObj.size()) { // Check if still within range");
1718 println(intface + "_CallbackSkeleton* skel = dynamic_cast<" + intface +
1719 "_CallbackSkeleton*> (vecCallbackObj.at(objId));");
1720 println("skel->invokeMethod(rmiObj);");
1721 println("} else {");
1722 println("cerr << \"Illegal object Id: \" << to_string(objId);");
1723 // TODO: perhaps need to change this into "throw" to make it cleaner (allow stack unfolding)
1724 println("exit(-1);");
1732 * HELPER: writeInitCallbackSendInfoCplusStub() writes the constructor of the stub class
1734 private void writeInitCallbackSendInfoCplusStub(InterfaceDecl intDecl) {
1736 // Generate info sending part
1737 println("void ___regCB() {");
1738 println("int numParam = 3;");
1739 String method = "___initCallBack()";
1740 println("int methodId = " + intDecl.getHelperMethodNumId(method) + ";");
1741 println("string retType = \"void\";");
1742 println("string paramCls[] = { \"int\", \"string\", \"int\" };");
1743 println("int rev = 0;");
1744 println("void* paramObj[] = { &ports[0], &address, &rev };");
1745 println("void* retObj = NULL;");
1746 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1752 * generateCPlusStubClasses() generate stubs based on the methods list in C++
1754 public void generateCPlusStubClasses() throws IOException {
1756 // Create a new directory
1757 String path = createDirectories(dir, subdir);
1758 for (String intface : mapIntfacePTH.keySet()) {
1760 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1761 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1762 // Open a new file to write into
1763 String newIntface = intMeth.getKey();
1764 String newStubClass = newIntface + "_Stub";
1765 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
1766 pw = new PrintWriter(new BufferedWriter(fw));
1767 // Write file headers
1768 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
1769 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
1770 println("#include <iostream>");
1771 // Find out if there are callback objects
1772 Set<String> methods = intMeth.getValue();
1773 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1774 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1775 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1776 boolean callbackExist = !callbackClasses.isEmpty();
1777 if (callbackExist) // Need thread library if this has callback
1778 println("#include <thread>");
1779 println("#include \"" + newIntface + ".hpp\""); println("");
1780 println("using namespace std;"); println("");
1781 println("class " + newStubClass + " : public " + newIntface); println("{");
1782 println("private:\n");
1783 writePropertiesCplusStub(intface, newIntface, callbackExist, callbackClasses);
1784 println("public:\n");
1785 // Add default constructor and destructor
1786 println(newStubClass + "() { }"); println("");
1787 writeConstructorCplusStub(newStubClass, callbackExist, callbackClasses);
1788 writeDeconstructorCplusStub(newStubClass, callbackExist, callbackClasses);
1790 writeMethodCplusStub(methods, intDecl, callbackClasses);
1791 print("}"); println(";");
1794 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".hpp...");
1801 * HELPER: writePropertiesCplusCallbackStub() writes the properties of the stub class
1803 private void writePropertiesCplusCallbackStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
1805 println("IoTRMICall *rmiCall;");
1806 // Get the object Id
1807 println("static int objectId;");
1808 if (callbackExist) {
1809 // We assume that each class only has one callback interface for now
1810 Iterator it = callbackClasses.iterator();
1811 String callbackType = (String) it.next();
1812 println("// Callback properties");
1813 println("IoTRMIObject *rmiObj;");
1814 println("vector<" + callbackType + "*> vecCallbackObj;");
1815 println("static int objIdCnt;");
1816 // TODO: Need to initialize address and ports if we want to have callback-in-callback
1817 println("string address;");
1818 println("vector<int> ports;\n");
1825 * HELPER: writeConstructorCplusCallbackStub() writes the constructor of the stub class
1827 private void writeConstructorCplusCallbackStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1829 println(newStubClass + "(IoTRMICall* _rmiCall, int _objectId) {");
1830 println("objectId = _objectId;");
1831 println("rmiCall = _rmiCall;");
1832 if (callbackExist) {
1833 Iterator it = callbackClasses.iterator();
1834 String callbackType = (String) it.next();
1835 println("thread th1 (&" + newStubClass + "::___initCallBack, this);");
1836 println("th1.detach();");
1837 println("___regCB();");
1844 * generateCPlusCallbackStubClasses() generate callback stubs based on the methods list in C++
1846 public void generateCPlusCallbackStubClasses() throws IOException {
1848 // Create a new directory
1849 String path = createDirectories(dir, subdir);
1850 for (String intface : mapIntfacePTH.keySet()) {
1852 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1853 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1854 // Open a new file to write into
1855 String newIntface = intMeth.getKey();
1856 String newStubClass = newIntface + "_CallbackStub";
1857 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
1858 pw = new PrintWriter(new BufferedWriter(fw));
1859 // Find out if there are callback objects
1860 Set<String> methods = intMeth.getValue();
1861 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1862 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1863 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1864 boolean callbackExist = !callbackClasses.isEmpty();
1865 // Write file headers
1866 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
1867 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
1868 println("#include <iostream>");
1870 println("#include <thread>");
1871 println("#include \"" + newIntface + ".hpp\""); println("");
1872 println("using namespace std;"); println("");
1873 println("class " + newStubClass + " : public " + newIntface); println("{");
1874 println("private:\n");
1875 writePropertiesCplusCallbackStub(intface, newIntface, callbackExist, callbackClasses);
1876 println("public:\n");
1877 // Add default constructor and destructor
1878 println(newStubClass + "() { }"); println("");
1879 writeConstructorCplusCallbackStub(newStubClass, callbackExist, callbackClasses);
1880 writeDeconstructorCplusStub(newStubClass, callbackExist, callbackClasses);
1882 writeMethodCplusStub(methods, intDecl, callbackClasses);
1883 print("}"); println(";");
1886 System.out.println("IoTCompiler: Generated callback stub class " + newIntface + ".hpp...");
1893 * HELPER: writePropertiesCplusSkeleton() writes the properties of the skeleton class
1895 private void writePropertiesCplusSkeleton(String intface, boolean callbackExist, Set<String> callbackClasses) {
1897 println(intface + " *mainObj;");
1898 //println("private int ports;");
1900 if (callbackExist) {
1901 Iterator it = callbackClasses.iterator();
1902 String callbackType = (String) it.next();
1903 String exchangeType = checkAndGetParamClass(callbackType);
1904 println("// Callback properties");
1905 println("static int objIdCnt;");
1906 println("vector<" + exchangeType + "*> vecCallbackObj;");
1907 println("IoTRMICall *rmiCall;");
1909 println("IoTRMIObject *rmiObj;\n");
1910 // Keep track of object Ids of all stubs registered to this interface
1911 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1912 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1913 String newIntface = intMeth.getKey();
1914 int newObjectId = mapNewIntfaceObjId.get(newIntface);
1915 // println("const static int object" + newObjectId + "Id = " +
1916 // newObjectId + ";\t//" + newIntface);
1923 * HELPER: writeConstructorCplusSkeleton() writes the constructor of the skeleton class
1925 private void writeConstructorCplusSkeleton(String newSkelClass, String intface, boolean callbackExist) {
1927 println(newSkelClass + "(" + intface + " *_mainObj, int _port) {");
1928 println("bool _bResult = false;");
1929 println("mainObj = _mainObj;");
1930 println("rmiObj = new IoTRMIObject(_port, &_bResult);");
1932 if (callbackExist) {
1933 println("objIdCnt = 0;");
1935 //println("set0Allowed = Arrays.asList(object0Permission);");
1936 println("___waitRequestInvokeMethod();");
1942 * HELPER: writeDeconstructorCplusSkeleton() writes the deconstructor of the skeleton class
1944 private void writeDeconstructorCplusSkeleton(String newSkelClass, boolean callbackExist, Set<String> callbackClasses) {
1946 println("~" + newSkelClass + "() {");
1947 println("if (rmiObj != NULL) {");
1948 println("delete rmiObj;");
1949 println("rmiObj = NULL;");
1951 if (callbackExist) {
1952 // We assume that each class only has one callback interface for now
1953 println("if (rmiCall != NULL) {");
1954 println("delete rmiCall;");
1955 println("rmiCall = NULL;");
1957 Iterator it = callbackClasses.iterator();
1958 String callbackType = (String) it.next();
1959 String exchangeType = checkAndGetParamClass(callbackType);
1960 println("for(" + exchangeType + "* cb : vecCallbackObj) {");
1961 println("delete cb;");
1962 println("cb = NULL;");
1971 * HELPER: writeStdMethodBodyCplusSkeleton() writes the standard method body in the skeleton class
1973 private void writeStdMethodBodyCplusSkeleton(List<String> methParams, String methodId, String methodType) {
1975 if (methodType.equals("void"))
1976 print("mainObj->" + methodId + "(");
1978 print("return mainObj->" + methodId + "(");
1979 for (int i = 0; i < methParams.size(); i++) {
1981 print(getSimpleIdentifier(methParams.get(i)));
1982 // Check if this is the last element (don't print a comma)
1983 if (i != methParams.size() - 1) {
1992 * HELPER: writeInitCallbackCplusSkeleton() writes the init callback method for skeleton class
1994 private void writeInitCallbackCplusSkeleton(boolean callbackSkeleton) {
1996 // This is a callback skeleton generation
1997 if (callbackSkeleton)
1998 println("void ___regCB(IoTRMIObject* rmiObj) {");
2000 println("void ___regCB() {");
2001 println("int numParam = 3;");
2002 println("int param1 = 0;");
2003 println("string param2 = \"\";");
2004 println("int param3 = 0;");
2005 println("void* paramObj[] = { ¶m1, ¶m2, ¶m3 };");
2006 println("bool bResult = false;");
2007 println("rmiCall = new IoTRMICall(param1, param2.c_str(), param3, &bResult);");
2013 * HELPER: writeMethodCplusSkeleton() writes the method of the skeleton class
2015 private void writeMethodCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl,
2016 Set<String> callbackClasses, boolean callbackSkeleton) {
2018 for (String method : methods) {
2020 List<String> methParams = intDecl.getMethodParams(method);
2021 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2022 String methodId = intDecl.getMethodId(method);
2023 String methodType = checkAndGetCplusType(intDecl.getMethodType(method));
2024 print(methodType + " " + methodId + "(");
2025 boolean isCallbackMethod = false;
2026 String callbackType = null;
2027 for (int i = 0; i < methParams.size(); i++) {
2029 String origParamType = methPrmTypes.get(i);
2030 if (callbackClasses.contains(origParamType)) { // Check if this has callback object
2031 isCallbackMethod = true;
2032 callbackType = origParamType;
2034 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
2035 String methPrmType = checkAndGetCplusType(paramType);
2036 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
2037 print(methParamComplete);
2038 // Check if this is the last element (don't print a comma)
2039 if (i != methParams.size() - 1) {
2044 // Now, write the body of skeleton!
2045 writeStdMethodBodyCplusSkeleton(methParams, methodId, intDecl.getMethodType(method));
2047 if (isCallbackMethod)
2048 writeInitCallbackCplusSkeleton(callbackSkeleton);
2054 * HELPER: writeCallbackCplusNumStubs() writes the numStubs variable
2056 private void writeCallbackCplusNumStubs(List<String> methParams, List<String> methPrmTypes, String callbackType) {
2058 for (int i = 0; i < methParams.size(); i++) {
2059 String paramType = methPrmTypes.get(i);
2060 String param = methParams.get(i);
2061 //if (callbackType.equals(paramType)) {
2062 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
2063 String exchParamType = checkAndGetParamClass(paramType);
2064 // Print array if this is array or list if this is a list of callback objects
2065 println("int numStubs" + i + " = 0;");
2072 * HELPER: writeCallbackCplusStubGeneration() writes the callback stub generation part
2074 private void writeCallbackCplusStubGeneration(List<String> methParams, List<String> methPrmTypes, String callbackType) {
2076 // Iterate over callback objects
2077 for (int i = 0; i < methParams.size(); i++) {
2078 String paramType = methPrmTypes.get(i);
2079 String param = methParams.get(i);
2080 // Generate a loop if needed
2081 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
2082 String exchParamType = checkAndGetParamClass(paramType);
2083 if (isArrayOrList(paramType, param)) {
2084 println("vector<" + exchParamType + "> stub;");
2085 println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
2086 println(exchParamType + "* cb" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
2087 println("stub" + i + ".push_back(cb);");
2088 println("vecCallbackObj.push_back(cb);");
2089 println("objIdCnt++;");
2092 println(exchParamType + "* stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
2093 println("vecCallbackObj.push_back(stub" + i + ");");
2094 println("objIdCnt++;");
2102 * HELPER: writeStdMethodHelperBodyCplusSkeleton() writes the standard method body helper in the skeleton class
2104 private void writeStdMethodHelperBodyCplusSkeleton(InterfaceDecl intDecl, List<String> methParams,
2105 List<String> methPrmTypes, String method, String methodId, Set<String> callbackClasses) {
2107 // Generate array of parameter types
2108 boolean isCallbackMethod = false;
2109 String callbackType = null;
2110 print("string paramCls[] = { ");
2111 for (int i = 0; i < methParams.size(); i++) {
2112 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2113 if (callbackClasses.contains(paramType)) {
2114 isCallbackMethod = true;
2115 callbackType = paramType;
2117 } else { // Generate normal classes if it's not a callback object
2118 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
2119 String prmType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
2120 print("\"" + prmType + "\"");
2122 if (i != methParams.size() - 1) {
2127 println("int numParam = " + methParams.size() + ";");
2128 if (isCallbackMethod)
2129 writeCallbackCplusNumStubs(methParams, methPrmTypes, callbackType);
2130 // Generate parameters
2131 for (int i = 0; i < methParams.size(); i++) {
2132 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2133 if (!callbackClasses.contains(paramType)) {
2134 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
2135 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
2136 println(methParamComplete + ";");
2139 // Generate array of parameter objects
2140 print("void* paramObj[] = { ");
2141 for (int i = 0; i < methParams.size(); i++) {
2142 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2143 if (callbackClasses.contains(paramType))
2144 print("&numStubs" + i);
2146 print("&" + getSimpleIdentifier(methParams.get(i)));
2147 if (i != methParams.size() - 1) {
2152 println("rmiObj->getMethodParams(paramCls, numParam, paramObj);");
2153 if (isCallbackMethod)
2154 writeCallbackCplusStubGeneration(methParams, methPrmTypes, callbackType);
2155 String retType = intDecl.getMethodType(method);
2156 // Check if this is "void"
2157 if (retType.equals("void")) {
2158 print(methodId + "(");
2159 for (int i = 0; i < methParams.size(); i++) {
2160 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2161 if (callbackClasses.contains(paramType))
2164 print(getSimpleIdentifier(methParams.get(i)));
2165 if (i != methParams.size() - 1) {
2170 } else { // We do have a return value
2171 print(checkAndGetCplusType(retType) + " retVal = " + methodId + "(");
2172 for (int i = 0; i < methParams.size(); i++) {
2173 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2174 if (callbackClasses.contains(paramType))
2177 print(getSimpleIdentifier(methParams.get(i)));
2178 if (i != methParams.size() - 1) {
2183 println("void* retObj = &retVal;");
2184 String retTypeC = checkAndGetCplusType(retType);
2185 println("rmiObj->sendReturnObj(retObj, \"" + checkAndGetCplusArrayType(retTypeC) + "\");");
2191 * HELPER: writeMethodHelperCplusSkeleton() writes the method helper of the skeleton class
2193 private void writeMethodHelperCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
2195 // Use this set to handle two same methodIds
2196 Set<String> uniqueMethodIds = new HashSet<String>();
2197 for (String method : methods) {
2199 List<String> methParams = intDecl.getMethodParams(method);
2200 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2201 String methodId = intDecl.getMethodId(method);
2203 String helperMethod = methodId;
2204 if (uniqueMethodIds.contains(methodId))
2205 helperMethod = helperMethod + intDecl.getMethodNumId(method);
2207 uniqueMethodIds.add(methodId);
2208 // Check if this is "void"
2209 String retType = intDecl.getMethodType(method);
2210 println(helperMethod + "() {");
2211 // Now, write the helper body of skeleton!
2212 writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses);
2219 * HELPER: writeCplusWaitRequestInvokeMethod() writes the main loop of the skeleton class
2221 private void writeCplusWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist) {
2223 // Use this set to handle two same methodIds
2224 Set<String> uniqueMethodIds = new HashSet<String>();
2225 println("void ___waitRequestInvokeMethod() {");
2226 // Write variables here if we have callbacks or enums or structs
2227 println("while (true) {");
2228 println("rmiObj->getMethodBytes();");
2229 println("int _objectId = rmiObj->getObjectId();");
2230 println("int methodId = rmiObj->getMethodId();");
2231 // TODO: code the permission check here!
2232 println("switch (methodId) {");
2233 // Print methods and method Ids
2234 for (String method : methods) {
2235 String methodId = intDecl.getMethodId(method);
2236 int methodNumId = intDecl.getMethodNumId(method);
2237 print("case " + methodNumId + ": ___");
2238 String helperMethod = methodId;
2239 if (uniqueMethodIds.contains(methodId))
2240 helperMethod = helperMethod + methodNumId;
2242 uniqueMethodIds.add(methodId);
2243 println(helperMethod + "(); break;");
2245 String method = "___initCallBack()";
2246 // Print case -9999 (callback handler) if callback exists
2247 if (callbackExist) {
2248 int methodId = intDecl.getHelperMethodNumId(method);
2249 println("case " + methodId + ": ___regCB(); break;");
2251 println("default: ");
2252 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
2253 println("throw exception();");
2261 * generateCplusSkeletonClass() generate skeletons based on the methods list in C++
2263 public void generateCplusSkeletonClass() throws IOException {
2265 // Create a new directory
2266 String path = createDirectories(dir, subdir);
2267 for (String intface : mapIntfacePTH.keySet()) {
2268 // Open a new file to write into
2269 String newSkelClass = intface + "_Skeleton";
2270 FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp");
2271 pw = new PrintWriter(new BufferedWriter(fw));
2272 // Write file headers
2273 println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
2274 println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
2275 println("#include <iostream>");
2276 println("#include \"" + intface + ".hpp\"\n");
2277 // Pass in set of methods and get import classes
2278 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2279 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2280 List<String> methods = intDecl.getMethods();
2281 Set<String> includeClasses = getIncludeClasses(methods, intDecl, true);
2282 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
2283 List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
2284 printIncludeStatements(allIncludeClasses); println("");
2285 println("using namespace std;\n");
2286 // Find out if there are callback objects
2287 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
2288 boolean callbackExist = !callbackClasses.isEmpty();
2289 // Write class header
2290 println("class " + newSkelClass + " : public " + intface); println("{");
2291 println("private:\n");
2293 writePropertiesCplusSkeleton(intface, callbackExist, callbackClasses);
2294 println("public:\n");
2295 // Write constructor
2296 writeConstructorCplusSkeleton(newSkelClass, intface, callbackExist);
2297 // Write deconstructor
2298 writeDeconstructorCplusSkeleton(newSkelClass, callbackExist, callbackClasses);
2300 writeMethodCplusSkeleton(methods, intDecl, callbackClasses, false);
2301 // Write method helper
2302 writeMethodHelperCplusSkeleton(methods, intDecl, callbackClasses);
2303 // Write waitRequestInvokeMethod() - main loop
2304 writeCplusWaitRequestInvokeMethod(methods, intDecl, callbackExist);
2308 System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".hpp...");
2314 * HELPER: writePropertiesCplusCallbackSkeleton() writes the properties of the callback skeleton class
2316 private void writePropertiesCplusCallbackSkeleton(String intface, boolean callbackExist, Set<String> callbackClasses) {
2318 println(intface + " *mainObj;");
2319 // Keep track of object Ids of all stubs registered to this interface
2320 println("static int objectId;");
2322 if (callbackExist) {
2323 Iterator it = callbackClasses.iterator();
2324 String callbackType = (String) it.next();
2325 String exchangeType = checkAndGetParamClass(callbackType);
2326 println("// Callback properties");
2327 println("IoTRMICall* rmiCall;");
2328 println("vector<" + exchangeType + "*> vecCallbackObj;");
2329 println("static int objIdCnt;");
2336 * HELPER: writeConstructorCplusCallbackSkeleton() writes the constructor of the skeleton class
2338 private void writeConstructorCplusCallbackSkeleton(String newSkelClass, String intface, boolean callbackExist) {
2340 println(newSkelClass + "(" + intface + " *_mainObj, int _objectId) {");
2341 println("mainObj = _mainObj;");
2342 println("objectId = _objectId;");
2344 if (callbackExist) {
2345 println("objIdCnt = 0;");
2352 * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
2354 private void writeDeconstructorCplusCallbackSkeleton(String newStubClass, boolean callbackExist,
2355 Set<String> callbackClasses) {
2357 println("~" + newStubClass + "() {");
2358 if (callbackExist) {
2359 // We assume that each class only has one callback interface for now
2360 println("if (rmiCall != NULL) {");
2361 println("delete rmiCall;");
2362 println("rmiCall = NULL;");
2364 Iterator it = callbackClasses.iterator();
2365 String callbackType = (String) it.next();
2366 String exchangeType = checkAndGetParamClass(callbackType);
2367 println("for(" + exchangeType + "* cb : vecCallbackObj) {");
2368 println("delete cb;");
2369 println("cb = NULL;");
2378 * HELPER: writeMethodHelperCplusCallbackSkeleton() writes the method helper of the callback skeleton class
2380 private void writeMethodHelperCplusCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl,
2381 Set<String> callbackClasses) {
2383 // Use this set to handle two same methodIds
2384 Set<String> uniqueMethodIds = new HashSet<String>();
2385 for (String method : methods) {
2387 List<String> methParams = intDecl.getMethodParams(method);
2388 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2389 String methodId = intDecl.getMethodId(method);
2391 String helperMethod = methodId;
2392 if (uniqueMethodIds.contains(methodId))
2393 helperMethod = helperMethod + intDecl.getMethodNumId(method);
2395 uniqueMethodIds.add(methodId);
2396 // Check if this is "void"
2397 String retType = intDecl.getMethodType(method);
2398 println(helperMethod + "(IoTRMIObject* rmiObj) {");
2399 // Now, write the helper body of skeleton!
2400 writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses);
2407 * HELPER: writeCplusCallbackWaitRequestInvokeMethod() writes the main loop of the skeleton class
2409 private void writeCplusCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl,
2410 boolean callbackExist) {
2412 // Use this set to handle two same methodIds
2413 Set<String> uniqueMethodIds = new HashSet<String>();
2414 println("void invokeMethod(IoTRMIObject* rmiObj) {");
2415 // Write variables here if we have callbacks or enums or structs
2416 println("int methodId = rmiObj->getMethodId();");
2417 // TODO: code the permission check here!
2418 println("switch (methodId) {");
2419 // Print methods and method Ids
2420 for (String method : methods) {
2421 String methodId = intDecl.getMethodId(method);
2422 int methodNumId = intDecl.getMethodNumId(method);
2423 print("case " + methodNumId + ": ___");
2424 String helperMethod = methodId;
2425 if (uniqueMethodIds.contains(methodId))
2426 helperMethod = helperMethod + methodNumId;
2428 uniqueMethodIds.add(methodId);
2429 println(helperMethod + "(rmiObj); break;");
2431 String method = "___initCallBack()";
2432 // Print case -9999 (callback handler) if callback exists
2433 if (callbackExist) {
2434 int methodId = intDecl.getHelperMethodNumId(method);
2435 println("case " + methodId + ": ___regCB(rmiObj); break;");
2437 println("default: ");
2438 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
2439 println("throw exception();");
2447 * generateCplusCallbackSkeletonClass() generate callback skeletons based on the methods list in C++
2449 public void generateCplusCallbackSkeletonClass() throws IOException {
2451 // Create a new directory
2452 String path = createDirectories(dir, subdir);
2453 for (String intface : mapIntfacePTH.keySet()) {
2454 // Open a new file to write into
2455 String newSkelClass = intface + "_CallbackSkeleton";
2456 FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp");
2457 pw = new PrintWriter(new BufferedWriter(fw));
2458 // Write file headers
2459 println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
2460 println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
2461 println("#include <iostream>");
2462 println("#include \"" + intface + ".hpp\"\n");
2463 // Pass in set of methods and get import classes
2464 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2465 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2466 List<String> methods = intDecl.getMethods();
2467 Set<String> includeClasses = getIncludeClasses(methods, intDecl, true);
2468 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
2469 List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
2470 printIncludeStatements(allIncludeClasses); println("");
2471 // Find out if there are callback objects
2472 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
2473 boolean callbackExist = !callbackClasses.isEmpty();
2474 println("using namespace std;\n");
2475 // Write class header
2476 println("class " + newSkelClass + " : public " + intface); println("{");
2477 println("private:\n");
2479 writePropertiesCplusCallbackSkeleton(intface, callbackExist, callbackClasses);
2480 println("public:\n");
2481 // Write constructor
2482 writeConstructorCplusCallbackSkeleton(newSkelClass, intface, callbackExist);
2483 // Write deconstructor
2484 writeDeconstructorCplusCallbackSkeleton(newSkelClass, callbackExist, callbackClasses);
2486 writeMethodCplusSkeleton(methods, intDecl, callbackClasses, true);
2487 // Write method helper
2488 writeMethodHelperCplusCallbackSkeleton(methods, intDecl, callbackClasses);
2489 // Write waitRequestInvokeMethod() - main loop
2490 writeCplusCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist);
2494 System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".hpp...");
2500 * generateInitializer() generate initializer based on type
2502 public String generateCplusInitializer(String type) {
2504 // Generate dummy returns for now
2505 if (type.equals("short")||
2506 type.equals("int") ||
2507 type.equals("long") ||
2508 type.equals("float")||
2509 type.equals("double")) {
2512 } else if ( type.equals("String") ||
2513 type.equals("string")) {
2516 } else if ( type.equals("char") ||
2517 type.equals("byte")) {
2520 } else if ( type.equals("boolean")) {
2530 * generateReturnStmt() generate return statement based on methType
2532 public String generateReturnStmt(String methType) {
2534 // Generate dummy returns for now
2535 if (methType.equals("short")||
2536 methType.equals("int") ||
2537 methType.equals("long") ||
2538 methType.equals("float")||
2539 methType.equals("double")) {
2542 } else if ( methType.equals("String")) {
2545 } else if ( methType.equals("char") ||
2546 methType.equals("byte")) {
2549 } else if ( methType.equals("boolean")) {
2559 * setDirectory() sets a new directory for stub files
2561 public void setDirectory(String _subdir) {
2568 * printUsage() prints the usage of this compiler
2570 public static void printUsage() {
2572 System.out.println();
2573 System.out.println("Sentinel interface and stub compiler version 1.0");
2574 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
2575 System.out.println("All rights reserved.");
2576 System.out.println("Usage:");
2577 System.out.println("\tjava IoTCompiler -help / --help / -h\n");
2578 System.out.println("\t\tDisplay this help texts\n\n");
2579 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>]");
2580 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>] [options]\n");
2581 System.out.println("\t\tTake one or more pairs of main-req policy files, and generate Java and/or C++ files\n");
2582 System.out.println("Options:");
2583 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
2584 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
2585 System.out.println();
2590 * parseFile() prepares Lexer and Parser objects, then parses the file
2592 public static ParseNode parseFile(String file) {
2594 ParseNode pn = null;
2596 ComplexSymbolFactory csf = new ComplexSymbolFactory();
2597 ScannerBuffer lexer =
2598 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf));
2599 Parser parse = new Parser(lexer,csf);
2600 pn = (ParseNode) parse.parse().value;
2601 } catch (Exception e) {
2602 e.printStackTrace();
2603 throw new Error("IoTCompiler: ERROR parsing policy file or wrong command line option: " + file);
2614 boolean newline=true;
2617 private void print(String str) {
2620 if (str.equals("}"))
2622 for(int i=0; i<tab; i++)
2632 * This function converts Java to C++ type for compilation
2634 private String convertType(String jType) {
2636 return mapPrimitives.get(jType);
2640 private void println(String str) {
2643 if (str.contains("}") && !str.contains("{"))
2645 for(int i=0; i<tab; i++)
2654 private void updatetabbing(String str) {
2656 tablevel+=count(str,'{')-count(str,'}');
2660 private int count(String str, char key) {
2661 char[] array = str.toCharArray();
2663 for(int i=0; i<array.length; i++) {
2664 if (array[i] == key)
2671 private void createDirectory(String dirName) {
2673 File file = new File(dirName);
2674 if (!file.exists()) {
2676 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
2678 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
2681 System.out.println("IoTCompiler: Directory " + dirName + " exists...");
2686 // Create a directory and possibly a sub directory
2687 private String createDirectories(String dir, String subdir) {
2690 createDirectory(path);
2691 if (subdir != null) {
2692 path = path + "/" + subdir;
2693 createDirectory(path);
2699 // Inserting array members into a Map object
2700 // that maps arrKey to arrVal objects
2701 private void arraysToMap(Map map, Object[] arrKey, Object[] arrVal) {
2703 for(int i = 0; i < arrKey.length; i++) {
2705 map.put(arrKey[i], arrVal[i]);
2710 // Return parameter category, i.e. PRIMITIVES, NONPRIMITIVES, or USERDEFINED
2711 private ParamCategory getParamCategory(String paramType) {
2713 if (mapPrimitives.containsKey(paramType)) {
2714 return ParamCategory.PRIMITIVES;
2715 // We can either use mapNonPrimitivesJava or mapNonPrimitivesCplus here
2716 } else if (mapNonPrimitivesJava.containsKey(getSimpleType(paramType))) {
2717 return ParamCategory.NONPRIMITIVES;
2719 return ParamCategory.USERDEFINED;
2723 // Return full class name for non-primitives to generate Java import statements
2724 // e.g. java.util.Set for Set, java.util.Map for Map
2725 private String getNonPrimitiveJavaClass(String paramNonPrimitives) {
2727 return mapNonPrimitivesJava.get(paramNonPrimitives);
2731 // Return full class name for non-primitives to generate Cplus include statements
2732 // e.g. #include <set> for Set, #include <map> for Map
2733 private String getNonPrimitiveCplusClass(String paramNonPrimitives) {
2735 return mapNonPrimitivesCplus.get(paramNonPrimitives);
2739 // Get simple types, e.g. HashSet for HashSet<...>
2740 // Basically strip off the "<...>"
2741 private String getSimpleType(String paramType) {
2743 // Check if this is generics
2744 if(paramType.contains("<")) {
2745 String[] type = paramType.split("<");
2752 // Generate a set of standard classes for import statements
2753 private List<String> getStandardJavaImportClasses() {
2755 List<String> importClasses = new ArrayList<String>();
2756 // Add the standard list first
2757 importClasses.add("java.io.IOException");
2758 importClasses.add("java.util.List");
2759 importClasses.add("java.util.ArrayList");
2760 importClasses.add("iotrmi.Java.IoTRMICall");
2761 importClasses.add("iotrmi.Java.IoTRMIObject");
2763 return importClasses;
2767 // Generate a set of standard classes for import statements
2768 private List<String> getStandardCplusIncludeClasses() {
2770 List<String> importClasses = new ArrayList<String>();
2771 // Add the standard list first
2772 importClasses.add("<vector>");
2773 importClasses.add("\"IoTRMICall.hpp\"");
2774 importClasses.add("\"IoTRMIObject.hpp\"");
2776 return importClasses;
2780 // Generate a set of standard classes for import statements
2781 private List<String> getAllLibClasses(Collection<String> stdLibClasses, Collection<String> libClasses) {
2783 List<String> allLibClasses = new ArrayList<String>(stdLibClasses);
2784 // Iterate over the list of import classes
2785 for (String str : libClasses) {
2786 if (!allLibClasses.contains(str)) {
2787 allLibClasses.add(str);
2791 return allLibClasses;
2796 // Generate a set of classes for import statements
2797 private Set<String> getImportClasses(Collection<String> methods, InterfaceDecl intDecl) {
2799 Set<String> importClasses = new HashSet<String>();
2800 for (String method : methods) {
2801 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2802 for (String paramType : methPrmTypes) {
2804 String simpleType = getSimpleType(paramType);
2805 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
2806 importClasses.add(getNonPrimitiveJavaClass(simpleType));
2810 return importClasses;
2814 // Generate a set of classes for include statements
2815 private Set<String> getIncludeClasses(Collection<String> methods, InterfaceDecl intDecl, boolean needExchange) {
2817 Set<String> includeClasses = new HashSet<String>();
2818 for (String method : methods) {
2820 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2821 List<String> methParams = intDecl.getMethodParams(method);
2822 for (int i = 0; i < methPrmTypes.size(); i++) {
2824 String simpleType = getSimpleType(methPrmTypes.get(i));
2825 String param = methParams.get(i);
2826 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
2827 includeClasses.add("<" + getNonPrimitiveCplusClass(simpleType) + ">");
2828 } else if (getParamCategory(simpleType) == ParamCategory.USERDEFINED) {
2829 // For original interface, we need it exchanged... not for stub interfaces
2831 includeClasses.add("\"" + exchangeParamType(simpleType) + ".hpp\"");
2832 includeClasses.add("\"" + exchangeParamType(simpleType) + "_CallbackStub.hpp\"");
2834 includeClasses.add("\"" + simpleType + ".hpp\"");
2835 includeClasses.add("\"" + simpleType + "_CallbackSkeleton.hpp\"");
2837 } else if (param.contains("[]")) {
2838 // Check if this is array for C++; translate into vector
2839 includeClasses.add("<vector>");
2843 return includeClasses;
2847 // Generate a set of callback classes
2848 private Set<String> getCallbackClasses(Collection<String> methods, InterfaceDecl intDecl) {
2850 Set<String> callbackClasses = new HashSet<String>();
2851 for (String method : methods) {
2853 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2854 List<String> methParams = intDecl.getMethodParams(method);
2855 for (int i = 0; i < methPrmTypes.size(); i++) {
2857 String type = methPrmTypes.get(i);
2858 if (getParamCategory(type) == ParamCategory.USERDEFINED) {
2859 callbackClasses.add(type);
2860 } else if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) {
2861 // Can be a List<...> of callback objects ...
2862 String genericType = getTypeOfGeneric(type)[0];
2863 if (getParamCategory(type) == ParamCategory.USERDEFINED) {
2864 callbackClasses.add(type);
2869 return callbackClasses;
2873 private void printImportStatements(Collection<String> importClasses) {
2875 for(String cls : importClasses) {
2876 println("import " + cls + ";");
2881 private void printIncludeStatements(Collection<String> includeClasses) {
2883 for(String cls : includeClasses) {
2884 println("#include " + cls);
2889 // Get the C++ version of a non-primitive type
2890 // e.g. set for Set and map for Map
2891 // Input nonPrimitiveType has to be generics in format
2892 private String[] getTypeOfGeneric(String nonPrimitiveType) {
2894 // Handle <, >, and , for 2-type generic/template
2895 String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(",");
2900 // This helper function strips off array declaration, e.g. D[] becomes D
2901 private String getSimpleIdentifier(String ident) {
2903 // Handle [ for array declaration
2904 String substr = ident;
2905 if (ident.contains("[]")) {
2906 substr = ident.split("\\[\\]")[0];
2912 private String checkAndGetCplusType(String paramType) {
2914 if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
2915 return convertType(paramType);
2916 } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) {
2918 // Check for generic/template format
2919 if (paramType.contains("<") && paramType.contains(">")) {
2921 String genericClass = getSimpleType(paramType);
2922 String[] genericType = getTypeOfGeneric(paramType);
2923 String cplusTemplate = null;
2924 if (genericType.length == 1) // Generic/template with one type
2925 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
2926 "<" + convertType(genericType[0]) + ">";
2927 else // Generic/template with two types
2928 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
2929 "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">";
2930 return cplusTemplate;
2932 return getNonPrimitiveCplusClass(paramType);
2933 } else if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
2934 return paramType + "*";
2936 // Just return it as is if it's not non-primitives
2938 //return checkAndGetParamClass(paramType, true);
2942 // Detect array declaration, e.g. int A[],
2943 // then generate "int A[]" in C++ as "vector<int> A"
2944 private String checkAndGetCplusArray(String paramType, String param) {
2946 String paramComplete = null;
2947 // Check for array declaration
2948 if (param.contains("[]")) {
2949 paramComplete = "vector<" + paramType + "> " + param.replace("[]","");
2951 // Just return it as is if it's not an array
2952 paramComplete = paramType + " " + param;
2954 return paramComplete;
2958 // Detect array declaration, e.g. int A[],
2959 // then generate "int A[]" in C++ as "vector<int> A"
2960 // This method just returns the type
2961 private String checkAndGetCplusArrayType(String paramType) {
2963 String paramTypeRet = null;
2964 // Check for array declaration
2965 if (paramType.contains("[]")) {
2966 String type = paramType.split("\\[\\]")[0];
2967 paramTypeRet = checkAndGetCplusType(type) + "[]";
2968 } else if (paramType.contains("vector")) {
2969 // Just return it as is if it's not an array
2970 String type = paramType.split("<")[1].split(">")[0];
2971 paramTypeRet = checkAndGetCplusType(type) + "[]";
2973 paramTypeRet = paramType;
2975 return paramTypeRet;
2979 // Detect array declaration, e.g. int A[],
2980 // then generate "int A[]" in C++ as "vector<int> A"
2981 // This method just returns the type
2982 private String checkAndGetCplusArrayType(String paramType, String param) {
2984 String paramTypeRet = null;
2985 // Check for array declaration
2986 if (param.contains("[]")) {
2987 paramTypeRet = checkAndGetCplusType(paramType) + "[]";
2988 } else if (paramType.contains("vector")) {
2989 // Just return it as is if it's not an array
2990 String type = paramType.split("<")[1].split(">")[0];
2991 paramTypeRet = checkAndGetCplusType(type) + "[]";
2993 paramTypeRet = paramType;
2995 return paramTypeRet;
2999 // Detect array declaration, e.g. int A[],
3000 // then generate type "int[]"
3001 private String checkAndGetArray(String paramType, String param) {
3003 String paramTypeRet = null;
3004 // Check for array declaration
3005 if (param.contains("[]")) {
3006 paramTypeRet = paramType + "[]";
3008 // Just return it as is if it's not an array
3009 paramTypeRet = paramType;
3011 return paramTypeRet;
3015 // Is array or list?
3016 private boolean isArrayOrList(String paramType, String param) {
3018 // Check for array declaration
3019 if (isArray(paramType, param))
3021 else if (isList(paramType, param))
3028 // Is array or list?
3029 private boolean isArray(String paramType, String param) {
3031 // Check for array declaration
3032 if (param.contains("[]"))
3039 // Is array or list?
3040 private boolean isList(String paramType, String param) {
3042 // Check for array declaration
3043 if (paramType.contains("List"))
3050 // Get the right type for a callback object
3051 private String checkAndGetParamClass(String paramType) {
3053 // Check if this is generics
3054 if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
3055 return exchangeParamType(paramType);
3061 // Returns the other interface for type-checking purposes for USERDEFINED
3062 // classes based on the information provided in multiple policy files
3063 // e.g. return CameraWithXXX instead of Camera
3064 private String exchangeParamType(String intface) {
3066 // Param type that's passed is the interface name we need to look for
3067 // in the map of interfaces, based on available policy files.
3068 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
3069 if (decHandler != null) {
3070 // We've found the required interface policy files
3071 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(intface);
3072 Set<String> setExchInt = reqDecl.getInterfaces();
3073 if (setExchInt.size() == 1) {
3074 Iterator iter = setExchInt.iterator();
3075 return (String) iter.next();
3077 throw new Error("IoTCompiler: Ambiguous stub interfaces: " + setExchInt.toString() +
3078 ". Only one new interface can be declared if the object " + intface +
3079 " needs to be passed in as an input parameter!");
3082 // NULL value - this means policy files missing
3083 throw new Error("IoTCompiler: Parameter type lookup failed for " + intface +
3084 "... Please provide the necessary policy files for user-defined types." +
3085 " If this is an array please type the brackets after the variable name," +
3086 " e.g. \"String str[]\", not \"String[] str\"." +
3087 " If this is a Collections (Java) / STL (C++) type, this compiler only" +
3088 " supports List/ArrayList (Java) or list (C++).");
3093 public static void main(String[] args) throws Exception {
3095 // If there is no argument or just "--help" or "-h", then invoke printUsage()
3096 if ((args[0].equals("-help") ||
3097 args[0].equals("--help")||
3098 args[0].equals("-h")) ||
3099 (args.length == 0)) {
3101 IoTCompiler.printUsage();
3103 } else if (args.length > 1) {
3105 IoTCompiler comp = new IoTCompiler();
3108 // Parse main policy file
3109 ParseNode pnPol = IoTCompiler.parseFile(args[i]);
3110 // Parse "requires" policy file
3111 ParseNode pnReq = IoTCompiler.parseFile(args[i+1]);
3112 // Get interface name
3113 String intface = ParseTreeHandler.getOrigIntface(pnPol);
3114 comp.setDataStructures(intface, pnPol, pnReq);
3115 comp.getMethodsForIntface(intface);
3117 // 1) Check if this is the last option before "-java" or "-cplus"
3118 // 2) Check if this is really the last option (no "-java" or "-cplus")
3119 } while(!args[i].equals("-java") &&
3120 !args[i].equals("-cplus") &&
3123 // Generate everything if we don't see "-java" or "-cplus"
3124 if (i == args.length) {
3125 comp.generateJavaLocalInterfaces();
3126 comp.generateJavaInterfaces();
3127 comp.generateJavaStubClasses();
3128 comp.generateJavaCallbackStubClasses();
3129 comp.generateJavaSkeletonClass();
3130 comp.generateJavaCallbackSkeletonClass();
3131 comp.generateCplusLocalInterfaces();
3132 comp.generateCPlusInterfaces();
3133 comp.generateCPlusStubClasses();
3134 comp.generateCPlusCallbackStubClasses();
3135 comp.generateCplusSkeletonClass();
3136 comp.generateCplusCallbackSkeletonClass();
3138 // Check other options
3139 while(i < args.length) {
3141 if (!args[i].equals("-java") &&
3142 !args[i].equals("-cplus")) {
3143 throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
3145 if (i + 1 < args.length) {
3146 comp.setDirectory(args[i+1]);
3148 throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
3150 if (args[i].equals("-java")) {
3151 comp.generateJavaLocalInterfaces();
3152 comp.generateJavaInterfaces();
3153 comp.generateJavaStubClasses();
3154 comp.generateJavaCallbackStubClasses();
3155 comp.generateJavaSkeletonClass();
3156 comp.generateJavaCallbackSkeletonClass();
3158 comp.generateCplusLocalInterfaces();
3159 comp.generateCPlusInterfaces();
3160 comp.generateCPlusStubClasses();
3161 comp.generateCPlusCallbackStubClasses();
3162 comp.generateCplusSkeletonClass();
3163 comp.generateCplusCallbackSkeletonClass();
3170 // Need to at least have exactly 2 parameters, i.e. main policy file and requires file
3171 IoTCompiler.printUsage();
3172 throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");