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: writePropertiesJavaPermission() writes the permission in properties
361 private void writePropertiesJavaPermission(String intface, InterfaceDecl intDecl) {
363 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
364 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
365 String newIntface = intMeth.getKey();
366 int newObjectId = mapNewIntfaceObjId.get(newIntface);
367 println("private final static int object" + newObjectId + "Id = " +
368 newObjectId + ";\t//" + newIntface);
369 Set<String> methodIds = intMeth.getValue();
370 print("private static Integer[] object" + newObjectId + "Permission = { ");
372 for (String methodId : methodIds) {
373 int methodNumId = intDecl.getMethodNumId(methodId);
374 print(Integer.toString(methodNumId));
375 // Check if this is the last element (don't print a comma)
376 if (i != methodIds.size() - 1) {
382 println("private List<Integer> set" + newObjectId + "Allowed;");
388 * HELPER: writePropertiesJavaStub() writes the properties of the stub class
390 private void writePropertiesJavaStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
392 println("private IoTRMICall rmiCall;");
393 println("private String address;");
394 println("private int[] ports;\n");
396 Integer objId = mapIntfaceObjId.get(intface);
397 println("private final static int objectId = " + objId + ";");
398 mapNewIntfaceObjId.put(newIntface, objId);
399 mapIntfaceObjId.put(intface, objId++);
401 // We assume that each class only has one callback interface for now
402 Iterator it = callbackClasses.iterator();
403 String callbackType = (String) it.next();
404 println("// Callback properties");
405 println("private IoTRMIObject rmiObj;");
406 println("List<" + callbackType + "> listCallbackObj;");
407 println("private static int objIdCnt = 0;");
408 // Generate permission stuff for callback stubs
409 DeclarationHandler decHandler = mapIntDeclHand.get(callbackType);
410 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(callbackType);
411 writePropertiesJavaPermission(callbackType, intDecl);
418 * HELPER: writeConstructorJavaPermission() writes the permission in constructor
420 private void writeConstructorJavaPermission(String intface) {
422 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
423 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
424 String newIntface = intMeth.getKey();
425 int newObjectId = mapNewIntfaceObjId.get(newIntface);
426 println("set" + newObjectId + "Allowed = Arrays.asList(object" + newObjectId +"Permission);");
432 * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
434 private void writeConstructorJavaStub(String intface, String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
436 println("public " + newStubClass + "(int _port, String _address, int _rev, int[] _ports) throws Exception {");
437 println("address = _address;");
438 println("ports = _ports;");
439 println("rmiCall = new IoTRMICall(_port, _address, _rev);");
441 Iterator it = callbackClasses.iterator();
442 String callbackType = (String) it.next();
443 writeConstructorJavaPermission(intface);
444 println("listCallbackObj = new ArrayList<" + callbackType + ">();");
445 println("___initCallBack();");
452 * HELPER: writeJavaMethodCallbackPermission() writes permission checks in stub for callbacks
454 private void writeJavaMethodCallbackPermission(String intface) {
456 println("int methodId = IoTRMIObject.getMethodId(method);");
457 // Get all the different stubs
458 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
459 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
460 String newIntface = intMeth.getKey();
461 int newObjectId = mapNewIntfaceObjId.get(newIntface);
462 println("if (!set" + newObjectId + "Allowed.contains(methodId)) {");
463 println("throw new Error(\"Callback object for " + intface + " is not allowed to access method: \" + methodId);");
470 * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
472 private void writeInitCallbackJavaStub(String intface, InterfaceDecl intDecl) {
474 println("public void ___initCallBack() {");
475 // Generate main thread for callbacks
476 println("Thread thread = new Thread() {");
477 println("public void run() {");
479 println("rmiObj = new IoTRMIObject(ports[0]);");
480 println("while (true) {");
481 println("byte[] method = rmiObj.getMethodBytes();");
482 writeJavaMethodCallbackPermission(intface);
483 println("int objId = IoTRMIObject.getObjectId(method);");
484 println(intface + "_CallbackSkeleton skel = (" + intface + "_CallbackSkeleton) listCallbackObj.get(objId);");
485 println("if (skel != null) {");
486 println("skel.invokeMethod(rmiObj);");
488 println("throw new Error(\"" + intface + ": Object with Id \" + objId + \" not found!\");");
491 println("} catch (Exception ex) {");
492 println("ex.printStackTrace();");
493 println("throw new Error(\"Error instantiating class " + intface + "_CallbackSkeleton!\");");
497 println("thread.start();\n");
498 // Generate info sending part
499 String method = "___initCallBack()";
500 println("int methodId = " + intDecl.getHelperMethodNumId(method) + ";");
501 println("Class<?> retType = void.class;");
502 println("Class<?>[] paramCls = new Class<?>[] { int.class, String.class, int.class };");
503 println("Object[] paramObj = new Object[] { ports[0], address, 0 };");
504 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
510 * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class
512 private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
513 List<String> methPrmTypes, String method) {
515 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
516 String retType = intDecl.getMethodType(method);
517 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
518 // Generate array of parameter types
519 print("Class<?>[] paramCls = new Class<?>[] { ");
520 for (int i = 0; i < methParams.size(); i++) {
521 String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
522 print(getSimpleType(paramType) + ".class");
523 // Check if this is the last element (don't print a comma)
524 if (i != methParams.size() - 1) {
529 // Generate array of parameter objects
530 print("Object[] paramObj = new Object[] { ");
531 for (int i = 0; i < methParams.size(); i++) {
532 print(getSimpleIdentifier(methParams.get(i)));
533 // Check if this is the last element (don't print a comma)
534 if (i != methParams.size() - 1) {
539 // Check if this is "void"
540 if (retType.equals("void")) {
541 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
542 } else { // We do have a return value
543 // Check if the return value NONPRIMITIVES
544 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
545 String[] retGenValType = getTypeOfGeneric(retType);
546 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
547 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
548 println("return (" + retType + ")retObj;");
550 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
551 println("return (" + retType + ")retObj;");
558 * HELPER: returnGenericCallbackType() returns the callback type
560 private String returnGenericCallbackType(String paramType) {
562 if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES)
563 return getTypeOfGeneric(paramType)[0];
570 * HELPER: checkCallbackType() checks the callback type
572 private boolean checkCallbackType(String paramType, String callbackType) {
574 String prmType = returnGenericCallbackType(paramType);
575 return callbackType.equals(prmType);
580 * HELPER: writeCallbackMethodBodyJavaStub() writes the callback method of the stub class
582 private void writeCallbackMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
583 List<String> methPrmTypes, String method, String callbackType) {
586 // Check if this is single object, array, or list of objects
587 for (int i = 0; i < methParams.size(); i++) {
589 String paramType = methPrmTypes.get(i);
590 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
591 String param = methParams.get(i);
592 if (isArrayOrList(paramType, param)) { // Generate loop
593 println("for (" + paramType + " cb : " + getSimpleIdentifier(param) + ") {");
594 println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);");
596 println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(" +
597 getSimpleIdentifier(param) + ", objIdCnt++);");
598 println("listCallbackObj.add(skel);");
599 if (isArrayOrList(paramType, param))
603 println("} catch (Exception ex) {");
604 println("ex.printStackTrace();");
605 println("throw new Error(\"Exception when generating skeleton objects!\");");
607 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
608 String retType = intDecl.getMethodType(method);
609 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
610 // Generate array of parameter types
611 print("Class<?>[] paramCls = new Class<?>[] { ");
612 for (int i = 0; i < methParams.size(); i++) {
613 String paramType = methPrmTypes.get(i);
614 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
616 } else { // Generate normal classes if it's not a callback object
617 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
618 print(getSimpleType(prmType) + ".class");
620 if (i != methParams.size() - 1) // Check if this is the last element
624 // Generate array of parameter objects
625 print("Object[] paramObj = new Object[] { ");
626 for (int i = 0; i < methParams.size(); i++) {
627 String paramType = methPrmTypes.get(i);
628 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
629 if (isArray(methPrmTypes.get(i), methParams.get(i)))
630 print(getSimpleIdentifier(methParams.get(i)) + ".length");
631 else if (isList(methPrmTypes.get(i), methParams.get(i)))
632 print(getSimpleIdentifier(methParams.get(i)) + ".size()");
634 print("new Integer(1)");
636 print(getSimpleIdentifier(methParams.get(i)));
637 if (i != methParams.size() - 1)
641 // Check if this is "void"
642 if (retType.equals("void")) {
643 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
644 } else { // We do have a return value
645 // Check if the return value NONPRIMITIVES
646 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
647 String[] retGenValType = getTypeOfGeneric(retType);
648 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
649 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
650 println("return (" + retType + ")retObj;");
652 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
653 println("return (" + retType + ")retObj;");
660 * HELPER: writeMethodJavaStub() writes the method of the stub class
662 private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
664 for (String method : methods) {
666 List<String> methParams = intDecl.getMethodParams(method);
667 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
668 print("public " + intDecl.getMethodType(method) + " " +
669 intDecl.getMethodId(method) + "(");
670 boolean isCallbackMethod = false;
671 String callbackType = null;
672 for (int i = 0; i < methParams.size(); i++) {
674 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
675 // Check if this has callback object
676 if (callbackClasses.contains(paramType)) {
677 isCallbackMethod = true;
678 callbackType = paramType;
679 // Even if there're 2 callback arguments, we expect them to be of the same interface
681 print(methPrmTypes.get(i) + " " + methParams.get(i));
682 // Check if this is the last element (don't print a comma)
683 if (i != methParams.size() - 1) {
688 // Now, write the body of stub!
689 if (isCallbackMethod)
690 writeCallbackMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method, callbackType);
692 writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
694 // Write the init callback helper method
695 if (isCallbackMethod)
696 writeInitCallbackJavaStub(callbackType, intDecl);
702 * generateJavaStubClasses() generate stubs based on the methods list in Java
704 public void generateJavaStubClasses() throws IOException {
706 // Create a new directory
707 String path = createDirectories(dir, subdir);
708 for (String intface : mapIntfacePTH.keySet()) {
710 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
711 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
713 // Open a new file to write into
714 String newIntface = intMeth.getKey();
715 String newStubClass = newIntface + "_Stub";
716 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
717 pw = new PrintWriter(new BufferedWriter(fw));
718 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
719 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
720 // Pass in set of methods and get import classes
721 Set<String> methods = intMeth.getValue();
722 Set<String> importClasses = getImportClasses(methods, intDecl);
723 List<String> stdImportClasses = getStandardJavaImportClasses();
724 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
725 printImportStatements(allImportClasses); println("");
726 // Find out if there are callback objects
727 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
728 boolean callbackExist = !callbackClasses.isEmpty();
729 // Write class header
730 println("public class " + newStubClass + " implements " + newIntface + " {\n");
732 writePropertiesJavaStub(intface, newIntface, callbackExist, callbackClasses);
734 writeConstructorJavaStub(intface, newStubClass, callbackExist, callbackClasses);
736 writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses);
739 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
746 * HELPER: writePropertiesJavaCallbackStub() writes the properties of the callback stub class
748 private void writePropertiesJavaCallbackStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
750 println("private IoTRMICall rmiCall;");
751 println("private String address;");
752 println("private int[] ports;\n");
754 println("private static int objectId = 0;");
756 // We assume that each class only has one callback interface for now
757 Iterator it = callbackClasses.iterator();
758 String callbackType = (String) it.next();
759 println("// Callback properties");
760 println("private IoTRMIObject rmiObj;");
761 println("List<" + callbackType + "> listCallbackObj;");
762 println("private static int objIdCnt = 0;");
763 // Generate permission stuff for callback stubs
764 DeclarationHandler decHandler = mapIntDeclHand.get(callbackType);
765 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(callbackType);
766 writePropertiesJavaPermission(callbackType, intDecl);
773 * HELPER: writeConstructorJavaCallbackStub() writes the constructor of the callback stub class
775 private void writeConstructorJavaCallbackStub(String intface, String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
777 // TODO: If we want callback in callback, then we need to add address and port initializations
778 println("public " + newStubClass + "(IoTRMICall _rmiCall, int _objectId) throws Exception {");
779 println("objectId = _objectId;");
780 println("rmiCall = _rmiCall;");
782 Iterator it = callbackClasses.iterator();
783 String callbackType = (String) it.next();
784 writeConstructorJavaPermission(intface);
785 println("listCallbackObj = new ArrayList<" + callbackType + ">();");
786 println("___initCallBack();");
787 println("// TODO: Add address and port initialization here if we want callback in callback!");
794 * generateJavaCallbackStubClasses() generate callback stubs based on the methods list in Java
796 * Callback stubs gets the IoTRMICall objects from outside of the class as contructor input
797 * because all these stubs are populated by the class that takes in this object as a callback
798 * object. In such a class, we only use one socket, hence one IoTRMICall, for all callback objects.
800 public void generateJavaCallbackStubClasses() throws IOException {
802 // Create a new directory
803 String path = createDirectories(dir, subdir);
804 for (String intface : mapIntfacePTH.keySet()) {
806 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
807 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
809 // Open a new file to write into
810 String newIntface = intMeth.getKey();
811 String newStubClass = newIntface + "_CallbackStub";
812 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
813 pw = new PrintWriter(new BufferedWriter(fw));
814 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
815 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
816 // Pass in set of methods and get import classes
817 Set<String> methods = intMeth.getValue();
818 Set<String> importClasses = getImportClasses(methods, intDecl);
819 List<String> stdImportClasses = getStandardJavaImportClasses();
820 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
821 printImportStatements(allImportClasses); println("");
822 // Find out if there are callback objects
823 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
824 boolean callbackExist = !callbackClasses.isEmpty();
825 // Write class header
826 println("public class " + newStubClass + " implements " + newIntface + " {\n");
828 writePropertiesJavaCallbackStub(intface, newIntface, callbackExist, callbackClasses);
830 writeConstructorJavaCallbackStub(intface, newStubClass, callbackExist, callbackClasses);
832 // TODO: perhaps need to generate callback for callback
833 writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses);
836 System.out.println("IoTCompiler: Generated callback stub class " + newStubClass + ".java...");
843 * HELPER: writePropertiesJavaSkeleton() writes the properties of the skeleton class
845 private void writePropertiesJavaSkeleton(String intface, boolean callbackExist, InterfaceDecl intDecl) {
847 println("private " + intface + " mainObj;");
848 //println("private int ports;");
849 println("private IoTRMIObject rmiObj;\n");
852 println("private static int objIdCnt = 0;");
853 println("private IoTRMICall rmiCall;");
855 writePropertiesJavaPermission(intface, intDecl);
861 * HELPER: writeConstructorJavaSkeleton() writes the constructor of the skeleton class
863 private void writeConstructorJavaSkeleton(String newSkelClass, String intface) {
865 println("public " + newSkelClass + "(" + intface + " _mainObj, int _port) throws Exception {");
866 println("mainObj = _mainObj;");
867 println("rmiObj = new IoTRMIObject(_port);");
868 // Generate permission control initialization
869 writeConstructorJavaPermission(intface);
870 println("___waitRequestInvokeMethod();");
876 * HELPER: writeStdMethodBodyJavaSkeleton() writes the standard method body in the skeleton class
878 private void writeStdMethodBodyJavaSkeleton(List<String> methParams, String methodId, String methodType) {
880 if (methodType.equals("void"))
881 print("mainObj." + methodId + "(");
883 print("return mainObj." + methodId + "(");
884 for (int i = 0; i < methParams.size(); i++) {
886 print(getSimpleIdentifier(methParams.get(i)));
887 // Check if this is the last element (don't print a comma)
888 if (i != methParams.size() - 1) {
897 * HELPER: writeInitCallbackJavaSkeleton() writes the init callback method for skeleton class
899 private void writeInitCallbackJavaSkeleton(boolean callbackSkeleton) {
901 // This is a callback skeleton generation
902 if (callbackSkeleton)
903 println("public void ___regCB(IoTRMIObject rmiObj) throws IOException {");
905 println("public void ___regCB() throws IOException {");
906 println("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class, String.class, int.class },");
907 println("\tnew Class<?>[] { null, null, null });");
908 println("rmiCall = new IoTRMICall((int) paramObj[0], (String) paramObj[1], (int) paramObj[2]);");
914 * HELPER: writeMethodJavaSkeleton() writes the method of the skeleton class
916 private void writeMethodJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses,
917 boolean callbackSkeleton) {
919 for (String method : methods) {
921 List<String> methParams = intDecl.getMethodParams(method);
922 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
923 String methodId = intDecl.getMethodId(method);
924 print("public " + intDecl.getMethodType(method) + " " + methodId + "(");
925 boolean isCallbackMethod = false;
926 String callbackType = null;
927 for (int i = 0; i < methParams.size(); i++) {
929 String origParamType = methPrmTypes.get(i);
930 String paramType = checkAndGetParamClass(origParamType);
931 if (callbackClasses.contains(origParamType)) { // Check if this has callback object
932 isCallbackMethod = true;
933 callbackType = origParamType;
935 print(paramType + " " + methParams.get(i));
936 // Check if this is the last element (don't print a comma)
937 if (i != methParams.size() - 1) {
942 // Now, write the body of skeleton!
943 writeStdMethodBodyJavaSkeleton(methParams, methodId, intDecl.getMethodType(method));
945 if (isCallbackMethod)
946 writeInitCallbackJavaSkeleton(callbackSkeleton);
952 * HELPER: writeCallbackJavaStubGeneration() writes the callback stub generation part
954 private Map<Integer,String> writeCallbackJavaStubGeneration(List<String> methParams, List<String> methPrmTypes, String callbackType) {
956 Map<Integer,String> mapStubParam = new HashMap<Integer,String>();
957 // Iterate over callback objects
958 for (int i = 0; i < methParams.size(); i++) {
959 String paramType = methPrmTypes.get(i);
960 String param = methParams.get(i);
961 //if (callbackType.equals(paramType)) {
962 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
964 String exchParamType = checkAndGetParamClass(paramType);
965 // Print array if this is array or list if this is a list of callback objects
966 if (isArray(paramType, param)) {
967 println("int numStubs" + i + " = (int) paramObj[" + i + "];");
968 println(exchParamType + "[] stub" + i + " = new " + exchParamType + "[numStubs" + i + "];");
969 } else if (isList(paramType, param)) {
970 println("int numStubs" + i + " = (int) paramObj[" + i + "];");
971 println("List<" + exchParamType + "> stub" + i + " = new ArrayList<" + exchParamType + ">();");
973 println(exchParamType + " stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
974 println("objIdCnt++;");
977 // Generate a loop if needed
978 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
979 String exchParamType = checkAndGetParamClass(paramType);
980 if (isArray(paramType, param)) {
981 println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
982 println("stub" + i + "[objId] = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
983 println("objIdCnt++;");
985 } else if (isList(paramType, param)) {
986 println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
987 println("stub" + i + ".add(new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt));");
988 println("objIdCnt++;");
991 mapStubParam.put(i, "stub" + i); // List of all stub parameters
999 * HELPER: writeStdMethodHelperBodyJavaSkeleton() writes the standard method body helper in the skeleton class
1001 private void writeStdMethodHelperBodyJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
1002 List<String> methPrmTypes, String method, Set<String> callbackClasses) {
1003 // Generate array of parameter objects
1004 boolean isCallbackMethod = false;
1005 String callbackType = null;
1006 print("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { ");
1007 for (int i = 0; i < methParams.size(); i++) {
1009 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
1010 if (callbackClasses.contains(paramType)) {
1011 isCallbackMethod = true;
1012 callbackType = paramType;
1014 } else { // Generate normal classes if it's not a callback object
1015 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
1016 print(getSimpleType(prmType) + ".class");
1018 if (i != methParams.size() - 1)
1022 // Generate generic class if it's a generic type.. null otherwise
1023 print("new Class<?>[] { ");
1024 for (int i = 0; i < methParams.size(); i++) {
1025 String prmType = methPrmTypes.get(i);
1026 if (getParamCategory(prmType) == ParamCategory.NONPRIMITIVES)
1027 print(getTypeOfGeneric(prmType)[0] + ".class");
1030 if (i != methParams.size() - 1)
1034 Map<Integer,String> mapStubParam = null;
1035 if (isCallbackMethod)
1036 mapStubParam = writeCallbackJavaStubGeneration(methParams, methPrmTypes, callbackType);
1037 // Check if this is "void"
1038 String retType = intDecl.getMethodType(method);
1039 if (retType.equals("void")) {
1040 print(intDecl.getMethodId(method) + "(");
1041 } else { // We do have a return value
1042 print("Object retObj = " + intDecl.getMethodId(method) + "(");
1044 for (int i = 0; i < methParams.size(); i++) {
1046 if (isCallbackMethod) {
1047 print(mapStubParam.get(i)); // Get the callback parameter
1049 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
1050 print("(" + prmType + ") paramObj[" + i + "]");
1052 if (i != methParams.size() - 1)
1056 if (!retType.equals("void"))
1057 println("rmiObj.sendReturnObj(retObj);");
1058 if (isCallbackMethod) { // Catch exception if this is callback
1059 println("} catch(Exception ex) {");
1060 println("ex.printStackTrace();");
1061 println("throw new Error(\"Exception from callback object instantiation!\");");
1068 * HELPER: writeMethodHelperJavaSkeleton() writes the method helper of the skeleton class
1070 private void writeMethodHelperJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1072 // Use this set to handle two same methodIds
1073 Set<String> uniqueMethodIds = new HashSet<String>();
1074 for (String method : methods) {
1076 List<String> methParams = intDecl.getMethodParams(method);
1077 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1078 String methodId = intDecl.getMethodId(method);
1079 print("public void ___");
1080 String helperMethod = methodId;
1081 if (uniqueMethodIds.contains(methodId))
1082 helperMethod = helperMethod + intDecl.getMethodNumId(method);
1084 uniqueMethodIds.add(methodId);
1085 // Check if this is "void"
1086 String retType = intDecl.getMethodType(method);
1087 if (retType.equals("void"))
1088 println(helperMethod + "() {");
1090 println(helperMethod + "() throws IOException {");
1091 // Now, write the helper body of skeleton!
1092 writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
1099 * HELPER: writeJavaMethodPermission() writes permission checks in skeleton
1101 private void writeJavaMethodPermission(String intface) {
1103 // Get all the different stubs
1104 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1105 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1106 String newIntface = intMeth.getKey();
1107 int newObjectId = mapNewIntfaceObjId.get(newIntface);
1108 println("if (_objectId == object" + newObjectId + "Id) {");
1109 println("if (!set" + newObjectId + "Allowed.contains(methodId)) {");
1110 println("throw new Error(\"Object with object Id: \" + _objectId + \" is not allowed to access method: \" + methodId);");
1113 println("throw new Error(\"Object Id: \" + _objectId + \" not recognized!\");");
1121 * HELPER: writeJavaWaitRequestInvokeMethod() writes the main loop of the skeleton class
1123 private void writeJavaWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist, String intface) {
1125 // Use this set to handle two same methodIds
1126 Set<String> uniqueMethodIds = new HashSet<String>();
1127 println("private void ___waitRequestInvokeMethod() throws IOException {");
1128 // Write variables here if we have callbacks or enums or structs
1129 println("while (true) {");
1130 println("rmiObj.getMethodBytes();");
1131 println("int _objectId = rmiObj.getObjectId();");
1132 println("int methodId = rmiObj.getMethodId();");
1133 // Generate permission check
1134 writeJavaMethodPermission(intface);
1135 println("switch (methodId) {");
1136 // Print methods and method Ids
1137 for (String method : methods) {
1138 String methodId = intDecl.getMethodId(method);
1139 int methodNumId = intDecl.getMethodNumId(method);
1140 print("case " + methodNumId + ": ___");
1141 String helperMethod = methodId;
1142 if (uniqueMethodIds.contains(methodId))
1143 helperMethod = helperMethod + methodNumId;
1145 uniqueMethodIds.add(methodId);
1146 println(helperMethod + "(); break;");
1148 String method = "___initCallBack()";
1149 // Print case -9999 (callback handler) if callback exists
1150 if (callbackExist) {
1151 int methodId = intDecl.getHelperMethodNumId(method);
1152 println("case " + methodId + ": ___regCB(); break;");
1154 println("default: ");
1155 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
1163 * generateJavaSkeletonClass() generate skeletons based on the methods list in Java
1165 public void generateJavaSkeletonClass() throws IOException {
1167 // Create a new directory
1168 String path = createDirectories(dir, subdir);
1169 for (String intface : mapIntfacePTH.keySet()) {
1170 // Open a new file to write into
1171 String newSkelClass = intface + "_Skeleton";
1172 FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
1173 pw = new PrintWriter(new BufferedWriter(fw));
1174 // Pass in set of methods and get import classes
1175 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1176 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1177 List<String> methods = intDecl.getMethods();
1178 Set<String> importClasses = getImportClasses(methods, intDecl);
1179 List<String> stdImportClasses = getStandardJavaImportClasses();
1180 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
1181 printImportStatements(allImportClasses);
1182 // Find out if there are callback objects
1183 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1184 boolean callbackExist = !callbackClasses.isEmpty();
1185 // Write class header
1187 println("public class " + newSkelClass + " implements " + intface + " {\n");
1189 writePropertiesJavaSkeleton(intface, callbackExist, intDecl);
1190 // Write constructor
1191 writeConstructorJavaSkeleton(newSkelClass, intface);
1193 writeMethodJavaSkeleton(methods, intDecl, callbackClasses, false);
1194 // Write method helper
1195 writeMethodHelperJavaSkeleton(methods, intDecl, callbackClasses);
1196 // Write waitRequestInvokeMethod() - main loop
1197 writeJavaWaitRequestInvokeMethod(methods, intDecl, callbackExist, intface);
1200 System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".java...");
1206 * HELPER: writePropertiesJavaCallbackSkeleton() writes the properties of the callback skeleton class
1208 private void writePropertiesJavaCallbackSkeleton(String intface, boolean callbackExist) {
1210 println("private " + intface + " mainObj;");
1211 // For callback skeletons, this is its own object Id
1212 println("private static int objectId = 0;");
1214 if (callbackExist) {
1215 println("private static int objIdCnt = 0;");
1216 println("private IoTRMICall rmiCall;");
1223 * HELPER: writeConstructorJavaCallbackSkeleton() writes the constructor of the skeleton class
1225 private void writeConstructorJavaCallbackSkeleton(String newSkelClass, String intface) {
1227 println("public " + newSkelClass + "(" + intface + " _mainObj, int _objectId) throws Exception {");
1228 println("mainObj = _mainObj;");
1229 println("objectId = _objectId;");
1235 * HELPER: writeMethodHelperJavaCallbackSkeleton() writes the method helper of the callback skeleton class
1237 private void writeMethodHelperJavaCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1239 // Use this set to handle two same methodIds
1240 Set<String> uniqueMethodIds = new HashSet<String>();
1241 for (String method : methods) {
1243 List<String> methParams = intDecl.getMethodParams(method);
1244 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1245 String methodId = intDecl.getMethodId(method);
1246 print("public void ___");
1247 String helperMethod = methodId;
1248 if (uniqueMethodIds.contains(methodId))
1249 helperMethod = helperMethod + intDecl.getMethodNumId(method);
1251 uniqueMethodIds.add(methodId);
1252 // Check if this is "void"
1253 String retType = intDecl.getMethodType(method);
1254 if (retType.equals("void"))
1255 println(helperMethod + "(IoTRMIObject rmiObj) {");
1257 println(helperMethod + "(IoTRMIObject rmiObj) throws IOException {");
1258 // Now, write the helper body of skeleton!
1259 writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
1266 * HELPER: writeJavaCallbackWaitRequestInvokeMethod() writes the main loop of the skeleton class
1268 private void writeJavaCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist) {
1270 // Use this set to handle two same methodIds
1271 Set<String> uniqueMethodIds = new HashSet<String>();
1272 println("public void invokeMethod(IoTRMIObject rmiObj) throws IOException {");
1273 // Write variables here if we have callbacks or enums or structs
1274 println("int methodId = rmiObj.getMethodId();");
1275 // TODO: code the permission check here!
1276 println("switch (methodId) {");
1277 // Print methods and method Ids
1278 for (String method : methods) {
1279 String methodId = intDecl.getMethodId(method);
1280 int methodNumId = intDecl.getMethodNumId(method);
1281 print("case " + methodNumId + ": ___");
1282 String helperMethod = methodId;
1283 if (uniqueMethodIds.contains(methodId))
1284 helperMethod = helperMethod + methodNumId;
1286 uniqueMethodIds.add(methodId);
1287 println(helperMethod + "(rmiObj); break;");
1289 String method = "___initCallBack()";
1290 // Print case -9999 (callback handler) if callback exists
1291 if (callbackExist) {
1292 int methodId = intDecl.getHelperMethodNumId(method);
1293 println("case " + methodId + ": ___regCB(rmiObj); break;");
1295 println("default: ");
1296 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
1303 * generateJavaCallbackSkeletonClass() generate callback skeletons based on the methods list in Java
1305 public void generateJavaCallbackSkeletonClass() throws IOException {
1307 // Create a new directory
1308 String path = createDirectories(dir, subdir);
1309 for (String intface : mapIntfacePTH.keySet()) {
1310 // Open a new file to write into
1311 String newSkelClass = intface + "_CallbackSkeleton";
1312 FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
1313 pw = new PrintWriter(new BufferedWriter(fw));
1314 // Pass in set of methods and get import classes
1315 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1316 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1317 List<String> methods = intDecl.getMethods();
1318 Set<String> importClasses = getImportClasses(methods, intDecl);
1319 List<String> stdImportClasses = getStandardJavaImportClasses();
1320 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
1321 printImportStatements(allImportClasses);
1322 // Find out if there are callback objects
1323 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1324 boolean callbackExist = !callbackClasses.isEmpty();
1325 // Write class header
1327 println("public class " + newSkelClass + " implements " + intface + " {\n");
1329 writePropertiesJavaCallbackSkeleton(intface, callbackExist);
1330 // Write constructor
1331 writeConstructorJavaCallbackSkeleton(newSkelClass, intface);
1333 writeMethodJavaSkeleton(methods, intDecl, callbackClasses, true);
1334 // Write method helper
1335 writeMethodHelperJavaCallbackSkeleton(methods, intDecl, callbackClasses);
1336 // Write waitRequestInvokeMethod() - main loop
1337 writeJavaCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist);
1340 System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".java...");
1346 * HELPER: writeMethodCplusLocalInterface() writes the method of the interface
1348 private void writeMethodCplusLocalInterface(Collection<String> methods, InterfaceDecl intDecl) {
1350 for (String method : methods) {
1352 List<String> methParams = intDecl.getMethodParams(method);
1353 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1354 print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
1355 intDecl.getMethodId(method) + "(");
1356 for (int i = 0; i < methParams.size(); i++) {
1357 // Check for params with driver class types and exchange it
1358 // with its remote interface
1359 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
1360 paramType = checkAndGetCplusType(paramType);
1361 // Check for arrays - translate into vector in C++
1362 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
1363 print(paramComplete);
1364 // Check if this is the last element (don't print a comma)
1365 if (i != methParams.size() - 1) {
1375 * HELPER: writeMethodCplusInterface() writes the method of the interface
1377 private void writeMethodCplusInterface(Collection<String> methods, InterfaceDecl intDecl) {
1379 for (String method : methods) {
1381 List<String> methParams = intDecl.getMethodParams(method);
1382 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1383 print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
1384 intDecl.getMethodId(method) + "(");
1385 for (int i = 0; i < methParams.size(); i++) {
1386 // Check for params with driver class types and exchange it
1387 // with its remote interface
1388 String paramType = methPrmTypes.get(i);
1389 paramType = checkAndGetCplusType(paramType);
1390 // Check for arrays - translate into vector in C++
1391 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
1392 print(paramComplete);
1393 // Check if this is the last element (don't print a comma)
1394 if (i != methParams.size() - 1) {
1404 * HELPER: writeEnumCplus() writes the enumeration declaration
1406 private void writeEnumCplus(EnumDecl enumDecl) {
1408 Set<String> enumTypes = enumDecl.getEnumDeclarations();
1409 // Iterate over enum declarations
1410 for (String enType : enumTypes) {
1412 println("enum " + enType + " {");
1413 List<String> enumMembers = enumDecl.getMembers(enType);
1414 for (int i = 0; i < enumMembers.size(); i++) {
1416 String member = enumMembers.get(i);
1418 // Check if this is the last element (don't print a comma)
1419 if (i != enumMembers.size() - 1)
1430 * HELPER: writeStructCplus() writes the struct declaration
1432 private void writeStructCplus(StructDecl structDecl) {
1434 List<String> structTypes = structDecl.getStructTypes();
1435 // Iterate over enum declarations
1436 for (String stType : structTypes) {
1438 println("struct " + stType + " {");
1439 List<String> structMemberTypes = structDecl.getMemberTypes(stType);
1440 List<String> structMembers = structDecl.getMembers(stType);
1441 for (int i = 0; i < structMembers.size(); i++) {
1443 String memberType = structMemberTypes.get(i);
1444 String member = structMembers.get(i);
1445 String structTypeC = checkAndGetCplusType(memberType);
1446 String structComplete = checkAndGetCplusArray(structTypeC, member);
1447 println(structComplete + ";");
1455 * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking.
1457 * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
1458 * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
1459 * The local interface has to be the input parameter for the stub and the stub
1460 * interface has to be the input parameter for the local class.
1462 public void generateCplusLocalInterfaces() throws IOException {
1464 // Create a new directory
1465 createDirectory(dir);
1466 for (String intface : mapIntfacePTH.keySet()) {
1467 // Open a new file to write into
1468 FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
1469 pw = new PrintWriter(new BufferedWriter(fw));
1470 // Write file headers
1471 println("#ifndef _" + intface.toUpperCase() + "_HPP__");
1472 println("#define _" + intface.toUpperCase() + "_HPP__");
1473 println("#include <iostream>");
1474 // Pass in set of methods and get include classes
1475 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1476 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1477 List<String> methods = intDecl.getMethods();
1478 Set<String> includeClasses = getIncludeClasses(methods, intDecl, true);
1479 printIncludeStatements(includeClasses); println("");
1480 println("using namespace std;\n");
1481 // Write enum if any...
1482 EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface);
1483 writeEnumCplus(enumDecl);
1484 // Write struct if any...
1485 StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
1486 writeStructCplus(structDecl);
1487 println("class " + intface); println("{");
1490 writeMethodCplusLocalInterface(methods, intDecl);
1494 System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
1500 * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
1502 * For C++ we use virtual classe as interface
1504 public void generateCPlusInterfaces() throws IOException {
1506 // Create a new directory
1507 String path = createDirectories(dir, subdir);
1508 for (String intface : mapIntfacePTH.keySet()) {
1510 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1511 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1513 // Open a new file to write into
1514 String newIntface = intMeth.getKey();
1515 FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp");
1516 pw = new PrintWriter(new BufferedWriter(fw));
1517 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1518 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1519 // Write file headers
1520 println("#ifndef _" + newIntface.toUpperCase() + "_HPP__");
1521 println("#define _" + newIntface.toUpperCase() + "_HPP__");
1522 println("#include <iostream>");
1523 // Pass in set of methods and get import classes
1524 Set<String> includeClasses = getIncludeClasses(intMeth.getValue(), intDecl, false);
1525 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
1526 List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
1527 printIncludeStatements(allIncludeClasses); println("");
1528 println("using namespace std;\n");
1529 println("class " + newIntface);
1533 writeMethodCplusInterface(intMeth.getValue(), intDecl);
1537 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
1544 * HELPER: writeMethodCplusStub() writes the method of the stub
1546 private void writeMethodCplusStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1548 for (String method : methods) {
1550 List<String> methParams = intDecl.getMethodParams(method);
1551 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1552 print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
1553 intDecl.getMethodId(method) + "(");
1554 boolean isCallbackMethod = false;
1555 String callbackType = null;
1556 for (int i = 0; i < methParams.size(); i++) {
1558 String paramType = methPrmTypes.get(i);
1559 // Check if this has callback object
1560 if (callbackClasses.contains(paramType)) {
1561 isCallbackMethod = true;
1562 callbackType = paramType;
1563 // Even if there're 2 callback arguments, we expect them to be of the same interface
1565 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
1566 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
1567 print(methParamComplete);
1568 // Check if this is the last element (don't print a comma)
1569 if (i != methParams.size() - 1) {
1574 if (isCallbackMethod)
1575 writeCallbackMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method, callbackType);
1577 writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method);
1579 // Write the init callback helper method
1580 if (isCallbackMethod) {
1581 writeInitCallbackCplusStub(callbackType, intDecl);
1582 writeInitCallbackSendInfoCplusStub(intDecl);
1589 * HELPER: writeCallbackMethodBodyCplusStub() writes the callback method of the stub class
1591 private void writeCallbackMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
1592 List<String> methPrmTypes, String method, String callbackType) {
1594 // Check if this is single object, array, or list of objects
1595 boolean isArrayOrList = false;
1596 String callbackParam = null;
1597 for (int i = 0; i < methParams.size(); i++) {
1599 String paramType = methPrmTypes.get(i);
1600 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1601 String param = methParams.get(i);
1602 if (isArrayOrList(paramType, param)) { // Generate loop
1603 println("for (" + paramType + "* cb : " + getSimpleIdentifier(param) + ") {");
1604 println(callbackType + "_CallbackSkeleton* skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);");
1605 isArrayOrList = true;
1606 callbackParam = getSimpleIdentifier(param);
1608 println(callbackType + "_CallbackSkeleton* skel = new " + callbackType + "_CallbackSkeleton(" +
1609 getSimpleIdentifier(param) + ", objIdCnt++);");
1610 println("vecCallbackObj.push_back(skel);");
1611 if (isArrayOrList(paramType, param))
1615 println("int numParam = " + methParams.size() + ";");
1616 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
1617 String retType = intDecl.getMethodType(method);
1618 String retTypeC = checkAndGetCplusType(retType);
1619 println("string retType = \"" + checkAndGetCplusArrayType(retTypeC) + "\";");
1620 // Generate array of parameter types
1621 print("string paramCls[] = { ");
1622 for (int i = 0; i < methParams.size(); i++) {
1623 String paramType = methPrmTypes.get(i);
1624 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1626 } else { // Generate normal classes if it's not a callback object
1627 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
1628 String prmType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
1629 print("\"" + prmType + "\"");
1631 if (i != methParams.size() - 1) // Check if this is the last element
1635 print("int ___paramCB = ");
1637 println(callbackParam + ".size();");
1640 // Generate array of parameter objects
1641 print("void* paramObj[] = { ");
1642 for (int i = 0; i < methParams.size(); i++) {
1643 String paramType = methPrmTypes.get(i);
1644 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1645 print("&___paramCB");
1647 print(getSimpleIdentifier(methParams.get(i)));
1648 if (i != methParams.size() - 1)
1652 // Check if this is "void"
1653 if (retType.equals("void")) {
1654 println("void* retObj = NULL;");
1655 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1656 } else { // We do have a return value
1657 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
1658 println(checkAndGetCplusType(retType) + " retVal;");
1660 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
1661 println("void* retObj = &retVal;");
1662 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1663 println("return retVal;");
1669 * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class
1671 private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
1672 List<String> methPrmTypes, String method) {
1674 println("int numParam = " + methParams.size() + ";");
1675 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
1676 String retType = intDecl.getMethodType(method);
1677 String retTypeC = checkAndGetCplusType(retType);
1678 println("string retType = \"" + checkAndGetCplusArrayType(retTypeC) + "\";");
1679 // Generate array of parameter types
1680 print("string paramCls[] = { ");
1681 for (int i = 0; i < methParams.size(); i++) {
1682 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
1683 String paramType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
1684 print("\"" + paramType + "\"");
1685 // Check if this is the last element (don't print a comma)
1686 if (i != methParams.size() - 1) {
1691 // Generate array of parameter objects
1692 print("void* paramObj[] = { ");
1693 for (int i = 0; i < methParams.size(); i++) {
1694 print("&" + getSimpleIdentifier(methParams.get(i)));
1695 // Check if this is the last element (don't print a comma)
1696 if (i != methParams.size() - 1) {
1701 // Check if this is "void"
1702 if (retType.equals("void")) {
1703 println("void* retObj = NULL;");
1704 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1705 } else { // We do have a return value
1706 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
1707 println(checkAndGetCplusType(retType) + " retVal;");
1709 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
1710 println("void* retObj = &retVal;");
1711 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1712 println("return retVal;");
1718 * HELPER: writePropertiesCplusStub() writes the properties of the stub class
1720 private void writePropertiesCplusPermission(String intface) {
1722 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1723 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1724 String newIntface = intMeth.getKey();
1725 int newObjectId = mapNewIntfaceObjId.get(newIntface);
1726 println("const static int object" + newObjectId + "Id = " + newObjectId + ";");
1727 println("const static set<int> set" + newObjectId + "Allowed;");
1732 * HELPER: writePropertiesCplusStub() writes the properties of the stub class
1734 private void writePropertiesCplusStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
1736 println("IoTRMICall *rmiCall;");
1737 //println("IoTRMIObject\t\t\t*rmiObj;");
1738 println("string address;");
1739 println("vector<int> ports;\n");
1740 // Get the object Id
1741 Integer objId = mapIntfaceObjId.get(intface);
1742 println("const static int objectId = " + objId + ";");
1743 mapNewIntfaceObjId.put(newIntface, objId);
1744 mapIntfaceObjId.put(intface, objId++);
1745 if (callbackExist) {
1746 // We assume that each class only has one callback interface for now
1747 Iterator it = callbackClasses.iterator();
1748 String callbackType = (String) it.next();
1749 println("// Callback properties");
1750 println("IoTRMIObject *rmiObj;");
1751 println("vector<" + callbackType + "*> vecCallbackObj;");
1752 println("static int objIdCnt;");
1753 // Generate permission stuff for callback stubs
1754 writePropertiesCplusPermission(callbackType);
1761 * HELPER: writeConstructorCplusStub() writes the constructor of the stub class
1763 private void writeConstructorCplusStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1765 println(newStubClass +
1766 "(int _port, const char* _address, int _rev, bool* _bResult, vector<int> _ports) {");
1767 println("address = _address;");
1768 println("ports = _ports;");
1769 println("rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);");
1770 if (callbackExist) {
1771 println("objIdCnt = 0;");
1772 Iterator it = callbackClasses.iterator();
1773 String callbackType = (String) it.next();
1774 println("thread th1 (&" + newStubClass + "::___initCallBack, this);");
1775 println("th1.detach();");
1776 println("___regCB();");
1783 * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
1785 private void writeDeconstructorCplusStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1787 println("~" + newStubClass + "() {");
1788 println("if (rmiCall != NULL) {");
1789 println("delete rmiCall;");
1790 println("rmiCall = NULL;");
1792 if (callbackExist) {
1793 // We assume that each class only has one callback interface for now
1794 println("if (rmiObj != NULL) {");
1795 println("delete rmiObj;");
1796 println("rmiObj = NULL;");
1798 Iterator it = callbackClasses.iterator();
1799 String callbackType = (String) it.next();
1800 println("for(" + callbackType + "* cb : vecCallbackObj) {");
1801 println("delete cb;");
1802 println("cb = NULL;");
1811 * HELPER: writeCplusMethodCallbackPermission() writes permission checks in stub for callbacks
1813 private void writeCplusMethodCallbackPermission(String intface) {
1815 println("int methodId = IoTRMIObject::getMethodId(method);");
1816 // Get all the different stubs
1817 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1818 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1819 String newIntface = intMeth.getKey();
1820 int newObjectId = mapNewIntfaceObjId.get(newIntface);
1821 println("if (set" + newObjectId + "Allowed.find(methodId) == set" + newObjectId + "Allowed.end()) {");
1822 println("cerr << \"Callback object for " + intface + " is not allowed to access method: \" << methodId;");
1823 println("exit(-1);");
1830 * HELPER: writeInitCallbackCplusStub() writes the initialization of callback
1832 private void writeInitCallbackCplusStub(String intface, InterfaceDecl intDecl) {
1834 println("void ___initCallBack() {");
1835 println("bool bResult = false;");
1836 println("rmiObj = new IoTRMIObject(ports[0], &bResult);");
1837 println("while (true) {");
1838 println("char* method = rmiObj->getMethodBytes();");
1839 writeCplusMethodCallbackPermission(intface);
1840 println("int objId = IoTRMIObject::getObjectId(method);");
1841 println("if (objId < vecCallbackObj.size()) { // Check if still within range");
1842 println(intface + "_CallbackSkeleton* skel = dynamic_cast<" + intface +
1843 "_CallbackSkeleton*> (vecCallbackObj.at(objId));");
1844 println("skel->invokeMethod(rmiObj);");
1845 println("} else {");
1846 println("cerr << \"Illegal object Id: \" << to_string(objId);");
1847 // TODO: perhaps need to change this into "throw" to make it cleaner (allow stack unfolding)
1848 println("exit(-1);");
1856 * HELPER: writeInitCallbackSendInfoCplusStub() writes the initialization of callback
1858 private void writeInitCallbackSendInfoCplusStub(InterfaceDecl intDecl) {
1860 // Generate info sending part
1861 println("void ___regCB() {");
1862 println("int numParam = 3;");
1863 String method = "___initCallBack()";
1864 println("int methodId = " + intDecl.getHelperMethodNumId(method) + ";");
1865 println("string retType = \"void\";");
1866 println("string paramCls[] = { \"int\", \"string\", \"int\" };");
1867 println("int rev = 0;");
1868 println("void* paramObj[] = { &ports[0], &address, &rev };");
1869 println("void* retObj = NULL;");
1870 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1876 * generateCPlusStubClasses() generate stubs based on the methods list in C++
1878 public void generateCPlusStubClasses() throws IOException {
1880 // Create a new directory
1881 String path = createDirectories(dir, subdir);
1882 for (String intface : mapIntfacePTH.keySet()) {
1884 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1885 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1886 // Open a new file to write into
1887 String newIntface = intMeth.getKey();
1888 String newStubClass = newIntface + "_Stub";
1889 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
1890 pw = new PrintWriter(new BufferedWriter(fw));
1891 // Write file headers
1892 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
1893 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
1894 println("#include <iostream>");
1895 // Find out if there are callback objects
1896 Set<String> methods = intMeth.getValue();
1897 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1898 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1899 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1900 boolean callbackExist = !callbackClasses.isEmpty();
1901 if (callbackExist) // Need thread library if this has callback
1902 println("#include <thread>");
1903 println("#include \"" + newIntface + ".hpp\""); println("");
1904 println("using namespace std;"); println("");
1905 println("class " + newStubClass + " : public " + newIntface); println("{");
1906 println("private:\n");
1907 writePropertiesCplusStub(intface, newIntface, callbackExist, callbackClasses);
1908 println("public:\n");
1909 // Add default constructor and destructor
1910 println(newStubClass + "() { }"); println("");
1911 writeConstructorCplusStub(newStubClass, callbackExist, callbackClasses);
1912 writeDeconstructorCplusStub(newStubClass, callbackExist, callbackClasses);
1914 writeMethodCplusStub(methods, intDecl, callbackClasses);
1915 print("}"); println(";");
1917 writePermissionInitializationCplus(intface, newStubClass, intDecl);
1920 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".hpp...");
1927 * HELPER: writePropertiesCplusCallbackStub() writes the properties of the stub class
1929 private void writePropertiesCplusCallbackStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
1931 println("IoTRMICall *rmiCall;");
1932 // Get the object Id
1933 println("static int objectId;");
1934 if (callbackExist) {
1935 // We assume that each class only has one callback interface for now
1936 Iterator it = callbackClasses.iterator();
1937 String callbackType = (String) it.next();
1938 println("// Callback properties");
1939 println("IoTRMIObject *rmiObj;");
1940 println("vector<" + callbackType + "*> vecCallbackObj;");
1941 println("static int objIdCnt;");
1942 // TODO: Need to initialize address and ports if we want to have callback-in-callback
1943 println("string address;");
1944 println("vector<int> ports;\n");
1945 writePropertiesCplusPermission(callbackType);
1952 * HELPER: writeConstructorCplusCallbackStub() writes the constructor of the stub class
1954 private void writeConstructorCplusCallbackStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1956 println(newStubClass + "(IoTRMICall* _rmiCall, int _objectId) {");
1957 println("objectId = _objectId;");
1958 println("rmiCall = _rmiCall;");
1959 if (callbackExist) {
1960 Iterator it = callbackClasses.iterator();
1961 String callbackType = (String) it.next();
1962 println("thread th1 (&" + newStubClass + "::___initCallBack, this);");
1963 println("th1.detach();");
1964 println("___regCB();");
1971 * generateCPlusCallbackStubClasses() generate callback stubs based on the methods list in C++
1973 public void generateCPlusCallbackStubClasses() throws IOException {
1975 // Create a new directory
1976 String path = createDirectories(dir, subdir);
1977 for (String intface : mapIntfacePTH.keySet()) {
1979 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1980 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1981 // Open a new file to write into
1982 String newIntface = intMeth.getKey();
1983 String newStubClass = newIntface + "_CallbackStub";
1984 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
1985 pw = new PrintWriter(new BufferedWriter(fw));
1986 // Find out if there are callback objects
1987 Set<String> methods = intMeth.getValue();
1988 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1989 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1990 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1991 boolean callbackExist = !callbackClasses.isEmpty();
1992 // Write file headers
1993 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
1994 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
1995 println("#include <iostream>");
1997 println("#include <thread>");
1998 println("#include \"" + newIntface + ".hpp\""); println("");
1999 println("using namespace std;"); println("");
2000 println("class " + newStubClass + " : public " + newIntface); println("{");
2001 println("private:\n");
2002 writePropertiesCplusCallbackStub(intface, newIntface, callbackExist, callbackClasses);
2003 println("public:\n");
2004 // Add default constructor and destructor
2005 println(newStubClass + "() { }"); println("");
2006 writeConstructorCplusCallbackStub(newStubClass, callbackExist, callbackClasses);
2007 writeDeconstructorCplusStub(newStubClass, callbackExist, callbackClasses);
2009 writeMethodCplusStub(methods, intDecl, callbackClasses);
2012 writePermissionInitializationCplus(intface, newStubClass, intDecl);
2015 System.out.println("IoTCompiler: Generated callback stub class " + newIntface + ".hpp...");
2022 * HELPER: writePropertiesCplusSkeleton() writes the properties of the skeleton class
2024 private void writePropertiesCplusSkeleton(String intface, boolean callbackExist, Set<String> callbackClasses) {
2026 println(intface + " *mainObj;");
2028 if (callbackExist) {
2029 Iterator it = callbackClasses.iterator();
2030 String callbackType = (String) it.next();
2031 String exchangeType = checkAndGetParamClass(callbackType);
2032 println("// Callback properties");
2033 println("static int objIdCnt;");
2034 println("vector<" + exchangeType + "*> vecCallbackObj;");
2035 println("IoTRMICall *rmiCall;");
2037 println("IoTRMIObject *rmiObj;\n");
2038 // Keep track of object Ids of all stubs registered to this interface
2039 writePropertiesCplusPermission(intface);
2045 * HELPER: writePermissionInitializationCplus() writes the initialization of permission set
2047 private void writePermissionInitializationCplus(String intface, String newSkelClass, InterfaceDecl intDecl) {
2049 // Keep track of object Ids of all stubs registered to this interface
2050 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
2051 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
2052 String newIntface = intMeth.getKey();
2053 int newObjectId = mapNewIntfaceObjId.get(newIntface);
2054 print("const set<int> " + newSkelClass + "::set" + newObjectId + "Allowed {");
2055 Set<String> methodIds = intMeth.getValue();
2057 for (String methodId : methodIds) {
2058 int methodNumId = intDecl.getMethodNumId(methodId);
2059 print(Integer.toString(methodNumId));
2060 // Check if this is the last element (don't print a comma)
2061 if (i != methodIds.size() - 1) {
2072 * HELPER: writeConstructorCplusSkeleton() writes the constructor of the skeleton class
2074 private void writeConstructorCplusSkeleton(String newSkelClass, String intface, boolean callbackExist) {
2076 println(newSkelClass + "(" + intface + " *_mainObj, int _port) {");
2077 println("bool _bResult = false;");
2078 println("mainObj = _mainObj;");
2079 println("rmiObj = new IoTRMIObject(_port, &_bResult);");
2081 if (callbackExist) {
2082 println("objIdCnt = 0;");
2084 //println("set0Allowed = Arrays.asList(object0Permission);");
2085 println("___waitRequestInvokeMethod();");
2091 * HELPER: writeDeconstructorCplusSkeleton() writes the deconstructor of the skeleton class
2093 private void writeDeconstructorCplusSkeleton(String newSkelClass, boolean callbackExist, Set<String> callbackClasses) {
2095 println("~" + newSkelClass + "() {");
2096 println("if (rmiObj != NULL) {");
2097 println("delete rmiObj;");
2098 println("rmiObj = NULL;");
2100 if (callbackExist) {
2101 // We assume that each class only has one callback interface for now
2102 println("if (rmiCall != NULL) {");
2103 println("delete rmiCall;");
2104 println("rmiCall = NULL;");
2106 Iterator it = callbackClasses.iterator();
2107 String callbackType = (String) it.next();
2108 String exchangeType = checkAndGetParamClass(callbackType);
2109 println("for(" + exchangeType + "* cb : vecCallbackObj) {");
2110 println("delete cb;");
2111 println("cb = NULL;");
2120 * HELPER: writeStdMethodBodyCplusSkeleton() writes the standard method body in the skeleton class
2122 private void writeStdMethodBodyCplusSkeleton(List<String> methParams, String methodId, String methodType) {
2124 if (methodType.equals("void"))
2125 print("mainObj->" + methodId + "(");
2127 print("return mainObj->" + methodId + "(");
2128 for (int i = 0; i < methParams.size(); i++) {
2130 print(getSimpleIdentifier(methParams.get(i)));
2131 // Check if this is the last element (don't print a comma)
2132 if (i != methParams.size() - 1) {
2141 * HELPER: writeInitCallbackCplusSkeleton() writes the init callback method for skeleton class
2143 private void writeInitCallbackCplusSkeleton(boolean callbackSkeleton) {
2145 // This is a callback skeleton generation
2146 if (callbackSkeleton)
2147 println("void ___regCB(IoTRMIObject* rmiObj) {");
2149 println("void ___regCB() {");
2150 println("int numParam = 3;");
2151 println("int param1 = 0;");
2152 println("string param2 = \"\";");
2153 println("int param3 = 0;");
2154 println("void* paramObj[] = { ¶m1, ¶m2, ¶m3 };");
2155 println("bool bResult = false;");
2156 println("rmiCall = new IoTRMICall(param1, param2.c_str(), param3, &bResult);");
2162 * HELPER: writeMethodCplusSkeleton() writes the method of the skeleton class
2164 private void writeMethodCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl,
2165 Set<String> callbackClasses, boolean callbackSkeleton) {
2167 for (String method : methods) {
2169 List<String> methParams = intDecl.getMethodParams(method);
2170 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2171 String methodId = intDecl.getMethodId(method);
2172 String methodType = checkAndGetCplusType(intDecl.getMethodType(method));
2173 print(methodType + " " + methodId + "(");
2174 boolean isCallbackMethod = false;
2175 String callbackType = null;
2176 for (int i = 0; i < methParams.size(); i++) {
2178 String origParamType = methPrmTypes.get(i);
2179 if (callbackClasses.contains(origParamType)) { // Check if this has callback object
2180 isCallbackMethod = true;
2181 callbackType = origParamType;
2183 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
2184 String methPrmType = checkAndGetCplusType(paramType);
2185 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
2186 print(methParamComplete);
2187 // Check if this is the last element (don't print a comma)
2188 if (i != methParams.size() - 1) {
2193 // Now, write the body of skeleton!
2194 writeStdMethodBodyCplusSkeleton(methParams, methodId, intDecl.getMethodType(method));
2196 if (isCallbackMethod)
2197 writeInitCallbackCplusSkeleton(callbackSkeleton);
2203 * HELPER: writeCallbackCplusNumStubs() writes the numStubs variable
2205 private void writeCallbackCplusNumStubs(List<String> methParams, List<String> methPrmTypes, String callbackType) {
2207 for (int i = 0; i < methParams.size(); i++) {
2208 String paramType = methPrmTypes.get(i);
2209 String param = methParams.get(i);
2210 //if (callbackType.equals(paramType)) {
2211 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
2212 String exchParamType = checkAndGetParamClass(paramType);
2213 // Print array if this is array or list if this is a list of callback objects
2214 println("int numStubs" + i + " = 0;");
2221 * HELPER: writeCallbackCplusStubGeneration() writes the callback stub generation part
2223 private void writeCallbackCplusStubGeneration(List<String> methParams, List<String> methPrmTypes, String callbackType) {
2225 // Iterate over callback objects
2226 for (int i = 0; i < methParams.size(); i++) {
2227 String paramType = methPrmTypes.get(i);
2228 String param = methParams.get(i);
2229 // Generate a loop if needed
2230 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
2231 String exchParamType = checkAndGetParamClass(paramType);
2232 if (isArrayOrList(paramType, param)) {
2233 println("vector<" + exchParamType + "> stub;");
2234 println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
2235 println(exchParamType + "* cb" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
2236 println("stub" + i + ".push_back(cb);");
2237 println("vecCallbackObj.push_back(cb);");
2238 println("objIdCnt++;");
2241 println(exchParamType + "* stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
2242 println("vecCallbackObj.push_back(stub" + i + ");");
2243 println("objIdCnt++;");
2251 * HELPER: writeStdMethodHelperBodyCplusSkeleton() writes the standard method body helper in the skeleton class
2253 private void writeStdMethodHelperBodyCplusSkeleton(InterfaceDecl intDecl, List<String> methParams,
2254 List<String> methPrmTypes, String method, String methodId, Set<String> callbackClasses) {
2256 // Generate array of parameter types
2257 boolean isCallbackMethod = false;
2258 String callbackType = null;
2259 print("string paramCls[] = { ");
2260 for (int i = 0; i < methParams.size(); i++) {
2261 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2262 if (callbackClasses.contains(paramType)) {
2263 isCallbackMethod = true;
2264 callbackType = paramType;
2266 } else { // Generate normal classes if it's not a callback object
2267 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
2268 String prmType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
2269 print("\"" + prmType + "\"");
2271 if (i != methParams.size() - 1) {
2276 println("int numParam = " + methParams.size() + ";");
2277 if (isCallbackMethod)
2278 writeCallbackCplusNumStubs(methParams, methPrmTypes, callbackType);
2279 // Generate parameters
2280 for (int i = 0; i < methParams.size(); i++) {
2281 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2282 if (!callbackClasses.contains(paramType)) {
2283 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
2284 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
2285 println(methParamComplete + ";");
2288 // Generate array of parameter objects
2289 print("void* paramObj[] = { ");
2290 for (int i = 0; i < methParams.size(); i++) {
2291 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2292 if (callbackClasses.contains(paramType))
2293 print("&numStubs" + i);
2295 print("&" + getSimpleIdentifier(methParams.get(i)));
2296 if (i != methParams.size() - 1) {
2301 println("rmiObj->getMethodParams(paramCls, numParam, paramObj);");
2302 if (isCallbackMethod)
2303 writeCallbackCplusStubGeneration(methParams, methPrmTypes, callbackType);
2304 String retType = intDecl.getMethodType(method);
2305 // Check if this is "void"
2306 if (retType.equals("void")) {
2307 print(methodId + "(");
2308 for (int i = 0; i < methParams.size(); i++) {
2309 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2310 if (callbackClasses.contains(paramType))
2313 print(getSimpleIdentifier(methParams.get(i)));
2314 if (i != methParams.size() - 1) {
2319 } else { // We do have a return value
2320 print(checkAndGetCplusType(retType) + " retVal = " + methodId + "(");
2321 for (int i = 0; i < methParams.size(); i++) {
2322 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2323 if (callbackClasses.contains(paramType))
2326 print(getSimpleIdentifier(methParams.get(i)));
2327 if (i != methParams.size() - 1) {
2332 println("void* retObj = &retVal;");
2333 String retTypeC = checkAndGetCplusType(retType);
2334 println("rmiObj->sendReturnObj(retObj, \"" + checkAndGetCplusArrayType(retTypeC) + "\");");
2340 * HELPER: writeMethodHelperCplusSkeleton() writes the method helper of the skeleton class
2342 private void writeMethodHelperCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
2344 // Use this set to handle two same methodIds
2345 Set<String> uniqueMethodIds = new HashSet<String>();
2346 for (String method : methods) {
2348 List<String> methParams = intDecl.getMethodParams(method);
2349 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2350 String methodId = intDecl.getMethodId(method);
2352 String helperMethod = methodId;
2353 if (uniqueMethodIds.contains(methodId))
2354 helperMethod = helperMethod + intDecl.getMethodNumId(method);
2356 uniqueMethodIds.add(methodId);
2357 // Check if this is "void"
2358 String retType = intDecl.getMethodType(method);
2359 println(helperMethod + "() {");
2360 // Now, write the helper body of skeleton!
2361 writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses);
2368 * HELPER: writeCplusMethodPermission() writes permission checks in skeleton
2370 private void writeCplusMethodPermission(String intface) {
2372 // Get all the different stubs
2373 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
2374 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
2375 String newIntface = intMeth.getKey();
2376 int newObjectId = mapNewIntfaceObjId.get(newIntface);
2377 println("if (_objectId == object" + newObjectId + "Id) {");
2378 println("if (set" + newObjectId + "Allowed.find(methodId) == set" + newObjectId + "Allowed.end()) {");
2379 println("cerr << \"Object with object Id: \" << _objectId << \" is not allowed to access method: \" << methodId << endl;");
2380 println("exit(-1);");
2383 println("cerr << \"Object Id: \" << _objectId << \" not recognized!\" << endl;");
2384 println("exit(-1);");
2392 * HELPER: writeCplusWaitRequestInvokeMethod() writes the main loop of the skeleton class
2394 private void writeCplusWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist, String intface) {
2396 // Use this set to handle two same methodIds
2397 Set<String> uniqueMethodIds = new HashSet<String>();
2398 println("void ___waitRequestInvokeMethod() {");
2399 // Write variables here if we have callbacks or enums or structs
2400 println("while (true) {");
2401 println("rmiObj->getMethodBytes();");
2402 println("int _objectId = rmiObj->getObjectId();");
2403 println("int methodId = rmiObj->getMethodId();");
2404 // Generate permission check
2405 writeCplusMethodPermission(intface);
2406 println("switch (methodId) {");
2407 // Print methods and method Ids
2408 for (String method : methods) {
2409 String methodId = intDecl.getMethodId(method);
2410 int methodNumId = intDecl.getMethodNumId(method);
2411 print("case " + methodNumId + ": ___");
2412 String helperMethod = methodId;
2413 if (uniqueMethodIds.contains(methodId))
2414 helperMethod = helperMethod + methodNumId;
2416 uniqueMethodIds.add(methodId);
2417 println(helperMethod + "(); break;");
2419 String method = "___initCallBack()";
2420 // Print case -9999 (callback handler) if callback exists
2421 if (callbackExist) {
2422 int methodId = intDecl.getHelperMethodNumId(method);
2423 println("case " + methodId + ": ___regCB(); break;");
2425 println("default: ");
2426 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
2427 println("throw exception();");
2435 * generateCplusSkeletonClass() generate skeletons based on the methods list in C++
2437 public void generateCplusSkeletonClass() throws IOException {
2439 // Create a new directory
2440 String path = createDirectories(dir, subdir);
2441 for (String intface : mapIntfacePTH.keySet()) {
2442 // Open a new file to write into
2443 String newSkelClass = intface + "_Skeleton";
2444 FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp");
2445 pw = new PrintWriter(new BufferedWriter(fw));
2446 // Write file headers
2447 println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
2448 println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
2449 println("#include <iostream>");
2450 println("#include \"" + intface + ".hpp\"\n");
2451 // Pass in set of methods and get import classes
2452 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2453 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2454 List<String> methods = intDecl.getMethods();
2455 Set<String> includeClasses = getIncludeClasses(methods, intDecl, true);
2456 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
2457 List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
2458 printIncludeStatements(allIncludeClasses); println("");
2459 println("using namespace std;\n");
2460 // Find out if there are callback objects
2461 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
2462 boolean callbackExist = !callbackClasses.isEmpty();
2463 // Write class header
2464 println("class " + newSkelClass + " : public " + intface); println("{");
2465 println("private:\n");
2467 writePropertiesCplusSkeleton(intface, callbackExist, callbackClasses);
2468 println("public:\n");
2469 // Write constructor
2470 writeConstructorCplusSkeleton(newSkelClass, intface, callbackExist);
2471 // Write deconstructor
2472 writeDeconstructorCplusSkeleton(newSkelClass, callbackExist, callbackClasses);
2474 writeMethodCplusSkeleton(methods, intDecl, callbackClasses, false);
2475 // Write method helper
2476 writeMethodHelperCplusSkeleton(methods, intDecl, callbackClasses);
2477 // Write waitRequestInvokeMethod() - main loop
2478 writeCplusWaitRequestInvokeMethod(methods, intDecl, callbackExist, intface);
2480 writePermissionInitializationCplus(intface, newSkelClass, intDecl);
2483 System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".hpp...");
2489 * HELPER: writePropertiesCplusCallbackSkeleton() writes the properties of the callback skeleton class
2491 private void writePropertiesCplusCallbackSkeleton(String intface, boolean callbackExist, Set<String> callbackClasses) {
2493 println(intface + " *mainObj;");
2494 // Keep track of object Ids of all stubs registered to this interface
2495 println("static int objectId;");
2497 if (callbackExist) {
2498 Iterator it = callbackClasses.iterator();
2499 String callbackType = (String) it.next();
2500 String exchangeType = checkAndGetParamClass(callbackType);
2501 println("// Callback properties");
2502 println("IoTRMICall* rmiCall;");
2503 println("vector<" + exchangeType + "*> vecCallbackObj;");
2504 println("static int objIdCnt;");
2511 * HELPER: writeConstructorCplusCallbackSkeleton() writes the constructor of the skeleton class
2513 private void writeConstructorCplusCallbackSkeleton(String newSkelClass, String intface, boolean callbackExist) {
2515 println(newSkelClass + "(" + intface + " *_mainObj, int _objectId) {");
2516 println("mainObj = _mainObj;");
2517 println("objectId = _objectId;");
2519 if (callbackExist) {
2520 println("objIdCnt = 0;");
2527 * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
2529 private void writeDeconstructorCplusCallbackSkeleton(String newStubClass, boolean callbackExist,
2530 Set<String> callbackClasses) {
2532 println("~" + newStubClass + "() {");
2533 if (callbackExist) {
2534 // We assume that each class only has one callback interface for now
2535 println("if (rmiCall != NULL) {");
2536 println("delete rmiCall;");
2537 println("rmiCall = NULL;");
2539 Iterator it = callbackClasses.iterator();
2540 String callbackType = (String) it.next();
2541 String exchangeType = checkAndGetParamClass(callbackType);
2542 println("for(" + exchangeType + "* cb : vecCallbackObj) {");
2543 println("delete cb;");
2544 println("cb = NULL;");
2553 * HELPER: writeMethodHelperCplusCallbackSkeleton() writes the method helper of the callback skeleton class
2555 private void writeMethodHelperCplusCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl,
2556 Set<String> callbackClasses) {
2558 // Use this set to handle two same methodIds
2559 Set<String> uniqueMethodIds = new HashSet<String>();
2560 for (String method : methods) {
2562 List<String> methParams = intDecl.getMethodParams(method);
2563 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2564 String methodId = intDecl.getMethodId(method);
2566 String helperMethod = methodId;
2567 if (uniqueMethodIds.contains(methodId))
2568 helperMethod = helperMethod + intDecl.getMethodNumId(method);
2570 uniqueMethodIds.add(methodId);
2571 // Check if this is "void"
2572 String retType = intDecl.getMethodType(method);
2573 println(helperMethod + "(IoTRMIObject* rmiObj) {");
2574 // Now, write the helper body of skeleton!
2575 writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses);
2582 * HELPER: writeCplusCallbackWaitRequestInvokeMethod() writes the main loop of the skeleton class
2584 private void writeCplusCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl,
2585 boolean callbackExist) {
2587 // Use this set to handle two same methodIds
2588 Set<String> uniqueMethodIds = new HashSet<String>();
2589 println("void invokeMethod(IoTRMIObject* rmiObj) {");
2590 // Write variables here if we have callbacks or enums or structs
2591 println("int methodId = rmiObj->getMethodId();");
2592 // TODO: code the permission check here!
2593 println("switch (methodId) {");
2594 // Print methods and method Ids
2595 for (String method : methods) {
2596 String methodId = intDecl.getMethodId(method);
2597 int methodNumId = intDecl.getMethodNumId(method);
2598 print("case " + methodNumId + ": ___");
2599 String helperMethod = methodId;
2600 if (uniqueMethodIds.contains(methodId))
2601 helperMethod = helperMethod + methodNumId;
2603 uniqueMethodIds.add(methodId);
2604 println(helperMethod + "(rmiObj); break;");
2606 String method = "___initCallBack()";
2607 // Print case -9999 (callback handler) if callback exists
2608 if (callbackExist) {
2609 int methodId = intDecl.getHelperMethodNumId(method);
2610 println("case " + methodId + ": ___regCB(rmiObj); break;");
2612 println("default: ");
2613 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
2614 println("throw exception();");
2622 * generateCplusCallbackSkeletonClass() generate callback skeletons based on the methods list in C++
2624 public void generateCplusCallbackSkeletonClass() throws IOException {
2626 // Create a new directory
2627 String path = createDirectories(dir, subdir);
2628 for (String intface : mapIntfacePTH.keySet()) {
2629 // Open a new file to write into
2630 String newSkelClass = intface + "_CallbackSkeleton";
2631 FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp");
2632 pw = new PrintWriter(new BufferedWriter(fw));
2633 // Write file headers
2634 println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
2635 println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
2636 println("#include <iostream>");
2637 println("#include \"" + intface + ".hpp\"\n");
2638 // Pass in set of methods and get import classes
2639 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2640 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2641 List<String> methods = intDecl.getMethods();
2642 Set<String> includeClasses = getIncludeClasses(methods, intDecl, true);
2643 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
2644 List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
2645 printIncludeStatements(allIncludeClasses); println("");
2646 // Find out if there are callback objects
2647 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
2648 boolean callbackExist = !callbackClasses.isEmpty();
2649 println("using namespace std;\n");
2650 // Write class header
2651 println("class " + newSkelClass + " : public " + intface); println("{");
2652 println("private:\n");
2654 writePropertiesCplusCallbackSkeleton(intface, callbackExist, callbackClasses);
2655 println("public:\n");
2656 // Write constructor
2657 writeConstructorCplusCallbackSkeleton(newSkelClass, intface, callbackExist);
2658 // Write deconstructor
2659 writeDeconstructorCplusCallbackSkeleton(newSkelClass, callbackExist, callbackClasses);
2661 writeMethodCplusSkeleton(methods, intDecl, callbackClasses, true);
2662 // Write method helper
2663 writeMethodHelperCplusCallbackSkeleton(methods, intDecl, callbackClasses);
2664 // Write waitRequestInvokeMethod() - main loop
2665 writeCplusCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist);
2669 System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".hpp...");
2675 * generateInitializer() generate initializer based on type
2677 public String generateCplusInitializer(String type) {
2679 // Generate dummy returns for now
2680 if (type.equals("short")||
2681 type.equals("int") ||
2682 type.equals("long") ||
2683 type.equals("float")||
2684 type.equals("double")) {
2687 } else if ( type.equals("String") ||
2688 type.equals("string")) {
2691 } else if ( type.equals("char") ||
2692 type.equals("byte")) {
2695 } else if ( type.equals("boolean")) {
2705 * generateReturnStmt() generate return statement based on methType
2707 public String generateReturnStmt(String methType) {
2709 // Generate dummy returns for now
2710 if (methType.equals("short")||
2711 methType.equals("int") ||
2712 methType.equals("long") ||
2713 methType.equals("float")||
2714 methType.equals("double")) {
2717 } else if ( methType.equals("String")) {
2720 } else if ( methType.equals("char") ||
2721 methType.equals("byte")) {
2724 } else if ( methType.equals("boolean")) {
2734 * setDirectory() sets a new directory for stub files
2736 public void setDirectory(String _subdir) {
2743 * printUsage() prints the usage of this compiler
2745 public static void printUsage() {
2747 System.out.println();
2748 System.out.println("Sentinel interface and stub compiler version 1.0");
2749 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
2750 System.out.println("All rights reserved.");
2751 System.out.println("Usage:");
2752 System.out.println("\tjava IoTCompiler -help / --help / -h\n");
2753 System.out.println("\t\tDisplay this help texts\n\n");
2754 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>]");
2755 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>] [options]\n");
2756 System.out.println("\t\tTake one or more pairs of main-req policy files, and generate Java and/or C++ files\n");
2757 System.out.println("Options:");
2758 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
2759 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
2760 System.out.println();
2765 * parseFile() prepares Lexer and Parser objects, then parses the file
2767 public static ParseNode parseFile(String file) {
2769 ParseNode pn = null;
2771 ComplexSymbolFactory csf = new ComplexSymbolFactory();
2772 ScannerBuffer lexer =
2773 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf));
2774 Parser parse = new Parser(lexer,csf);
2775 pn = (ParseNode) parse.parse().value;
2776 } catch (Exception e) {
2777 e.printStackTrace();
2778 throw new Error("IoTCompiler: ERROR parsing policy file or wrong command line option: " + file);
2789 boolean newline=true;
2792 private void print(String str) {
2795 if (str.equals("}"))
2797 for(int i=0; i<tab; i++)
2807 * This function converts Java to C++ type for compilation
2809 private String convertType(String jType) {
2811 return mapPrimitives.get(jType);
2815 private void println(String str) {
2818 if (str.contains("}") && !str.contains("{"))
2820 for(int i=0; i<tab; i++)
2829 private void updatetabbing(String str) {
2831 tablevel+=count(str,'{')-count(str,'}');
2835 private int count(String str, char key) {
2836 char[] array = str.toCharArray();
2838 for(int i=0; i<array.length; i++) {
2839 if (array[i] == key)
2846 private void createDirectory(String dirName) {
2848 File file = new File(dirName);
2849 if (!file.exists()) {
2851 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
2853 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
2856 System.out.println("IoTCompiler: Directory " + dirName + " exists...");
2861 // Create a directory and possibly a sub directory
2862 private String createDirectories(String dir, String subdir) {
2865 createDirectory(path);
2866 if (subdir != null) {
2867 path = path + "/" + subdir;
2868 createDirectory(path);
2874 // Inserting array members into a Map object
2875 // that maps arrKey to arrVal objects
2876 private void arraysToMap(Map map, Object[] arrKey, Object[] arrVal) {
2878 for(int i = 0; i < arrKey.length; i++) {
2880 map.put(arrKey[i], arrVal[i]);
2885 // Return parameter category, i.e. PRIMITIVES, NONPRIMITIVES, or USERDEFINED
2886 private ParamCategory getParamCategory(String paramType) {
2888 if (mapPrimitives.containsKey(paramType)) {
2889 return ParamCategory.PRIMITIVES;
2890 // We can either use mapNonPrimitivesJava or mapNonPrimitivesCplus here
2891 } else if (mapNonPrimitivesJava.containsKey(getSimpleType(paramType))) {
2892 return ParamCategory.NONPRIMITIVES;
2894 return ParamCategory.USERDEFINED;
2898 // Return full class name for non-primitives to generate Java import statements
2899 // e.g. java.util.Set for Set, java.util.Map for Map
2900 private String getNonPrimitiveJavaClass(String paramNonPrimitives) {
2902 return mapNonPrimitivesJava.get(paramNonPrimitives);
2906 // Return full class name for non-primitives to generate Cplus include statements
2907 // e.g. #include <set> for Set, #include <map> for Map
2908 private String getNonPrimitiveCplusClass(String paramNonPrimitives) {
2910 return mapNonPrimitivesCplus.get(paramNonPrimitives);
2914 // Get simple types, e.g. HashSet for HashSet<...>
2915 // Basically strip off the "<...>"
2916 private String getSimpleType(String paramType) {
2918 // Check if this is generics
2919 if(paramType.contains("<")) {
2920 String[] type = paramType.split("<");
2927 // Generate a set of standard classes for import statements
2928 private List<String> getStandardJavaImportClasses() {
2930 List<String> importClasses = new ArrayList<String>();
2931 // Add the standard list first
2932 importClasses.add("java.io.IOException");
2933 importClasses.add("java.util.List");
2934 importClasses.add("java.util.ArrayList");
2935 importClasses.add("java.util.Arrays");
2936 importClasses.add("iotrmi.Java.IoTRMICall");
2937 importClasses.add("iotrmi.Java.IoTRMIObject");
2939 return importClasses;
2943 // Generate a set of standard classes for import statements
2944 private List<String> getStandardCplusIncludeClasses() {
2946 List<String> importClasses = new ArrayList<String>();
2947 // Add the standard list first
2948 importClasses.add("<vector>");
2949 importClasses.add("<set>");
2950 importClasses.add("\"IoTRMICall.hpp\"");
2951 importClasses.add("\"IoTRMIObject.hpp\"");
2953 return importClasses;
2957 // Generate a set of standard classes for import statements
2958 private List<String> getAllLibClasses(Collection<String> stdLibClasses, Collection<String> libClasses) {
2960 List<String> allLibClasses = new ArrayList<String>(stdLibClasses);
2961 // Iterate over the list of import classes
2962 for (String str : libClasses) {
2963 if (!allLibClasses.contains(str)) {
2964 allLibClasses.add(str);
2968 return allLibClasses;
2973 // Generate a set of classes for import statements
2974 private Set<String> getImportClasses(Collection<String> methods, InterfaceDecl intDecl) {
2976 Set<String> importClasses = new HashSet<String>();
2977 for (String method : methods) {
2978 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2979 for (String paramType : methPrmTypes) {
2981 String simpleType = getSimpleType(paramType);
2982 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
2983 importClasses.add(getNonPrimitiveJavaClass(simpleType));
2987 return importClasses;
2991 // Generate a set of classes for include statements
2992 private Set<String> getIncludeClasses(Collection<String> methods, InterfaceDecl intDecl, boolean needExchange) {
2994 Set<String> includeClasses = new HashSet<String>();
2995 for (String method : methods) {
2997 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2998 List<String> methParams = intDecl.getMethodParams(method);
2999 for (int i = 0; i < methPrmTypes.size(); i++) {
3001 String simpleType = getSimpleType(methPrmTypes.get(i));
3002 String param = methParams.get(i);
3003 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
3004 includeClasses.add("<" + getNonPrimitiveCplusClass(simpleType) + ">");
3005 } else if (getParamCategory(simpleType) == ParamCategory.USERDEFINED) {
3006 // For original interface, we need it exchanged... not for stub interfaces
3008 includeClasses.add("\"" + exchangeParamType(simpleType) + ".hpp\"");
3009 includeClasses.add("\"" + exchangeParamType(simpleType) + "_CallbackStub.hpp\"");
3011 includeClasses.add("\"" + simpleType + ".hpp\"");
3012 includeClasses.add("\"" + simpleType + "_CallbackSkeleton.hpp\"");
3014 } else if (param.contains("[]")) {
3015 // Check if this is array for C++; translate into vector
3016 includeClasses.add("<vector>");
3020 return includeClasses;
3024 // Generate a set of callback classes
3025 private Set<String> getCallbackClasses(Collection<String> methods, InterfaceDecl intDecl) {
3027 Set<String> callbackClasses = new HashSet<String>();
3028 for (String method : methods) {
3030 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
3031 List<String> methParams = intDecl.getMethodParams(method);
3032 for (int i = 0; i < methPrmTypes.size(); i++) {
3034 String type = methPrmTypes.get(i);
3035 if (getParamCategory(type) == ParamCategory.USERDEFINED) {
3036 callbackClasses.add(type);
3037 } else if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) {
3038 // Can be a List<...> of callback objects ...
3039 String genericType = getTypeOfGeneric(type)[0];
3040 if (getParamCategory(type) == ParamCategory.USERDEFINED) {
3041 callbackClasses.add(type);
3046 return callbackClasses;
3050 private void printImportStatements(Collection<String> importClasses) {
3052 for(String cls : importClasses) {
3053 println("import " + cls + ";");
3058 private void printIncludeStatements(Collection<String> includeClasses) {
3060 for(String cls : includeClasses) {
3061 println("#include " + cls);
3066 // Get the C++ version of a non-primitive type
3067 // e.g. set for Set and map for Map
3068 // Input nonPrimitiveType has to be generics in format
3069 private String[] getTypeOfGeneric(String nonPrimitiveType) {
3071 // Handle <, >, and , for 2-type generic/template
3072 String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(",");
3077 // This helper function strips off array declaration, e.g. D[] becomes D
3078 private String getSimpleIdentifier(String ident) {
3080 // Handle [ for array declaration
3081 String substr = ident;
3082 if (ident.contains("[]")) {
3083 substr = ident.split("\\[\\]")[0];
3089 private String checkAndGetCplusType(String paramType) {
3091 if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
3092 return convertType(paramType);
3093 } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) {
3095 // Check for generic/template format
3096 if (paramType.contains("<") && paramType.contains(">")) {
3098 String genericClass = getSimpleType(paramType);
3099 String[] genericType = getTypeOfGeneric(paramType);
3100 String cplusTemplate = null;
3101 if (genericType.length == 1) // Generic/template with one type
3102 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
3103 "<" + convertType(genericType[0]) + ">";
3104 else // Generic/template with two types
3105 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
3106 "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">";
3107 return cplusTemplate;
3109 return getNonPrimitiveCplusClass(paramType);
3110 } else if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
3111 return paramType + "*";
3113 // Just return it as is if it's not non-primitives
3115 //return checkAndGetParamClass(paramType, true);
3119 // Detect array declaration, e.g. int A[],
3120 // then generate "int A[]" in C++ as "vector<int> A"
3121 private String checkAndGetCplusArray(String paramType, String param) {
3123 String paramComplete = null;
3124 // Check for array declaration
3125 if (param.contains("[]")) {
3126 paramComplete = "vector<" + paramType + "> " + param.replace("[]","");
3128 // Just return it as is if it's not an array
3129 paramComplete = paramType + " " + param;
3131 return paramComplete;
3135 // Detect array declaration, e.g. int A[],
3136 // then generate "int A[]" in C++ as "vector<int> A"
3137 // This method just returns the type
3138 private String checkAndGetCplusArrayType(String paramType) {
3140 String paramTypeRet = null;
3141 // Check for array declaration
3142 if (paramType.contains("[]")) {
3143 String type = paramType.split("\\[\\]")[0];
3144 paramTypeRet = checkAndGetCplusType(type) + "[]";
3145 } else if (paramType.contains("vector")) {
3146 // Just return it as is if it's not an array
3147 String type = paramType.split("<")[1].split(">")[0];
3148 paramTypeRet = checkAndGetCplusType(type) + "[]";
3150 paramTypeRet = paramType;
3152 return paramTypeRet;
3156 // Detect array declaration, e.g. int A[],
3157 // then generate "int A[]" in C++ as "vector<int> A"
3158 // This method just returns the type
3159 private String checkAndGetCplusArrayType(String paramType, String param) {
3161 String paramTypeRet = null;
3162 // Check for array declaration
3163 if (param.contains("[]")) {
3164 paramTypeRet = checkAndGetCplusType(paramType) + "[]";
3165 } else if (paramType.contains("vector")) {
3166 // Just return it as is if it's not an array
3167 String type = paramType.split("<")[1].split(">")[0];
3168 paramTypeRet = checkAndGetCplusType(type) + "[]";
3170 paramTypeRet = paramType;
3172 return paramTypeRet;
3176 // Detect array declaration, e.g. int A[],
3177 // then generate type "int[]"
3178 private String checkAndGetArray(String paramType, String param) {
3180 String paramTypeRet = null;
3181 // Check for array declaration
3182 if (param.contains("[]")) {
3183 paramTypeRet = paramType + "[]";
3185 // Just return it as is if it's not an array
3186 paramTypeRet = paramType;
3188 return paramTypeRet;
3192 // Is array or list?
3193 private boolean isArrayOrList(String paramType, String param) {
3195 // Check for array declaration
3196 if (isArray(paramType, param))
3198 else if (isList(paramType, param))
3205 // Is array or list?
3206 private boolean isArray(String paramType, String param) {
3208 // Check for array declaration
3209 if (param.contains("[]"))
3216 // Is array or list?
3217 private boolean isList(String paramType, String param) {
3219 // Check for array declaration
3220 if (paramType.contains("List"))
3227 // Get the right type for a callback object
3228 private String checkAndGetParamClass(String paramType) {
3230 // Check if this is generics
3231 if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
3232 return exchangeParamType(paramType);
3238 // Returns the other interface for type-checking purposes for USERDEFINED
3239 // classes based on the information provided in multiple policy files
3240 // e.g. return CameraWithXXX instead of Camera
3241 private String exchangeParamType(String intface) {
3243 // Param type that's passed is the interface name we need to look for
3244 // in the map of interfaces, based on available policy files.
3245 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
3246 if (decHandler != null) {
3247 // We've found the required interface policy files
3248 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(intface);
3249 Set<String> setExchInt = reqDecl.getInterfaces();
3250 if (setExchInt.size() == 1) {
3251 Iterator iter = setExchInt.iterator();
3252 return (String) iter.next();
3254 throw new Error("IoTCompiler: Ambiguous stub interfaces: " + setExchInt.toString() +
3255 ". Only one new interface can be declared if the object " + intface +
3256 " needs to be passed in as an input parameter!");
3259 // NULL value - this means policy files missing
3260 throw new Error("IoTCompiler: Parameter type lookup failed for " + intface +
3261 "... Please provide the necessary policy files for user-defined types." +
3262 " If this is an array please type the brackets after the variable name," +
3263 " e.g. \"String str[]\", not \"String[] str\"." +
3264 " If this is a Collections (Java) / STL (C++) type, this compiler only" +
3265 " supports List/ArrayList (Java) or list (C++).");
3270 public static void main(String[] args) throws Exception {
3272 // If there is no argument or just "--help" or "-h", then invoke printUsage()
3273 if ((args[0].equals("-help") ||
3274 args[0].equals("--help")||
3275 args[0].equals("-h")) ||
3276 (args.length == 0)) {
3278 IoTCompiler.printUsage();
3280 } else if (args.length > 1) {
3282 IoTCompiler comp = new IoTCompiler();
3285 // Parse main policy file
3286 ParseNode pnPol = IoTCompiler.parseFile(args[i]);
3287 // Parse "requires" policy file
3288 ParseNode pnReq = IoTCompiler.parseFile(args[i+1]);
3289 // Get interface name
3290 String intface = ParseTreeHandler.getOrigIntface(pnPol);
3291 comp.setDataStructures(intface, pnPol, pnReq);
3292 comp.getMethodsForIntface(intface);
3294 // 1) Check if this is the last option before "-java" or "-cplus"
3295 // 2) Check if this is really the last option (no "-java" or "-cplus")
3296 } while(!args[i].equals("-java") &&
3297 !args[i].equals("-cplus") &&
3300 // Generate everything if we don't see "-java" or "-cplus"
3301 if (i == args.length) {
3302 comp.generateJavaLocalInterfaces();
3303 comp.generateJavaInterfaces();
3304 comp.generateJavaStubClasses();
3305 comp.generateJavaCallbackStubClasses();
3306 comp.generateJavaSkeletonClass();
3307 comp.generateJavaCallbackSkeletonClass();
3308 comp.generateCplusLocalInterfaces();
3309 comp.generateCPlusInterfaces();
3310 comp.generateCPlusStubClasses();
3311 comp.generateCPlusCallbackStubClasses();
3312 comp.generateCplusSkeletonClass();
3313 comp.generateCplusCallbackSkeletonClass();
3315 // Check other options
3316 while(i < args.length) {
3318 if (!args[i].equals("-java") &&
3319 !args[i].equals("-cplus")) {
3320 throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
3322 if (i + 1 < args.length) {
3323 comp.setDirectory(args[i+1]);
3325 throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
3327 if (args[i].equals("-java")) {
3328 comp.generateJavaLocalInterfaces();
3329 comp.generateJavaInterfaces();
3330 comp.generateJavaStubClasses();
3331 comp.generateJavaCallbackStubClasses();
3332 comp.generateJavaSkeletonClass();
3333 comp.generateJavaCallbackSkeletonClass();
3335 comp.generateCplusLocalInterfaces();
3336 comp.generateCPlusInterfaces();
3337 comp.generateCPlusStubClasses();
3338 comp.generateCPlusCallbackStubClasses();
3339 comp.generateCplusSkeletonClass();
3340 comp.generateCplusCallbackSkeletonClass();
3347 // Need to at least have exactly 2 parameters, i.e. main policy file and requires file
3348 IoTCompiler.printUsage();
3349 throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");