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: writeConstructorJavaStub() writes the constructor of the stub class
420 private void writeConstructorJavaStub(String intface, String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
422 println("public " + newStubClass + "(int _port, String _address, int _rev, int[] _ports) throws Exception {");
423 println("address = _address;");
424 println("ports = _ports;");
425 println("rmiCall = new IoTRMICall(_port, _address, _rev);");
427 Iterator it = callbackClasses.iterator();
428 String callbackType = (String) it.next();
429 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
430 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
431 String newIntface = intMeth.getKey();
432 int newObjectId = mapNewIntfaceObjId.get(newIntface);
433 println("set" + newObjectId + "Allowed = Arrays.asList(object" + newObjectId +"Permission);");
435 println("listCallbackObj = new ArrayList<" + callbackType + ">();");
436 println("___initCallBack();");
443 * HELPER: writeJavaMethodCallbackPermission() writes permission checks in stub for callbacks
445 private void writeJavaMethodCallbackPermission(String intface) {
447 println("int methodId = IoTRMIObject.getMethodId(method);");
448 // Get all the different stubs
449 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
450 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
451 String newIntface = intMeth.getKey();
452 int newObjectId = mapNewIntfaceObjId.get(newIntface);
453 println("if (!set" + newObjectId + "Allowed.contains(methodId)) {");
454 println("throw new Error(\"Callback object for " + intface + " is not allowed to access method: \" + methodId);");
461 * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
463 private void writeInitCallbackJavaStub(String intface, InterfaceDecl intDecl) {
465 println("public void ___initCallBack() {");
466 // Generate main thread for callbacks
467 println("Thread thread = new Thread() {");
468 println("public void run() {");
470 println("rmiObj = new IoTRMIObject(ports[0]);");
471 println("while (true) {");
472 println("byte[] method = rmiObj.getMethodBytes();");
473 writeJavaMethodCallbackPermission(intface);
474 println("int objId = IoTRMIObject.getObjectId(method);");
475 println(intface + "_CallbackSkeleton skel = (" + intface + "_CallbackSkeleton) listCallbackObj.get(objId);");
476 println("if (skel != null) {");
477 println("skel.invokeMethod(rmiObj);");
479 println("throw new Error(\"" + intface + ": Object with Id \" + objId + \" not found!\");");
482 println("} catch (Exception ex) {");
483 println("ex.printStackTrace();");
484 println("throw new Error(\"Error instantiating class " + intface + "_CallbackSkeleton!\");");
488 println("thread.start();\n");
489 // Generate info sending part
490 String method = "___initCallBack()";
491 println("int methodId = " + intDecl.getHelperMethodNumId(method) + ";");
492 println("Class<?> retType = void.class;");
493 println("Class<?>[] paramCls = new Class<?>[] { int.class, String.class, int.class };");
494 println("Object[] paramObj = new Object[] { ports[0], address, 0 };");
495 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
501 * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class
503 private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
504 List<String> methPrmTypes, String method) {
506 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
507 String retType = intDecl.getMethodType(method);
508 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
509 // Generate array of parameter types
510 print("Class<?>[] paramCls = new Class<?>[] { ");
511 for (int i = 0; i < methParams.size(); i++) {
512 String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
513 print(getSimpleType(paramType) + ".class");
514 // Check if this is the last element (don't print a comma)
515 if (i != methParams.size() - 1) {
520 // Generate array of parameter objects
521 print("Object[] paramObj = new Object[] { ");
522 for (int i = 0; i < methParams.size(); i++) {
523 print(getSimpleIdentifier(methParams.get(i)));
524 // Check if this is the last element (don't print a comma)
525 if (i != methParams.size() - 1) {
530 // Check if this is "void"
531 if (retType.equals("void")) {
532 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
533 } else { // We do have a return value
534 // Check if the return value NONPRIMITIVES
535 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
536 String[] retGenValType = getTypeOfGeneric(retType);
537 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
538 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
539 println("return (" + retType + ")retObj;");
541 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
542 println("return (" + retType + ")retObj;");
549 * HELPER: returnGenericCallbackType() returns the callback type
551 private String returnGenericCallbackType(String paramType) {
553 if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES)
554 return getTypeOfGeneric(paramType)[0];
561 * HELPER: checkCallbackType() checks the callback type
563 private boolean checkCallbackType(String paramType, String callbackType) {
565 String prmType = returnGenericCallbackType(paramType);
566 return callbackType.equals(prmType);
571 * HELPER: writeCallbackMethodBodyJavaStub() writes the callback method of the stub class
573 private void writeCallbackMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
574 List<String> methPrmTypes, String method, String callbackType) {
577 // Check if this is single object, array, or list of objects
578 for (int i = 0; i < methParams.size(); i++) {
580 String paramType = methPrmTypes.get(i);
581 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
582 String param = methParams.get(i);
583 if (isArrayOrList(paramType, param)) { // Generate loop
584 println("for (" + paramType + " cb : " + getSimpleIdentifier(param) + ") {");
585 println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);");
587 println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(" +
588 getSimpleIdentifier(param) + ", objIdCnt++);");
589 println("listCallbackObj.add(skel);");
590 if (isArrayOrList(paramType, param))
594 println("} catch (Exception ex) {");
595 println("ex.printStackTrace();");
596 println("throw new Error(\"Exception when generating skeleton objects!\");");
598 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
599 String retType = intDecl.getMethodType(method);
600 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
601 // Generate array of parameter types
602 print("Class<?>[] paramCls = new Class<?>[] { ");
603 for (int i = 0; i < methParams.size(); i++) {
604 String paramType = methPrmTypes.get(i);
605 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
607 } else { // Generate normal classes if it's not a callback object
608 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
609 print(getSimpleType(prmType) + ".class");
611 if (i != methParams.size() - 1) // Check if this is the last element
615 // Generate array of parameter objects
616 print("Object[] paramObj = new Object[] { ");
617 for (int i = 0; i < methParams.size(); i++) {
618 String paramType = methPrmTypes.get(i);
619 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
620 if (isArray(methPrmTypes.get(i), methParams.get(i)))
621 print(getSimpleIdentifier(methParams.get(i)) + ".length");
622 else if (isList(methPrmTypes.get(i), methParams.get(i)))
623 print(getSimpleIdentifier(methParams.get(i)) + ".size()");
625 print("new Integer(1)");
627 print(getSimpleIdentifier(methParams.get(i)));
628 if (i != methParams.size() - 1)
632 // Check if this is "void"
633 if (retType.equals("void")) {
634 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
635 } else { // We do have a return value
636 // Check if the return value NONPRIMITIVES
637 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
638 String[] retGenValType = getTypeOfGeneric(retType);
639 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
640 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
641 println("return (" + retType + ")retObj;");
643 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
644 println("return (" + retType + ")retObj;");
651 * HELPER: writeMethodJavaStub() writes the method of the stub class
653 private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
655 for (String method : methods) {
657 List<String> methParams = intDecl.getMethodParams(method);
658 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
659 print("public " + intDecl.getMethodType(method) + " " +
660 intDecl.getMethodId(method) + "(");
661 boolean isCallbackMethod = false;
662 String callbackType = null;
663 for (int i = 0; i < methParams.size(); i++) {
665 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
666 // Check if this has callback object
667 if (callbackClasses.contains(paramType)) {
668 isCallbackMethod = true;
669 callbackType = paramType;
670 // Even if there're 2 callback arguments, we expect them to be of the same interface
672 print(methPrmTypes.get(i) + " " + methParams.get(i));
673 // Check if this is the last element (don't print a comma)
674 if (i != methParams.size() - 1) {
679 // Now, write the body of stub!
680 if (isCallbackMethod)
681 writeCallbackMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method, callbackType);
683 writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
685 // Write the init callback helper method
686 if (isCallbackMethod)
687 writeInitCallbackJavaStub(callbackType, intDecl);
693 * generateJavaStubClasses() generate stubs based on the methods list in Java
695 public void generateJavaStubClasses() throws IOException {
697 // Create a new directory
698 String path = createDirectories(dir, subdir);
699 for (String intface : mapIntfacePTH.keySet()) {
701 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
702 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
704 // Open a new file to write into
705 String newIntface = intMeth.getKey();
706 String newStubClass = newIntface + "_Stub";
707 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
708 pw = new PrintWriter(new BufferedWriter(fw));
709 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
710 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
711 // Pass in set of methods and get import classes
712 Set<String> methods = intMeth.getValue();
713 Set<String> importClasses = getImportClasses(methods, intDecl);
714 List<String> stdImportClasses = getStandardJavaImportClasses();
715 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
716 printImportStatements(allImportClasses); println("");
717 // Find out if there are callback objects
718 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
719 boolean callbackExist = !callbackClasses.isEmpty();
720 // Write class header
721 println("public class " + newStubClass + " implements " + newIntface + " {\n");
723 writePropertiesJavaStub(intface, newIntface, callbackExist, callbackClasses);
725 writeConstructorJavaStub(intface, newStubClass, callbackExist, callbackClasses);
727 writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses);
730 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
737 * HELPER: writePropertiesJavaCallbackStub() writes the properties of the callback stub class
739 private void writePropertiesJavaCallbackStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
741 println("private IoTRMICall rmiCall;");
742 println("private String address;");
743 println("private int[] ports;\n");
745 println("private static int objectId = 0;");
747 // We assume that each class only has one callback interface for now
748 Iterator it = callbackClasses.iterator();
749 String callbackType = (String) it.next();
750 println("// Callback properties");
751 println("private IoTRMIObject rmiObj;");
752 println("List<" + callbackType + "> listCallbackObj;");
753 println("private static int objIdCnt = 0;");
754 // Generate permission stuff for callback stubs
755 DeclarationHandler decHandler = mapIntDeclHand.get(callbackType);
756 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(callbackType);
757 writePropertiesJavaPermission(callbackType, intDecl);
764 * HELPER: writeConstructorJavaCallbackStub() writes the constructor of the callback stub class
766 private void writeConstructorJavaCallbackStub(String intface, String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
768 // TODO: If we want callback in callback, then we need to add address and port initializations
769 println("public " + newStubClass + "(IoTRMICall _rmiCall, int _objectId) throws Exception {");
770 println("objectId = _objectId;");
771 println("rmiCall = _rmiCall;");
773 Iterator it = callbackClasses.iterator();
774 String callbackType = (String) it.next();
775 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
776 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
777 String newIntface = intMeth.getKey();
778 int newObjectId = mapNewIntfaceObjId.get(newIntface);
779 println("set" + newObjectId + "Allowed = Arrays.asList(object" + newObjectId +"Permission);");
781 println("listCallbackObj = new ArrayList<" + callbackType + ">();");
782 println("___initCallBack();");
783 println("// TODO: Add address and port initialization here if we want callback in callback!");
790 * generateJavaCallbackStubClasses() generate callback stubs based on the methods list in Java
792 * Callback stubs gets the IoTRMICall objects from outside of the class as contructor input
793 * because all these stubs are populated by the class that takes in this object as a callback
794 * object. In such a class, we only use one socket, hence one IoTRMICall, for all callback objects.
796 public void generateJavaCallbackStubClasses() throws IOException {
798 // Create a new directory
799 String path = createDirectories(dir, subdir);
800 for (String intface : mapIntfacePTH.keySet()) {
802 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
803 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
805 // Open a new file to write into
806 String newIntface = intMeth.getKey();
807 String newStubClass = newIntface + "_CallbackStub";
808 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
809 pw = new PrintWriter(new BufferedWriter(fw));
810 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
811 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
812 // Pass in set of methods and get import classes
813 Set<String> methods = intMeth.getValue();
814 Set<String> importClasses = getImportClasses(methods, intDecl);
815 List<String> stdImportClasses = getStandardJavaImportClasses();
816 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
817 printImportStatements(allImportClasses); println("");
818 // Find out if there are callback objects
819 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
820 boolean callbackExist = !callbackClasses.isEmpty();
821 // Write class header
822 println("public class " + newStubClass + " implements " + newIntface + " {\n");
824 writePropertiesJavaCallbackStub(intface, newIntface, callbackExist, callbackClasses);
826 writeConstructorJavaCallbackStub(intface, newStubClass, callbackExist, callbackClasses);
828 // TODO: perhaps need to generate callback for callback
829 writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses);
832 System.out.println("IoTCompiler: Generated callback stub class " + newStubClass + ".java...");
839 * HELPER: writePropertiesJavaSkeleton() writes the properties of the skeleton class
841 private void writePropertiesJavaSkeleton(String intface, boolean callbackExist, InterfaceDecl intDecl) {
843 println("private " + intface + " mainObj;");
844 //println("private int ports;");
845 println("private IoTRMIObject rmiObj;\n");
848 println("private static int objIdCnt = 0;");
849 println("private IoTRMICall rmiCall;");
851 writePropertiesJavaPermission(intface, intDecl);
857 * HELPER: writeConstructorJavaSkeleton() writes the constructor of the skeleton class
859 private void writeConstructorJavaSkeleton(String newSkelClass, String intface) {
861 println("public " + newSkelClass + "(" + intface + " _mainObj, int _port) throws Exception {");
862 println("mainObj = _mainObj;");
863 println("rmiObj = new IoTRMIObject(_port);");
864 // Generate permission control initialization
865 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
866 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
867 String newIntface = intMeth.getKey();
868 int newObjectId = mapNewIntfaceObjId.get(newIntface);
869 println("set" + newObjectId + "Allowed = Arrays.asList(object" + newObjectId +"Permission);");
871 println("___waitRequestInvokeMethod();");
877 * HELPER: writeStdMethodBodyJavaSkeleton() writes the standard method body in the skeleton class
879 private void writeStdMethodBodyJavaSkeleton(List<String> methParams, String methodId, String methodType) {
881 if (methodType.equals("void"))
882 print("mainObj." + methodId + "(");
884 print("return mainObj." + methodId + "(");
885 for (int i = 0; i < methParams.size(); i++) {
887 print(getSimpleIdentifier(methParams.get(i)));
888 // Check if this is the last element (don't print a comma)
889 if (i != methParams.size() - 1) {
898 * HELPER: writeInitCallbackJavaSkeleton() writes the init callback method for skeleton class
900 private void writeInitCallbackJavaSkeleton(boolean callbackSkeleton) {
902 // This is a callback skeleton generation
903 if (callbackSkeleton)
904 println("public void ___regCB(IoTRMIObject rmiObj) throws IOException {");
906 println("public void ___regCB() throws IOException {");
907 println("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class, String.class, int.class },");
908 println("\tnew Class<?>[] { null, null, null });");
909 println("rmiCall = new IoTRMICall((int) paramObj[0], (String) paramObj[1], (int) paramObj[2]);");
915 * HELPER: writeMethodJavaSkeleton() writes the method of the skeleton class
917 private void writeMethodJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses,
918 boolean callbackSkeleton) {
920 for (String method : methods) {
922 List<String> methParams = intDecl.getMethodParams(method);
923 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
924 String methodId = intDecl.getMethodId(method);
925 print("public " + intDecl.getMethodType(method) + " " + methodId + "(");
926 boolean isCallbackMethod = false;
927 String callbackType = null;
928 for (int i = 0; i < methParams.size(); i++) {
930 String origParamType = methPrmTypes.get(i);
931 String paramType = checkAndGetParamClass(origParamType);
932 if (callbackClasses.contains(origParamType)) { // Check if this has callback object
933 isCallbackMethod = true;
934 callbackType = origParamType;
936 print(paramType + " " + methParams.get(i));
937 // Check if this is the last element (don't print a comma)
938 if (i != methParams.size() - 1) {
943 // Now, write the body of skeleton!
944 writeStdMethodBodyJavaSkeleton(methParams, methodId, intDecl.getMethodType(method));
946 if (isCallbackMethod)
947 writeInitCallbackJavaSkeleton(callbackSkeleton);
953 * HELPER: writeCallbackJavaStubGeneration() writes the callback stub generation part
955 private Map<Integer,String> writeCallbackJavaStubGeneration(List<String> methParams, List<String> methPrmTypes, String callbackType) {
957 Map<Integer,String> mapStubParam = new HashMap<Integer,String>();
958 // Iterate over callback objects
959 for (int i = 0; i < methParams.size(); i++) {
960 String paramType = methPrmTypes.get(i);
961 String param = methParams.get(i);
962 //if (callbackType.equals(paramType)) {
963 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
965 String exchParamType = checkAndGetParamClass(paramType);
966 // Print array if this is array or list if this is a list of callback objects
967 if (isArray(paramType, param)) {
968 println("int numStubs" + i + " = (int) paramObj[" + i + "];");
969 println(exchParamType + "[] stub" + i + " = new " + exchParamType + "[numStubs" + i + "];");
970 } else if (isList(paramType, param)) {
971 println("int numStubs" + i + " = (int) paramObj[" + i + "];");
972 println("List<" + exchParamType + "> stub" + i + " = new ArrayList<" + exchParamType + ">();");
974 println(exchParamType + " stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
975 println("objIdCnt++;");
978 // Generate a loop if needed
979 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
980 String exchParamType = checkAndGetParamClass(paramType);
981 if (isArray(paramType, param)) {
982 println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
983 println("stub" + i + "[objId] = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
984 println("objIdCnt++;");
986 } else if (isList(paramType, param)) {
987 println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
988 println("stub" + i + ".add(new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt));");
989 println("objIdCnt++;");
992 mapStubParam.put(i, "stub" + i); // List of all stub parameters
1000 * HELPER: writeStdMethodHelperBodyJavaSkeleton() writes the standard method body helper in the skeleton class
1002 private void writeStdMethodHelperBodyJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
1003 List<String> methPrmTypes, String method, Set<String> callbackClasses) {
1004 // Generate array of parameter objects
1005 boolean isCallbackMethod = false;
1006 String callbackType = null;
1007 print("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { ");
1008 for (int i = 0; i < methParams.size(); i++) {
1010 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
1011 if (callbackClasses.contains(paramType)) {
1012 isCallbackMethod = true;
1013 callbackType = paramType;
1015 } else { // Generate normal classes if it's not a callback object
1016 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
1017 print(getSimpleType(prmType) + ".class");
1019 if (i != methParams.size() - 1)
1023 // Generate generic class if it's a generic type.. null otherwise
1024 print("new Class<?>[] { ");
1025 for (int i = 0; i < methParams.size(); i++) {
1026 String prmType = methPrmTypes.get(i);
1027 if (getParamCategory(prmType) == ParamCategory.NONPRIMITIVES)
1028 print(getTypeOfGeneric(prmType)[0] + ".class");
1031 if (i != methParams.size() - 1)
1035 Map<Integer,String> mapStubParam = null;
1036 if (isCallbackMethod)
1037 mapStubParam = writeCallbackJavaStubGeneration(methParams, methPrmTypes, callbackType);
1038 // Check if this is "void"
1039 String retType = intDecl.getMethodType(method);
1040 if (retType.equals("void")) {
1041 print(intDecl.getMethodId(method) + "(");
1042 } else { // We do have a return value
1043 print("Object retObj = " + intDecl.getMethodId(method) + "(");
1045 for (int i = 0; i < methParams.size(); i++) {
1047 if (isCallbackMethod) {
1048 print(mapStubParam.get(i)); // Get the callback parameter
1050 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
1051 print("(" + prmType + ") paramObj[" + i + "]");
1053 if (i != methParams.size() - 1)
1057 if (!retType.equals("void"))
1058 println("rmiObj.sendReturnObj(retObj);");
1059 if (isCallbackMethod) { // Catch exception if this is callback
1060 println("} catch(Exception ex) {");
1061 println("ex.printStackTrace();");
1062 println("throw new Error(\"Exception from callback object instantiation!\");");
1069 * HELPER: writeMethodHelperJavaSkeleton() writes the method helper of the skeleton class
1071 private void writeMethodHelperJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1073 // Use this set to handle two same methodIds
1074 Set<String> uniqueMethodIds = new HashSet<String>();
1075 for (String method : methods) {
1077 List<String> methParams = intDecl.getMethodParams(method);
1078 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1079 String methodId = intDecl.getMethodId(method);
1080 print("public void ___");
1081 String helperMethod = methodId;
1082 if (uniqueMethodIds.contains(methodId))
1083 helperMethod = helperMethod + intDecl.getMethodNumId(method);
1085 uniqueMethodIds.add(methodId);
1086 // Check if this is "void"
1087 String retType = intDecl.getMethodType(method);
1088 if (retType.equals("void"))
1089 println(helperMethod + "() {");
1091 println(helperMethod + "() throws IOException {");
1092 // Now, write the helper body of skeleton!
1093 writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
1100 * HELPER: writeJavaMethodPermission() writes permission checks in skeleton
1102 private void writeJavaMethodPermission(String intface) {
1104 // Get all the different stubs
1105 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1106 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1107 String newIntface = intMeth.getKey();
1108 int newObjectId = mapNewIntfaceObjId.get(newIntface);
1109 println("if (_objectId == object" + newObjectId + "Id) {");
1110 println("if (!set" + newObjectId + "Allowed.contains(methodId)) {");
1111 println("throw new Error(\"Object with object Id: \" + _objectId + \" is not allowed to access method: \" + methodId);");
1114 println("throw new Error(\"Object Id: \" + _objectId + \" not recognized!\");");
1122 * HELPER: writeJavaWaitRequestInvokeMethod() writes the main loop of the skeleton class
1124 private void writeJavaWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist, String intface) {
1126 // Use this set to handle two same methodIds
1127 Set<String> uniqueMethodIds = new HashSet<String>();
1128 println("private void ___waitRequestInvokeMethod() throws IOException {");
1129 // Write variables here if we have callbacks or enums or structs
1130 println("while (true) {");
1131 println("rmiObj.getMethodBytes();");
1132 println("int _objectId = rmiObj.getObjectId();");
1133 println("int methodId = rmiObj.getMethodId();");
1134 // Generate permission check
1135 writeJavaMethodPermission(intface);
1136 println("switch (methodId) {");
1137 // Print methods and method Ids
1138 for (String method : methods) {
1139 String methodId = intDecl.getMethodId(method);
1140 int methodNumId = intDecl.getMethodNumId(method);
1141 print("case " + methodNumId + ": ___");
1142 String helperMethod = methodId;
1143 if (uniqueMethodIds.contains(methodId))
1144 helperMethod = helperMethod + methodNumId;
1146 uniqueMethodIds.add(methodId);
1147 println(helperMethod + "(); break;");
1149 String method = "___initCallBack()";
1150 // Print case -9999 (callback handler) if callback exists
1151 if (callbackExist) {
1152 int methodId = intDecl.getHelperMethodNumId(method);
1153 println("case " + methodId + ": ___regCB(); break;");
1155 println("default: ");
1156 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
1164 * generateJavaSkeletonClass() generate skeletons based on the methods list in Java
1166 public void generateJavaSkeletonClass() throws IOException {
1168 // Create a new directory
1169 String path = createDirectories(dir, subdir);
1170 for (String intface : mapIntfacePTH.keySet()) {
1171 // Open a new file to write into
1172 String newSkelClass = intface + "_Skeleton";
1173 FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
1174 pw = new PrintWriter(new BufferedWriter(fw));
1175 // Pass in set of methods and get import classes
1176 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1177 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1178 List<String> methods = intDecl.getMethods();
1179 Set<String> importClasses = getImportClasses(methods, intDecl);
1180 List<String> stdImportClasses = getStandardJavaImportClasses();
1181 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
1182 printImportStatements(allImportClasses);
1183 // Find out if there are callback objects
1184 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1185 boolean callbackExist = !callbackClasses.isEmpty();
1186 // Write class header
1188 println("public class " + newSkelClass + " implements " + intface + " {\n");
1190 writePropertiesJavaSkeleton(intface, callbackExist, intDecl);
1191 // Write constructor
1192 writeConstructorJavaSkeleton(newSkelClass, intface);
1194 writeMethodJavaSkeleton(methods, intDecl, callbackClasses, false);
1195 // Write method helper
1196 writeMethodHelperJavaSkeleton(methods, intDecl, callbackClasses);
1197 // Write waitRequestInvokeMethod() - main loop
1198 writeJavaWaitRequestInvokeMethod(methods, intDecl, callbackExist, intface);
1201 System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".java...");
1207 * HELPER: writePropertiesJavaCallbackSkeleton() writes the properties of the callback skeleton class
1209 private void writePropertiesJavaCallbackSkeleton(String intface, boolean callbackExist) {
1211 println("private " + intface + " mainObj;");
1212 // For callback skeletons, this is its own object Id
1213 println("private static int objectId = 0;");
1215 if (callbackExist) {
1216 println("private static int objIdCnt = 0;");
1217 println("private IoTRMICall rmiCall;");
1224 * HELPER: writeConstructorJavaCallbackSkeleton() writes the constructor of the skeleton class
1226 private void writeConstructorJavaCallbackSkeleton(String newSkelClass, String intface) {
1228 println("public " + newSkelClass + "(" + intface + " _mainObj, int _objectId) throws Exception {");
1229 println("mainObj = _mainObj;");
1230 println("objectId = _objectId;");
1236 * HELPER: writeMethodHelperJavaCallbackSkeleton() writes the method helper of the callback skeleton class
1238 private void writeMethodHelperJavaCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1240 // Use this set to handle two same methodIds
1241 Set<String> uniqueMethodIds = new HashSet<String>();
1242 for (String method : methods) {
1244 List<String> methParams = intDecl.getMethodParams(method);
1245 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1246 String methodId = intDecl.getMethodId(method);
1247 print("public void ___");
1248 String helperMethod = methodId;
1249 if (uniqueMethodIds.contains(methodId))
1250 helperMethod = helperMethod + intDecl.getMethodNumId(method);
1252 uniqueMethodIds.add(methodId);
1253 // Check if this is "void"
1254 String retType = intDecl.getMethodType(method);
1255 if (retType.equals("void"))
1256 println(helperMethod + "(IoTRMIObject rmiObj) {");
1258 println(helperMethod + "(IoTRMIObject rmiObj) throws IOException {");
1259 // Now, write the helper body of skeleton!
1260 writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
1267 * HELPER: writeJavaCallbackWaitRequestInvokeMethod() writes the main loop of the skeleton class
1269 private void writeJavaCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist) {
1271 // Use this set to handle two same methodIds
1272 Set<String> uniqueMethodIds = new HashSet<String>();
1273 println("public void invokeMethod(IoTRMIObject rmiObj) throws IOException {");
1274 // Write variables here if we have callbacks or enums or structs
1275 println("int methodId = rmiObj.getMethodId();");
1276 // TODO: code the permission check here!
1277 println("switch (methodId) {");
1278 // Print methods and method Ids
1279 for (String method : methods) {
1280 String methodId = intDecl.getMethodId(method);
1281 int methodNumId = intDecl.getMethodNumId(method);
1282 print("case " + methodNumId + ": ___");
1283 String helperMethod = methodId;
1284 if (uniqueMethodIds.contains(methodId))
1285 helperMethod = helperMethod + methodNumId;
1287 uniqueMethodIds.add(methodId);
1288 println(helperMethod + "(rmiObj); break;");
1290 String method = "___initCallBack()";
1291 // Print case -9999 (callback handler) if callback exists
1292 if (callbackExist) {
1293 int methodId = intDecl.getHelperMethodNumId(method);
1294 println("case " + methodId + ": ___regCB(rmiObj); break;");
1296 println("default: ");
1297 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
1304 * generateJavaCallbackSkeletonClass() generate callback skeletons based on the methods list in Java
1306 public void generateJavaCallbackSkeletonClass() throws IOException {
1308 // Create a new directory
1309 String path = createDirectories(dir, subdir);
1310 for (String intface : mapIntfacePTH.keySet()) {
1311 // Open a new file to write into
1312 String newSkelClass = intface + "_CallbackSkeleton";
1313 FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
1314 pw = new PrintWriter(new BufferedWriter(fw));
1315 // Pass in set of methods and get import classes
1316 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1317 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1318 List<String> methods = intDecl.getMethods();
1319 Set<String> importClasses = getImportClasses(methods, intDecl);
1320 List<String> stdImportClasses = getStandardJavaImportClasses();
1321 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
1322 printImportStatements(allImportClasses);
1323 // Find out if there are callback objects
1324 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1325 boolean callbackExist = !callbackClasses.isEmpty();
1326 // Write class header
1328 println("public class " + newSkelClass + " implements " + intface + " {\n");
1330 writePropertiesJavaCallbackSkeleton(intface, callbackExist);
1331 // Write constructor
1332 writeConstructorJavaCallbackSkeleton(newSkelClass, intface);
1334 writeMethodJavaSkeleton(methods, intDecl, callbackClasses, true);
1335 // Write method helper
1336 writeMethodHelperJavaCallbackSkeleton(methods, intDecl, callbackClasses);
1337 // Write waitRequestInvokeMethod() - main loop
1338 writeJavaCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist);
1341 System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".java...");
1347 * HELPER: writeMethodCplusLocalInterface() writes the method of the interface
1349 private void writeMethodCplusLocalInterface(Collection<String> methods, InterfaceDecl intDecl) {
1351 for (String method : methods) {
1353 List<String> methParams = intDecl.getMethodParams(method);
1354 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1355 print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
1356 intDecl.getMethodId(method) + "(");
1357 for (int i = 0; i < methParams.size(); i++) {
1358 // Check for params with driver class types and exchange it
1359 // with its remote interface
1360 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
1361 paramType = checkAndGetCplusType(paramType);
1362 // Check for arrays - translate into vector in C++
1363 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
1364 print(paramComplete);
1365 // Check if this is the last element (don't print a comma)
1366 if (i != methParams.size() - 1) {
1376 * HELPER: writeMethodCplusInterface() writes the method of the interface
1378 private void writeMethodCplusInterface(Collection<String> methods, InterfaceDecl intDecl) {
1380 for (String method : methods) {
1382 List<String> methParams = intDecl.getMethodParams(method);
1383 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1384 print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
1385 intDecl.getMethodId(method) + "(");
1386 for (int i = 0; i < methParams.size(); i++) {
1387 // Check for params with driver class types and exchange it
1388 // with its remote interface
1389 String paramType = methPrmTypes.get(i);
1390 paramType = checkAndGetCplusType(paramType);
1391 // Check for arrays - translate into vector in C++
1392 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
1393 print(paramComplete);
1394 // Check if this is the last element (don't print a comma)
1395 if (i != methParams.size() - 1) {
1405 * HELPER: writeEnumCplus() writes the enumeration declaration
1407 private void writeEnumCplus(EnumDecl enumDecl) {
1409 Set<String> enumTypes = enumDecl.getEnumDeclarations();
1410 // Iterate over enum declarations
1411 for (String enType : enumTypes) {
1413 println("enum " + enType + " {");
1414 List<String> enumMembers = enumDecl.getMembers(enType);
1415 for (int i = 0; i < enumMembers.size(); i++) {
1417 String member = enumMembers.get(i);
1419 // Check if this is the last element (don't print a comma)
1420 if (i != enumMembers.size() - 1)
1431 * HELPER: writeStructCplus() writes the struct declaration
1433 private void writeStructCplus(StructDecl structDecl) {
1435 List<String> structTypes = structDecl.getStructTypes();
1436 // Iterate over enum declarations
1437 for (String stType : structTypes) {
1439 println("struct " + stType + " {");
1440 List<String> structMemberTypes = structDecl.getMemberTypes(stType);
1441 List<String> structMembers = structDecl.getMembers(stType);
1442 for (int i = 0; i < structMembers.size(); i++) {
1444 String memberType = structMemberTypes.get(i);
1445 String member = structMembers.get(i);
1446 String structTypeC = checkAndGetCplusType(memberType);
1447 String structComplete = checkAndGetCplusArray(structTypeC, member);
1448 println(structComplete + ";");
1456 * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking.
1458 * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
1459 * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
1460 * The local interface has to be the input parameter for the stub and the stub
1461 * interface has to be the input parameter for the local class.
1463 public void generateCplusLocalInterfaces() throws IOException {
1465 // Create a new directory
1466 createDirectory(dir);
1467 for (String intface : mapIntfacePTH.keySet()) {
1468 // Open a new file to write into
1469 FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
1470 pw = new PrintWriter(new BufferedWriter(fw));
1471 // Write file headers
1472 println("#ifndef _" + intface.toUpperCase() + "_HPP__");
1473 println("#define _" + intface.toUpperCase() + "_HPP__");
1474 println("#include <iostream>");
1475 // Pass in set of methods and get include classes
1476 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1477 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1478 List<String> methods = intDecl.getMethods();
1479 Set<String> includeClasses = getIncludeClasses(methods, intDecl, true);
1480 printIncludeStatements(includeClasses); println("");
1481 println("using namespace std;\n");
1482 // Write enum if any...
1483 EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface);
1484 writeEnumCplus(enumDecl);
1485 // Write struct if any...
1486 StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
1487 writeStructCplus(structDecl);
1488 println("class " + intface); println("{");
1491 writeMethodCplusLocalInterface(methods, intDecl);
1495 System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
1501 * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
1503 * For C++ we use virtual classe as interface
1505 public void generateCPlusInterfaces() throws IOException {
1507 // Create a new directory
1508 String path = createDirectories(dir, subdir);
1509 for (String intface : mapIntfacePTH.keySet()) {
1511 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1512 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1514 // Open a new file to write into
1515 String newIntface = intMeth.getKey();
1516 FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp");
1517 pw = new PrintWriter(new BufferedWriter(fw));
1518 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1519 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1520 // Write file headers
1521 println("#ifndef _" + newIntface.toUpperCase() + "_HPP__");
1522 println("#define _" + newIntface.toUpperCase() + "_HPP__");
1523 println("#include <iostream>");
1524 // Pass in set of methods and get import classes
1525 Set<String> includeClasses = getIncludeClasses(intMeth.getValue(), intDecl, false);
1526 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
1527 List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
1528 printIncludeStatements(allIncludeClasses); println("");
1529 println("using namespace std;\n");
1530 println("class " + newIntface);
1534 writeMethodCplusInterface(intMeth.getValue(), intDecl);
1538 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
1545 * HELPER: writeMethodCplusStub() writes the method of the stub
1547 private void writeMethodCplusStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1549 for (String method : methods) {
1551 List<String> methParams = intDecl.getMethodParams(method);
1552 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1553 print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
1554 intDecl.getMethodId(method) + "(");
1555 boolean isCallbackMethod = false;
1556 String callbackType = null;
1557 for (int i = 0; i < methParams.size(); i++) {
1559 String paramType = methPrmTypes.get(i);
1560 // Check if this has callback object
1561 if (callbackClasses.contains(paramType)) {
1562 isCallbackMethod = true;
1563 callbackType = paramType;
1564 // Even if there're 2 callback arguments, we expect them to be of the same interface
1566 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
1567 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
1568 print(methParamComplete);
1569 // Check if this is the last element (don't print a comma)
1570 if (i != methParams.size() - 1) {
1575 if (isCallbackMethod)
1576 writeCallbackMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method, callbackType);
1578 writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method);
1580 // Write the init callback helper method
1581 if (isCallbackMethod) {
1582 writeInitCallbackCplusStub(callbackType, intDecl);
1583 writeInitCallbackSendInfoCplusStub(intDecl);
1590 * HELPER: writeCallbackMethodBodyCplusStub() writes the callback method of the stub class
1592 private void writeCallbackMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
1593 List<String> methPrmTypes, String method, String callbackType) {
1595 // Check if this is single object, array, or list of objects
1596 boolean isArrayOrList = false;
1597 String callbackParam = null;
1598 for (int i = 0; i < methParams.size(); i++) {
1600 String paramType = methPrmTypes.get(i);
1601 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1602 String param = methParams.get(i);
1603 if (isArrayOrList(paramType, param)) { // Generate loop
1604 println("for (" + paramType + "* cb : " + getSimpleIdentifier(param) + ") {");
1605 println(callbackType + "_CallbackSkeleton* skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);");
1606 isArrayOrList = true;
1607 callbackParam = getSimpleIdentifier(param);
1609 println(callbackType + "_CallbackSkeleton* skel = new " + callbackType + "_CallbackSkeleton(" +
1610 getSimpleIdentifier(param) + ", objIdCnt++);");
1611 println("vecCallbackObj.push_back(skel);");
1612 if (isArrayOrList(paramType, param))
1616 println("int numParam = " + methParams.size() + ";");
1617 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
1618 String retType = intDecl.getMethodType(method);
1619 String retTypeC = checkAndGetCplusType(retType);
1620 println("string retType = \"" + checkAndGetCplusArrayType(retTypeC) + "\";");
1621 // Generate array of parameter types
1622 print("string paramCls[] = { ");
1623 for (int i = 0; i < methParams.size(); i++) {
1624 String paramType = methPrmTypes.get(i);
1625 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1627 } else { // Generate normal classes if it's not a callback object
1628 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
1629 String prmType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
1630 print("\"" + prmType + "\"");
1632 if (i != methParams.size() - 1) // Check if this is the last element
1636 print("int ___paramCB = ");
1638 println(callbackParam + ".size();");
1641 // Generate array of parameter objects
1642 print("void* paramObj[] = { ");
1643 for (int i = 0; i < methParams.size(); i++) {
1644 String paramType = methPrmTypes.get(i);
1645 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1646 print("&___paramCB");
1648 print(getSimpleIdentifier(methParams.get(i)));
1649 if (i != methParams.size() - 1)
1653 // Check if this is "void"
1654 if (retType.equals("void")) {
1655 println("void* retObj = NULL;");
1656 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1657 } else { // We do have a return value
1658 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
1659 println(checkAndGetCplusType(retType) + " retVal;");
1661 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
1662 println("void* retObj = &retVal;");
1663 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1664 println("return retVal;");
1670 * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class
1672 private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
1673 List<String> methPrmTypes, String method) {
1675 println("int numParam = " + methParams.size() + ";");
1676 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
1677 String retType = intDecl.getMethodType(method);
1678 String retTypeC = checkAndGetCplusType(retType);
1679 println("string retType = \"" + checkAndGetCplusArrayType(retTypeC) + "\";");
1680 // Generate array of parameter types
1681 print("string paramCls[] = { ");
1682 for (int i = 0; i < methParams.size(); i++) {
1683 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
1684 String paramType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
1685 print("\"" + paramType + "\"");
1686 // Check if this is the last element (don't print a comma)
1687 if (i != methParams.size() - 1) {
1692 // Generate array of parameter objects
1693 print("void* paramObj[] = { ");
1694 for (int i = 0; i < methParams.size(); i++) {
1695 print("&" + getSimpleIdentifier(methParams.get(i)));
1696 // Check if this is the last element (don't print a comma)
1697 if (i != methParams.size() - 1) {
1702 // Check if this is "void"
1703 if (retType.equals("void")) {
1704 println("void* retObj = NULL;");
1705 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1706 } else { // We do have a return value
1707 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
1708 println(checkAndGetCplusType(retType) + " retVal;");
1710 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
1711 println("void* retObj = &retVal;");
1712 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1713 println("return retVal;");
1719 * HELPER: writePropertiesCplusStub() writes the properties of the stub class
1721 private void writePropertiesCplusPermission(String intface) {
1723 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1724 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1725 String newIntface = intMeth.getKey();
1726 int newObjectId = mapNewIntfaceObjId.get(newIntface);
1727 println("const static int object" + newObjectId + "Id = " + newObjectId + ";");
1728 println("const static set<int> set" + newObjectId + "Allowed;");
1733 * HELPER: writePropertiesCplusStub() writes the properties of the stub class
1735 private void writePropertiesCplusStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
1737 println("IoTRMICall *rmiCall;");
1738 //println("IoTRMIObject\t\t\t*rmiObj;");
1739 println("string address;");
1740 println("vector<int> ports;\n");
1741 // Get the object Id
1742 Integer objId = mapIntfaceObjId.get(intface);
1743 println("const static int objectId = " + objId + ";");
1744 mapNewIntfaceObjId.put(newIntface, objId);
1745 mapIntfaceObjId.put(intface, objId++);
1746 if (callbackExist) {
1747 // We assume that each class only has one callback interface for now
1748 Iterator it = callbackClasses.iterator();
1749 String callbackType = (String) it.next();
1750 println("// Callback properties");
1751 println("IoTRMIObject *rmiObj;");
1752 println("vector<" + callbackType + "*> vecCallbackObj;");
1753 println("static int objIdCnt;");
1754 // Generate permission stuff for callback stubs
1755 writePropertiesCplusPermission(callbackType);
1762 * HELPER: writeConstructorCplusStub() writes the constructor of the stub class
1764 private void writeConstructorCplusStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1766 println(newStubClass +
1767 "(int _port, const char* _address, int _rev, bool* _bResult, vector<int> _ports) {");
1768 println("address = _address;");
1769 println("ports = _ports;");
1770 println("rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);");
1771 if (callbackExist) {
1772 println("objIdCnt = 0;");
1773 Iterator it = callbackClasses.iterator();
1774 String callbackType = (String) it.next();
1775 println("thread th1 (&" + newStubClass + "::___initCallBack, this);");
1776 println("th1.detach();");
1777 println("___regCB();");
1784 * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
1786 private void writeDeconstructorCplusStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1788 println("~" + newStubClass + "() {");
1789 println("if (rmiCall != NULL) {");
1790 println("delete rmiCall;");
1791 println("rmiCall = NULL;");
1793 if (callbackExist) {
1794 // We assume that each class only has one callback interface for now
1795 println("if (rmiObj != NULL) {");
1796 println("delete rmiObj;");
1797 println("rmiObj = NULL;");
1799 Iterator it = callbackClasses.iterator();
1800 String callbackType = (String) it.next();
1801 println("for(" + callbackType + "* cb : vecCallbackObj) {");
1802 println("delete cb;");
1803 println("cb = NULL;");
1812 * HELPER: writeCplusMethodCallbackPermission() writes permission checks in stub for callbacks
1814 private void writeCplusMethodCallbackPermission(String intface) {
1816 println("int methodId = IoTRMIObject::getMethodId(method);");
1817 // Get all the different stubs
1818 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1819 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1820 String newIntface = intMeth.getKey();
1821 int newObjectId = mapNewIntfaceObjId.get(newIntface);
1822 println("if (set" + newObjectId + "Allowed.find(methodId) == set" + newObjectId + "Allowed.end()) {");
1823 println("cerr << \"Callback object for " + intface + " is not allowed to access method: \" << methodId;");
1824 println("exit(-1);");
1831 * HELPER: writeInitCallbackCplusStub() writes the initialization of callback
1833 private void writeInitCallbackCplusStub(String intface, InterfaceDecl intDecl) {
1835 println("void ___initCallBack() {");
1836 println("bool bResult = false;");
1837 println("rmiObj = new IoTRMIObject(ports[0], &bResult);");
1838 println("while (true) {");
1839 println("char* method = rmiObj->getMethodBytes();");
1840 writeCplusMethodCallbackPermission(intface);
1841 println("int objId = IoTRMIObject::getObjectId(method);");
1842 println("if (objId < vecCallbackObj.size()) { // Check if still within range");
1843 println(intface + "_CallbackSkeleton* skel = dynamic_cast<" + intface +
1844 "_CallbackSkeleton*> (vecCallbackObj.at(objId));");
1845 println("skel->invokeMethod(rmiObj);");
1846 println("} else {");
1847 println("cerr << \"Illegal object Id: \" << to_string(objId);");
1848 // TODO: perhaps need to change this into "throw" to make it cleaner (allow stack unfolding)
1849 println("exit(-1);");
1857 * HELPER: writeInitCallbackSendInfoCplusStub() writes the initialization of callback
1859 private void writeInitCallbackSendInfoCplusStub(InterfaceDecl intDecl) {
1861 // Generate info sending part
1862 println("void ___regCB() {");
1863 println("int numParam = 3;");
1864 String method = "___initCallBack()";
1865 println("int methodId = " + intDecl.getHelperMethodNumId(method) + ";");
1866 println("string retType = \"void\";");
1867 println("string paramCls[] = { \"int\", \"string\", \"int\" };");
1868 println("int rev = 0;");
1869 println("void* paramObj[] = { &ports[0], &address, &rev };");
1870 println("void* retObj = NULL;");
1871 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1877 * generateCPlusStubClasses() generate stubs based on the methods list in C++
1879 public void generateCPlusStubClasses() throws IOException {
1881 // Create a new directory
1882 String path = createDirectories(dir, subdir);
1883 for (String intface : mapIntfacePTH.keySet()) {
1885 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1886 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1887 // Open a new file to write into
1888 String newIntface = intMeth.getKey();
1889 String newStubClass = newIntface + "_Stub";
1890 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
1891 pw = new PrintWriter(new BufferedWriter(fw));
1892 // Write file headers
1893 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
1894 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
1895 println("#include <iostream>");
1896 // Find out if there are callback objects
1897 Set<String> methods = intMeth.getValue();
1898 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1899 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1900 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1901 boolean callbackExist = !callbackClasses.isEmpty();
1902 if (callbackExist) // Need thread library if this has callback
1903 println("#include <thread>");
1904 println("#include \"" + newIntface + ".hpp\""); println("");
1905 println("using namespace std;"); println("");
1906 println("class " + newStubClass + " : public " + newIntface); println("{");
1907 println("private:\n");
1908 writePropertiesCplusStub(intface, newIntface, callbackExist, callbackClasses);
1909 println("public:\n");
1910 // Add default constructor and destructor
1911 println(newStubClass + "() { }"); println("");
1912 writeConstructorCplusStub(newStubClass, callbackExist, callbackClasses);
1913 writeDeconstructorCplusStub(newStubClass, callbackExist, callbackClasses);
1915 writeMethodCplusStub(methods, intDecl, callbackClasses);
1916 print("}"); println(";");
1918 writePermissionInitializationCplus(intface, newStubClass, intDecl);
1921 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".hpp...");
1928 * HELPER: writePropertiesCplusCallbackStub() writes the properties of the stub class
1930 private void writePropertiesCplusCallbackStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
1932 println("IoTRMICall *rmiCall;");
1933 // Get the object Id
1934 println("static int objectId;");
1935 if (callbackExist) {
1936 // We assume that each class only has one callback interface for now
1937 Iterator it = callbackClasses.iterator();
1938 String callbackType = (String) it.next();
1939 println("// Callback properties");
1940 println("IoTRMIObject *rmiObj;");
1941 println("vector<" + callbackType + "*> vecCallbackObj;");
1942 println("static int objIdCnt;");
1943 // TODO: Need to initialize address and ports if we want to have callback-in-callback
1944 println("string address;");
1945 println("vector<int> ports;\n");
1946 writePropertiesCplusPermission(callbackType);
1953 * HELPER: writeConstructorCplusCallbackStub() writes the constructor of the stub class
1955 private void writeConstructorCplusCallbackStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1957 println(newStubClass + "(IoTRMICall* _rmiCall, int _objectId) {");
1958 println("objectId = _objectId;");
1959 println("rmiCall = _rmiCall;");
1960 if (callbackExist) {
1961 Iterator it = callbackClasses.iterator();
1962 String callbackType = (String) it.next();
1963 println("thread th1 (&" + newStubClass + "::___initCallBack, this);");
1964 println("th1.detach();");
1965 println("___regCB();");
1972 * generateCPlusCallbackStubClasses() generate callback stubs based on the methods list in C++
1974 public void generateCPlusCallbackStubClasses() throws IOException {
1976 // Create a new directory
1977 String path = createDirectories(dir, subdir);
1978 for (String intface : mapIntfacePTH.keySet()) {
1980 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1981 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1982 // Open a new file to write into
1983 String newIntface = intMeth.getKey();
1984 String newStubClass = newIntface + "_CallbackStub";
1985 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
1986 pw = new PrintWriter(new BufferedWriter(fw));
1987 // Find out if there are callback objects
1988 Set<String> methods = intMeth.getValue();
1989 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1990 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1991 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1992 boolean callbackExist = !callbackClasses.isEmpty();
1993 // Write file headers
1994 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
1995 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
1996 println("#include <iostream>");
1998 println("#include <thread>");
1999 println("#include \"" + newIntface + ".hpp\""); println("");
2000 println("using namespace std;"); println("");
2001 println("class " + newStubClass + " : public " + newIntface); println("{");
2002 println("private:\n");
2003 writePropertiesCplusCallbackStub(intface, newIntface, callbackExist, callbackClasses);
2004 println("public:\n");
2005 // Add default constructor and destructor
2006 println(newStubClass + "() { }"); println("");
2007 writeConstructorCplusCallbackStub(newStubClass, callbackExist, callbackClasses);
2008 writeDeconstructorCplusStub(newStubClass, callbackExist, callbackClasses);
2010 writeMethodCplusStub(methods, intDecl, callbackClasses);
2013 writePermissionInitializationCplus(intface, newStubClass, intDecl);
2016 System.out.println("IoTCompiler: Generated callback stub class " + newIntface + ".hpp...");
2023 * HELPER: writePropertiesCplusSkeleton() writes the properties of the skeleton class
2025 private void writePropertiesCplusSkeleton(String intface, boolean callbackExist, Set<String> callbackClasses) {
2027 println(intface + " *mainObj;");
2029 if (callbackExist) {
2030 Iterator it = callbackClasses.iterator();
2031 String callbackType = (String) it.next();
2032 String exchangeType = checkAndGetParamClass(callbackType);
2033 println("// Callback properties");
2034 println("static int objIdCnt;");
2035 println("vector<" + exchangeType + "*> vecCallbackObj;");
2036 println("IoTRMICall *rmiCall;");
2038 println("IoTRMIObject *rmiObj;\n");
2039 // Keep track of object Ids of all stubs registered to this interface
2040 writePropertiesCplusPermission(intface);
2046 * HELPER: writePermissionInitializationCplus() writes the initialization of permission set
2048 private void writePermissionInitializationCplus(String intface, String newSkelClass, InterfaceDecl intDecl) {
2050 // Keep track of object Ids of all stubs registered to this interface
2051 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
2052 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
2053 String newIntface = intMeth.getKey();
2054 int newObjectId = mapNewIntfaceObjId.get(newIntface);
2055 print("const set<int> " + newSkelClass + "::set" + newObjectId + "Allowed {");
2056 Set<String> methodIds = intMeth.getValue();
2058 for (String methodId : methodIds) {
2059 int methodNumId = intDecl.getMethodNumId(methodId);
2060 print(Integer.toString(methodNumId));
2061 // Check if this is the last element (don't print a comma)
2062 if (i != methodIds.size() - 1) {
2073 * HELPER: writeConstructorCplusSkeleton() writes the constructor of the skeleton class
2075 private void writeConstructorCplusSkeleton(String newSkelClass, String intface, boolean callbackExist) {
2077 println(newSkelClass + "(" + intface + " *_mainObj, int _port) {");
2078 println("bool _bResult = false;");
2079 println("mainObj = _mainObj;");
2080 println("rmiObj = new IoTRMIObject(_port, &_bResult);");
2082 if (callbackExist) {
2083 println("objIdCnt = 0;");
2085 //println("set0Allowed = Arrays.asList(object0Permission);");
2086 println("___waitRequestInvokeMethod();");
2092 * HELPER: writeDeconstructorCplusSkeleton() writes the deconstructor of the skeleton class
2094 private void writeDeconstructorCplusSkeleton(String newSkelClass, boolean callbackExist, Set<String> callbackClasses) {
2096 println("~" + newSkelClass + "() {");
2097 println("if (rmiObj != NULL) {");
2098 println("delete rmiObj;");
2099 println("rmiObj = NULL;");
2101 if (callbackExist) {
2102 // We assume that each class only has one callback interface for now
2103 println("if (rmiCall != NULL) {");
2104 println("delete rmiCall;");
2105 println("rmiCall = NULL;");
2107 Iterator it = callbackClasses.iterator();
2108 String callbackType = (String) it.next();
2109 String exchangeType = checkAndGetParamClass(callbackType);
2110 println("for(" + exchangeType + "* cb : vecCallbackObj) {");
2111 println("delete cb;");
2112 println("cb = NULL;");
2121 * HELPER: writeStdMethodBodyCplusSkeleton() writes the standard method body in the skeleton class
2123 private void writeStdMethodBodyCplusSkeleton(List<String> methParams, String methodId, String methodType) {
2125 if (methodType.equals("void"))
2126 print("mainObj->" + methodId + "(");
2128 print("return mainObj->" + methodId + "(");
2129 for (int i = 0; i < methParams.size(); i++) {
2131 print(getSimpleIdentifier(methParams.get(i)));
2132 // Check if this is the last element (don't print a comma)
2133 if (i != methParams.size() - 1) {
2142 * HELPER: writeInitCallbackCplusSkeleton() writes the init callback method for skeleton class
2144 private void writeInitCallbackCplusSkeleton(boolean callbackSkeleton) {
2146 // This is a callback skeleton generation
2147 if (callbackSkeleton)
2148 println("void ___regCB(IoTRMIObject* rmiObj) {");
2150 println("void ___regCB() {");
2151 println("int numParam = 3;");
2152 println("int param1 = 0;");
2153 println("string param2 = \"\";");
2154 println("int param3 = 0;");
2155 println("void* paramObj[] = { ¶m1, ¶m2, ¶m3 };");
2156 println("bool bResult = false;");
2157 println("rmiCall = new IoTRMICall(param1, param2.c_str(), param3, &bResult);");
2163 * HELPER: writeMethodCplusSkeleton() writes the method of the skeleton class
2165 private void writeMethodCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl,
2166 Set<String> callbackClasses, boolean callbackSkeleton) {
2168 for (String method : methods) {
2170 List<String> methParams = intDecl.getMethodParams(method);
2171 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2172 String methodId = intDecl.getMethodId(method);
2173 String methodType = checkAndGetCplusType(intDecl.getMethodType(method));
2174 print(methodType + " " + methodId + "(");
2175 boolean isCallbackMethod = false;
2176 String callbackType = null;
2177 for (int i = 0; i < methParams.size(); i++) {
2179 String origParamType = methPrmTypes.get(i);
2180 if (callbackClasses.contains(origParamType)) { // Check if this has callback object
2181 isCallbackMethod = true;
2182 callbackType = origParamType;
2184 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
2185 String methPrmType = checkAndGetCplusType(paramType);
2186 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
2187 print(methParamComplete);
2188 // Check if this is the last element (don't print a comma)
2189 if (i != methParams.size() - 1) {
2194 // Now, write the body of skeleton!
2195 writeStdMethodBodyCplusSkeleton(methParams, methodId, intDecl.getMethodType(method));
2197 if (isCallbackMethod)
2198 writeInitCallbackCplusSkeleton(callbackSkeleton);
2204 * HELPER: writeCallbackCplusNumStubs() writes the numStubs variable
2206 private void writeCallbackCplusNumStubs(List<String> methParams, List<String> methPrmTypes, String callbackType) {
2208 for (int i = 0; i < methParams.size(); i++) {
2209 String paramType = methPrmTypes.get(i);
2210 String param = methParams.get(i);
2211 //if (callbackType.equals(paramType)) {
2212 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
2213 String exchParamType = checkAndGetParamClass(paramType);
2214 // Print array if this is array or list if this is a list of callback objects
2215 println("int numStubs" + i + " = 0;");
2222 * HELPER: writeCallbackCplusStubGeneration() writes the callback stub generation part
2224 private void writeCallbackCplusStubGeneration(List<String> methParams, List<String> methPrmTypes, String callbackType) {
2226 // Iterate over callback objects
2227 for (int i = 0; i < methParams.size(); i++) {
2228 String paramType = methPrmTypes.get(i);
2229 String param = methParams.get(i);
2230 // Generate a loop if needed
2231 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
2232 String exchParamType = checkAndGetParamClass(paramType);
2233 if (isArrayOrList(paramType, param)) {
2234 println("vector<" + exchParamType + "> stub;");
2235 println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
2236 println(exchParamType + "* cb" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
2237 println("stub" + i + ".push_back(cb);");
2238 println("vecCallbackObj.push_back(cb);");
2239 println("objIdCnt++;");
2242 println(exchParamType + "* stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
2243 println("vecCallbackObj.push_back(stub" + i + ");");
2244 println("objIdCnt++;");
2252 * HELPER: writeStdMethodHelperBodyCplusSkeleton() writes the standard method body helper in the skeleton class
2254 private void writeStdMethodHelperBodyCplusSkeleton(InterfaceDecl intDecl, List<String> methParams,
2255 List<String> methPrmTypes, String method, String methodId, Set<String> callbackClasses) {
2257 // Generate array of parameter types
2258 boolean isCallbackMethod = false;
2259 String callbackType = null;
2260 print("string paramCls[] = { ");
2261 for (int i = 0; i < methParams.size(); i++) {
2262 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2263 if (callbackClasses.contains(paramType)) {
2264 isCallbackMethod = true;
2265 callbackType = paramType;
2267 } else { // Generate normal classes if it's not a callback object
2268 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
2269 String prmType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
2270 print("\"" + prmType + "\"");
2272 if (i != methParams.size() - 1) {
2277 println("int numParam = " + methParams.size() + ";");
2278 if (isCallbackMethod)
2279 writeCallbackCplusNumStubs(methParams, methPrmTypes, callbackType);
2280 // Generate parameters
2281 for (int i = 0; i < methParams.size(); i++) {
2282 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2283 if (!callbackClasses.contains(paramType)) {
2284 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
2285 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
2286 println(methParamComplete + ";");
2289 // Generate array of parameter objects
2290 print("void* paramObj[] = { ");
2291 for (int i = 0; i < methParams.size(); i++) {
2292 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2293 if (callbackClasses.contains(paramType))
2294 print("&numStubs" + i);
2296 print("&" + getSimpleIdentifier(methParams.get(i)));
2297 if (i != methParams.size() - 1) {
2302 println("rmiObj->getMethodParams(paramCls, numParam, paramObj);");
2303 if (isCallbackMethod)
2304 writeCallbackCplusStubGeneration(methParams, methPrmTypes, callbackType);
2305 String retType = intDecl.getMethodType(method);
2306 // Check if this is "void"
2307 if (retType.equals("void")) {
2308 print(methodId + "(");
2309 for (int i = 0; i < methParams.size(); i++) {
2310 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2311 if (callbackClasses.contains(paramType))
2314 print(getSimpleIdentifier(methParams.get(i)));
2315 if (i != methParams.size() - 1) {
2320 } else { // We do have a return value
2321 print(checkAndGetCplusType(retType) + " retVal = " + methodId + "(");
2322 for (int i = 0; i < methParams.size(); i++) {
2323 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2324 if (callbackClasses.contains(paramType))
2327 print(getSimpleIdentifier(methParams.get(i)));
2328 if (i != methParams.size() - 1) {
2333 println("void* retObj = &retVal;");
2334 String retTypeC = checkAndGetCplusType(retType);
2335 println("rmiObj->sendReturnObj(retObj, \"" + checkAndGetCplusArrayType(retTypeC) + "\");");
2341 * HELPER: writeMethodHelperCplusSkeleton() writes the method helper of the skeleton class
2343 private void writeMethodHelperCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
2345 // Use this set to handle two same methodIds
2346 Set<String> uniqueMethodIds = new HashSet<String>();
2347 for (String method : methods) {
2349 List<String> methParams = intDecl.getMethodParams(method);
2350 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2351 String methodId = intDecl.getMethodId(method);
2353 String helperMethod = methodId;
2354 if (uniqueMethodIds.contains(methodId))
2355 helperMethod = helperMethod + intDecl.getMethodNumId(method);
2357 uniqueMethodIds.add(methodId);
2358 // Check if this is "void"
2359 String retType = intDecl.getMethodType(method);
2360 println(helperMethod + "() {");
2361 // Now, write the helper body of skeleton!
2362 writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses);
2369 * HELPER: writeCplusMethodPermission() writes permission checks in skeleton
2371 private void writeCplusMethodPermission(String intface) {
2373 // Get all the different stubs
2374 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
2375 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
2376 String newIntface = intMeth.getKey();
2377 int newObjectId = mapNewIntfaceObjId.get(newIntface);
2378 println("if (_objectId == object" + newObjectId + "Id) {");
2379 println("if (set" + newObjectId + "Allowed.find(methodId) == set" + newObjectId + "Allowed.end()) {");
2380 println("cerr << \"Object with object Id: \" << _objectId << \" is not allowed to access method: \" << methodId << endl;");
2381 println("exit(-1);");
2384 println("cerr << \"Object Id: \" << _objectId << \" not recognized!\" << endl;");
2385 println("exit(-1);");
2393 * HELPER: writeCplusWaitRequestInvokeMethod() writes the main loop of the skeleton class
2395 private void writeCplusWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist, String intface) {
2397 // Use this set to handle two same methodIds
2398 Set<String> uniqueMethodIds = new HashSet<String>();
2399 println("void ___waitRequestInvokeMethod() {");
2400 // Write variables here if we have callbacks or enums or structs
2401 println("while (true) {");
2402 println("rmiObj->getMethodBytes();");
2403 println("int _objectId = rmiObj->getObjectId();");
2404 println("int methodId = rmiObj->getMethodId();");
2405 // Generate permission check
2406 writeCplusMethodPermission(intface);
2407 println("switch (methodId) {");
2408 // Print methods and method Ids
2409 for (String method : methods) {
2410 String methodId = intDecl.getMethodId(method);
2411 int methodNumId = intDecl.getMethodNumId(method);
2412 print("case " + methodNumId + ": ___");
2413 String helperMethod = methodId;
2414 if (uniqueMethodIds.contains(methodId))
2415 helperMethod = helperMethod + methodNumId;
2417 uniqueMethodIds.add(methodId);
2418 println(helperMethod + "(); break;");
2420 String method = "___initCallBack()";
2421 // Print case -9999 (callback handler) if callback exists
2422 if (callbackExist) {
2423 int methodId = intDecl.getHelperMethodNumId(method);
2424 println("case " + methodId + ": ___regCB(); break;");
2426 println("default: ");
2427 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
2428 println("throw exception();");
2436 * generateCplusSkeletonClass() generate skeletons based on the methods list in C++
2438 public void generateCplusSkeletonClass() throws IOException {
2440 // Create a new directory
2441 String path = createDirectories(dir, subdir);
2442 for (String intface : mapIntfacePTH.keySet()) {
2443 // Open a new file to write into
2444 String newSkelClass = intface + "_Skeleton";
2445 FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp");
2446 pw = new PrintWriter(new BufferedWriter(fw));
2447 // Write file headers
2448 println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
2449 println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
2450 println("#include <iostream>");
2451 println("#include \"" + intface + ".hpp\"\n");
2452 // Pass in set of methods and get import classes
2453 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2454 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2455 List<String> methods = intDecl.getMethods();
2456 Set<String> includeClasses = getIncludeClasses(methods, intDecl, true);
2457 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
2458 List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
2459 printIncludeStatements(allIncludeClasses); println("");
2460 println("using namespace std;\n");
2461 // Find out if there are callback objects
2462 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
2463 boolean callbackExist = !callbackClasses.isEmpty();
2464 // Write class header
2465 println("class " + newSkelClass + " : public " + intface); println("{");
2466 println("private:\n");
2468 writePropertiesCplusSkeleton(intface, callbackExist, callbackClasses);
2469 println("public:\n");
2470 // Write constructor
2471 writeConstructorCplusSkeleton(newSkelClass, intface, callbackExist);
2472 // Write deconstructor
2473 writeDeconstructorCplusSkeleton(newSkelClass, callbackExist, callbackClasses);
2475 writeMethodCplusSkeleton(methods, intDecl, callbackClasses, false);
2476 // Write method helper
2477 writeMethodHelperCplusSkeleton(methods, intDecl, callbackClasses);
2478 // Write waitRequestInvokeMethod() - main loop
2479 writeCplusWaitRequestInvokeMethod(methods, intDecl, callbackExist, intface);
2481 writePermissionInitializationCplus(intface, newSkelClass, intDecl);
2484 System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".hpp...");
2490 * HELPER: writePropertiesCplusCallbackSkeleton() writes the properties of the callback skeleton class
2492 private void writePropertiesCplusCallbackSkeleton(String intface, boolean callbackExist, Set<String> callbackClasses) {
2494 println(intface + " *mainObj;");
2495 // Keep track of object Ids of all stubs registered to this interface
2496 println("static int objectId;");
2498 if (callbackExist) {
2499 Iterator it = callbackClasses.iterator();
2500 String callbackType = (String) it.next();
2501 String exchangeType = checkAndGetParamClass(callbackType);
2502 println("// Callback properties");
2503 println("IoTRMICall* rmiCall;");
2504 println("vector<" + exchangeType + "*> vecCallbackObj;");
2505 println("static int objIdCnt;");
2512 * HELPER: writeConstructorCplusCallbackSkeleton() writes the constructor of the skeleton class
2514 private void writeConstructorCplusCallbackSkeleton(String newSkelClass, String intface, boolean callbackExist) {
2516 println(newSkelClass + "(" + intface + " *_mainObj, int _objectId) {");
2517 println("mainObj = _mainObj;");
2518 println("objectId = _objectId;");
2520 if (callbackExist) {
2521 println("objIdCnt = 0;");
2528 * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
2530 private void writeDeconstructorCplusCallbackSkeleton(String newStubClass, boolean callbackExist,
2531 Set<String> callbackClasses) {
2533 println("~" + newStubClass + "() {");
2534 if (callbackExist) {
2535 // We assume that each class only has one callback interface for now
2536 println("if (rmiCall != NULL) {");
2537 println("delete rmiCall;");
2538 println("rmiCall = NULL;");
2540 Iterator it = callbackClasses.iterator();
2541 String callbackType = (String) it.next();
2542 String exchangeType = checkAndGetParamClass(callbackType);
2543 println("for(" + exchangeType + "* cb : vecCallbackObj) {");
2544 println("delete cb;");
2545 println("cb = NULL;");
2554 * HELPER: writeMethodHelperCplusCallbackSkeleton() writes the method helper of the callback skeleton class
2556 private void writeMethodHelperCplusCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl,
2557 Set<String> callbackClasses) {
2559 // Use this set to handle two same methodIds
2560 Set<String> uniqueMethodIds = new HashSet<String>();
2561 for (String method : methods) {
2563 List<String> methParams = intDecl.getMethodParams(method);
2564 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2565 String methodId = intDecl.getMethodId(method);
2567 String helperMethod = methodId;
2568 if (uniqueMethodIds.contains(methodId))
2569 helperMethod = helperMethod + intDecl.getMethodNumId(method);
2571 uniqueMethodIds.add(methodId);
2572 // Check if this is "void"
2573 String retType = intDecl.getMethodType(method);
2574 println(helperMethod + "(IoTRMIObject* rmiObj) {");
2575 // Now, write the helper body of skeleton!
2576 writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses);
2583 * HELPER: writeCplusCallbackWaitRequestInvokeMethod() writes the main loop of the skeleton class
2585 private void writeCplusCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl,
2586 boolean callbackExist) {
2588 // Use this set to handle two same methodIds
2589 Set<String> uniqueMethodIds = new HashSet<String>();
2590 println("void invokeMethod(IoTRMIObject* rmiObj) {");
2591 // Write variables here if we have callbacks or enums or structs
2592 println("int methodId = rmiObj->getMethodId();");
2593 // TODO: code the permission check here!
2594 println("switch (methodId) {");
2595 // Print methods and method Ids
2596 for (String method : methods) {
2597 String methodId = intDecl.getMethodId(method);
2598 int methodNumId = intDecl.getMethodNumId(method);
2599 print("case " + methodNumId + ": ___");
2600 String helperMethod = methodId;
2601 if (uniqueMethodIds.contains(methodId))
2602 helperMethod = helperMethod + methodNumId;
2604 uniqueMethodIds.add(methodId);
2605 println(helperMethod + "(rmiObj); break;");
2607 String method = "___initCallBack()";
2608 // Print case -9999 (callback handler) if callback exists
2609 if (callbackExist) {
2610 int methodId = intDecl.getHelperMethodNumId(method);
2611 println("case " + methodId + ": ___regCB(rmiObj); break;");
2613 println("default: ");
2614 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
2615 println("throw exception();");
2623 * generateCplusCallbackSkeletonClass() generate callback skeletons based on the methods list in C++
2625 public void generateCplusCallbackSkeletonClass() throws IOException {
2627 // Create a new directory
2628 String path = createDirectories(dir, subdir);
2629 for (String intface : mapIntfacePTH.keySet()) {
2630 // Open a new file to write into
2631 String newSkelClass = intface + "_CallbackSkeleton";
2632 FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp");
2633 pw = new PrintWriter(new BufferedWriter(fw));
2634 // Write file headers
2635 println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
2636 println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
2637 println("#include <iostream>");
2638 println("#include \"" + intface + ".hpp\"\n");
2639 // Pass in set of methods and get import classes
2640 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2641 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2642 List<String> methods = intDecl.getMethods();
2643 Set<String> includeClasses = getIncludeClasses(methods, intDecl, true);
2644 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
2645 List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
2646 printIncludeStatements(allIncludeClasses); println("");
2647 // Find out if there are callback objects
2648 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
2649 boolean callbackExist = !callbackClasses.isEmpty();
2650 println("using namespace std;\n");
2651 // Write class header
2652 println("class " + newSkelClass + " : public " + intface); println("{");
2653 println("private:\n");
2655 writePropertiesCplusCallbackSkeleton(intface, callbackExist, callbackClasses);
2656 println("public:\n");
2657 // Write constructor
2658 writeConstructorCplusCallbackSkeleton(newSkelClass, intface, callbackExist);
2659 // Write deconstructor
2660 writeDeconstructorCplusCallbackSkeleton(newSkelClass, callbackExist, callbackClasses);
2662 writeMethodCplusSkeleton(methods, intDecl, callbackClasses, true);
2663 // Write method helper
2664 writeMethodHelperCplusCallbackSkeleton(methods, intDecl, callbackClasses);
2665 // Write waitRequestInvokeMethod() - main loop
2666 writeCplusCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist);
2670 System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".hpp...");
2676 * generateInitializer() generate initializer based on type
2678 public String generateCplusInitializer(String type) {
2680 // Generate dummy returns for now
2681 if (type.equals("short")||
2682 type.equals("int") ||
2683 type.equals("long") ||
2684 type.equals("float")||
2685 type.equals("double")) {
2688 } else if ( type.equals("String") ||
2689 type.equals("string")) {
2692 } else if ( type.equals("char") ||
2693 type.equals("byte")) {
2696 } else if ( type.equals("boolean")) {
2706 * generateReturnStmt() generate return statement based on methType
2708 public String generateReturnStmt(String methType) {
2710 // Generate dummy returns for now
2711 if (methType.equals("short")||
2712 methType.equals("int") ||
2713 methType.equals("long") ||
2714 methType.equals("float")||
2715 methType.equals("double")) {
2718 } else if ( methType.equals("String")) {
2721 } else if ( methType.equals("char") ||
2722 methType.equals("byte")) {
2725 } else if ( methType.equals("boolean")) {
2735 * setDirectory() sets a new directory for stub files
2737 public void setDirectory(String _subdir) {
2744 * printUsage() prints the usage of this compiler
2746 public static void printUsage() {
2748 System.out.println();
2749 System.out.println("Sentinel interface and stub compiler version 1.0");
2750 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
2751 System.out.println("All rights reserved.");
2752 System.out.println("Usage:");
2753 System.out.println("\tjava IoTCompiler -help / --help / -h\n");
2754 System.out.println("\t\tDisplay this help texts\n\n");
2755 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>]");
2756 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>] [options]\n");
2757 System.out.println("\t\tTake one or more pairs of main-req policy files, and generate Java and/or C++ files\n");
2758 System.out.println("Options:");
2759 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
2760 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
2761 System.out.println();
2766 * parseFile() prepares Lexer and Parser objects, then parses the file
2768 public static ParseNode parseFile(String file) {
2770 ParseNode pn = null;
2772 ComplexSymbolFactory csf = new ComplexSymbolFactory();
2773 ScannerBuffer lexer =
2774 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf));
2775 Parser parse = new Parser(lexer,csf);
2776 pn = (ParseNode) parse.parse().value;
2777 } catch (Exception e) {
2778 e.printStackTrace();
2779 throw new Error("IoTCompiler: ERROR parsing policy file or wrong command line option: " + file);
2790 boolean newline=true;
2793 private void print(String str) {
2796 if (str.equals("}"))
2798 for(int i=0; i<tab; i++)
2808 * This function converts Java to C++ type for compilation
2810 private String convertType(String jType) {
2812 return mapPrimitives.get(jType);
2816 private void println(String str) {
2819 if (str.contains("}") && !str.contains("{"))
2821 for(int i=0; i<tab; i++)
2830 private void updatetabbing(String str) {
2832 tablevel+=count(str,'{')-count(str,'}');
2836 private int count(String str, char key) {
2837 char[] array = str.toCharArray();
2839 for(int i=0; i<array.length; i++) {
2840 if (array[i] == key)
2847 private void createDirectory(String dirName) {
2849 File file = new File(dirName);
2850 if (!file.exists()) {
2852 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
2854 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
2857 System.out.println("IoTCompiler: Directory " + dirName + " exists...");
2862 // Create a directory and possibly a sub directory
2863 private String createDirectories(String dir, String subdir) {
2866 createDirectory(path);
2867 if (subdir != null) {
2868 path = path + "/" + subdir;
2869 createDirectory(path);
2875 // Inserting array members into a Map object
2876 // that maps arrKey to arrVal objects
2877 private void arraysToMap(Map map, Object[] arrKey, Object[] arrVal) {
2879 for(int i = 0; i < arrKey.length; i++) {
2881 map.put(arrKey[i], arrVal[i]);
2886 // Return parameter category, i.e. PRIMITIVES, NONPRIMITIVES, or USERDEFINED
2887 private ParamCategory getParamCategory(String paramType) {
2889 if (mapPrimitives.containsKey(paramType)) {
2890 return ParamCategory.PRIMITIVES;
2891 // We can either use mapNonPrimitivesJava or mapNonPrimitivesCplus here
2892 } else if (mapNonPrimitivesJava.containsKey(getSimpleType(paramType))) {
2893 return ParamCategory.NONPRIMITIVES;
2895 return ParamCategory.USERDEFINED;
2899 // Return full class name for non-primitives to generate Java import statements
2900 // e.g. java.util.Set for Set, java.util.Map for Map
2901 private String getNonPrimitiveJavaClass(String paramNonPrimitives) {
2903 return mapNonPrimitivesJava.get(paramNonPrimitives);
2907 // Return full class name for non-primitives to generate Cplus include statements
2908 // e.g. #include <set> for Set, #include <map> for Map
2909 private String getNonPrimitiveCplusClass(String paramNonPrimitives) {
2911 return mapNonPrimitivesCplus.get(paramNonPrimitives);
2915 // Get simple types, e.g. HashSet for HashSet<...>
2916 // Basically strip off the "<...>"
2917 private String getSimpleType(String paramType) {
2919 // Check if this is generics
2920 if(paramType.contains("<")) {
2921 String[] type = paramType.split("<");
2928 // Generate a set of standard classes for import statements
2929 private List<String> getStandardJavaImportClasses() {
2931 List<String> importClasses = new ArrayList<String>();
2932 // Add the standard list first
2933 importClasses.add("java.io.IOException");
2934 importClasses.add("java.util.List");
2935 importClasses.add("java.util.ArrayList");
2936 importClasses.add("java.util.Arrays");
2937 importClasses.add("iotrmi.Java.IoTRMICall");
2938 importClasses.add("iotrmi.Java.IoTRMIObject");
2940 return importClasses;
2944 // Generate a set of standard classes for import statements
2945 private List<String> getStandardCplusIncludeClasses() {
2947 List<String> importClasses = new ArrayList<String>();
2948 // Add the standard list first
2949 importClasses.add("<vector>");
2950 importClasses.add("<set>");
2951 importClasses.add("\"IoTRMICall.hpp\"");
2952 importClasses.add("\"IoTRMIObject.hpp\"");
2954 return importClasses;
2958 // Generate a set of standard classes for import statements
2959 private List<String> getAllLibClasses(Collection<String> stdLibClasses, Collection<String> libClasses) {
2961 List<String> allLibClasses = new ArrayList<String>(stdLibClasses);
2962 // Iterate over the list of import classes
2963 for (String str : libClasses) {
2964 if (!allLibClasses.contains(str)) {
2965 allLibClasses.add(str);
2969 return allLibClasses;
2974 // Generate a set of classes for import statements
2975 private Set<String> getImportClasses(Collection<String> methods, InterfaceDecl intDecl) {
2977 Set<String> importClasses = new HashSet<String>();
2978 for (String method : methods) {
2979 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2980 for (String paramType : methPrmTypes) {
2982 String simpleType = getSimpleType(paramType);
2983 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
2984 importClasses.add(getNonPrimitiveJavaClass(simpleType));
2988 return importClasses;
2992 // Generate a set of classes for include statements
2993 private Set<String> getIncludeClasses(Collection<String> methods, InterfaceDecl intDecl, boolean needExchange) {
2995 Set<String> includeClasses = new HashSet<String>();
2996 for (String method : methods) {
2998 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2999 List<String> methParams = intDecl.getMethodParams(method);
3000 for (int i = 0; i < methPrmTypes.size(); i++) {
3002 String simpleType = getSimpleType(methPrmTypes.get(i));
3003 String param = methParams.get(i);
3004 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
3005 includeClasses.add("<" + getNonPrimitiveCplusClass(simpleType) + ">");
3006 } else if (getParamCategory(simpleType) == ParamCategory.USERDEFINED) {
3007 // For original interface, we need it exchanged... not for stub interfaces
3009 includeClasses.add("\"" + exchangeParamType(simpleType) + ".hpp\"");
3010 includeClasses.add("\"" + exchangeParamType(simpleType) + "_CallbackStub.hpp\"");
3012 includeClasses.add("\"" + simpleType + ".hpp\"");
3013 includeClasses.add("\"" + simpleType + "_CallbackSkeleton.hpp\"");
3015 } else if (param.contains("[]")) {
3016 // Check if this is array for C++; translate into vector
3017 includeClasses.add("<vector>");
3021 return includeClasses;
3025 // Generate a set of callback classes
3026 private Set<String> getCallbackClasses(Collection<String> methods, InterfaceDecl intDecl) {
3028 Set<String> callbackClasses = new HashSet<String>();
3029 for (String method : methods) {
3031 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
3032 List<String> methParams = intDecl.getMethodParams(method);
3033 for (int i = 0; i < methPrmTypes.size(); i++) {
3035 String type = methPrmTypes.get(i);
3036 if (getParamCategory(type) == ParamCategory.USERDEFINED) {
3037 callbackClasses.add(type);
3038 } else if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) {
3039 // Can be a List<...> of callback objects ...
3040 String genericType = getTypeOfGeneric(type)[0];
3041 if (getParamCategory(type) == ParamCategory.USERDEFINED) {
3042 callbackClasses.add(type);
3047 return callbackClasses;
3051 private void printImportStatements(Collection<String> importClasses) {
3053 for(String cls : importClasses) {
3054 println("import " + cls + ";");
3059 private void printIncludeStatements(Collection<String> includeClasses) {
3061 for(String cls : includeClasses) {
3062 println("#include " + cls);
3067 // Get the C++ version of a non-primitive type
3068 // e.g. set for Set and map for Map
3069 // Input nonPrimitiveType has to be generics in format
3070 private String[] getTypeOfGeneric(String nonPrimitiveType) {
3072 // Handle <, >, and , for 2-type generic/template
3073 String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(",");
3078 // This helper function strips off array declaration, e.g. D[] becomes D
3079 private String getSimpleIdentifier(String ident) {
3081 // Handle [ for array declaration
3082 String substr = ident;
3083 if (ident.contains("[]")) {
3084 substr = ident.split("\\[\\]")[0];
3090 private String checkAndGetCplusType(String paramType) {
3092 if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
3093 return convertType(paramType);
3094 } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) {
3096 // Check for generic/template format
3097 if (paramType.contains("<") && paramType.contains(">")) {
3099 String genericClass = getSimpleType(paramType);
3100 String[] genericType = getTypeOfGeneric(paramType);
3101 String cplusTemplate = null;
3102 if (genericType.length == 1) // Generic/template with one type
3103 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
3104 "<" + convertType(genericType[0]) + ">";
3105 else // Generic/template with two types
3106 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
3107 "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">";
3108 return cplusTemplate;
3110 return getNonPrimitiveCplusClass(paramType);
3111 } else if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
3112 return paramType + "*";
3114 // Just return it as is if it's not non-primitives
3116 //return checkAndGetParamClass(paramType, true);
3120 // Detect array declaration, e.g. int A[],
3121 // then generate "int A[]" in C++ as "vector<int> A"
3122 private String checkAndGetCplusArray(String paramType, String param) {
3124 String paramComplete = null;
3125 // Check for array declaration
3126 if (param.contains("[]")) {
3127 paramComplete = "vector<" + paramType + "> " + param.replace("[]","");
3129 // Just return it as is if it's not an array
3130 paramComplete = paramType + " " + param;
3132 return paramComplete;
3136 // Detect array declaration, e.g. int A[],
3137 // then generate "int A[]" in C++ as "vector<int> A"
3138 // This method just returns the type
3139 private String checkAndGetCplusArrayType(String paramType) {
3141 String paramTypeRet = null;
3142 // Check for array declaration
3143 if (paramType.contains("[]")) {
3144 String type = paramType.split("\\[\\]")[0];
3145 paramTypeRet = checkAndGetCplusType(type) + "[]";
3146 } else if (paramType.contains("vector")) {
3147 // Just return it as is if it's not an array
3148 String type = paramType.split("<")[1].split(">")[0];
3149 paramTypeRet = checkAndGetCplusType(type) + "[]";
3151 paramTypeRet = paramType;
3153 return paramTypeRet;
3157 // Detect array declaration, e.g. int A[],
3158 // then generate "int A[]" in C++ as "vector<int> A"
3159 // This method just returns the type
3160 private String checkAndGetCplusArrayType(String paramType, String param) {
3162 String paramTypeRet = null;
3163 // Check for array declaration
3164 if (param.contains("[]")) {
3165 paramTypeRet = checkAndGetCplusType(paramType) + "[]";
3166 } else if (paramType.contains("vector")) {
3167 // Just return it as is if it's not an array
3168 String type = paramType.split("<")[1].split(">")[0];
3169 paramTypeRet = checkAndGetCplusType(type) + "[]";
3171 paramTypeRet = paramType;
3173 return paramTypeRet;
3177 // Detect array declaration, e.g. int A[],
3178 // then generate type "int[]"
3179 private String checkAndGetArray(String paramType, String param) {
3181 String paramTypeRet = null;
3182 // Check for array declaration
3183 if (param.contains("[]")) {
3184 paramTypeRet = paramType + "[]";
3186 // Just return it as is if it's not an array
3187 paramTypeRet = paramType;
3189 return paramTypeRet;
3193 // Is array or list?
3194 private boolean isArrayOrList(String paramType, String param) {
3196 // Check for array declaration
3197 if (isArray(paramType, param))
3199 else if (isList(paramType, param))
3206 // Is array or list?
3207 private boolean isArray(String paramType, String param) {
3209 // Check for array declaration
3210 if (param.contains("[]"))
3217 // Is array or list?
3218 private boolean isList(String paramType, String param) {
3220 // Check for array declaration
3221 if (paramType.contains("List"))
3228 // Get the right type for a callback object
3229 private String checkAndGetParamClass(String paramType) {
3231 // Check if this is generics
3232 if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
3233 return exchangeParamType(paramType);
3239 // Returns the other interface for type-checking purposes for USERDEFINED
3240 // classes based on the information provided in multiple policy files
3241 // e.g. return CameraWithXXX instead of Camera
3242 private String exchangeParamType(String intface) {
3244 // Param type that's passed is the interface name we need to look for
3245 // in the map of interfaces, based on available policy files.
3246 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
3247 if (decHandler != null) {
3248 // We've found the required interface policy files
3249 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(intface);
3250 Set<String> setExchInt = reqDecl.getInterfaces();
3251 if (setExchInt.size() == 1) {
3252 Iterator iter = setExchInt.iterator();
3253 return (String) iter.next();
3255 throw new Error("IoTCompiler: Ambiguous stub interfaces: " + setExchInt.toString() +
3256 ". Only one new interface can be declared if the object " + intface +
3257 " needs to be passed in as an input parameter!");
3260 // NULL value - this means policy files missing
3261 throw new Error("IoTCompiler: Parameter type lookup failed for " + intface +
3262 "... Please provide the necessary policy files for user-defined types." +
3263 " If this is an array please type the brackets after the variable name," +
3264 " e.g. \"String str[]\", not \"String[] str\"." +
3265 " If this is a Collections (Java) / STL (C++) type, this compiler only" +
3266 " supports List/ArrayList (Java) or list (C++).");
3271 public static void main(String[] args) throws Exception {
3273 // If there is no argument or just "--help" or "-h", then invoke printUsage()
3274 if ((args[0].equals("-help") ||
3275 args[0].equals("--help")||
3276 args[0].equals("-h")) ||
3277 (args.length == 0)) {
3279 IoTCompiler.printUsage();
3281 } else if (args.length > 1) {
3283 IoTCompiler comp = new IoTCompiler();
3286 // Parse main policy file
3287 ParseNode pnPol = IoTCompiler.parseFile(args[i]);
3288 // Parse "requires" policy file
3289 ParseNode pnReq = IoTCompiler.parseFile(args[i+1]);
3290 // Get interface name
3291 String intface = ParseTreeHandler.getOrigIntface(pnPol);
3292 comp.setDataStructures(intface, pnPol, pnReq);
3293 comp.getMethodsForIntface(intface);
3295 // 1) Check if this is the last option before "-java" or "-cplus"
3296 // 2) Check if this is really the last option (no "-java" or "-cplus")
3297 } while(!args[i].equals("-java") &&
3298 !args[i].equals("-cplus") &&
3301 // Generate everything if we don't see "-java" or "-cplus"
3302 if (i == args.length) {
3303 comp.generateJavaLocalInterfaces();
3304 comp.generateJavaInterfaces();
3305 comp.generateJavaStubClasses();
3306 comp.generateJavaCallbackStubClasses();
3307 comp.generateJavaSkeletonClass();
3308 comp.generateJavaCallbackSkeletonClass();
3309 comp.generateCplusLocalInterfaces();
3310 comp.generateCPlusInterfaces();
3311 comp.generateCPlusStubClasses();
3312 comp.generateCPlusCallbackStubClasses();
3313 comp.generateCplusSkeletonClass();
3314 comp.generateCplusCallbackSkeletonClass();
3316 // Check other options
3317 while(i < args.length) {
3319 if (!args[i].equals("-java") &&
3320 !args[i].equals("-cplus")) {
3321 throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
3323 if (i + 1 < args.length) {
3324 comp.setDirectory(args[i+1]);
3326 throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
3328 if (args[i].equals("-java")) {
3329 comp.generateJavaLocalInterfaces();
3330 comp.generateJavaInterfaces();
3331 comp.generateJavaStubClasses();
3332 comp.generateJavaCallbackStubClasses();
3333 comp.generateJavaSkeletonClass();
3334 comp.generateJavaCallbackSkeletonClass();
3336 comp.generateCplusLocalInterfaces();
3337 comp.generateCPlusInterfaces();
3338 comp.generateCPlusStubClasses();
3339 comp.generateCPlusCallbackStubClasses();
3340 comp.generateCplusSkeletonClass();
3341 comp.generateCplusCallbackSkeletonClass();
3348 // Need to at least have exactly 2 parameters, i.e. main policy file and requires file
3349 IoTCompiler.printUsage();
3350 throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");