619146e6bdbac8b8517dd60baff6850c471e0269
[iot2.git] / iotjava / iotpolicy / IoTCompiler.java
1 package iotpolicy;
2
3 import java_cup.runtime.ComplexSymbolFactory;
4 import java_cup.runtime.ScannerBuffer;
5 import java.io.*;
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;
14 import java.util.Map;
15 import java.util.Set;
16
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;
29
30 import iotrmi.Java.IoTRMITypes;
31
32
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.
37  *
38  * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
39  * @version     1.0
40  * @since       2016-09-22
41  */
42 public class IoTCompiler {
43
44         /**
45          * Class properties
46          */
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;
59         private String dir;
60         private String subdir;
61
62         /**
63          * Class constants
64          */
65         private final static String OUTPUT_DIRECTORY = "output_files";
66
67         private enum ParamCategory {
68
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
72         }
73
74         /**
75          * Class constructors
76          */
77         public IoTCompiler() {
78
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);
90                 pw = null;
91                 dir = OUTPUT_DIRECTORY;
92                 subdir = null;
93         }
94
95
96         /**
97          * setDataStructures() sets parse tree and other data structures based on policy files.
98          * <p>
99          * It also generates parse tree (ParseTreeHandler) and
100          * copies useful information from parse tree into
101          * InterfaceDecl, CapabilityDecl, and RequiresDecl 
102          * data structures.
103          * Additionally, the data structure handles are
104          * returned from tree-parsing for further process.
105          *
106          */
107         public void setDataStructures(String origInt, ParseNode pnPol, ParseNode pnReq) {
108
109                 ParseTreeHandler ptHandler = new ParseTreeHandler(origInt, pnPol, pnReq);
110                 DeclarationHandler decHandler = new DeclarationHandler();
111                 // Process ParseNode and generate Declaration objects
112                 // Interface
113                 ptHandler.processInterfaceDecl();
114                 InterfaceDecl intDecl = ptHandler.getInterfaceDecl();
115                 decHandler.addInterfaceDecl(origInt, intDecl);
116                 // Capabilities
117                 ptHandler.processCapabilityDecl();
118                 CapabilityDecl capDecl = ptHandler.getCapabilityDecl();
119                 decHandler.addCapabilityDecl(origInt, capDecl);
120                 // Requires
121                 ptHandler.processRequiresDecl();
122                 RequiresDecl reqDecl = ptHandler.getRequiresDecl();
123                 decHandler.addRequiresDecl(origInt, reqDecl);
124                 // Enumeration
125                 ptHandler.processEnumDecl();
126                 EnumDecl enumDecl = ptHandler.getEnumDecl();
127                 decHandler.addEnumDecl(origInt, enumDecl);
128                 // Struct
129                 ptHandler.processStructDecl();
130                 StructDecl structDecl = ptHandler.getStructDecl();
131                 decHandler.addStructDecl(origInt, structDecl);
132
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));
137         }
138
139
140         /**
141          * getMethodsForIntface() reads for methods in the data structure
142          * <p>
143          * It is going to give list of methods for a certain interface
144          *              based on the declaration of capabilities.
145          */
146         public void getMethodsForIntface(String origInt) {
147
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) {
157
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) {
163
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) {
168
169                                         // Add methods into setMethods
170                                         // This is to also handle redundancies (say two capabilities
171                                         //              share the same methods)
172                                         setMethods.add(strMeth);
173                                 }
174                         }
175                         // Add interface and methods information into map
176                         mapNewIntMethods.put(strInt, setMethods);
177                 }
178                 // Map the map of interface-methods to the original interface
179                 mapInt2NewInts.put(origInt, mapNewIntMethods);
180         }
181
182
183         /**
184          * HELPER: writeMethodJavaLocalInterface() writes the method of the interface
185          */
186         private void writeMethodJavaLocalInterface(Collection<String> methods, InterfaceDecl intDecl) {
187
188                 for (String method : methods) {
189
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) {
201                                         print(", ");
202                                 }
203                         }
204                         println(");");
205                 }
206         }
207
208
209         /**
210          * HELPER: writeMethodJavaInterface() writes the method of the interface
211          */
212         private void writeMethodJavaInterface(Collection<String> methods, InterfaceDecl intDecl) {
213
214                 for (String method : methods) {
215
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) {
227                                         print(", ");
228                                 }
229                         }
230                         println(");");
231                 }
232         }
233
234
235         /**
236          * HELPER: writeEnumJava() writes the enumeration declaration
237          */
238         private void writeEnumJava(EnumDecl enumDecl) {
239
240                 Set<String> enumTypes = enumDecl.getEnumDeclarations();
241                 // Iterate over enum declarations
242                 for (String enType : enumTypes) {
243
244                         println("public enum " + enType + " {");
245                         List<String> enumMembers = enumDecl.getMembers(enType);
246                         for (int i = 0; i < enumMembers.size(); i++) {
247
248                                 String member = enumMembers.get(i);
249                                 print(member);
250                                 // Check if this is the last element (don't print a comma)
251                                 if (i != enumMembers.size() - 1)
252                                         println(",");
253                                 else
254                                         println("");
255                         }
256                         println("}\n");
257                 }
258         }
259
260
261         /**
262          * HELPER: writeStructJava() writes the struct declaration
263          */
264         private void writeStructJava(StructDecl structDecl) {
265
266                 List<String> structTypes = structDecl.getStructTypes();
267                 // Iterate over enum declarations
268                 for (String stType : structTypes) {
269
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++) {
274
275                                 String memberType = structMemberTypes.get(i);
276                                 String member = structMembers.get(i);
277                                 println("public static " + memberType + " " + member + ";");
278                         }
279                         println("}\n");
280                 }
281         }
282
283
284         /**
285          * generateJavaLocalInterface() writes the local interface and provides type-checking.
286          * <p>
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.
291          */
292         public void generateJavaLocalInterfaces() throws IOException {
293
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
307                         println("");
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);
315                         // Write methods
316                         writeMethodJavaLocalInterface(methods, intDecl);
317                         println("}");
318                         pw.close();
319                         System.out.println("IoTCompiler: Generated local interface " + intface + ".java...");
320                 }
321         }
322
323
324         /**
325          * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
326          */
327         public void generateJavaInterfaces() throws IOException {
328
329                 // Create a new directory
330                 String path = createDirectories(dir, subdir);
331                 for (String intface : mapIntfacePTH.keySet()) {
332
333                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
334                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
335
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
346                                 println("");
347                                 println("public interface " + newIntface + " {\n");
348                                 // Write methods
349                                 writeMethodJavaInterface(intMeth.getValue(), intDecl);
350                                 println("}");
351                                 pw.close();
352                                 System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
353                         }
354                 }
355         }
356
357
358         /**
359          * HELPER: writePropertiesJavaStub() writes the properties of the stub class
360          */
361         private void writePropertiesJavaStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
362
363                 println("private IoTRMICall rmiCall;");
364                 println("private String address;");
365                 println("private int[] ports;\n");
366                 // Get the object Id
367                 Integer objId = mapIntfaceObjId.get(intface);
368                 println("private final static int objectId = " + objId + ";");
369                 mapNewIntfaceObjId.put(newIntface, objId);
370                 mapIntfaceObjId.put(intface, objId++);
371                 if (callbackExist) {
372                 // We assume that each class only has one callback interface for now
373                         Iterator it = callbackClasses.iterator();
374                         String callbackType = (String) it.next();
375                         println("// Callback properties");
376                         println("private IoTRMIObject rmiObj;");
377                         println("List<" + callbackType + "> listCallbackObj;");
378                         println("private static int objIdCnt = 0;");
379                 }
380                 println("\n");
381         }
382
383
384         /**
385          * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
386          */
387         private void writeConstructorJavaStub(String intface, boolean callbackExist, Set<String> callbackClasses) {
388
389                 println("public " + intface + "(int _port, String _address, int _rev, int[] _ports) throws Exception {");
390                 println("address = _address;");
391                 println("ports = _ports;");
392                 println("rmiCall = new IoTRMICall(_port, _address, _rev);");
393                 if (callbackExist) {
394                         Iterator it = callbackClasses.iterator();
395                         String callbackType = (String) it.next();
396                         println("listCallbackObj = new ArrayList<" + callbackType + ">();");
397                         println("___initCallBack();");
398                 }
399                 println("}\n");
400         }
401
402
403         /**
404          * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
405          */
406         private void writeInitCallbackJavaStub(String intface, InterfaceDecl intDecl) {
407
408                 println("public void ___initCallBack() {");
409                 // Generate main thread for callbacks
410                 println("Thread thread = new Thread() {");
411                 println("public void run() {");
412                 println("try {");
413                 println("rmiObj = new IoTRMIObject(ports[0]);");
414                 println("while (true) {");
415                 println("byte[] method = rmiObj.getMethodBytes();");
416                 println("int objId = IoTRMIObject.getObjectId(method);");
417                 println(intface + "_CallbackSkeleton skel = (" + intface + "_CallbackSkeleton) listCallbackObj.get(objId);");
418                 println("if (skel != null) {");
419                 println("skel.invokeMethod(rmiObj);");
420                 println("} else {");
421                 println("throw new Error(\"" + intface + ": Object with Id \" + objId + \" not found!\");");
422                 println("}");
423                 println("}");
424                 println("} catch (Exception ex) {");
425                 println("ex.printStackTrace();");
426                 println("throw new Error(\"Error instantiating class " + intface + "_CallbackSkeleton!\");");
427                 println("}");
428                 println("}");
429                 println("};");
430                 println("thread.start();\n");
431                 // Generate info sending part
432                 String method = "___initCallBack()";
433                 println("int methodId = " + intDecl.getHelperMethodNumId(method) + ";");
434                 println("Class<?> retType = void.class;");
435                 println("Class<?>[] paramCls = new Class<?>[] { int.class, String.class, int.class };");
436                 println("Object[] paramObj = new Object[] { ports[0], address, 0 };");
437                 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
438                 println("}\n");
439         }
440
441
442         /**
443          * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class
444          */
445         private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
446                         List<String> methPrmTypes, String method) {
447
448                 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
449                 String retType = intDecl.getMethodType(method);
450                 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
451                 // Generate array of parameter types
452                 print("Class<?>[] paramCls = new Class<?>[] { ");
453                 for (int i = 0; i < methParams.size(); i++) {
454                         String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
455                         print(getSimpleType(paramType) + ".class");
456                         // Check if this is the last element (don't print a comma)
457                         if (i != methParams.size() - 1) {
458                                 print(", ");
459                         }
460                 }
461                 println(" };");
462                 // Generate array of parameter objects
463                 print("Object[] paramObj = new Object[] { ");
464                 for (int i = 0; i < methParams.size(); i++) {
465                         print(getSimpleIdentifier(methParams.get(i)));
466                         // Check if this is the last element (don't print a comma)
467                         if (i != methParams.size() - 1) {
468                                 print(", ");
469                         }
470                 }
471                 println(" };");
472                 // Check if this is "void"
473                 if (retType.equals("void")) {
474                         println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
475                 } else { // We do have a return value
476                 // Check if the return value NONPRIMITIVES
477                         if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
478                                 String[] retGenValType = getTypeOfGeneric(retType);
479                                 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
480                                 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
481                                 println("return (" + retType + ")retObj;");
482                         } else {
483                                 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
484                                 println("return (" + retType + ")retObj;");
485                         }
486                 }
487         }
488
489
490         /**
491          * HELPER: returnGenericCallbackType() returns the callback type
492          */
493         private String returnGenericCallbackType(String paramType) {
494
495                 if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES)
496                         return getTypeOfGeneric(paramType)[0];
497                 else
498                         return paramType;
499         }
500
501
502         /**
503          * HELPER: checkCallbackType() checks the callback type
504          */
505         private boolean checkCallbackType(String paramType, String callbackType) {
506
507                 String prmType = returnGenericCallbackType(paramType);
508                 return callbackType.equals(prmType);
509         }
510
511
512         /**
513          * HELPER: writeCallbackMethodBodyJavaStub() writes the callback method of the stub class
514          */
515         private void writeCallbackMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
516                         List<String> methPrmTypes, String method, String callbackType) {
517
518                 println("try {");
519                 // Check if this is single object, array, or list of objects
520                 for (int i = 0; i < methParams.size(); i++) {
521
522                         String paramType = methPrmTypes.get(i);
523                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
524                                 String param = methParams.get(i);
525                                 if (isArrayOrList(paramType, param)) {  // Generate loop
526                                         println("for (" + paramType + " cb : " + getSimpleIdentifier(param) + ") {");
527                                         println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);");
528                                 } else
529                                         println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(" +
530                                                 getSimpleIdentifier(param) + ", objIdCnt++);");
531                                 println("listCallbackObj.add(skel);");
532                                 if (isArrayOrList(paramType, param))
533                                         println("}");
534                         }
535                 }
536                 println("} catch (Exception ex) {");
537                 println("ex.printStackTrace();");
538                 println("throw new Error(\"Exception when generating skeleton objects!\");");
539                 println("}\n");
540                 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
541                 String retType = intDecl.getMethodType(method);
542                 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
543                 // Generate array of parameter types
544                 print("Class<?>[] paramCls = new Class<?>[] { ");
545                 for (int i = 0; i < methParams.size(); i++) {
546                         String paramType = methPrmTypes.get(i);
547                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
548                                 print("int.class");
549                         } else { // Generate normal classes if it's not a callback object
550                                 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
551                                 print(getSimpleType(prmType) + ".class");
552                         }
553                         if (i != methParams.size() - 1) // Check if this is the last element
554                                 print(", ");
555                 }
556                 println(" };");
557                 // Generate array of parameter objects
558                 print("Object[] paramObj = new Object[] { ");
559                 for (int i = 0; i < methParams.size(); i++) {
560                         String paramType = methPrmTypes.get(i);
561                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
562                                 if (isArray(methPrmTypes.get(i), methParams.get(i)))
563                                         print(getSimpleIdentifier(methParams.get(i)) + ".length");
564                                 else if (isList(methPrmTypes.get(i), methParams.get(i)))
565                                         print(getSimpleIdentifier(methParams.get(i)) + ".size()");
566                                 else
567                                         print("new Integer(1)");
568                         } else
569                                 print(getSimpleIdentifier(methParams.get(i)));
570                         if (i != methParams.size() - 1)
571                                 print(", ");
572                 }
573                 println(" };");
574                 // Check if this is "void"
575                 if (retType.equals("void")) {
576                         println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
577                 } else { // We do have a return value
578                 // Check if the return value NONPRIMITIVES
579                         if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
580                                 String[] retGenValType = getTypeOfGeneric(retType);
581                                 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
582                                 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
583                                 println("return (" + retType + ")retObj;");
584                         } else {
585                                 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
586                                 println("return (" + retType + ")retObj;");
587                         }
588                 }
589         }
590
591
592         /**
593          * HELPER: writeMethodJavaStub() writes the method of the stub class
594          */
595         private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
596
597                 for (String method : methods) {
598
599                         List<String> methParams = intDecl.getMethodParams(method);
600                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
601                         print("public " + intDecl.getMethodType(method) + " " +
602                                 intDecl.getMethodId(method) + "(");
603                         boolean isCallbackMethod = false;
604                         String callbackType = null;
605                         for (int i = 0; i < methParams.size(); i++) {
606
607                                 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
608                                 // Check if this has callback object
609                                 if (callbackClasses.contains(paramType)) {
610                                         isCallbackMethod = true;
611                                         callbackType = paramType;       
612                                         // Even if there're 2 callback arguments, we expect them to be of the same interface
613                                 }
614                                 print(methPrmTypes.get(i) + " " + methParams.get(i));
615                                 // Check if this is the last element (don't print a comma)
616                                 if (i != methParams.size() - 1) {
617                                         print(", ");
618                                 }
619                         }
620                         println(") {");
621                         // Now, write the body of stub!
622                         if (isCallbackMethod)
623                                 writeCallbackMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method, callbackType);
624                         else
625                                 writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
626                         println("}\n");
627                         // Write the init callback helper method
628                         if (isCallbackMethod)
629                                 writeInitCallbackJavaStub(callbackType, intDecl);
630                 }
631         }
632
633
634         /**
635          * generateJavaStubClasses() generate stubs based on the methods list in Java
636          */
637         public void generateJavaStubClasses() throws IOException {
638
639                 // Create a new directory
640                 String path = createDirectories(dir, subdir);
641                 for (String intface : mapIntfacePTH.keySet()) {
642
643                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
644                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
645
646                                 // Open a new file to write into
647                                 String newIntface = intMeth.getKey();
648                                 String newStubClass = newIntface + "_Stub";
649                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
650                                 pw = new PrintWriter(new BufferedWriter(fw));
651                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
652                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
653                                 // Pass in set of methods and get import classes
654                                 Set<String> methods = intMeth.getValue();
655                                 Set<String> importClasses = getImportClasses(methods, intDecl);
656                                 List<String> stdImportClasses = getStandardJavaImportClasses();
657                                 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
658                                 printImportStatements(allImportClasses); println("");
659                                 // Find out if there are callback objects
660                                 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
661                                 boolean callbackExist = !callbackClasses.isEmpty();
662                                 // Write class header
663                                 println("public class " + newStubClass + " implements " + newIntface + " {\n");
664                                 // Write properties
665                                 writePropertiesJavaStub(intface, newIntface, callbackExist, callbackClasses);
666                                 // Write constructor
667                                 writeConstructorJavaStub(newStubClass, callbackExist, callbackClasses);
668                                 // Write methods
669                                 writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses);
670                                 println("}");
671                                 pw.close();
672                                 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
673                         }
674                 }
675         }
676
677
678         /**
679          * HELPER: writePropertiesJavaCallbackStub() writes the properties of the callback stub class
680          */
681         private void writePropertiesJavaCallbackStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
682
683                 println("private IoTRMICall rmiCall;");
684                 println("private String address;");
685                 println("private int[] ports;\n");
686                 // Get the object Id
687                 println("private static int objectId = 0;");
688                 if (callbackExist) {
689                 // We assume that each class only has one callback interface for now
690                         Iterator it = callbackClasses.iterator();
691                         String callbackType = (String) it.next();
692                         println("// Callback properties");
693                         println("private IoTRMIObject rmiObj;");
694                         println("List<" + callbackType + "> listCallbackObj;");
695                         println("private static int objIdCnt = 0;");
696                 }
697                 println("\n");
698         }
699
700
701         /**
702          * HELPER: writeConstructorJavaCallbackStub() writes the constructor of the callback stub class
703          */
704         private void writeConstructorJavaCallbackStub(String intface, boolean callbackExist, Set<String> callbackClasses) {
705
706                 // TODO: If we want callback in callback, then we need to add address and port initializations
707                 println("public " + intface + "(IoTRMICall _rmiCall, int _objectId) throws Exception {");
708                 println("objectId = _objectId;");
709                 println("rmiCall = _rmiCall;");
710                 if (callbackExist) {
711                         Iterator it = callbackClasses.iterator();
712                         String callbackType = (String) it.next();
713                         println("listCallbackObj = new ArrayList<" + callbackType + ">();");
714                         println("___initCallBack();");
715                         println("// TODO: Add address and port initialization here if we want callback in callback!");
716                 }
717                 println("}\n");
718         }
719
720
721         /**
722          * generateJavaCallbackStubClasses() generate callback stubs based on the methods list in Java
723          * <p>
724          * Callback stubs gets the IoTRMICall objects from outside of the class as contructor input
725          * because all these stubs are populated by the class that takes in this object as a callback
726          * object. In such a class, we only use one socket, hence one IoTRMICall, for all callback objects.
727          */
728         public void generateJavaCallbackStubClasses() throws IOException {
729
730                 // Create a new directory
731                 String path = createDirectories(dir, subdir);
732                 for (String intface : mapIntfacePTH.keySet()) {
733
734                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
735                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
736
737                                 // Open a new file to write into
738                                 String newIntface = intMeth.getKey();
739                                 String newStubClass = newIntface + "_CallbackStub";
740                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
741                                 pw = new PrintWriter(new BufferedWriter(fw));
742                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
743                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
744                                 // Pass in set of methods and get import classes
745                                 Set<String> methods = intMeth.getValue();
746                                 Set<String> importClasses = getImportClasses(methods, intDecl);
747                                 List<String> stdImportClasses = getStandardJavaImportClasses();
748                                 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
749                                 printImportStatements(allImportClasses); println("");
750                                 // Find out if there are callback objects
751                                 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
752                                 boolean callbackExist = !callbackClasses.isEmpty();
753                                 // Write class header
754                                 println("public class " + newStubClass + " implements " + newIntface + " {\n");
755                                 // Write properties
756                                 writePropertiesJavaCallbackStub(intface, newIntface, callbackExist, callbackClasses);
757                                 // Write constructor
758                                 writeConstructorJavaCallbackStub(newStubClass, callbackExist, callbackClasses);
759                                 // Write methods
760                                 // TODO: perhaps need to generate callback for callback
761                                 writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses);
762                                 println("}");
763                                 pw.close();
764                                 System.out.println("IoTCompiler: Generated callback stub class " + newStubClass + ".java...");
765                         }
766                 }
767         }
768
769
770         /**
771          * HELPER: writePropertiesJavaSkeleton() writes the properties of the skeleton class
772          */
773         private void writePropertiesJavaSkeleton(String intface, boolean callbackExist) {
774
775                 println("private " + intface + " mainObj;");
776                 //println("private int ports;");
777                 println("private IoTRMIObject rmiObj;\n");
778                 // Callback
779                 if (callbackExist) {
780                         println("private static int objIdCnt = 0;");
781                         println("private IoTRMICall rmiCall;");
782                 }
783                 // Keep track of object Ids of all stubs registered to this interface
784                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
785                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
786                         String newIntface = intMeth.getKey();
787                         int newObjectId = mapNewIntfaceObjId.get(newIntface);
788                         println("private final static int object" + newObjectId + "Id = " + 
789                                 newObjectId + ";\t//" + newIntface);
790                 }
791                 println("\n");
792         }
793
794
795         /**
796          * HELPER: writeConstructorJavaSkeleton() writes the constructor of the skeleton class
797          */
798         private void writeConstructorJavaSkeleton(String newSkelClass, String intface) {
799
800                 println("public " + newSkelClass + "(" + intface + " _mainObj, int _port) throws Exception {");
801                 println("mainObj = _mainObj;");
802                 println("rmiObj = new IoTRMIObject(_port);");
803                 //println("set0Allowed = Arrays.asList(object0Permission);");
804                 println("___waitRequestInvokeMethod();");
805                 println("}\n");
806         }
807
808
809         /**
810          * HELPER: writeStdMethodBodyJavaSkeleton() writes the standard method body in the skeleton class
811          */
812         private void writeStdMethodBodyJavaSkeleton(List<String> methParams, String methodId, String methodType) {
813
814                 if (methodType.equals("void"))
815                         print("mainObj." + methodId + "(");
816                 else
817                         print("return mainObj." + methodId + "(");
818                 for (int i = 0; i < methParams.size(); i++) {
819
820                         print(getSimpleIdentifier(methParams.get(i)));
821                         // Check if this is the last element (don't print a comma)
822                         if (i != methParams.size() - 1) {
823                                 print(", ");
824                         }
825                 }
826                 println(");");
827         }
828
829
830         /**
831          * HELPER: writeInitCallbackJavaSkeleton() writes the init callback method for skeleton class
832          */
833         private void writeInitCallbackJavaSkeleton(boolean callbackSkeleton) {
834
835                 // This is a callback skeleton generation
836                 if (callbackSkeleton)
837                         println("public void ___regCB(IoTRMIObject rmiObj) throws IOException {");
838                 else
839                         println("public void ___regCB() throws IOException {");
840                 println("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class, String.class, int.class },");
841                 println("\tnew Class<?>[] { null, null, null });");
842                 println("rmiCall = new IoTRMICall((int) paramObj[0], (String) paramObj[1], (int) paramObj[2]);");
843                 println("}\n");
844         }
845
846
847         /**
848          * HELPER: writeMethodJavaSkeleton() writes the method of the skeleton class
849          */
850         private void writeMethodJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses, 
851                         boolean callbackSkeleton) {
852
853                 for (String method : methods) {
854
855                         List<String> methParams = intDecl.getMethodParams(method);
856                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
857                         String methodId = intDecl.getMethodId(method);
858                         print("public " + intDecl.getMethodType(method) + " " + methodId + "(");
859                         boolean isCallbackMethod = false;
860                         String callbackType = null;
861                         for (int i = 0; i < methParams.size(); i++) {
862
863                                 String origParamType = methPrmTypes.get(i);
864                                 String paramType = checkAndGetParamClass(origParamType);
865                                 if (callbackClasses.contains(origParamType)) { // Check if this has callback object
866                                         isCallbackMethod = true;
867                                         callbackType = origParamType;   
868                                 }
869                                 print(paramType + " " + methParams.get(i));
870                                 // Check if this is the last element (don't print a comma)
871                                 if (i != methParams.size() - 1) {
872                                         print(", ");
873                                 }
874                         }
875                         println(") {");
876                         // Now, write the body of skeleton!
877                         writeStdMethodBodyJavaSkeleton(methParams, methodId, intDecl.getMethodType(method));
878                         println("}\n");
879                         if (isCallbackMethod)
880                                 writeInitCallbackJavaSkeleton(callbackSkeleton);
881                 }
882         }
883
884
885         /**
886          * HELPER: writeCallbackJavaStubGeneration() writes the callback stub generation part
887          */
888         private Map<Integer,String> writeCallbackJavaStubGeneration(List<String> methParams, List<String> methPrmTypes, String callbackType) {
889
890                 Map<Integer,String> mapStubParam = new HashMap<Integer,String>();
891                 // Iterate over callback objects
892                 for (int i = 0; i < methParams.size(); i++) {
893                         String paramType = methPrmTypes.get(i);
894                         String param = methParams.get(i);
895                         //if (callbackType.equals(paramType)) {
896                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
897                                 println("try {");
898                                 String exchParamType = checkAndGetParamClass(paramType);
899                                 // Print array if this is array or list if this is a list of callback objects
900                                 if (isArray(paramType, param)) {
901                                         println("int numStubs" + i + " = (int) paramObj[" + i + "];");
902                                         println(exchParamType + "[] stub" + i + " = new " + exchParamType + "[numStubs" + i + "];");
903                                 } else if (isList(paramType, param)) {
904                                         println("int numStubs" + i + " = (int) paramObj[" + i + "];");
905                                         println("List<" + exchParamType + "> stub" + i + " = new ArrayList<" + exchParamType + ">();");
906                                 } else {
907                                         println(exchParamType + " stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
908                                         println("objIdCnt++;");
909                                 }
910                         }
911                         // Generate a loop if needed
912                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
913                                 String exchParamType = checkAndGetParamClass(paramType);
914                                 if (isArray(paramType, param)) {
915                                         println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
916                                         println("stub" + i + "[objId] = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
917                                         println("objIdCnt++;");
918                                         println("}");
919                                 } else if (isList(paramType, param)) {
920                                         println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
921                                         println("stub" + i + ".add(new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt));");
922                                         println("objIdCnt++;");
923                                         println("}");
924                                 }
925                                 mapStubParam.put(i, "stub" + i);        // List of all stub parameters
926                         }
927                 }
928                 return mapStubParam;
929         }
930
931
932         /**
933          * HELPER: writeStdMethodHelperBodyJavaSkeleton() writes the standard method body helper in the skeleton class
934          */
935         private void writeStdMethodHelperBodyJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
936                         List<String> methPrmTypes, String method, Set<String> callbackClasses) {
937                 // Generate array of parameter objects
938                 boolean isCallbackMethod = false;
939                 String callbackType = null;
940                 print("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { ");
941                 for (int i = 0; i < methParams.size(); i++) {
942
943                         String paramType = returnGenericCallbackType(methPrmTypes.get(i));
944                         if (callbackClasses.contains(paramType)) {
945                                 isCallbackMethod = true;
946                                 callbackType = paramType;
947                                 print("int.class");
948                         } else {        // Generate normal classes if it's not a callback object
949                                 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
950                                 print(getSimpleType(prmType) + ".class");
951                         }
952                         if (i != methParams.size() - 1)
953                                 print(", ");
954                 }
955                 println(" }, ");
956                 // Generate generic class if it's a generic type.. null otherwise
957                 print("new Class<?>[] { ");
958                 for (int i = 0; i < methParams.size(); i++) {
959                         String prmType = methPrmTypes.get(i);
960                         if (getParamCategory(prmType) == ParamCategory.NONPRIMITIVES)
961                                 print(getTypeOfGeneric(prmType)[0] + ".class");
962                         else
963                                 print("null");
964                         if (i != methParams.size() - 1)
965                                 print(", ");
966                 }
967                 println(" });");
968                 Map<Integer,String> mapStubParam = null;
969                 if (isCallbackMethod)
970                         mapStubParam = writeCallbackJavaStubGeneration(methParams, methPrmTypes, callbackType);
971                 // Check if this is "void"
972                 String retType = intDecl.getMethodType(method);
973                 if (retType.equals("void")) {
974                         print(intDecl.getMethodId(method) + "(");
975                 } else { // We do have a return value
976                         print("Object retObj = " + intDecl.getMethodId(method) + "(");
977                 }
978                 for (int i = 0; i < methParams.size(); i++) {
979
980                         if (isCallbackMethod) {
981                                 print(mapStubParam.get(i));     // Get the callback parameter
982                         } else {
983                                 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
984                                 print("(" + prmType + ") paramObj[" + i + "]");
985                         }
986                         if (i != methParams.size() - 1)
987                                 print(", ");
988                 }
989                 println(");");
990                 if (!retType.equals("void"))
991                         println("rmiObj.sendReturnObj(retObj);");
992                 if (isCallbackMethod) { // Catch exception if this is callback
993                         println("} catch(Exception ex) {");
994                         println("ex.printStackTrace();");
995                         println("throw new Error(\"Exception from callback object instantiation!\");");
996                         println("}");
997                 }
998         }
999
1000
1001         /**
1002          * HELPER: writeMethodHelperJavaSkeleton() writes the method helper of the skeleton class
1003          */
1004         private void writeMethodHelperJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1005
1006                 // Use this set to handle two same methodIds
1007                 Set<String> uniqueMethodIds = new HashSet<String>();
1008                 for (String method : methods) {
1009
1010                         List<String> methParams = intDecl.getMethodParams(method);
1011                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1012                         String methodId = intDecl.getMethodId(method);
1013                         print("public void ___");
1014                         String helperMethod = methodId;
1015                         if (uniqueMethodIds.contains(methodId))
1016                                 helperMethod = helperMethod + intDecl.getMethodNumId(method);
1017                         else
1018                                 uniqueMethodIds.add(methodId);
1019                         // Check if this is "void"
1020                         String retType = intDecl.getMethodType(method);
1021                         if (retType.equals("void"))
1022                                 println(helperMethod + "() {");
1023                         else
1024                                 println(helperMethod + "() throws IOException {");
1025                         // Now, write the helper body of skeleton!
1026                         writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
1027                         println("}\n");
1028                 }
1029         }
1030
1031
1032         /**
1033          * HELPER: writeJavaWaitRequestInvokeMethod() writes the main loop of the skeleton class
1034          */
1035         private void writeJavaWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist) {
1036
1037                 // Use this set to handle two same methodIds
1038                 Set<String> uniqueMethodIds = new HashSet<String>();
1039                 println("private void ___waitRequestInvokeMethod() throws IOException {");
1040                 // Write variables here if we have callbacks or enums or structs
1041                 println("while (true) {");
1042                 println("rmiObj.getMethodBytes();");
1043                 println("int _objectId = rmiObj.getObjectId();");
1044                 println("int methodId = rmiObj.getMethodId();");
1045                 // TODO: code the permission check here!
1046                 println("switch (methodId) {");
1047                 // Print methods and method Ids
1048                 for (String method : methods) {
1049                         String methodId = intDecl.getMethodId(method);
1050                         int methodNumId = intDecl.getMethodNumId(method);
1051                         print("case " + methodNumId + ": ___");
1052                         String helperMethod = methodId;
1053                         if (uniqueMethodIds.contains(methodId))
1054                                 helperMethod = helperMethod + methodNumId;
1055                         else
1056                                 uniqueMethodIds.add(methodId);
1057                         println(helperMethod + "(); break;");
1058                 }
1059                 String method = "___initCallBack()";
1060                 // Print case -9999 (callback handler) if callback exists
1061                 if (callbackExist) {
1062                         int methodId = intDecl.getHelperMethodNumId(method);
1063                         println("case " + methodId + ": ___regCB(); break;");
1064                 }
1065                 println("default: ");
1066                 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
1067                 println("}");
1068                 println("}");
1069                 println("}\n");
1070         }
1071
1072
1073         /**
1074          * generateJavaSkeletonClass() generate skeletons based on the methods list in Java
1075          */
1076         public void generateJavaSkeletonClass() throws IOException {
1077
1078                 // Create a new directory
1079                 String path = createDirectories(dir, subdir);
1080                 for (String intface : mapIntfacePTH.keySet()) {
1081                         // Open a new file to write into
1082                         String newSkelClass = intface + "_Skeleton";
1083                         FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
1084                         pw = new PrintWriter(new BufferedWriter(fw));
1085                         // Pass in set of methods and get import classes
1086                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1087                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1088                         List<String> methods = intDecl.getMethods();
1089                         Set<String> importClasses = getImportClasses(methods, intDecl);
1090                         List<String> stdImportClasses = getStandardJavaImportClasses();
1091                         List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
1092                         printImportStatements(allImportClasses);
1093                         // Find out if there are callback objects
1094                         Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1095                         boolean callbackExist = !callbackClasses.isEmpty();
1096                         // Write class header
1097                         println("");
1098                         println("public class " + newSkelClass  + " implements " + intface + " {\n");
1099                         // Write properties
1100                         writePropertiesJavaSkeleton(intface, callbackExist);
1101                         // Write constructor
1102                         writeConstructorJavaSkeleton(newSkelClass, intface);
1103                         // Write methods
1104                         writeMethodJavaSkeleton(methods, intDecl, callbackClasses, false);
1105                         // Write method helper
1106                         writeMethodHelperJavaSkeleton(methods, intDecl, callbackClasses);
1107                         // Write waitRequestInvokeMethod() - main loop
1108                         writeJavaWaitRequestInvokeMethod(methods, intDecl, callbackExist);
1109                         println("}");
1110                         pw.close();
1111                         System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".java...");
1112                 }
1113         }
1114
1115
1116         /**
1117          * HELPER: writePropertiesJavaCallbackSkeleton() writes the properties of the callback skeleton class
1118          */
1119         private void writePropertiesJavaCallbackSkeleton(String intface, boolean callbackExist) {
1120
1121                 println("private " + intface + " mainObj;");
1122                 // For callback skeletons, this is its own object Id
1123                 println("private static int objectId = 0;");
1124                 // Callback
1125                 if (callbackExist) {
1126                         println("private static int objIdCnt = 0;");
1127                         println("private IoTRMICall rmiCall;");
1128                 }
1129                 println("\n");
1130         }
1131
1132
1133         /**
1134          * HELPER: writeConstructorJavaCallbackSkeleton() writes the constructor of the skeleton class
1135          */
1136         private void writeConstructorJavaCallbackSkeleton(String newSkelClass, String intface) {
1137
1138                 println("public " + newSkelClass + "(" + intface + " _mainObj, int _objectId) throws Exception {");
1139                 println("mainObj = _mainObj;");
1140                 println("objectId = _objectId;");
1141                 println("}\n");
1142         }
1143
1144
1145         /**
1146          * HELPER: writeMethodHelperJavaCallbackSkeleton() writes the method helper of the callback skeleton class
1147          */
1148         private void writeMethodHelperJavaCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1149
1150                 // Use this set to handle two same methodIds
1151                 Set<String> uniqueMethodIds = new HashSet<String>();
1152                 for (String method : methods) {
1153
1154                         List<String> methParams = intDecl.getMethodParams(method);
1155                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1156                         String methodId = intDecl.getMethodId(method);
1157                         print("public void ___");
1158                         String helperMethod = methodId;
1159                         if (uniqueMethodIds.contains(methodId))
1160                                 helperMethod = helperMethod + intDecl.getMethodNumId(method);
1161                         else
1162                                 uniqueMethodIds.add(methodId);
1163                         // Check if this is "void"
1164                         String retType = intDecl.getMethodType(method);
1165                         if (retType.equals("void"))
1166                                 println(helperMethod + "(IoTRMIObject rmiObj) {");
1167                         else
1168                                 println(helperMethod + "(IoTRMIObject rmiObj) throws IOException {");
1169                         // Now, write the helper body of skeleton!
1170                         writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
1171                         println("}\n");
1172                 }
1173         }
1174
1175
1176         /**
1177          * HELPER: writeJavaCallbackWaitRequestInvokeMethod() writes the main loop of the skeleton class
1178          */
1179         private void writeJavaCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist) {
1180
1181                 // Use this set to handle two same methodIds
1182                 Set<String> uniqueMethodIds = new HashSet<String>();
1183                 println("public void invokeMethod(IoTRMIObject rmiObj) throws IOException {");
1184                 // Write variables here if we have callbacks or enums or structs
1185                 println("int methodId = rmiObj.getMethodId();");
1186                 // TODO: code the permission check here!
1187                 println("switch (methodId) {");
1188                 // Print methods and method Ids
1189                 for (String method : methods) {
1190                         String methodId = intDecl.getMethodId(method);
1191                         int methodNumId = intDecl.getMethodNumId(method);
1192                         print("case " + methodNumId + ": ___");
1193                         String helperMethod = methodId;
1194                         if (uniqueMethodIds.contains(methodId))
1195                                 helperMethod = helperMethod + methodNumId;
1196                         else
1197                                 uniqueMethodIds.add(methodId);
1198                         println(helperMethod + "(rmiObj); break;");
1199                 }
1200                 String method = "___initCallBack()";
1201                 // Print case -9999 (callback handler) if callback exists
1202                 if (callbackExist) {
1203                         int methodId = intDecl.getHelperMethodNumId(method);
1204                         println("case " + methodId + ": ___regCB(rmiObj); break;");
1205                 }
1206                 println("default: ");
1207                 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
1208                 println("}");
1209                 println("}\n");
1210         }
1211
1212
1213         /**
1214          * generateJavaCallbackSkeletonClass() generate callback skeletons based on the methods list in Java
1215          */
1216         public void generateJavaCallbackSkeletonClass() throws IOException {
1217
1218                 // Create a new directory
1219                 String path = createDirectories(dir, subdir);
1220                 for (String intface : mapIntfacePTH.keySet()) {
1221                         // Open a new file to write into
1222                         String newSkelClass = intface + "_CallbackSkeleton";
1223                         FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
1224                         pw = new PrintWriter(new BufferedWriter(fw));
1225                         // Pass in set of methods and get import classes
1226                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1227                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1228                         List<String> methods = intDecl.getMethods();
1229                         Set<String> importClasses = getImportClasses(methods, intDecl);
1230                         List<String> stdImportClasses = getStandardJavaImportClasses();
1231                         List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
1232                         printImportStatements(allImportClasses);
1233                         // Find out if there are callback objects
1234                         Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1235                         boolean callbackExist = !callbackClasses.isEmpty();
1236                         // Write class header
1237                         println("");
1238                         println("public class " + newSkelClass  + " implements " + intface + " {\n");
1239                         // Write properties
1240                         writePropertiesJavaCallbackSkeleton(intface, callbackExist);
1241                         // Write constructor
1242                         writeConstructorJavaCallbackSkeleton(newSkelClass, intface);
1243                         // Write methods
1244                         writeMethodJavaSkeleton(methods, intDecl, callbackClasses, true);
1245                         // Write method helper
1246                         writeMethodHelperJavaCallbackSkeleton(methods, intDecl, callbackClasses);
1247                         // Write waitRequestInvokeMethod() - main loop
1248                         writeJavaCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist);
1249                         println("}");
1250                         pw.close();
1251                         System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".java...");
1252                 }
1253         }
1254
1255
1256         /**
1257          * HELPER: writeMethodCplusLocalInterface() writes the method of the interface
1258          */
1259         private void writeMethodCplusLocalInterface(Collection<String> methods, InterfaceDecl intDecl) {
1260
1261                 for (String method : methods) {
1262
1263                         List<String> methParams = intDecl.getMethodParams(method);
1264                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1265                         print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
1266                                 intDecl.getMethodId(method) + "(");
1267                         for (int i = 0; i < methParams.size(); i++) {
1268                                 // Check for params with driver class types and exchange it 
1269                                 //              with its remote interface
1270                                 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
1271                                 paramType = checkAndGetCplusType(paramType);
1272                                 // Check for arrays - translate into vector in C++
1273                                 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
1274                                 print(paramComplete);
1275                                 // Check if this is the last element (don't print a comma)
1276                                 if (i != methParams.size() - 1) {
1277                                         print(", ");
1278                                 }
1279                         }
1280                         println(") = 0;");
1281                 }
1282         }
1283
1284
1285         /**
1286          * HELPER: writeMethodCplusInterface() writes the method of the interface
1287          */
1288         private void writeMethodCplusInterface(Collection<String> methods, InterfaceDecl intDecl) {
1289
1290                 for (String method : methods) {
1291
1292                         List<String> methParams = intDecl.getMethodParams(method);
1293                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1294                         print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
1295                                 intDecl.getMethodId(method) + "(");
1296                         for (int i = 0; i < methParams.size(); i++) {
1297                                 // Check for params with driver class types and exchange it 
1298                                 //              with its remote interface
1299                                 String paramType = methPrmTypes.get(i);
1300                                 paramType = checkAndGetCplusType(paramType);
1301                                 // Check for arrays - translate into vector in C++
1302                                 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
1303                                 print(paramComplete);
1304                                 // Check if this is the last element (don't print a comma)
1305                                 if (i != methParams.size() - 1) {
1306                                         print(", ");
1307                                 }
1308                         }
1309                         println(") = 0;");
1310                 }
1311         }
1312
1313
1314         /**
1315          * HELPER: writeEnumCplus() writes the enumeration declaration
1316          */
1317         private void writeEnumCplus(EnumDecl enumDecl) {
1318
1319                 Set<String> enumTypes = enumDecl.getEnumDeclarations();
1320                 // Iterate over enum declarations
1321                 for (String enType : enumTypes) {
1322
1323                         println("enum " + enType + " {");
1324                         List<String> enumMembers = enumDecl.getMembers(enType);
1325                         for (int i = 0; i < enumMembers.size(); i++) {
1326
1327                                 String member = enumMembers.get(i);
1328                                 print(member);
1329                                 // Check if this is the last element (don't print a comma)
1330                                 if (i != enumMembers.size() - 1)
1331                                         println(",");
1332                                 else
1333                                         println("");
1334                         }
1335                         println("};\n");
1336                 }
1337         }
1338
1339
1340         /**
1341          * HELPER: writeStructCplus() writes the struct declaration
1342          */
1343         private void writeStructCplus(StructDecl structDecl) {
1344
1345                 List<String> structTypes = structDecl.getStructTypes();
1346                 // Iterate over enum declarations
1347                 for (String stType : structTypes) {
1348
1349                         println("struct " + stType + " {");
1350                         List<String> structMemberTypes = structDecl.getMemberTypes(stType);
1351                         List<String> structMembers = structDecl.getMembers(stType);
1352                         for (int i = 0; i < structMembers.size(); i++) {
1353
1354                                 String memberType = structMemberTypes.get(i);
1355                                 String member = structMembers.get(i);
1356                                 String structTypeC = checkAndGetCplusType(memberType);
1357                                 String structComplete = checkAndGetCplusArray(structTypeC, member);
1358                                 println(structComplete + ";");
1359                         }
1360                         println("};\n");
1361                 }
1362         }
1363
1364
1365         /**
1366          * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking.
1367          * <p>
1368          * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
1369          * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
1370          * The local interface has to be the input parameter for the stub and the stub 
1371          * interface has to be the input parameter for the local class.
1372          */
1373         public void generateCplusLocalInterfaces() throws IOException {
1374
1375                 // Create a new directory
1376                 createDirectory(dir);
1377                 for (String intface : mapIntfacePTH.keySet()) {
1378                         // Open a new file to write into
1379                         FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
1380                         pw = new PrintWriter(new BufferedWriter(fw));
1381                         // Write file headers
1382                         println("#ifndef _" + intface.toUpperCase() + "_HPP__");
1383                         println("#define _" + intface.toUpperCase() + "_HPP__");
1384                         println("#include <iostream>");
1385                         // Pass in set of methods and get include classes
1386                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1387                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1388                         List<String> methods = intDecl.getMethods();
1389                         Set<String> includeClasses = getIncludeClasses(methods, intDecl, true);
1390                         printIncludeStatements(includeClasses); println("");
1391                         println("using namespace std;\n");
1392                         // Write enum if any...
1393                         EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface);
1394                         writeEnumCplus(enumDecl);
1395                         // Write struct if any...
1396                         StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
1397                         writeStructCplus(structDecl);
1398                         println("class " + intface); println("{");
1399                         println("public:");
1400                         // Write methods
1401                         writeMethodCplusLocalInterface(methods, intDecl);
1402                         println("};");
1403                         println("#endif");
1404                         pw.close();
1405                         System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
1406                 }
1407         }
1408
1409
1410         /**
1411          * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
1412          * <p>
1413          * For C++ we use virtual classe as interface
1414          */
1415         public void generateCPlusInterfaces() throws IOException {
1416
1417                 // Create a new directory
1418                 String path = createDirectories(dir, subdir);
1419                 for (String intface : mapIntfacePTH.keySet()) {
1420
1421                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1422                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1423
1424                                 // Open a new file to write into
1425                                 String newIntface = intMeth.getKey();
1426                                 FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp");
1427                                 pw = new PrintWriter(new BufferedWriter(fw));
1428                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1429                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1430                                 // Write file headers
1431                                 println("#ifndef _" + newIntface.toUpperCase() + "_HPP__");
1432                                 println("#define _" + newIntface.toUpperCase() + "_HPP__");
1433                                 println("#include <iostream>");
1434                                 // Pass in set of methods and get import classes
1435                                 Set<String> includeClasses = getIncludeClasses(intMeth.getValue(), intDecl, false);
1436                                 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
1437                                 List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
1438                                 printIncludeStatements(allIncludeClasses); println("");                 
1439                                 println("using namespace std;\n");
1440                                 println("class " + newIntface);
1441                                 println("{");
1442                                 println("public:");
1443                                 // Write methods
1444                                 writeMethodCplusInterface(intMeth.getValue(), intDecl);
1445                                 println("};");
1446                                 println("#endif");
1447                                 pw.close();
1448                                 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
1449                         }
1450                 }
1451         }
1452
1453
1454         /**
1455          * HELPER: writeMethodCplusStub() writes the method of the stub
1456          */
1457         private void writeMethodCplusStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1458
1459                 for (String method : methods) {
1460
1461                         List<String> methParams = intDecl.getMethodParams(method);
1462                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1463                         print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
1464                                 intDecl.getMethodId(method) + "(");
1465                         boolean isCallbackMethod = false;
1466                         String callbackType = null;
1467                         for (int i = 0; i < methParams.size(); i++) {
1468
1469                                 String paramType = methPrmTypes.get(i);
1470                                 // Check if this has callback object
1471                                 if (callbackClasses.contains(paramType)) {
1472                                         isCallbackMethod = true;
1473                                         callbackType = paramType;       
1474                                         // Even if there're 2 callback arguments, we expect them to be of the same interface
1475                                 }
1476                                 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
1477                                 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
1478                                 print(methParamComplete);
1479                                 // Check if this is the last element (don't print a comma)
1480                                 if (i != methParams.size() - 1) {
1481                                         print(", ");
1482                                 }
1483                         }
1484                         println(") { ");
1485                         if (isCallbackMethod)
1486                                 writeCallbackMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method, callbackType);
1487                         else
1488                                 writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method);
1489                         println("}\n");
1490                         // Write the init callback helper method
1491                         if (isCallbackMethod) {
1492                                 writeInitCallbackCplusStub(callbackType, intDecl);
1493                                 writeInitCallbackSendInfoCplusStub(intDecl);
1494                         }
1495                 }
1496         }
1497
1498
1499         /**
1500          * HELPER: writeCallbackMethodBodyCplusStub() writes the callback method of the stub class
1501          */
1502         private void writeCallbackMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
1503                         List<String> methPrmTypes, String method, String callbackType) {
1504
1505                 // Check if this is single object, array, or list of objects
1506                 boolean isArrayOrList = false;
1507                 String callbackParam = null;
1508                 for (int i = 0; i < methParams.size(); i++) {
1509
1510                         String paramType = methPrmTypes.get(i);
1511                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1512                                 String param = methParams.get(i);
1513                                 if (isArrayOrList(paramType, param)) {  // Generate loop
1514                                         println("for (" + paramType + "* cb : " + getSimpleIdentifier(param) + ") {");
1515                                         println(callbackType + "_CallbackSkeleton* skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);");
1516                                         isArrayOrList = true;
1517                                         callbackParam = getSimpleIdentifier(param);
1518                                 } else
1519                                         println(callbackType + "_CallbackSkeleton* skel = new " + callbackType + "_CallbackSkeleton(" +
1520                                                 getSimpleIdentifier(param) + ", objIdCnt++);");
1521                                 println("vecCallbackObj.push_back(skel);");
1522                                 if (isArrayOrList(paramType, param))
1523                                         println("}");
1524                         }
1525                 }
1526                 println("int numParam = " + methParams.size() + ";");
1527                 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
1528                 String retType = intDecl.getMethodType(method);
1529                 String retTypeC = checkAndGetCplusType(retType);
1530                 println("string retType = \"" + checkAndGetCplusArrayType(retTypeC) + "\";");
1531                 // Generate array of parameter types
1532                 print("string paramCls[] = { ");
1533                 for (int i = 0; i < methParams.size(); i++) {
1534                         String paramType = methPrmTypes.get(i);
1535                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1536                                 print("\"int\"");
1537                         } else { // Generate normal classes if it's not a callback object
1538                                 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
1539                                 String prmType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
1540                                 print("\"" + prmType + "\"");
1541                         }
1542                         if (i != methParams.size() - 1) // Check if this is the last element
1543                                 print(", ");
1544                 }
1545                 println(" };");
1546                 print("int ___paramCB = ");
1547                 if (isArrayOrList)
1548                         println(callbackParam + ".size();");
1549                 else
1550                         println("1;");
1551                 // Generate array of parameter objects
1552                 print("void* paramObj[] = { ");
1553                 for (int i = 0; i < methParams.size(); i++) {
1554                         String paramType = methPrmTypes.get(i);
1555                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1556                                 print("&___paramCB");
1557                         } else
1558                                 print(getSimpleIdentifier(methParams.get(i)));
1559                         if (i != methParams.size() - 1)
1560                                 print(", ");
1561                 }
1562                 println(" };");
1563                 // Check if this is "void"
1564                 if (retType.equals("void")) {
1565                         println("void* retObj = NULL;");
1566                         println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1567                 } else { // We do have a return value
1568                         if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
1569                                 println(checkAndGetCplusType(retType) + " retVal;");
1570                         else
1571                                 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
1572                         println("void* retObj = &retVal;");
1573                         println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1574                         println("return retVal;");
1575                 }
1576         }
1577
1578
1579         /**
1580          * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class
1581          */
1582         private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
1583                         List<String> methPrmTypes, String method) {
1584
1585                 println("int numParam = " + methParams.size() + ";");
1586                 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
1587                 String retType = intDecl.getMethodType(method);
1588                 String retTypeC = checkAndGetCplusType(retType);
1589                 println("string retType = \"" + checkAndGetCplusArrayType(retTypeC) + "\";");
1590                 // Generate array of parameter types
1591                 print("string paramCls[] = { ");
1592                 for (int i = 0; i < methParams.size(); i++) {
1593                         String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
1594                         String paramType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
1595                         print("\"" + paramType + "\"");
1596                         // Check if this is the last element (don't print a comma)
1597                         if (i != methParams.size() - 1) {
1598                                 print(", ");
1599                         }
1600                 }
1601                 println(" };");
1602                 // Generate array of parameter objects
1603                 print("void* paramObj[] = { ");
1604                 for (int i = 0; i < methParams.size(); i++) {
1605                         print("&" + getSimpleIdentifier(methParams.get(i)));
1606                         // Check if this is the last element (don't print a comma)
1607                         if (i != methParams.size() - 1) {
1608                                 print(", ");
1609                         }
1610                 }
1611                 println(" };");
1612                 // Check if this is "void"
1613                 if (retType.equals("void")) {
1614                         println("void* retObj = NULL;");
1615                         println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1616                 } else { // We do have a return value
1617                         if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
1618                                 println(checkAndGetCplusType(retType) + " retVal;");
1619                         else
1620                                 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
1621                         println("void* retObj = &retVal;");
1622                         println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1623                         println("return retVal;");
1624                 }
1625         }
1626
1627
1628         /**
1629          * HELPER: writePropertiesCplusStub() writes the properties of the stub class
1630          */
1631         private void writePropertiesCplusStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
1632
1633                 println("IoTRMICall *rmiCall;");
1634                 //println("IoTRMIObject\t\t\t*rmiObj;");
1635                 println("string address;");
1636                 println("vector<int> ports;\n");
1637                 // Get the object Id
1638                 Integer objId = mapIntfaceObjId.get(intface);
1639                 println("const static int objectId = " + objId + ";");
1640                 mapNewIntfaceObjId.put(newIntface, objId);
1641                 mapIntfaceObjId.put(intface, objId++);
1642                 if (callbackExist) {
1643                 // We assume that each class only has one callback interface for now
1644                         Iterator it = callbackClasses.iterator();
1645                         String callbackType = (String) it.next();
1646                         println("// Callback properties");
1647                         println("IoTRMIObject *rmiObj;");
1648                         println("vector<" + callbackType + "*> vecCallbackObj;");
1649                         println("static int objIdCnt;");
1650                 }
1651                 println("\n");
1652         }
1653
1654
1655         /**
1656          * HELPER: writeConstructorCplusStub() writes the constructor of the stub class
1657          */
1658         private void writeConstructorCplusStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1659
1660                 println(newStubClass + 
1661                         "(int _port, const char* _address, int _rev, bool* _bResult, vector<int> _ports) {");
1662                 println("address = _address;");
1663                 println("ports = _ports;");
1664                 println("rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);");
1665                 if (callbackExist) {
1666                         println("objIdCnt = 0;");
1667                         Iterator it = callbackClasses.iterator();
1668                         String callbackType = (String) it.next();
1669                         println("thread th1 (&" + newStubClass + "::___initCallBack, this);");
1670                         println("th1.detach();");
1671                         println("___regCB();");
1672                 }
1673                 println("}\n");
1674         }
1675
1676
1677         /**
1678          * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
1679          */
1680         private void writeDeconstructorCplusStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1681
1682                 println("~" + newStubClass + "() {");
1683                 println("if (rmiCall != NULL) {");
1684                 println("delete rmiCall;");
1685                 println("rmiCall = NULL;");
1686                 println("}");
1687                 if (callbackExist) {
1688                 // We assume that each class only has one callback interface for now
1689                         println("if (rmiObj != NULL) {");
1690                         println("delete rmiObj;");
1691                         println("rmiObj = NULL;");
1692                         println("}");
1693                         Iterator it = callbackClasses.iterator();
1694                         String callbackType = (String) it.next();
1695                         println("for(" + callbackType + "* cb : vecCallbackObj) {");
1696                         println("delete cb;");
1697                         println("cb = NULL;");
1698                         println("}");
1699                 }
1700                 println("}");
1701                 println("");
1702         }
1703
1704
1705         /**
1706          * HELPER: writeInitCallbackCplusStub() writes the constructor of the stub class
1707          */
1708         private void writeInitCallbackCplusStub(String intface, InterfaceDecl intDecl) {
1709
1710                 println("void ___initCallBack() {");
1711                 println("bool bResult = false;");
1712                 println("rmiObj = new IoTRMIObject(ports[0], &bResult);");
1713                 println("while (true) {");
1714                 println("char* method = rmiObj->getMethodBytes();");
1715                 println("int methodId = IoTRMIObject::getMethodId(method);");
1716                 println("int objId = IoTRMIObject::getObjectId(method);");
1717                 println("if (objId < vecCallbackObj.size()) {   // Check if still within range");
1718                 println(intface + "_CallbackSkeleton* skel = dynamic_cast<" + intface + 
1719                         "_CallbackSkeleton*> (vecCallbackObj.at(objId));");
1720                 println("skel->invokeMethod(rmiObj);");
1721                 println("} else {");
1722                 println("cerr << \"Illegal object Id: \" << to_string(objId);");
1723                 // TODO: perhaps need to change this into "throw" to make it cleaner (allow stack unfolding)
1724                 println("exit(-1);");
1725                 println("}");
1726                 println("}");
1727                 println("}\n");
1728         }
1729
1730
1731         /**
1732          * HELPER: writeInitCallbackSendInfoCplusStub() writes the constructor of the stub class
1733          */
1734         private void writeInitCallbackSendInfoCplusStub(InterfaceDecl intDecl) {
1735
1736                 // Generate info sending part
1737                 println("void ___regCB() {");
1738                 println("int numParam = 3;");
1739                 String method = "___initCallBack()";
1740                 println("int methodId = " + intDecl.getHelperMethodNumId(method) + ";");
1741                 println("string retType = \"void\";");
1742                 println("string paramCls[] = { \"int\", \"string\", \"int\" };");
1743                 println("int rev = 0;");
1744                 println("void* paramObj[] = { &ports[0], &address, &rev };");
1745                 println("void* retObj = NULL;");
1746                 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
1747                 println("}\n");
1748         }
1749
1750
1751         /**
1752          * generateCPlusStubClasses() generate stubs based on the methods list in C++
1753          */
1754         public void generateCPlusStubClasses() throws IOException {
1755
1756                 // Create a new directory
1757                 String path = createDirectories(dir, subdir);
1758                 for (String intface : mapIntfacePTH.keySet()) {
1759
1760                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1761                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1762                                 // Open a new file to write into
1763                                 String newIntface = intMeth.getKey();
1764                                 String newStubClass = newIntface + "_Stub";
1765                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
1766                                 pw = new PrintWriter(new BufferedWriter(fw));
1767                                 // Write file headers
1768                                 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
1769                                 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
1770                                 println("#include <iostream>");
1771                                 // Find out if there are callback objects
1772                                 Set<String> methods = intMeth.getValue();
1773                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1774                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1775                                 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1776                                 boolean callbackExist = !callbackClasses.isEmpty();
1777                                 if (callbackExist)      // Need thread library if this has callback
1778                                         println("#include <thread>");
1779                                 println("#include \"" + newIntface + ".hpp\""); println("");            
1780                                 println("using namespace std;"); println("");
1781                                 println("class " + newStubClass + " : public " + newIntface); println("{");
1782                                 println("private:\n");
1783                                 writePropertiesCplusStub(intface, newIntface, callbackExist, callbackClasses);
1784                                 println("public:\n");
1785                                 // Add default constructor and destructor
1786                                 println(newStubClass + "() { }"); println("");
1787                                 writeConstructorCplusStub(newStubClass, callbackExist, callbackClasses);
1788                                 writeDeconstructorCplusStub(newStubClass, callbackExist, callbackClasses);
1789                                 // Write methods
1790                                 writeMethodCplusStub(methods, intDecl, callbackClasses);
1791                                 print("}"); println(";");
1792                                 println("#endif");
1793                                 pw.close();
1794                                 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".hpp...");
1795                         }
1796                 }
1797         }
1798
1799
1800         /**
1801          * HELPER: writePropertiesCplusCallbackStub() writes the properties of the stub class
1802          */
1803         private void writePropertiesCplusCallbackStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
1804
1805                 println("IoTRMICall *rmiCall;");
1806                 // Get the object Id
1807                 println("static int objectId;");
1808                 if (callbackExist) {
1809                 // We assume that each class only has one callback interface for now
1810                         Iterator it = callbackClasses.iterator();
1811                         String callbackType = (String) it.next();
1812                         println("// Callback properties");
1813                         println("IoTRMIObject *rmiObj;");
1814                         println("vector<" + callbackType + "*> vecCallbackObj;");
1815                         println("static int objIdCnt;");
1816                         // TODO: Need to initialize address and ports if we want to have callback-in-callback
1817                         println("string address;");
1818                         println("vector<int> ports;\n");
1819                 }
1820                 println("\n");
1821         }
1822
1823
1824         /**
1825          * HELPER: writeConstructorCplusCallbackStub() writes the constructor of the stub class
1826          */
1827         private void writeConstructorCplusCallbackStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1828
1829                 println(newStubClass + "(IoTRMICall* _rmiCall, int _objectId) {");
1830                 println("objectId = _objectId;");
1831                 println("rmiCall = _rmiCall;");
1832                 if (callbackExist) {
1833                         Iterator it = callbackClasses.iterator();
1834                         String callbackType = (String) it.next();
1835                         println("thread th1 (&" + newStubClass + "::___initCallBack, this);");
1836                         println("th1.detach();");
1837                         println("___regCB();");
1838                 }
1839                 println("}\n");
1840         }
1841
1842
1843         /**
1844          * generateCPlusCallbackStubClasses() generate callback stubs based on the methods list in C++
1845          */
1846         public void generateCPlusCallbackStubClasses() throws IOException {
1847
1848                 // Create a new directory
1849                 String path = createDirectories(dir, subdir);
1850                 for (String intface : mapIntfacePTH.keySet()) {
1851
1852                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1853                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1854                                 // Open a new file to write into
1855                                 String newIntface = intMeth.getKey();
1856                                 String newStubClass = newIntface + "_CallbackStub";
1857                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
1858                                 pw = new PrintWriter(new BufferedWriter(fw));
1859                                 // Find out if there are callback objects
1860                                 Set<String> methods = intMeth.getValue();
1861                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1862                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1863                                 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1864                                 boolean callbackExist = !callbackClasses.isEmpty();
1865                                 // Write file headers
1866                                 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
1867                                 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
1868                                 println("#include <iostream>");
1869                                 if (callbackExist)
1870                                         println("#include <thread>");
1871                                 println("#include \"" + newIntface + ".hpp\""); println("");            
1872                                 println("using namespace std;"); println("");
1873                                 println("class " + newStubClass + " : public " + newIntface); println("{");
1874                                 println("private:\n");
1875                                 writePropertiesCplusCallbackStub(intface, newIntface, callbackExist, callbackClasses);
1876                                 println("public:\n");
1877                                 // Add default constructor and destructor
1878                                 println(newStubClass + "() { }"); println("");
1879                                 writeConstructorCplusCallbackStub(newStubClass, callbackExist, callbackClasses);
1880                                 writeDeconstructorCplusStub(newStubClass, callbackExist, callbackClasses);
1881                                 // Write methods
1882                                 writeMethodCplusStub(methods, intDecl, callbackClasses);
1883                                 print("}"); println(";");
1884                                 println("#endif");
1885                                 pw.close();
1886                                 System.out.println("IoTCompiler: Generated callback stub class " + newIntface + ".hpp...");
1887                         }
1888                 }
1889         }
1890
1891
1892         /**
1893          * HELPER: writePropertiesCplusSkeleton() writes the properties of the skeleton class
1894          */
1895         private void writePropertiesCplusSkeleton(String intface, boolean callbackExist, Set<String> callbackClasses) {
1896
1897                 println(intface + " *mainObj;");
1898                 //println("private int ports;");
1899                 // Callback
1900                 if (callbackExist) {
1901                         Iterator it = callbackClasses.iterator();
1902                         String callbackType = (String) it.next();
1903                         String exchangeType = checkAndGetParamClass(callbackType);
1904                         println("// Callback properties");
1905                         println("static int objIdCnt;");
1906                         println("vector<" + exchangeType + "*> vecCallbackObj;");
1907                         println("IoTRMICall *rmiCall;");
1908                 }
1909                 println("IoTRMIObject *rmiObj;\n");
1910                 // Keep track of object Ids of all stubs registered to this interface
1911                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1912                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1913                         String newIntface = intMeth.getKey();
1914                         int newObjectId = mapNewIntfaceObjId.get(newIntface);
1915 //                      println("const static int object" + newObjectId + "Id = " + 
1916 //                              newObjectId + ";\t//" + newIntface);
1917                 }
1918                 println("\n");
1919         }
1920
1921
1922         /**
1923          * HELPER: writeConstructorCplusSkeleton() writes the constructor of the skeleton class
1924          */
1925         private void writeConstructorCplusSkeleton(String newSkelClass, String intface, boolean callbackExist) {
1926
1927                 println(newSkelClass + "(" + intface + " *_mainObj, int _port) {");
1928                 println("bool _bResult = false;");
1929                 println("mainObj = _mainObj;");
1930                 println("rmiObj = new IoTRMIObject(_port, &_bResult);");
1931                 // Callback
1932                 if (callbackExist) {
1933                         println("objIdCnt = 0;");
1934                 }
1935                 //println("set0Allowed = Arrays.asList(object0Permission);");
1936                 println("___waitRequestInvokeMethod();");
1937                 println("}\n");
1938         }
1939
1940
1941         /**
1942          * HELPER: writeDeconstructorCplusSkeleton() writes the deconstructor of the skeleton class
1943          */
1944         private void writeDeconstructorCplusSkeleton(String newSkelClass, boolean callbackExist, Set<String> callbackClasses) {
1945
1946                 println("~" + newSkelClass + "() {");
1947                 println("if (rmiObj != NULL) {");
1948                 println("delete rmiObj;");
1949                 println("rmiObj = NULL;");
1950                 println("}");
1951                 if (callbackExist) {
1952                 // We assume that each class only has one callback interface for now
1953                         println("if (rmiCall != NULL) {");
1954                         println("delete rmiCall;");
1955                         println("rmiCall = NULL;");
1956                         println("}");
1957                         Iterator it = callbackClasses.iterator();
1958                         String callbackType = (String) it.next();
1959                         String exchangeType = checkAndGetParamClass(callbackType);
1960                         println("for(" + exchangeType + "* cb : vecCallbackObj) {");
1961                         println("delete cb;");
1962                         println("cb = NULL;");
1963                         println("}");
1964                 }
1965                 println("}");
1966                 println("");
1967         }
1968
1969
1970         /**
1971          * HELPER: writeStdMethodBodyCplusSkeleton() writes the standard method body in the skeleton class
1972          */
1973         private void writeStdMethodBodyCplusSkeleton(List<String> methParams, String methodId, String methodType) {
1974
1975                 if (methodType.equals("void"))
1976                         print("mainObj->" + methodId + "(");
1977                 else
1978                         print("return mainObj->" + methodId + "(");
1979                 for (int i = 0; i < methParams.size(); i++) {
1980
1981                         print(getSimpleIdentifier(methParams.get(i)));
1982                         // Check if this is the last element (don't print a comma)
1983                         if (i != methParams.size() - 1) {
1984                                 print(", ");
1985                         }
1986                 }
1987                 println(");");
1988         }
1989
1990
1991         /**
1992          * HELPER: writeInitCallbackCplusSkeleton() writes the init callback method for skeleton class
1993          */
1994         private void writeInitCallbackCplusSkeleton(boolean callbackSkeleton) {
1995
1996                 // This is a callback skeleton generation
1997                 if (callbackSkeleton)
1998                         println("void ___regCB(IoTRMIObject* rmiObj) {");
1999                 else
2000                         println("void ___regCB() {");
2001                 println("int numParam = 3;");
2002                 println("int param1 = 0;");
2003                 println("string param2 = \"\";");
2004                 println("int param3 = 0;");
2005                 println("void* paramObj[] = { &param1, &param2, &param3 };");
2006                 println("bool bResult = false;");
2007                 println("rmiCall = new IoTRMICall(param1, param2.c_str(), param3, &bResult);");
2008                 println("}\n");
2009         }
2010
2011
2012         /**
2013          * HELPER: writeMethodCplusSkeleton() writes the method of the skeleton class
2014          */
2015         private void writeMethodCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl, 
2016                         Set<String> callbackClasses, boolean callbackSkeleton) {
2017
2018                 for (String method : methods) {
2019
2020                         List<String> methParams = intDecl.getMethodParams(method);
2021                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2022                         String methodId = intDecl.getMethodId(method);
2023                         String methodType = checkAndGetCplusType(intDecl.getMethodType(method));
2024                         print(methodType + " " + methodId + "(");
2025                         boolean isCallbackMethod = false;
2026                         String callbackType = null;
2027                         for (int i = 0; i < methParams.size(); i++) {
2028
2029                                 String origParamType = methPrmTypes.get(i);
2030                                 if (callbackClasses.contains(origParamType)) { // Check if this has callback object
2031                                         isCallbackMethod = true;
2032                                         callbackType = origParamType;   
2033                                 }
2034                                 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
2035                                 String methPrmType = checkAndGetCplusType(paramType);
2036                                 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
2037                                 print(methParamComplete);
2038                                 // Check if this is the last element (don't print a comma)
2039                                 if (i != methParams.size() - 1) {
2040                                         print(", ");
2041                                 }
2042                         }
2043                         println(") {");
2044                         // Now, write the body of skeleton!
2045                         writeStdMethodBodyCplusSkeleton(methParams, methodId, intDecl.getMethodType(method));
2046                         println("}\n");
2047                         if (isCallbackMethod)
2048                                 writeInitCallbackCplusSkeleton(callbackSkeleton);
2049                 }
2050         }
2051
2052
2053         /**
2054          * HELPER: writeCallbackCplusNumStubs() writes the numStubs variable
2055          */
2056         private void writeCallbackCplusNumStubs(List<String> methParams, List<String> methPrmTypes, String callbackType) {
2057
2058                 for (int i = 0; i < methParams.size(); i++) {
2059                         String paramType = methPrmTypes.get(i);
2060                         String param = methParams.get(i);
2061                         //if (callbackType.equals(paramType)) {
2062                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
2063                                 String exchParamType = checkAndGetParamClass(paramType);
2064                                 // Print array if this is array or list if this is a list of callback objects
2065                                 println("int numStubs" + i + " = 0;");
2066                         }
2067                 }
2068         }
2069
2070
2071         /**
2072          * HELPER: writeCallbackCplusStubGeneration() writes the callback stub generation part
2073          */
2074         private void writeCallbackCplusStubGeneration(List<String> methParams, List<String> methPrmTypes, String callbackType) {
2075
2076                 // Iterate over callback objects
2077                 for (int i = 0; i < methParams.size(); i++) {
2078                         String paramType = methPrmTypes.get(i);
2079                         String param = methParams.get(i);
2080                         // Generate a loop if needed
2081                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
2082                                 String exchParamType = checkAndGetParamClass(paramType);
2083                                 if (isArrayOrList(paramType, param)) {
2084                                         println("vector<" + exchParamType + "> stub;");
2085                                         println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
2086                                         println(exchParamType + "* cb" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
2087                                         println("stub" + i + ".push_back(cb);");
2088                                         println("vecCallbackObj.push_back(cb);");
2089                                         println("objIdCnt++;");
2090                                         println("}");
2091                                 } else {
2092                                         println(exchParamType + "* stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
2093                                         println("vecCallbackObj.push_back(stub" + i + ");");
2094                                         println("objIdCnt++;");
2095                                 }
2096                         }
2097                 }
2098         }
2099
2100
2101         /**
2102          * HELPER: writeStdMethodHelperBodyCplusSkeleton() writes the standard method body helper in the skeleton class
2103          */
2104         private void writeStdMethodHelperBodyCplusSkeleton(InterfaceDecl intDecl, List<String> methParams,
2105                         List<String> methPrmTypes, String method, String methodId, Set<String> callbackClasses) {
2106
2107                 // Generate array of parameter types
2108                 boolean isCallbackMethod = false;
2109                 String callbackType = null;
2110                 print("string paramCls[] = { ");
2111                 for (int i = 0; i < methParams.size(); i++) {
2112                         String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2113                         if (callbackClasses.contains(paramType)) {
2114                                 isCallbackMethod = true;
2115                                 callbackType = paramType;
2116                                 print("\"int\"");
2117                         } else {        // Generate normal classes if it's not a callback object
2118                                 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
2119                                 String prmType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
2120                                 print("\"" + prmType + "\"");
2121                         }
2122                         if (i != methParams.size() - 1) {
2123                                 print(", ");
2124                         }
2125                 }
2126                 println(" };");
2127                 println("int numParam = " + methParams.size() + ";");
2128                 if (isCallbackMethod)
2129                         writeCallbackCplusNumStubs(methParams, methPrmTypes, callbackType);
2130                 // Generate parameters
2131                 for (int i = 0; i < methParams.size(); i++) {
2132                         String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2133                         if (!callbackClasses.contains(paramType)) {                     
2134                                 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
2135                                 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
2136                                 println(methParamComplete + ";");
2137                         }
2138                 }
2139                 // Generate array of parameter objects
2140                 print("void* paramObj[] = { ");
2141                 for (int i = 0; i < methParams.size(); i++) {
2142                         String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2143                         if (callbackClasses.contains(paramType))
2144                                 print("&numStubs" + i);
2145                         else
2146                                 print("&" + getSimpleIdentifier(methParams.get(i)));
2147                         if (i != methParams.size() - 1) {
2148                                 print(", ");
2149                         }
2150                 }
2151                 println(" };");
2152                 println("rmiObj->getMethodParams(paramCls, numParam, paramObj);");
2153                 if (isCallbackMethod)
2154                         writeCallbackCplusStubGeneration(methParams, methPrmTypes, callbackType);
2155                 String retType = intDecl.getMethodType(method);
2156                 // Check if this is "void"
2157                 if (retType.equals("void")) {
2158                         print(methodId + "(");
2159                         for (int i = 0; i < methParams.size(); i++) {
2160                                 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2161                                 if (callbackClasses.contains(paramType))
2162                                         print("stub" + i);
2163                                 else
2164                                         print(getSimpleIdentifier(methParams.get(i)));
2165                                 if (i != methParams.size() - 1) {
2166                                         print(", ");
2167                                 }
2168                         }
2169                         println(");");
2170                 } else { // We do have a return value
2171                         print(checkAndGetCplusType(retType) + " retVal = " + methodId + "(");
2172                         for (int i = 0; i < methParams.size(); i++) {
2173                                 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
2174                                 if (callbackClasses.contains(paramType))
2175                                         print("stub" + i);
2176                                 else
2177                                         print(getSimpleIdentifier(methParams.get(i)));
2178                                 if (i != methParams.size() - 1) {
2179                                         print(", ");
2180                                 }
2181                         }
2182                         println(");");
2183                         println("void* retObj = &retVal;");
2184                         String retTypeC = checkAndGetCplusType(retType);
2185                         println("rmiObj->sendReturnObj(retObj, \"" + checkAndGetCplusArrayType(retTypeC) + "\");");
2186                 }
2187         }
2188
2189
2190         /**
2191          * HELPER: writeMethodHelperCplusSkeleton() writes the method helper of the skeleton class
2192          */
2193         private void writeMethodHelperCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
2194
2195                 // Use this set to handle two same methodIds
2196                 Set<String> uniqueMethodIds = new HashSet<String>();
2197                 for (String method : methods) {
2198
2199                         List<String> methParams = intDecl.getMethodParams(method);
2200                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2201                         String methodId = intDecl.getMethodId(method);
2202                         print("void ___");
2203                         String helperMethod = methodId;
2204                         if (uniqueMethodIds.contains(methodId))
2205                                 helperMethod = helperMethod + intDecl.getMethodNumId(method);
2206                         else
2207                                 uniqueMethodIds.add(methodId);
2208                         // Check if this is "void"
2209                         String retType = intDecl.getMethodType(method);
2210                         println(helperMethod + "() {");
2211                         // Now, write the helper body of skeleton!
2212                         writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses);
2213                         println("}\n");
2214                 }
2215         }
2216
2217
2218         /**
2219          * HELPER: writeCplusWaitRequestInvokeMethod() writes the main loop of the skeleton class
2220          */
2221         private void writeCplusWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist) {
2222
2223                 // Use this set to handle two same methodIds
2224                 Set<String> uniqueMethodIds = new HashSet<String>();
2225                 println("void ___waitRequestInvokeMethod() {");
2226                 // Write variables here if we have callbacks or enums or structs
2227                 println("while (true) {");
2228                 println("rmiObj->getMethodBytes();");
2229                 println("int _objectId = rmiObj->getObjectId();");
2230                 println("int methodId = rmiObj->getMethodId();");
2231                 // TODO: code the permission check here!
2232                 println("switch (methodId) {");
2233                 // Print methods and method Ids
2234                 for (String method : methods) {
2235                         String methodId = intDecl.getMethodId(method);
2236                         int methodNumId = intDecl.getMethodNumId(method);
2237                         print("case " + methodNumId + ": ___");
2238                         String helperMethod = methodId;
2239                         if (uniqueMethodIds.contains(methodId))
2240                                 helperMethod = helperMethod + methodNumId;
2241                         else
2242                                 uniqueMethodIds.add(methodId);
2243                         println(helperMethod + "(); break;");
2244                 }
2245                 String method = "___initCallBack()";
2246                 // Print case -9999 (callback handler) if callback exists
2247                 if (callbackExist) {
2248                         int methodId = intDecl.getHelperMethodNumId(method);
2249                         println("case " + methodId + ": ___regCB(); break;");
2250                 }
2251                 println("default: ");
2252                 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
2253                 println("throw exception();");
2254                 println("}");
2255                 println("}");
2256                 println("}\n");
2257         }
2258
2259
2260         /**
2261          * generateCplusSkeletonClass() generate skeletons based on the methods list in C++
2262          */
2263         public void generateCplusSkeletonClass() throws IOException {
2264
2265                 // Create a new directory
2266                 String path = createDirectories(dir, subdir);
2267                 for (String intface : mapIntfacePTH.keySet()) {
2268                         // Open a new file to write into
2269                         String newSkelClass = intface + "_Skeleton";
2270                         FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp");
2271                         pw = new PrintWriter(new BufferedWriter(fw));
2272                         // Write file headers
2273                         println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
2274                         println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
2275                         println("#include <iostream>");
2276                         println("#include \"" + intface + ".hpp\"\n");
2277                         // Pass in set of methods and get import classes
2278                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2279                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2280                         List<String> methods = intDecl.getMethods();
2281                         Set<String> includeClasses = getIncludeClasses(methods, intDecl, true);
2282                         List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
2283                         List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
2284                         printIncludeStatements(allIncludeClasses); println("");
2285                         println("using namespace std;\n");
2286                         // Find out if there are callback objects
2287                         Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
2288                         boolean callbackExist = !callbackClasses.isEmpty();
2289                         // Write class header
2290                         println("class " + newSkelClass + " : public " + intface); println("{");
2291                         println("private:\n");
2292                         // Write properties
2293                         writePropertiesCplusSkeleton(intface, callbackExist, callbackClasses);
2294                         println("public:\n");
2295                         // Write constructor
2296                         writeConstructorCplusSkeleton(newSkelClass, intface, callbackExist);
2297                         // Write deconstructor
2298                         writeDeconstructorCplusSkeleton(newSkelClass, callbackExist, callbackClasses);
2299                         // Write methods
2300                         writeMethodCplusSkeleton(methods, intDecl, callbackClasses, false);
2301                         // Write method helper
2302                         writeMethodHelperCplusSkeleton(methods, intDecl, callbackClasses);
2303                         // Write waitRequestInvokeMethod() - main loop
2304                         writeCplusWaitRequestInvokeMethod(methods, intDecl, callbackExist);
2305                         println("};");
2306                         println("#endif");
2307                         pw.close();
2308                         System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".hpp...");
2309                 }
2310         }
2311
2312
2313         /**
2314          * HELPER: writePropertiesCplusCallbackSkeleton() writes the properties of the callback skeleton class
2315          */
2316         private void writePropertiesCplusCallbackSkeleton(String intface, boolean callbackExist, Set<String> callbackClasses) {
2317
2318                 println(intface + " *mainObj;");
2319                 // Keep track of object Ids of all stubs registered to this interface
2320                 println("static int objectId;");
2321                 // Callback
2322                 if (callbackExist) {
2323                         Iterator it = callbackClasses.iterator();
2324                         String callbackType = (String) it.next();
2325                         String exchangeType = checkAndGetParamClass(callbackType);
2326                         println("// Callback properties");
2327                         println("IoTRMICall* rmiCall;");
2328                         println("vector<" + exchangeType + "*> vecCallbackObj;");
2329                         println("static int objIdCnt;");
2330                 }
2331                 println("\n");
2332         }
2333
2334
2335         /**
2336          * HELPER: writeConstructorCplusCallbackSkeleton() writes the constructor of the skeleton class
2337          */
2338         private void writeConstructorCplusCallbackSkeleton(String newSkelClass, String intface, boolean callbackExist) {
2339
2340                 println(newSkelClass + "(" + intface + " *_mainObj, int _objectId) {");
2341                 println("mainObj = _mainObj;");
2342                 println("objectId = _objectId;");
2343                 // Callback
2344                 if (callbackExist) {
2345                         println("objIdCnt = 0;");
2346                 }
2347                 println("}\n");
2348         }
2349
2350
2351         /**
2352          * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
2353          */
2354         private void writeDeconstructorCplusCallbackSkeleton(String newStubClass, boolean callbackExist, 
2355                         Set<String> callbackClasses) {
2356
2357                 println("~" + newStubClass + "() {");
2358                 if (callbackExist) {
2359                 // We assume that each class only has one callback interface for now
2360                         println("if (rmiCall != NULL) {");
2361                         println("delete rmiCall;");
2362                         println("rmiCall = NULL;");
2363                         println("}");
2364                         Iterator it = callbackClasses.iterator();
2365                         String callbackType = (String) it.next();
2366                         String exchangeType = checkAndGetParamClass(callbackType);
2367                         println("for(" + exchangeType + "* cb : vecCallbackObj) {");
2368                         println("delete cb;");
2369                         println("cb = NULL;");
2370                         println("}");
2371                 }
2372                 println("}");
2373                 println("");
2374         }
2375
2376
2377         /**
2378          * HELPER: writeMethodHelperCplusCallbackSkeleton() writes the method helper of the callback skeleton class
2379          */
2380         private void writeMethodHelperCplusCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl, 
2381                         Set<String> callbackClasses) {
2382
2383                 // Use this set to handle two same methodIds
2384                 Set<String> uniqueMethodIds = new HashSet<String>();
2385                 for (String method : methods) {
2386
2387                         List<String> methParams = intDecl.getMethodParams(method);
2388                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2389                         String methodId = intDecl.getMethodId(method);
2390                         print("void ___");
2391                         String helperMethod = methodId;
2392                         if (uniqueMethodIds.contains(methodId))
2393                                 helperMethod = helperMethod + intDecl.getMethodNumId(method);
2394                         else
2395                                 uniqueMethodIds.add(methodId);
2396                         // Check if this is "void"
2397                         String retType = intDecl.getMethodType(method);
2398                         println(helperMethod + "(IoTRMIObject* rmiObj) {");
2399                         // Now, write the helper body of skeleton!
2400                         writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses);
2401                         println("}\n");
2402                 }
2403         }
2404
2405
2406         /**
2407          * HELPER: writeCplusCallbackWaitRequestInvokeMethod() writes the main loop of the skeleton class
2408          */
2409         private void writeCplusCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, 
2410                         boolean callbackExist) {
2411
2412                 // Use this set to handle two same methodIds
2413                 Set<String> uniqueMethodIds = new HashSet<String>();
2414                 println("void invokeMethod(IoTRMIObject* rmiObj) {");
2415                 // Write variables here if we have callbacks or enums or structs
2416                 println("int methodId = rmiObj->getMethodId();");
2417                 // TODO: code the permission check here!
2418                 println("switch (methodId) {");
2419                 // Print methods and method Ids
2420                 for (String method : methods) {
2421                         String methodId = intDecl.getMethodId(method);
2422                         int methodNumId = intDecl.getMethodNumId(method);
2423                         print("case " + methodNumId + ": ___");
2424                         String helperMethod = methodId;
2425                         if (uniqueMethodIds.contains(methodId))
2426                                 helperMethod = helperMethod + methodNumId;
2427                         else
2428                                 uniqueMethodIds.add(methodId);
2429                         println(helperMethod + "(rmiObj); break;");
2430                 }
2431                 String method = "___initCallBack()";
2432                 // Print case -9999 (callback handler) if callback exists
2433                 if (callbackExist) {
2434                         int methodId = intDecl.getHelperMethodNumId(method);
2435                         println("case " + methodId + ": ___regCB(rmiObj); break;");
2436                 }
2437                 println("default: ");
2438                 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
2439                 println("throw exception();");
2440                 println("}");
2441                 println("}\n");
2442         }
2443
2444
2445
2446         /**
2447          * generateCplusCallbackSkeletonClass() generate callback skeletons based on the methods list in C++
2448          */
2449         public void generateCplusCallbackSkeletonClass() throws IOException {
2450
2451                 // Create a new directory
2452                 String path = createDirectories(dir, subdir);
2453                 for (String intface : mapIntfacePTH.keySet()) {
2454                         // Open a new file to write into
2455                         String newSkelClass = intface + "_CallbackSkeleton";
2456                         FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp");
2457                         pw = new PrintWriter(new BufferedWriter(fw));
2458                         // Write file headers
2459                         println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
2460                         println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
2461                         println("#include <iostream>");
2462                         println("#include \"" + intface + ".hpp\"\n");
2463                         // Pass in set of methods and get import classes
2464                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2465                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2466                         List<String> methods = intDecl.getMethods();
2467                         Set<String> includeClasses = getIncludeClasses(methods, intDecl, true);
2468                         List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
2469                         List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
2470                         printIncludeStatements(allIncludeClasses); println("");                 
2471                         // Find out if there are callback objects
2472                         Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
2473                         boolean callbackExist = !callbackClasses.isEmpty();
2474                         println("using namespace std;\n");
2475                         // Write class header
2476                         println("class " + newSkelClass + " : public " + intface); println("{");
2477                         println("private:\n");
2478                         // Write properties
2479                         writePropertiesCplusCallbackSkeleton(intface, callbackExist, callbackClasses);
2480                         println("public:\n");
2481                         // Write constructor
2482                         writeConstructorCplusCallbackSkeleton(newSkelClass, intface, callbackExist);
2483                         // Write deconstructor
2484                         writeDeconstructorCplusCallbackSkeleton(newSkelClass, callbackExist, callbackClasses);
2485                         // Write methods
2486                         writeMethodCplusSkeleton(methods, intDecl, callbackClasses, true);
2487                         // Write method helper
2488                         writeMethodHelperCplusCallbackSkeleton(methods, intDecl, callbackClasses);
2489                         // Write waitRequestInvokeMethod() - main loop
2490                         writeCplusCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist);
2491                         println("};");
2492                         println("#endif");
2493                         pw.close();
2494                         System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".hpp...");
2495                 }
2496         }
2497
2498
2499         /**
2500          * generateInitializer() generate initializer based on type
2501          */
2502         public String generateCplusInitializer(String type) {
2503
2504                 // Generate dummy returns for now
2505                 if (type.equals("short")||
2506                         type.equals("int")      ||
2507                         type.equals("long") ||
2508                         type.equals("float")||
2509                         type.equals("double")) {
2510
2511                         return "0";
2512                 } else if ( type.equals("String") ||
2513                                         type.equals("string")) {
2514   
2515                         return "\"\"";
2516                 } else if ( type.equals("char") ||
2517                                         type.equals("byte")) {
2518
2519                         return "\' \'";
2520                 } else if ( type.equals("boolean")) {
2521
2522                         return "false";
2523                 } else {
2524                         return "NULL";
2525                 }
2526         }
2527
2528
2529         /**
2530          * generateReturnStmt() generate return statement based on methType
2531          */
2532         public String generateReturnStmt(String methType) {
2533
2534                 // Generate dummy returns for now
2535                 if (methType.equals("short")||
2536                         methType.equals("int")  ||
2537                         methType.equals("long") ||
2538                         methType.equals("float")||
2539                         methType.equals("double")) {
2540
2541                         return "1";
2542                 } else if ( methType.equals("String")) {
2543   
2544                         return "\"a\"";
2545                 } else if ( methType.equals("char") ||
2546                                         methType.equals("byte")) {
2547
2548                         return "\'a\'";
2549                 } else if ( methType.equals("boolean")) {
2550
2551                         return "true";
2552                 } else {
2553                         return "null";
2554                 }
2555         }
2556
2557
2558         /**
2559          * setDirectory() sets a new directory for stub files
2560          */
2561         public void setDirectory(String _subdir) {
2562
2563                 subdir = _subdir;
2564         }
2565
2566
2567         /**
2568          * printUsage() prints the usage of this compiler
2569          */
2570         public static void printUsage() {
2571
2572                 System.out.println();
2573                 System.out.println("Sentinel interface and stub compiler version 1.0");
2574                 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
2575                 System.out.println("All rights reserved.");
2576                 System.out.println("Usage:");
2577                 System.out.println("\tjava IoTCompiler -help / --help / -h\n");
2578                 System.out.println("\t\tDisplay this help texts\n\n");
2579                 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>]");
2580                 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>] [options]\n");
2581                 System.out.println("\t\tTake one or more pairs of main-req policy files, and generate Java and/or C++ files\n");
2582                 System.out.println("Options:");
2583                 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
2584                 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
2585                 System.out.println();
2586         }
2587
2588
2589         /**
2590          * parseFile() prepares Lexer and Parser objects, then parses the file
2591          */
2592         public static ParseNode parseFile(String file) {
2593
2594                 ParseNode pn = null;
2595                 try {
2596                         ComplexSymbolFactory csf = new ComplexSymbolFactory();
2597                         ScannerBuffer lexer = 
2598                                 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf));
2599                         Parser parse = new Parser(lexer,csf);
2600                         pn = (ParseNode) parse.parse().value;
2601                 } catch (Exception e) {
2602                         e.printStackTrace();
2603                         throw new Error("IoTCompiler: ERROR parsing policy file or wrong command line option: " + file);
2604                 }
2605
2606                 return pn;
2607         }
2608
2609
2610         /**================
2611          * Helper functions
2612          **================
2613          */
2614         boolean newline=true;
2615         int tablevel=0;
2616
2617         private void print(String str) {
2618                 if (newline) {
2619                         int tab=tablevel;
2620                         if (str.equals("}"))
2621                                 tab--;
2622                         for(int i=0; i<tab; i++)
2623                                 pw.print("\t");
2624                 }
2625                 pw.print(str);
2626                 updatetabbing(str);
2627                 newline=false;
2628         }
2629
2630
2631         /**
2632          * This function converts Java to C++ type for compilation
2633          */
2634         private String convertType(String jType) {
2635
2636                 return mapPrimitives.get(jType);
2637         }
2638
2639
2640         private void println(String str) {
2641                 if (newline) {
2642                         int tab = tablevel;
2643                         if (str.contains("}") && !str.contains("{"))
2644                                 tab--;
2645                         for(int i=0; i<tab; i++)
2646                                 pw.print("\t");
2647                 }
2648                 pw.println(str);
2649                 updatetabbing(str);
2650                 newline = true;
2651         }
2652
2653
2654         private void updatetabbing(String str) {
2655
2656                 tablevel+=count(str,'{')-count(str,'}');
2657         }
2658
2659
2660         private int count(String str, char key) {
2661                 char[] array = str.toCharArray();
2662                 int count = 0;
2663                 for(int i=0; i<array.length; i++) {
2664                         if (array[i] == key)
2665                                 count++;
2666                 }
2667                 return count;
2668         }
2669
2670
2671         private void createDirectory(String dirName) {
2672
2673                 File file = new File(dirName);
2674                 if (!file.exists()) {
2675                         if (file.mkdir()) {
2676                                 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
2677                         } else {
2678                                 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
2679                         }
2680                 } else {
2681                         System.out.println("IoTCompiler: Directory " + dirName + " exists...");
2682                 }
2683         }
2684
2685
2686         // Create a directory and possibly a sub directory
2687         private String createDirectories(String dir, String subdir) {
2688
2689                 String path = dir;
2690                 createDirectory(path);
2691                 if (subdir != null) {
2692                         path = path + "/" + subdir;
2693                         createDirectory(path);
2694                 }
2695                 return path;
2696         }
2697
2698
2699         // Inserting array members into a Map object
2700         // that maps arrKey to arrVal objects
2701         private void arraysToMap(Map map, Object[] arrKey, Object[] arrVal) {
2702
2703                 for(int i = 0; i < arrKey.length; i++) {
2704
2705                         map.put(arrKey[i], arrVal[i]);
2706                 }
2707         }
2708
2709
2710         // Return parameter category, i.e. PRIMITIVES, NONPRIMITIVES, or USERDEFINED
2711         private ParamCategory getParamCategory(String paramType) {
2712
2713                 if (mapPrimitives.containsKey(paramType)) {
2714                         return ParamCategory.PRIMITIVES;
2715                 // We can either use mapNonPrimitivesJava or mapNonPrimitivesCplus here
2716                 } else if (mapNonPrimitivesJava.containsKey(getSimpleType(paramType))) {
2717                         return ParamCategory.NONPRIMITIVES;
2718                 } else
2719                         return ParamCategory.USERDEFINED;
2720         }
2721
2722
2723         // Return full class name for non-primitives to generate Java import statements
2724         // e.g. java.util.Set for Set, java.util.Map for Map
2725         private String getNonPrimitiveJavaClass(String paramNonPrimitives) {
2726
2727                 return mapNonPrimitivesJava.get(paramNonPrimitives);
2728         }
2729
2730
2731         // Return full class name for non-primitives to generate Cplus include statements
2732         // e.g. #include <set> for Set, #include <map> for Map
2733         private String getNonPrimitiveCplusClass(String paramNonPrimitives) {
2734
2735                 return mapNonPrimitivesCplus.get(paramNonPrimitives);
2736         }
2737
2738
2739         // Get simple types, e.g. HashSet for HashSet<...>
2740         // Basically strip off the "<...>"
2741         private String getSimpleType(String paramType) {
2742
2743                 // Check if this is generics
2744                 if(paramType.contains("<")) {
2745                         String[] type = paramType.split("<");
2746                         return type[0];
2747                 } else
2748                         return paramType;
2749         }
2750
2751
2752         // Generate a set of standard classes for import statements
2753         private List<String> getStandardJavaImportClasses() {
2754
2755                 List<String> importClasses = new ArrayList<String>();
2756                 // Add the standard list first
2757                 importClasses.add("java.io.IOException");
2758                 importClasses.add("java.util.List");
2759                 importClasses.add("java.util.ArrayList");
2760                 importClasses.add("iotrmi.Java.IoTRMICall");
2761                 importClasses.add("iotrmi.Java.IoTRMIObject");
2762
2763                 return importClasses;
2764         }
2765
2766
2767         // Generate a set of standard classes for import statements
2768         private List<String> getStandardCplusIncludeClasses() {
2769
2770                 List<String> importClasses = new ArrayList<String>();
2771                 // Add the standard list first
2772                 importClasses.add("<vector>");
2773                 importClasses.add("\"IoTRMICall.hpp\"");
2774                 importClasses.add("\"IoTRMIObject.hpp\"");
2775
2776                 return importClasses;
2777         }
2778
2779
2780         // Generate a set of standard classes for import statements
2781         private List<String> getAllLibClasses(Collection<String> stdLibClasses, Collection<String> libClasses) {
2782
2783                 List<String> allLibClasses = new ArrayList<String>(stdLibClasses);
2784                 // Iterate over the list of import classes
2785                 for (String str : libClasses) {
2786                         if (!allLibClasses.contains(str)) {
2787                                 allLibClasses.add(str);
2788                         }
2789                 }
2790
2791                 return allLibClasses;
2792         }
2793
2794
2795
2796         // Generate a set of classes for import statements
2797         private Set<String> getImportClasses(Collection<String> methods, InterfaceDecl intDecl) {
2798
2799                 Set<String> importClasses = new HashSet<String>();
2800                 for (String method : methods) {
2801                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2802                         for (String paramType : methPrmTypes) {
2803
2804                                 String simpleType = getSimpleType(paramType);
2805                                 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
2806                                         importClasses.add(getNonPrimitiveJavaClass(simpleType));
2807                                 }
2808                         }
2809                 }
2810                 return importClasses;
2811         }
2812
2813
2814         // Generate a set of classes for include statements
2815         private Set<String> getIncludeClasses(Collection<String> methods, InterfaceDecl intDecl, boolean needExchange) {
2816
2817                 Set<String> includeClasses = new HashSet<String>();
2818                 for (String method : methods) {
2819
2820                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2821                         List<String> methParams = intDecl.getMethodParams(method);
2822                         for (int i = 0; i < methPrmTypes.size(); i++) {
2823
2824                                 String simpleType = getSimpleType(methPrmTypes.get(i));
2825                                 String param = methParams.get(i);
2826                                 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
2827                                         includeClasses.add("<" + getNonPrimitiveCplusClass(simpleType) + ">");
2828                                 } else if (getParamCategory(simpleType) == ParamCategory.USERDEFINED) {
2829                                         // For original interface, we need it exchanged... not for stub interfaces
2830                                         if (needExchange) {
2831                                                 includeClasses.add("\"" + exchangeParamType(simpleType) + ".hpp\"");
2832                                                 includeClasses.add("\"" + exchangeParamType(simpleType) + "_CallbackStub.hpp\"");
2833                                         } else {
2834                                                 includeClasses.add("\"" + simpleType + ".hpp\"");
2835                                                 includeClasses.add("\"" + simpleType + "_CallbackSkeleton.hpp\"");
2836                                         }
2837                                 } else if (param.contains("[]")) {
2838                                 // Check if this is array for C++; translate into vector
2839                                         includeClasses.add("<vector>");
2840                                 }
2841                         }
2842                 }
2843                 return includeClasses;
2844         }
2845
2846
2847         // Generate a set of callback classes
2848         private Set<String> getCallbackClasses(Collection<String> methods, InterfaceDecl intDecl) {
2849
2850                 Set<String> callbackClasses = new HashSet<String>();
2851                 for (String method : methods) {
2852
2853                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2854                         List<String> methParams = intDecl.getMethodParams(method);
2855                         for (int i = 0; i < methPrmTypes.size(); i++) {
2856
2857                                 String type = methPrmTypes.get(i);
2858                                 if (getParamCategory(type) == ParamCategory.USERDEFINED) {
2859                                         callbackClasses.add(type);
2860                                 } else if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) {
2861                                 // Can be a List<...> of callback objects ...
2862                                         String genericType = getTypeOfGeneric(type)[0];
2863                                         if (getParamCategory(type) == ParamCategory.USERDEFINED) {
2864                                                 callbackClasses.add(type);
2865                                         }
2866                                 }
2867                         }
2868                 }
2869                 return callbackClasses;
2870         }
2871
2872
2873         private void printImportStatements(Collection<String> importClasses) {
2874
2875                 for(String cls : importClasses) {
2876                         println("import " + cls + ";");
2877                 }
2878         }
2879
2880
2881         private void printIncludeStatements(Collection<String> includeClasses) {
2882
2883                 for(String cls : includeClasses) {
2884                         println("#include " + cls);
2885                 }
2886         }
2887
2888
2889         // Get the C++ version of a non-primitive type
2890         // e.g. set for Set and map for Map
2891         // Input nonPrimitiveType has to be generics in format
2892         private String[] getTypeOfGeneric(String nonPrimitiveType) {
2893
2894                 // Handle <, >, and , for 2-type generic/template
2895                 String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(",");
2896                 return substr;
2897         }
2898
2899
2900         // This helper function strips off array declaration, e.g. D[] becomes D
2901         private String getSimpleIdentifier(String ident) {
2902
2903                 // Handle [ for array declaration
2904                 String substr = ident;
2905                 if (ident.contains("[]")) {
2906                         substr = ident.split("\\[\\]")[0];
2907                 }
2908                 return substr;
2909         }
2910
2911
2912         private String checkAndGetCplusType(String paramType) {
2913
2914                 if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
2915                         return convertType(paramType);
2916                 } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) {
2917
2918                         // Check for generic/template format
2919                         if (paramType.contains("<") && paramType.contains(">")) {
2920
2921                                 String genericClass = getSimpleType(paramType);
2922                                 String[] genericType = getTypeOfGeneric(paramType);
2923                                 String cplusTemplate = null;
2924                                 if (genericType.length == 1) // Generic/template with one type
2925                                         cplusTemplate = getNonPrimitiveCplusClass(genericClass) + 
2926                                                 "<" + convertType(genericType[0]) + ">";
2927                                 else // Generic/template with two types
2928                                         cplusTemplate = getNonPrimitiveCplusClass(genericClass) + 
2929                                                 "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">";
2930                                 return cplusTemplate;
2931                         } else
2932                                 return getNonPrimitiveCplusClass(paramType);
2933                 } else if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
2934                         return paramType + "*";
2935                 } else
2936                         // Just return it as is if it's not non-primitives
2937                         return paramType;
2938                         //return checkAndGetParamClass(paramType, true);
2939         }
2940
2941
2942         // Detect array declaration, e.g. int A[],
2943         //              then generate "int A[]" in C++ as "vector<int> A"
2944         private String checkAndGetCplusArray(String paramType, String param) {
2945
2946                 String paramComplete = null;
2947                 // Check for array declaration
2948                 if (param.contains("[]")) {
2949                         paramComplete = "vector<" + paramType + "> " + param.replace("[]","");
2950                 } else
2951                         // Just return it as is if it's not an array
2952                         paramComplete = paramType + " " + param;
2953
2954                 return paramComplete;
2955         }
2956         
2957
2958         // Detect array declaration, e.g. int A[],
2959         //              then generate "int A[]" in C++ as "vector<int> A"
2960         // This method just returns the type
2961         private String checkAndGetCplusArrayType(String paramType) {
2962
2963                 String paramTypeRet = null;
2964                 // Check for array declaration
2965                 if (paramType.contains("[]")) {
2966                         String type = paramType.split("\\[\\]")[0];
2967                         paramTypeRet = checkAndGetCplusType(type) + "[]";
2968                 } else if (paramType.contains("vector")) {
2969                         // Just return it as is if it's not an array
2970                         String type = paramType.split("<")[1].split(">")[0];
2971                         paramTypeRet = checkAndGetCplusType(type) + "[]";
2972                 } else
2973                         paramTypeRet = paramType;
2974
2975                 return paramTypeRet;
2976         }
2977         
2978         
2979         // Detect array declaration, e.g. int A[],
2980         //              then generate "int A[]" in C++ as "vector<int> A"
2981         // This method just returns the type
2982         private String checkAndGetCplusArrayType(String paramType, String param) {
2983
2984                 String paramTypeRet = null;
2985                 // Check for array declaration
2986                 if (param.contains("[]")) {
2987                         paramTypeRet = checkAndGetCplusType(paramType) + "[]";
2988                 } else if (paramType.contains("vector")) {
2989                         // Just return it as is if it's not an array
2990                         String type = paramType.split("<")[1].split(">")[0];
2991                         paramTypeRet = checkAndGetCplusType(type) + "[]";
2992                 } else
2993                         paramTypeRet = paramType;
2994
2995                 return paramTypeRet;
2996         }
2997
2998
2999         // Detect array declaration, e.g. int A[],
3000         //              then generate type "int[]"
3001         private String checkAndGetArray(String paramType, String param) {
3002
3003                 String paramTypeRet = null;
3004                 // Check for array declaration
3005                 if (param.contains("[]")) {
3006                         paramTypeRet = paramType + "[]";
3007                 } else
3008                         // Just return it as is if it's not an array
3009                         paramTypeRet = paramType;
3010
3011                 return paramTypeRet;
3012         }
3013
3014
3015         // Is array or list?
3016         private boolean isArrayOrList(String paramType, String param) {
3017
3018                 // Check for array declaration
3019                 if (isArray(paramType, param))
3020                         return true;
3021                 else if (isList(paramType, param))
3022                         return true;
3023                 else
3024                         return false;
3025         }
3026
3027
3028         // Is array or list?
3029         private boolean isArray(String paramType, String param) {
3030
3031                 // Check for array declaration
3032                 if (param.contains("[]"))
3033                         return true;
3034                 else
3035                         return false;
3036         }
3037
3038
3039         // Is array or list?
3040         private boolean isList(String paramType, String param) {
3041
3042                 // Check for array declaration
3043                 if (paramType.contains("List"))
3044                         return true;
3045                 else
3046                         return false;
3047         }
3048
3049
3050         // Get the right type for a callback object
3051         private String checkAndGetParamClass(String paramType) {
3052
3053                 // Check if this is generics
3054                 if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
3055                         return exchangeParamType(paramType);
3056                 } else
3057                         return paramType;
3058         }
3059
3060
3061         // Returns the other interface for type-checking purposes for USERDEFINED
3062         //              classes based on the information provided in multiple policy files
3063         // e.g. return CameraWithXXX instead of Camera
3064         private String exchangeParamType(String intface) {
3065
3066                 // Param type that's passed is the interface name we need to look for
3067                 //              in the map of interfaces, based on available policy files.
3068                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
3069                 if (decHandler != null) {
3070                 // We've found the required interface policy files
3071                         RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(intface);
3072                         Set<String> setExchInt = reqDecl.getInterfaces();
3073                         if (setExchInt.size() == 1) {
3074                                 Iterator iter = setExchInt.iterator();
3075                                 return (String) iter.next();
3076                         } else {
3077                                 throw new Error("IoTCompiler: Ambiguous stub interfaces: " + setExchInt.toString() + 
3078                                         ". Only one new interface can be declared if the object " + intface +
3079                                         " needs to be passed in as an input parameter!");
3080                         }
3081                 } else {
3082                 // NULL value - this means policy files missing
3083                         throw new Error("IoTCompiler: Parameter type lookup failed for " + intface +
3084                                 "... Please provide the necessary policy files for user-defined types." +
3085                                 " If this is an array please type the brackets after the variable name," +
3086                                 " e.g. \"String str[]\", not \"String[] str\"." +
3087                                 " If this is a Collections (Java) / STL (C++) type, this compiler only" +
3088                                 " supports List/ArrayList (Java) or list (C++).");
3089                 }
3090         }
3091
3092
3093         public static void main(String[] args) throws Exception {
3094
3095                 // If there is no argument or just "--help" or "-h", then invoke printUsage()
3096                 if ((args[0].equals("-help") ||
3097                          args[0].equals("--help")||
3098                          args[0].equals("-h"))   ||
3099                         (args.length == 0)) {
3100
3101                         IoTCompiler.printUsage();
3102
3103                 } else if (args.length > 1) {
3104
3105                         IoTCompiler comp = new IoTCompiler();
3106                         int i = 0;                              
3107                         do {
3108                                 // Parse main policy file
3109                                 ParseNode pnPol = IoTCompiler.parseFile(args[i]);
3110                                 // Parse "requires" policy file
3111                                 ParseNode pnReq = IoTCompiler.parseFile(args[i+1]);
3112                                 // Get interface name
3113                                 String intface = ParseTreeHandler.getOrigIntface(pnPol);
3114                                 comp.setDataStructures(intface, pnPol, pnReq);
3115                                 comp.getMethodsForIntface(intface);
3116                                 i = i + 2;
3117                         // 1) Check if this is the last option before "-java" or "-cplus"
3118                         // 2) Check if this is really the last option (no "-java" or "-cplus")
3119                         } while(!args[i].equals("-java") &&
3120                                         !args[i].equals("-cplus") &&
3121                                         (i < args.length));
3122
3123                         // Generate everything if we don't see "-java" or "-cplus"
3124                         if (i == args.length) {
3125                                 comp.generateJavaLocalInterfaces();
3126                                 comp.generateJavaInterfaces();
3127                                 comp.generateJavaStubClasses();
3128                                 comp.generateJavaCallbackStubClasses();
3129                                 comp.generateJavaSkeletonClass();
3130                                 comp.generateJavaCallbackSkeletonClass();
3131                                 comp.generateCplusLocalInterfaces();
3132                                 comp.generateCPlusInterfaces();
3133                                 comp.generateCPlusStubClasses();
3134                                 comp.generateCPlusCallbackStubClasses();
3135                                 comp.generateCplusSkeletonClass();
3136                                 comp.generateCplusCallbackSkeletonClass();
3137                         } else {
3138                         // Check other options
3139                                 while(i < args.length) {
3140                                         // Error checking
3141                                         if (!args[i].equals("-java") &&
3142                                                 !args[i].equals("-cplus")) {
3143                                                 throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
3144                                         } else {
3145                                                 if (i + 1 < args.length) {
3146                                                         comp.setDirectory(args[i+1]);
3147                                                 } else
3148                                                         throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
3149
3150                                                 if (args[i].equals("-java")) {
3151                                                         comp.generateJavaLocalInterfaces();
3152                                                         comp.generateJavaInterfaces();
3153                                                         comp.generateJavaStubClasses();
3154                                                         comp.generateJavaCallbackStubClasses();
3155                                                         comp.generateJavaSkeletonClass();
3156                                                         comp.generateJavaCallbackSkeletonClass();
3157                                                 } else {
3158                                                         comp.generateCplusLocalInterfaces();
3159                                                         comp.generateCPlusInterfaces();
3160                                                         comp.generateCPlusStubClasses();
3161                                                         comp.generateCPlusCallbackStubClasses();
3162                                                         comp.generateCplusSkeletonClass();
3163                                                         comp.generateCplusCallbackSkeletonClass();
3164                                                 }
3165                                         }
3166                                         i = i + 2;
3167                                 }
3168                         }
3169                 } else {
3170                 // Need to at least have exactly 2 parameters, i.e. main policy file and requires file
3171                         IoTCompiler.printUsage();
3172                         throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");
3173                 }
3174         }
3175 }
3176
3177
3178
3179