Adding permission insertion for struct (will be tested later)
[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         /**
64          * Class constants
65          */
66         private final static String OUTPUT_DIRECTORY = "output_files";
67
68         private enum ParamCategory {
69
70                 PRIMITIVES,             // All the primitive types, e.g. byte, short, int, long, etc.
71                 NONPRIMITIVES,  // Non-primitive types, e.g. Set, Map, List, etc.
72                 ENUM,                   // Enum type
73                 STRUCT,                 // Struct type
74                 USERDEFINED             // Assumed as driver classes
75         }
76
77
78         /**
79          * Class constructors
80          */
81         public IoTCompiler() {
82
83                 mapIntfacePTH = new HashMap<String,ParseTreeHandler>();
84                 mapIntDeclHand = new HashMap<String,DeclarationHandler>();
85                 mapInt2NewInts = new HashMap<String,Map<String,Set<String>>>();
86                 mapIntfaceObjId = new HashMap<String,Integer>();
87                 mapNewIntfaceObjId = new HashMap<String,Integer>();
88                 mapPrimitives = new HashMap<String,String>();
89                         arraysToMap(mapPrimitives, IoTRMITypes.primitivesJava, IoTRMITypes.primitivesCplus);
90                 mapNonPrimitivesJava = new HashMap<String,String>();
91                         arraysToMap(mapNonPrimitivesJava, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitiveJavaLibs);
92                 mapNonPrimitivesCplus = new HashMap<String,String>();
93                         arraysToMap(mapNonPrimitivesCplus, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitivesCplus);
94                 pw = null;
95                 dir = OUTPUT_DIRECTORY;
96                 subdir = null;
97         }
98
99
100         /**
101          * setDataStructures() sets parse tree and other data structures based on policy files.
102          * <p>
103          * It also generates parse tree (ParseTreeHandler) and
104          * copies useful information from parse tree into
105          * InterfaceDecl, CapabilityDecl, and RequiresDecl 
106          * data structures.
107          * Additionally, the data structure handles are
108          * returned from tree-parsing for further process.
109          */
110         public void setDataStructures(String origInt, ParseNode pnPol, ParseNode pnReq) {
111
112                 ParseTreeHandler ptHandler = new ParseTreeHandler(origInt, pnPol, pnReq);
113                 DeclarationHandler decHandler = new DeclarationHandler();
114                 // Process ParseNode and generate Declaration objects
115                 // Interface
116                 ptHandler.processInterfaceDecl();
117                 InterfaceDecl intDecl = ptHandler.getInterfaceDecl();
118                 decHandler.addInterfaceDecl(origInt, intDecl);
119                 // Capabilities
120                 ptHandler.processCapabilityDecl();
121                 CapabilityDecl capDecl = ptHandler.getCapabilityDecl();
122                 decHandler.addCapabilityDecl(origInt, capDecl);
123                 // Requires
124                 ptHandler.processRequiresDecl();
125                 RequiresDecl reqDecl = ptHandler.getRequiresDecl();
126                 decHandler.addRequiresDecl(origInt, reqDecl);
127                 // Enumeration
128                 ptHandler.processEnumDecl();
129                 EnumDecl enumDecl = ptHandler.getEnumDecl();
130                 decHandler.addEnumDecl(origInt, enumDecl);
131                 // Struct
132                 ptHandler.processStructDecl();
133                 StructDecl structDecl = ptHandler.getStructDecl();
134                 decHandler.addStructDecl(origInt, structDecl);
135
136                 mapIntfacePTH.put(origInt, ptHandler);
137                 mapIntDeclHand.put(origInt, decHandler);
138                 // Set object Id counter to 0 for each interface
139                 mapIntfaceObjId.put(origInt, new Integer(0));
140         }
141
142
143         /**
144          * getMethodsForIntface() reads for methods in the data structure
145          * <p>
146          * It is going to give list of methods for a certain interface
147          *              based on the declaration of capabilities.
148          */
149         public void getMethodsForIntface(String origInt) {
150
151                 ParseTreeHandler ptHandler = mapIntfacePTH.get(origInt);
152                 Map<String,Set<String>> mapNewIntMethods = new HashMap<String,Set<String>>();
153                 // Get set of new interfaces, e.g. CameraWithCaptureAndData
154                 // Generate this new interface with all the methods it needs
155                 //              from different capabilities it declares
156                 DeclarationHandler decHandler = mapIntDeclHand.get(origInt);
157                 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(origInt);
158                 Set<String> setIntfaces = reqDecl.getInterfaces();
159                 for (String strInt : setIntfaces) {
160
161                         // Initialize a set of methods
162                         Set<String> setMethods = new HashSet<String>();
163                         // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc.
164                         List<String> listCapab = reqDecl.getCapabList(strInt);
165                         for (String strCap : listCapab) {
166
167                                 // Get list of methods for each capability
168                                 CapabilityDecl capDecl = (CapabilityDecl) decHandler.getCapabilityDecl(origInt);
169                                 List<String> listCapabMeth = capDecl.getMethods(strCap);
170                                 for (String strMeth : listCapabMeth) {
171
172                                         // Add methods into setMethods
173                                         // This is to also handle redundancies (say two capabilities
174                                         //              share the same methods)
175                                         setMethods.add(strMeth);
176                                 }
177                         }
178                         // Add interface and methods information into map
179                         mapNewIntMethods.put(strInt, setMethods);
180                 }
181                 // Map the map of interface-methods to the original interface
182                 mapInt2NewInts.put(origInt, mapNewIntMethods);
183         }
184
185
186         /**
187          * HELPER: writeMethodJavaLocalInterface() writes the method of the local interface
188          */
189         private void writeMethodJavaLocalInterface(Collection<String> methods, InterfaceDecl intDecl) {
190
191                 for (String method : methods) {
192
193                         List<String> methParams = intDecl.getMethodParams(method);
194                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
195                         print("public " + intDecl.getMethodType(method) + " " +
196                                 intDecl.getMethodId(method) + "(");
197                         for (int i = 0; i < methParams.size(); i++) {
198                                 // Check for params with driver class types and exchange it 
199                                 //              with its remote interface
200                                 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
201                                 print(paramType + " " + methParams.get(i));
202                                 // Check if this is the last element (don't print a comma)
203                                 if (i != methParams.size() - 1) {
204                                         print(", ");
205                                 }
206                         }
207                         println(");");
208                 }
209         }
210
211
212         /**
213          * HELPER: writeMethodJavaInterface() writes the method of the interface
214          */
215         private void writeMethodJavaInterface(Collection<String> methods, InterfaceDecl intDecl) {
216
217                 for (String method : methods) {
218
219                         List<String> methParams = intDecl.getMethodParams(method);
220                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
221                         print("public " + intDecl.getMethodType(method) + " " +
222                                 intDecl.getMethodId(method) + "(");
223                         for (int i = 0; i < methParams.size(); i++) {
224                                 // Check for params with driver class types and exchange it 
225                                 //              with its remote interface
226                                 String paramType = methPrmTypes.get(i);
227                                 print(paramType + " " + methParams.get(i));
228                                 // Check if this is the last element (don't print a comma)
229                                 if (i != methParams.size() - 1) {
230                                         print(", ");
231                                 }
232                         }
233                         println(");");
234                 }
235         }
236
237
238         /**
239          * HELPER: generateEnumJava() writes the enumeration declaration
240          */
241         private void generateEnumJava() throws IOException {
242
243                 // Create a new directory
244                 createDirectory(dir);
245                 for (String intface : mapIntfacePTH.keySet()) {
246                         // Get the right EnumDecl
247                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
248                         EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface);
249                         Set<String> enumTypes = enumDecl.getEnumDeclarations();
250                         // Iterate over enum declarations
251                         for (String enType : enumTypes) {
252                                 // Open a new file to write into
253                                 FileWriter fw = new FileWriter(dir + "/" + enType + ".java");
254                                 pw = new PrintWriter(new BufferedWriter(fw));
255                                 println("public enum " + enType + " {");
256                                 List<String> enumMembers = enumDecl.getMembers(enType);
257                                 for (int i = 0; i < enumMembers.size(); i++) {
258
259                                         String member = enumMembers.get(i);
260                                         print(member);
261                                         // Check if this is the last element (don't print a comma)
262                                         if (i != enumMembers.size() - 1)
263                                                 println(",");
264                                         else
265                                                 println("");
266                                 }
267                                 println("}\n");
268                                 pw.close();
269                                 System.out.println("IoTCompiler: Generated enum class " + enType + ".java...");
270                         }
271                 }
272         }
273
274
275         /**
276          * HELPER: generateStructJava() writes the struct declaration
277          */
278         private void generateStructJava() throws IOException {
279
280                 // Create a new directory
281                 createDirectory(dir);
282                 for (String intface : mapIntfacePTH.keySet()) {
283                         // Get the right StructDecl
284                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
285                         StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
286                         List<String> structTypes = structDecl.getStructTypes();
287                         // Iterate over enum declarations
288                         for (String stType : structTypes) {
289                                 // Open a new file to write into
290                                 FileWriter fw = new FileWriter(dir + "/" + stType + ".java");
291                                 pw = new PrintWriter(new BufferedWriter(fw));
292                                 println("public class " + stType + " {");
293                                 List<String> structMemberTypes = structDecl.getMemberTypes(stType);
294                                 List<String> structMembers = structDecl.getMembers(stType);
295                                 for (int i = 0; i < structMembers.size(); i++) {
296
297                                         String memberType = structMemberTypes.get(i);
298                                         String member = structMembers.get(i);
299                                         println("public static " + memberType + " " + member + ";");
300                                 }
301                                 println("}\n");
302                                 pw.close();
303                                 System.out.println("IoTCompiler: Generated struct class " + stType + ".java...");
304                         }
305                 }
306         }
307
308
309         /**
310          * generateJavaLocalInterface() writes the local interface and provides type-checking.
311          * <p>
312          * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
313          * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
314          * The local interface has to be the input parameter for the stub and the stub 
315          * interface has to be the input parameter for the local class.
316          */
317         public void generateJavaLocalInterfaces() throws IOException {
318
319                 // Create a new directory
320                 createDirectory(dir);
321                 for (String intface : mapIntfacePTH.keySet()) {
322                         // Open a new file to write into
323                         FileWriter fw = new FileWriter(dir + "/" + intface + ".java");
324                         pw = new PrintWriter(new BufferedWriter(fw));
325                         // Pass in set of methods and get import classes
326                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
327                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
328                         List<String> methods = intDecl.getMethods();
329                         Set<String> importClasses = getImportClasses(methods, intDecl);
330                         List<String> stdImportClasses = getStandardJavaIntfaceImportClasses();
331                         List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
332                         printImportStatements(allImportClasses);
333                         // Write interface header
334                         println("");
335                         println("public interface " + intface + " {");
336                         // Write methods
337                         writeMethodJavaLocalInterface(methods, intDecl);
338                         println("}");
339                         pw.close();
340                         System.out.println("IoTCompiler: Generated local interface " + intface + ".java...");
341                 }
342         }
343
344
345         /**
346          * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
347          */
348         public void generateJavaInterfaces() throws IOException {
349
350                 // Create a new directory
351                 String path = createDirectories(dir, subdir);
352                 for (String intface : mapIntfacePTH.keySet()) {
353
354                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
355                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
356
357                                 // Open a new file to write into
358                                 String newIntface = intMeth.getKey();
359                                 FileWriter fw = new FileWriter(path + "/" + newIntface + ".java");
360                                 pw = new PrintWriter(new BufferedWriter(fw));
361                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
362                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
363                                 // Pass in set of methods and get import classes
364                                 List<String> methods = intDecl.getMethods();
365                                 Set<String> importClasses = getImportClasses(methods, intDecl);
366                                 List<String> stdImportClasses = getStandardJavaIntfaceImportClasses();
367                                 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
368                                 printImportStatements(allImportClasses);
369                                 // Write interface header
370                                 println("");
371                                 println("public interface " + newIntface + " {\n");
372                                 // Write methods
373                                 writeMethodJavaInterface(methods, intDecl);
374                                 println("}");
375                                 pw.close();
376                                 System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
377                         }
378                 }
379         }
380
381
382         /**
383          * HELPER: writePropertiesJavaPermission() writes the permission in properties
384          */
385         private void writePropertiesJavaPermission(String intface, InterfaceDecl intDecl) {
386
387                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
388                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
389                         String newIntface = intMeth.getKey();
390                         int newObjectId = getNewIntfaceObjectId(newIntface);
391                         println("private final static int object" + newObjectId + "Id = " + 
392                                 newObjectId + ";\t//" + newIntface);
393                         Set<String> methodIds = intMeth.getValue();
394                         print("private static Integer[] object" + newObjectId + "Permission = { ");
395                         int i = 0;
396                         for (String methodId : methodIds) {
397                                 int methodNumId = intDecl.getMethodNumId(methodId);
398                                 print(Integer.toString(methodNumId));
399                                 // Check if this is the last element (don't print a comma)
400                                 if (i != methodIds.size() - 1) {
401                                         print(", ");
402                                 }
403                                 i++;
404                         }
405                         println(" };");
406                         println("private static List<Integer> set" + newObjectId + "Allowed;");
407                 }
408         }
409
410
411         /**
412          * HELPER: writePropertiesJavaStub() writes the properties of the stub class
413          */
414         private void writePropertiesJavaStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
415
416                 println("private IoTRMICall rmiCall;");
417                 println("private String address;");
418                 println("private int[] ports;\n");
419                 // Get the object Id
420                 Integer objId = mapIntfaceObjId.get(intface);
421                 println("private final static int objectId = " + objId + ";");
422                 mapNewIntfaceObjId.put(newIntface, objId);
423                 mapIntfaceObjId.put(intface, objId++);
424                 if (callbackExist) {
425                 // We assume that each class only has one callback interface for now
426                         Iterator it = callbackClasses.iterator();
427                         String callbackType = (String) it.next();
428                         println("// Callback properties");
429                         println("private IoTRMIObject rmiObj;");
430                         println("List<" + callbackType + "> listCallbackObj;");
431                         println("private static int objIdCnt = 0;");
432                         // Generate permission stuff for callback stubs
433                         DeclarationHandler decHandler = mapIntDeclHand.get(callbackType);
434                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(callbackType);
435                         writePropertiesJavaPermission(callbackType, intDecl);
436                 }
437                 println("\n");
438         }
439
440
441         /**
442          * HELPER: writeConstructorJavaPermission() writes the permission in constructor
443          */
444         private void writeConstructorJavaPermission(String intface) {
445
446                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
447                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
448                         String newIntface = intMeth.getKey();
449                         int newObjectId = getNewIntfaceObjectId(newIntface);
450                         println("set" + newObjectId + "Allowed = Arrays.asList(object" + newObjectId +"Permission);");
451                 }
452         }
453
454
455         /**
456          * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
457          */
458         private void writeConstructorJavaStub(String intface, String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
459
460                 println("public " + newStubClass + "(int _port, String _address, int _rev, int[] _ports) throws Exception {");
461                 println("address = _address;");
462                 println("ports = _ports;");
463                 println("rmiCall = new IoTRMICall(_port, _address, _rev);");
464                 if (callbackExist) {
465                         Iterator it = callbackClasses.iterator();
466                         String callbackType = (String) it.next();
467                         writeConstructorJavaPermission(intface);
468                         println("listCallbackObj = new ArrayList<" + callbackType + ">();");
469                         println("___initCallBack();");
470                 }
471                 println("}\n");
472         }
473
474
475         /**
476          * HELPER: writeJavaMethodCallbackPermission() writes permission checks in stub for callbacks
477          */
478         private void writeJavaMethodCallbackPermission(String intface) {
479
480                 println("int methodId = IoTRMIObject.getMethodId(method);");
481                 // Get all the different stubs
482                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
483                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
484                         String newIntface = intMeth.getKey();
485                         int newObjectId = getNewIntfaceObjectId(newIntface);
486                         println("if (!set" + newObjectId + "Allowed.contains(methodId)) {");
487                         println("throw new Error(\"Callback object for " + intface + " is not allowed to access method: \" + methodId);");
488                         println("}");
489                 }
490         }
491
492
493         /**
494          * HELPER: writeJavaInitCallbackPermission() writes the permission for callback
495          */
496         private void writeJavaInitCallbackPermission(String intface, InterfaceDecl intDecl) {
497
498                 String method = "___initCallBack()";
499                 int methodNumId = intDecl.getHelperMethodNumId(method);
500                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
501                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
502                         String newIntface = intMeth.getKey();
503                         int newObjectId = getNewIntfaceObjectId(newIntface);
504                         println("set" + newObjectId + "Allowed.add(" + methodNumId + ");");
505                 }
506         }
507
508
509         /**
510          * HELPER: writeInitCallbackJavaStub() writes callback initialization in stub
511          */
512         private void writeInitCallbackJavaStub(String intface, InterfaceDecl intDecl) {
513
514                 println("public void ___initCallBack() {");
515                 // Generate main thread for callbacks
516                 println("Thread thread = new Thread() {");
517                 println("public void run() {");
518                 println("try {");
519                 println("rmiObj = new IoTRMIObject(ports[0]);");
520                 println("while (true) {");
521                 println("byte[] method = rmiObj.getMethodBytes();");
522                 writeJavaMethodCallbackPermission(intface);
523                 println("int objId = IoTRMIObject.getObjectId(method);");
524                 println(intface + "_CallbackSkeleton skel = (" + intface + "_CallbackSkeleton) listCallbackObj.get(objId);");
525                 println("if (skel != null) {");
526                 println("skel.invokeMethod(rmiObj);");
527                 print("}");
528                 println(" else {");
529                 println("throw new Error(\"" + intface + ": Object with Id \" + objId + \" not found!\");");
530                 println("}");
531                 println("}");
532                 print("}");
533                 println(" catch (Exception ex) {");
534                 println("ex.printStackTrace();");
535                 println("throw new Error(\"Error instantiating class " + intface + "_CallbackSkeleton!\");");
536                 println("}");
537                 println("}");
538                 println("};");
539                 println("thread.start();\n");
540                 // Generate info sending part
541                 String method = "___initCallBack()";
542                 int methodNumId = intDecl.getHelperMethodNumId(method);
543                 println("int methodId = " + methodNumId + ";");
544                 println("Class<?> retType = void.class;");
545                 println("Class<?>[] paramCls = new Class<?>[] { int.class, String.class, int.class };");
546                 println("Object[] paramObj = new Object[] { ports[0], address, 0 };");
547                 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
548                 println("}\n");
549         }
550
551
552         /**
553          * HELPER: checkAndWriteEnumTypeJavaStub() writes the enum type (convert from enum to int)
554          */
555         private void checkAndWriteEnumTypeJavaStub(List<String> methParams, List<String> methPrmTypes) {
556
557                 // Iterate and find enum declarations
558                 for (int i = 0; i < methParams.size(); i++) {
559                         String paramType = methPrmTypes.get(i);
560                         String param = methParams.get(i);
561                         String simpleType = getSimpleType(paramType);
562                         if (isEnumClass(simpleType)) {
563                         // Check if this is enum type
564                                 if (isArray(param)) {   // An array
565                                         println("int len" + i + " = " + param + ".length;");
566                                         println("int paramEnum" + i + "[] = new int[len];");
567                                         println("for (int i = 0; i < len" + i + "; i++) {");
568                                         println("paramEnum" + i + "[i] = " + param + "[i].ordinal();");
569                                         println("}");
570                                 } else if (isList(paramType)) { // A list
571                                         println("int len" + i + " = " + param + ".size();");
572                                         println("int paramEnum" + i + "[] = new int[len];");
573                                         println("for (int i = 0; i < len" + i + "; i++) {");
574                                         println("paramEnum" + i + "[i] = " + param + ".get(i).ordinal();");
575                                         println("}");
576                                 } else {        // Just one element
577                                         println("int paramEnum" + i + "[] = new int[1];");
578                                         println("paramEnum" + i + "[0] = " + param + ".ordinal();");
579                                 }
580                         }
581                 }
582         }
583
584
585         /**
586          * HELPER: checkAndWriteEnumRetTypeJavaStub() writes the enum return type (convert from enum to int)
587          */
588         private void checkAndWriteEnumRetTypeJavaStub(String retType) {
589
590                 // Strips off array "[]" for return type
591                 String pureType = getSimpleArrayType(getSimpleType(retType));
592                 // Take the inner type of generic
593                 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
594                         pureType = getTypeOfGeneric(retType)[0];
595                 if (isEnumClass(pureType)) {
596                 // Check if this is enum type
597                         // Enum decoder
598                         println("int[] retEnum = (int[]) retObj;");
599                         println(pureType + "[] enumVals = " + pureType + ".values();");
600                         if (isArray(retType)) {                 // An array
601                                 println("int retLen = retEnum.length;");
602                                 println(pureType + "[] enumRetVal = new " + pureType + "[retLen];");
603                                 println("for (int i = 0; i < retLen; i++) {");
604                                 println("enumRetVal[i] = enumVals[retEnum[i]];");
605                                 println("}");
606                         } else if (isList(retType)) {   // A list
607                                 println("int retLen = retEnum.length;");
608                                 println("List<" + pureType + "> enumRetVal = new ArrayList<" + pureType + ">();");
609                                 println("for (int i = 0; i < retLen; i++) {");
610                                 println("enumRetVal.add(enumVals[retEnum[i]]);");
611                                 println("}");
612                         } else {        // Just one element
613                                 println(pureType + " enumRetVal = enumVals[retEnum[0]];");
614                         }
615                         println("return enumRetVal;");
616                 }
617         }
618
619
620         /**
621          * HELPER: checkAndWriteStructSetupJavaStub() writes the struct type setup
622          */
623         private void checkAndWriteStructSetupJavaStub(List<String> methParams, List<String> methPrmTypes, 
624                         InterfaceDecl intDecl, String method) {
625                 
626                 // Iterate and find struct declarations
627                 for (int i = 0; i < methParams.size(); i++) {
628                         String paramType = methPrmTypes.get(i);
629                         String param = methParams.get(i);
630                         String simpleType = getSimpleType(paramType);
631                         if (isStructClass(simpleType)) {
632                         // Check if this is enum type
633                                 int methodNumId = intDecl.getMethodNumId(method);
634                                 String helperMethod = methodNumId + "struct" + i;
635                                 println("int methodIdStruct" + i + " = " + intDecl.getHelperMethodNumId(helperMethod) + ";");
636                                 println("Class<?> retTypeStruct" + i + " = void.class;");
637                                 println("Class<?>[] paramClsStruct" + i + " = new Class<?>[] { int.class };");
638                                 if (isArray(param)) {   // An array
639                                         println("Object[] paramObjStruct" + i + " = new Object[] { " + getSimpleArrayType(param) + ".length };");
640                                 } else if (isList(paramType)) { // A list
641                                         println("Object[] paramObjStruct" + i + " = new Object[] { " + getSimpleArrayType(param) + ".size() };");
642                                 } else {        // Just one element
643                                         println("Object[] paramObjStruct" + i + " = new Object[] { new Integer(1) };");
644                                 }
645                                 println("rmiCall.remoteCall(objectId, methodIdStruct" + i + 
646                                                 ", retTypeStruct" + i + ", null, paramClsStruct" + i + 
647                                                 ", paramObjStruct" + i + ");\n");
648                         }
649                 }
650         }
651
652
653         /**
654          * HELPER: isStructPresent() checks presence of struct
655          */
656         private boolean isStructPresent(List<String> methParams, List<String> methPrmTypes) {
657
658                 // Iterate and find enum declarations
659                 for (int i = 0; i < methParams.size(); i++) {
660                         String paramType = methPrmTypes.get(i);
661                         String param = methParams.get(i);
662                         String simpleType = getSimpleType(paramType);
663                         if (isStructClass(simpleType))
664                                 return true;
665                 }
666                 return false;
667         }
668
669
670         /**
671          * HELPER: writeLengthStructParamClassJavaStub() writes lengths of parameters
672          */
673         private void writeLengthStructParamClassJavaStub(List<String> methParams, List<String> methPrmTypes) {
674
675                 // Iterate and find struct declarations - count number of params
676                 for (int i = 0; i < methParams.size(); i++) {
677                         String paramType = methPrmTypes.get(i);
678                         String param = methParams.get(i);
679                         String simpleType = getGenericType(paramType);
680                         if (isStructClass(simpleType)) {
681                                 int members = getNumOfMembers(simpleType);
682                                 if (isArray(param)) {                   // An array
683                                         String structLen = param + ".length";
684                                         print(members + "*" + structLen);
685                                 } else if (isList(paramType)) { // A list
686                                         String structLen = param + ".size()";
687                                         print(members + "*" + structLen);
688                                 } else
689                                         print(Integer.toString(members));
690                         } else
691                                 print("1");
692                         if (i != methParams.size() - 1) {
693                                 print("+");
694                         }
695                 }
696         }
697
698
699         /**
700          * HELPER: writeStructMembersJavaStub() writes parameters of struct
701          */
702         private void writeStructMembersJavaStub(String simpleType, String paramType, String param) {
703
704                 // Get the struct declaration for this struct and generate initialization code
705                 StructDecl structDecl = getStructDecl(simpleType);
706                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
707                 List<String> members = structDecl.getMembers(simpleType);
708                 if (isArray(param)) {                   // An array
709                         println("for(int i = 0; i < " + param + ".length; i++) {");
710                 } else if (isList(paramType)) { // A list
711                         println("for(int i = 0; i < " + param + ".size(); i++) {");
712                 }
713                 if (isArrayOrList(param, paramType)) {  // An array or list
714                         for (int i = 0; i < members.size(); i++) {
715                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
716                                 println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
717                                 print("paramObj[pos++] = " + param + "[i].");
718                                 print(getSimpleIdentifier(members.get(i)));
719                                 println(";");
720                         }
721                         println("}");
722                 } else {        // Just one struct element
723                         for (int i = 0; i < members.size(); i++) {
724                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
725                                 println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
726                                 print("paramObj[pos++] = " + param + ".");
727                                 print(getSimpleIdentifier(members.get(i)));
728                                 println(";");
729                         }
730                 }
731         }
732
733
734         /**
735          * HELPER: writeStructParamClassJavaStub() writes parameters if struct is present
736          */
737         private void writeStructParamClassJavaStub(List<String> methParams, List<String> methPrmTypes) {
738
739                 print("int paramLen = ");
740                 writeLengthStructParamClassJavaStub(methParams, methPrmTypes);
741                 println(";");
742                 println("Object[] paramObj = new Object[paramLen];");
743                 println("Class<?>[] paramCls = new Class<?>[paramLen];");
744                 println("int pos = 0;");
745                 // Iterate again over the parameters
746                 for (int i = 0; i < methParams.size(); i++) {
747                         String paramType = methPrmTypes.get(i);
748                         String param = methParams.get(i);
749                         String simpleType = getGenericType(paramType);
750                         if (isStructClass(simpleType)) {
751                                 writeStructMembersJavaStub(simpleType, paramType, param);
752                         } else {
753                                 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
754                                 println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
755                                 print("paramObj[pos++] = ");
756                                 print(getEnumParam(methPrmTypes.get(i), getSimpleIdentifier(methParams.get(i)), i));
757                                 println(";");
758                         }
759                 }
760                 
761         }
762
763
764         /**
765          * HELPER: writeStructRetMembersJavaStub() writes parameters of struct for return statement
766          */
767         private void writeStructRetMembersJavaStub(String simpleType, String retType) {
768
769                 // Get the struct declaration for this struct and generate initialization code
770                 StructDecl structDecl = getStructDecl(simpleType);
771                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
772                 List<String> members = structDecl.getMembers(simpleType);
773                 if (isArrayOrList(retType, retType)) {  // An array or list
774                         println("for(int i = 0; i < retLen; i++) {");
775                 }
776                 if (isArray(retType)) { // An array
777                         for (int i = 0; i < members.size(); i++) {
778                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
779                                 print("structRet[i]." + getSimpleIdentifier(members.get(i)));
780                                 println(" = (" + getSimpleType(getEnumType(prmType)) + ") retObj[retObjPos++];");
781                         }
782                         println("}");
783                 } else if (isList(retType)) {   // A list
784                         println(simpleType + " structRetMem = new " + simpleType + "();");
785                         for (int i = 0; i < members.size(); i++) {
786                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
787                                 print("structRetMem." + getSimpleIdentifier(members.get(i)));
788                                 println(" = (" + getSimpleType(getEnumType(prmType)) + ") retObj[retObjPos++];");
789                         }
790                         println("structRet.add(structRetMem);");
791                         println("}");
792                 } else {        // Just one struct element
793                         for (int i = 0; i < members.size(); i++) {
794                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
795                                 print("structRet." + getSimpleIdentifier(members.get(i)));
796                                 println(" = (" + getSimpleType(getEnumType(prmType)) + ") retObj[retObjPos++];");
797                         }
798                 }
799                 println("return structRet;");
800         }
801
802
803         /**
804          * HELPER: writeStructReturnJavaStub() writes parameters if struct is present for return statement
805          */
806         private void writeStructReturnJavaStub(String simpleType, String retType) {
807
808                 // Handle the returned struct!!!
809                 println("Object retLenObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
810                 // Minimum retLen is 1 if this is a single struct object
811                 println("int retLen = (int) retLenObj;");
812                 int numMem = getNumOfMembers(simpleType);
813                 println("Class<?>[] retCls = new Class<?>[" + numMem + "*retLen];");
814                 println("Class<?>[] retClsVal = new Class<?>[" + numMem + "*retLen];");
815                 println("int retPos = 0;");
816                 // Get the struct declaration for this struct and generate initialization code
817                 StructDecl structDecl = getStructDecl(simpleType);
818                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
819                 List<String> members = structDecl.getMembers(simpleType);
820                 if (isArrayOrList(retType, retType)) {  // An array or list
821                         println("for(int i = 0; i < retLen; i++) {");
822                         for (int i = 0; i < members.size(); i++) {
823                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
824                                 println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
825                                 println("retClsVal[retPos++] = null;");
826                         }
827                         println("}");
828                 } else {        // Just one struct element
829                         for (int i = 0; i < members.size(); i++) {
830                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
831                                 println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
832                                 println("retClsVal[retPos++] = null;");
833                         }
834                 }
835                 println("Object[] retObj = rmiCall.getStructObjects(retCls, retClsVal);");
836                 if (isArray(retType)) {                 // An array
837                         println(simpleType + "[] structRet = new " + simpleType + "[retLen];");
838                         println("for(int i = 0; i < retLen; i++) {");
839                         println("structRet[i] = new " + simpleType + "();");
840                         println("}");
841                 } else if (isList(retType)) {   // A list
842                         println("List<" + simpleType + "> structRet = new ArrayList<" + simpleType + ">();");
843                 } else
844                         println(simpleType + " structRet = new " + simpleType + "();");
845                 println("int retObjPos = 0;");
846                 writeStructRetMembersJavaStub(simpleType, retType);
847         }
848
849
850         /**
851          * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class
852          */
853         private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
854                         List<String> methPrmTypes, String method) {
855
856                 checkAndWriteStructSetupJavaStub(methParams, methPrmTypes, intDecl, method);
857                 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
858                 String retType = intDecl.getMethodType(method);
859                 println("Class<?> retType = " + getSimpleType(getStructType(getEnumType(retType))) + ".class;");
860                 checkAndWriteEnumTypeJavaStub(methParams, methPrmTypes);
861                 // Generate array of parameter types
862                 if (isStructPresent(methParams, methPrmTypes)) {
863                         writeStructParamClassJavaStub(methParams, methPrmTypes);
864                 } else {
865                         print("Class<?>[] paramCls = new Class<?>[] { ");
866                         for (int i = 0; i < methParams.size(); i++) {
867                                 String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
868                                 print(getSimpleType(getEnumType(paramType)) + ".class");
869                                 // Check if this is the last element (don't print a comma)
870                                 if (i != methParams.size() - 1) {
871                                         print(", ");
872                                 }
873                         }
874                         println(" };");
875                         // Generate array of parameter objects
876                         print("Object[] paramObj = new Object[] { ");
877                         for (int i = 0; i < methParams.size(); i++) {
878                                 print(getEnumParam(methPrmTypes.get(i), getSimpleIdentifier(methParams.get(i)), i));
879                                 // Check if this is the last element (don't print a comma)
880                                 if (i != methParams.size() - 1) {
881                                         print(", ");
882                                 }
883                         }
884                         println(" };");
885                 }
886                 // Check if this is "void"
887                 if (retType.equals("void")) {
888                         println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
889                 } else { // We do have a return value
890                         // Generate array of parameter types
891                         if (isStructClass(getGenericType(getSimpleArrayType(retType)))) {
892                                 writeStructReturnJavaStub(getGenericType(getSimpleArrayType(retType)), retType);
893                         } else {
894                         // Check if the return value NONPRIMITIVES
895                                 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
896                                         String[] retGenValType = getTypeOfGeneric(retType);
897                                         println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
898                                         println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
899                                         println("return (" + retType + ")retObj;");
900                                 } else if (getParamCategory(retType) == ParamCategory.ENUM) {
901                                 // This is an enum type
902                                         println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
903                                         checkAndWriteEnumRetTypeJavaStub(retType);
904                                 } else {
905                                         println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
906                                         println("return (" + retType + ")retObj;");
907                                 }
908                         }
909                 }
910         }
911
912
913         /**
914          * HELPER: returnGenericCallbackType() returns the callback type
915          */
916         private String returnGenericCallbackType(String paramType) {
917
918                 if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES)
919                         return getTypeOfGeneric(paramType)[0];
920                 else
921                         return paramType;
922         }
923
924
925         /**
926          * HELPER: checkCallbackType() checks the callback type
927          */
928         private boolean checkCallbackType(String paramType, String callbackType) {
929
930                 String prmType = returnGenericCallbackType(paramType);
931                 return callbackType.equals(prmType);
932         }
933
934
935         /**
936          * HELPER: writeCallbackMethodBodyJavaStub() writes the callback method of the stub class
937          */
938         private void writeCallbackMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
939                         List<String> methPrmTypes, String method, String callbackType) {
940
941                 println("try {");
942                 // Check if this is single object, array, or list of objects
943                 for (int i = 0; i < methParams.size(); i++) {
944                         String paramType = methPrmTypes.get(i);
945                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
946                                 String param = methParams.get(i);
947                                 if (isArrayOrList(paramType, param)) {  // Generate loop
948                                         println("for (" + paramType + " cb : " + getSimpleIdentifier(param) + ") {");
949                                         println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);");
950                                 } else
951                                         println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(" +
952                                                 getSimpleIdentifier(param) + ", objIdCnt++);");
953                                 println("listCallbackObj.add(skel);");
954                                 if (isArrayOrList(paramType, param))
955                                         println("}");
956                         }
957                 }
958                 print("}");
959                 println(" catch (Exception ex) {");
960                 println("ex.printStackTrace();");
961                 println("throw new Error(\"Exception when generating skeleton objects!\");");
962                 println("}\n");
963                 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
964                 String retType = intDecl.getMethodType(method);
965                 println("Class<?> retType = " + getSimpleType(getEnumType(retType)) + ".class;");
966                 // Generate array of parameter types
967                 print("Class<?>[] paramCls = new Class<?>[] { ");
968                 for (int i = 0; i < methParams.size(); i++) {
969                         String paramType = methPrmTypes.get(i);
970                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
971                                 print("int.class");
972                         } else { // Generate normal classes if it's not a callback object
973                                 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
974                                 print(getSimpleType(prmType) + ".class");
975                         }
976                         if (i != methParams.size() - 1) // Check if this is the last element
977                                 print(", ");
978                 }
979                 println(" };");
980                 // Generate array of parameter objects
981                 print("Object[] paramObj = new Object[] { ");
982                 for (int i = 0; i < methParams.size(); i++) {
983                         String paramType = methPrmTypes.get(i);
984                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
985                                 //if (isArray(methPrmTypes.get(i), methParams.get(i)))
986                                 if (isArray(methParams.get(i)))
987                                         print(getSimpleIdentifier(methParams.get(i)) + ".length");
988                                 else if (isList(methPrmTypes.get(i)))
989                                         print(getSimpleIdentifier(methParams.get(i)) + ".size()");
990                                 else
991                                         print("new Integer(1)");
992                         } else
993                                 print(getSimpleIdentifier(methParams.get(i)));
994                         if (i != methParams.size() - 1)
995                                 print(", ");
996                 }
997                 println(" };");
998                 // Check if this is "void"
999                 if (retType.equals("void")) {
1000                         println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
1001                 } else { // We do have a return value
1002                 // Check if the return value NONPRIMITIVES
1003                         if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
1004                                 String[] retGenValType = getTypeOfGeneric(retType);
1005                                 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
1006                                 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
1007                                 println("return (" + retType + ")retObj;");
1008                         } else {
1009                                 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
1010                                 println("return (" + retType + ")retObj;");
1011                         }
1012                 }
1013         }
1014
1015
1016         /**
1017          * HELPER: writeMethodJavaStub() writes the methods of the stub class
1018          */
1019         private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1020
1021                 for (String method : methods) {
1022
1023                         List<String> methParams = intDecl.getMethodParams(method);
1024                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1025                         print("public " + intDecl.getMethodType(method) + " " +
1026                                 intDecl.getMethodId(method) + "(");
1027                         boolean isCallbackMethod = false;
1028                         String callbackType = null;
1029                         for (int i = 0; i < methParams.size(); i++) {
1030
1031                                 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
1032                                 // Check if this has callback object
1033                                 if (callbackClasses.contains(paramType)) {
1034                                         isCallbackMethod = true;
1035                                         callbackType = paramType;       
1036                                         // Even if there're 2 callback arguments, we expect them to be of the same interface
1037                                 }
1038                                 print(methPrmTypes.get(i) + " " + methParams.get(i));
1039                                 // Check if this is the last element (don't print a comma)
1040                                 if (i != methParams.size() - 1) {
1041                                         print(", ");
1042                                 }
1043                         }
1044                         println(") {");
1045                         // Now, write the body of stub!
1046                         if (isCallbackMethod)
1047                                 writeCallbackMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method, callbackType);
1048                         else
1049                                 writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
1050                         println("}\n");
1051                         // Write the init callback helper method
1052                         if (isCallbackMethod)
1053                                 writeInitCallbackJavaStub(callbackType, intDecl);
1054                 }
1055         }
1056
1057
1058         /**
1059          * generateJavaStubClasses() generate stubs based on the methods list in Java
1060          */
1061         public void generateJavaStubClasses() throws IOException {
1062
1063                 // Create a new directory
1064                 String path = createDirectories(dir, subdir);
1065                 for (String intface : mapIntfacePTH.keySet()) {
1066
1067                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1068                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1069
1070                                 // Open a new file to write into
1071                                 String newIntface = intMeth.getKey();
1072                                 String newStubClass = newIntface + "_Stub";
1073                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
1074                                 pw = new PrintWriter(new BufferedWriter(fw));
1075                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1076                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1077                                 // Pass in set of methods and get import classes
1078                                 Set<String> methods = intMeth.getValue();
1079                                 Set<String> importClasses = getImportClasses(methods, intDecl);
1080                                 List<String> stdImportClasses = getStandardJavaImportClasses();
1081                                 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
1082                                 printImportStatements(allImportClasses); println("");
1083                                 // Find out if there are callback objects
1084                                 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1085                                 boolean callbackExist = !callbackClasses.isEmpty();
1086                                 // Write class header
1087                                 println("public class " + newStubClass + " implements " + newIntface + " {\n");
1088                                 // Write properties
1089                                 writePropertiesJavaStub(intface, newIntface, callbackExist, callbackClasses);
1090                                 // Write constructor
1091                                 writeConstructorJavaStub(intface, newStubClass, callbackExist, callbackClasses);
1092                                 // Write methods
1093                                 writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses);
1094                                 println("}");
1095                                 pw.close();
1096                                 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
1097                         }
1098                 }
1099         }
1100
1101
1102         /**
1103          * HELPER: writePropertiesJavaCallbackStub() writes the properties of the callback stub class
1104          */
1105         private void writePropertiesJavaCallbackStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
1106
1107                 println("private IoTRMICall rmiCall;");
1108                 println("private String address;");
1109                 println("private int[] ports;\n");
1110                 // Get the object Id
1111                 println("private static int objectId = 0;");
1112                 if (callbackExist) {
1113                 // We assume that each class only has one callback interface for now
1114                         Iterator it = callbackClasses.iterator();
1115                         String callbackType = (String) it.next();
1116                         println("// Callback properties");
1117                         println("private IoTRMIObject rmiObj;");
1118                         println("List<" + callbackType + "> listCallbackObj;");
1119                         println("private static int objIdCnt = 0;");
1120                         // Generate permission stuff for callback stubs
1121                         DeclarationHandler decHandler = mapIntDeclHand.get(callbackType);
1122                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(callbackType);
1123                         writePropertiesJavaPermission(callbackType, intDecl);
1124                 }
1125                 println("\n");
1126         }
1127
1128
1129         /**
1130          * HELPER: writeConstructorJavaCallbackStub() writes the constructor of the callback stub class
1131          */
1132         private void writeConstructorJavaCallbackStub(String intface, String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1133
1134                 // TODO: If we want callback in callback, then we need to add address and port initializations
1135                 println("public " + newStubClass + "(IoTRMICall _rmiCall, int _objectId) throws Exception {");
1136                 println("objectId = _objectId;");
1137                 println("rmiCall = _rmiCall;");
1138                 if (callbackExist) {
1139                         Iterator it = callbackClasses.iterator();
1140                         String callbackType = (String) it.next();
1141                         writeConstructorJavaPermission(intface);
1142                         println("listCallbackObj = new ArrayList<" + callbackType + ">();");
1143                         println("___initCallBack();");
1144                         println("// TODO: Add address and port initialization here if we want callback in callback!");
1145                 }
1146                 println("}\n");
1147         }
1148
1149
1150         /**
1151          * generateJavaCallbackStubClasses() generate callback stubs based on the methods list in Java
1152          * <p>
1153          * Callback stubs gets the IoTRMICall objects from outside of the class as contructor input
1154          * because all these stubs are populated by the class that takes in this object as a callback
1155          * object. In such a class, we only use one socket, hence one IoTRMICall, for all callback objects.
1156          */
1157         public void generateJavaCallbackStubClasses() throws IOException {
1158
1159                 // Create a new directory
1160                 String path = createDirectories(dir, subdir);
1161                 for (String intface : mapIntfacePTH.keySet()) {
1162
1163                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1164                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1165
1166                                 // Open a new file to write into
1167                                 String newIntface = intMeth.getKey();
1168                                 String newStubClass = newIntface + "_CallbackStub";
1169                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
1170                                 pw = new PrintWriter(new BufferedWriter(fw));
1171                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1172                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1173                                 // Pass in set of methods and get import classes
1174                                 Set<String> methods = intMeth.getValue();
1175                                 Set<String> importClasses = getImportClasses(methods, intDecl);
1176                                 List<String> stdImportClasses = getStandardJavaImportClasses();
1177                                 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
1178                                 printImportStatements(allImportClasses); println("");
1179                                 // Find out if there are callback objects
1180                                 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1181                                 boolean callbackExist = !callbackClasses.isEmpty();
1182                                 // Write class header
1183                                 println("public class " + newStubClass + " implements " + newIntface + " {\n");
1184                                 // Write properties
1185                                 writePropertiesJavaCallbackStub(intface, newIntface, callbackExist, callbackClasses);
1186                                 // Write constructor
1187                                 writeConstructorJavaCallbackStub(intface, newStubClass, callbackExist, callbackClasses);
1188                                 // Write methods
1189                                 // TODO: perhaps need to generate callback for callback
1190                                 writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses);
1191                                 println("}");
1192                                 pw.close();
1193                                 System.out.println("IoTCompiler: Generated callback stub class " + newStubClass + ".java...");
1194                         }
1195                 }
1196         }
1197
1198
1199         /**
1200          * HELPER: writePropertiesJavaSkeleton() writes the properties of the skeleton class
1201          */
1202         private void writePropertiesJavaSkeleton(String intface, boolean callbackExist, InterfaceDecl intDecl) {
1203
1204                 println("private " + intface + " mainObj;");
1205                 //println("private int ports;");
1206                 println("private IoTRMIObject rmiObj;\n");
1207                 // Callback
1208                 if (callbackExist) {
1209                         println("private static int objIdCnt = 0;");
1210                         println("private IoTRMICall rmiCall;");
1211                 }
1212                 writePropertiesJavaPermission(intface, intDecl);
1213                 println("\n");
1214         }
1215
1216
1217         /**
1218          * HELPER: writeStructPermissionJavaSkeleton() writes permission for struct helper
1219          */
1220         private void writeStructPermissionJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, String intface) {
1221
1222                 // Use this set to handle two same methodIds
1223                 for (String method : methods) {
1224                         List<String> methParams = intDecl.getMethodParams(method);
1225                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1226                         // Check for params with structs
1227                         for (int i = 0; i < methParams.size(); i++) {
1228                                 String paramType = methPrmTypes.get(i);
1229                                 String param = methParams.get(i);
1230                                 String simpleType = getSimpleType(paramType);
1231                                 if (isStructClass(simpleType)) {
1232                                         int methodNumId = intDecl.getMethodNumId(method);
1233                                         // Iterate over interfaces to give permissions to
1234                                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1235                                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1236                                                 String newIntface = intMeth.getKey();
1237                                                 int newObjectId = getNewIntfaceObjectId(newIntface);
1238                                                 println("set" + newObjectId + "Allowed.add(" + methodNumId + ");");
1239                                         }
1240                                 }
1241                         }
1242                 }
1243         }
1244
1245
1246         /**
1247          * HELPER: writeConstructorJavaSkeleton() writes the constructor of the skeleton class
1248          */
1249         private void writeConstructorJavaSkeleton(String newSkelClass, String intface, InterfaceDecl intDecl, Collection<String> methods) {
1250
1251                 println("public " + newSkelClass + "(" + intface + " _mainObj, int _port) throws Exception {");
1252                 println("mainObj = _mainObj;");
1253                 println("rmiObj = new IoTRMIObject(_port);");
1254                 // Generate permission control initialization
1255                 writeConstructorJavaPermission(intface);
1256                 writeJavaInitCallbackPermission(intface, intDecl);
1257                 writeStructPermissionJavaSkeleton(methods, intDecl, intface);
1258                 println("___waitRequestInvokeMethod();");
1259                 println("}\n");
1260         }
1261
1262
1263         /**
1264          * HELPER: writeStdMethodBodyJavaSkeleton() writes the standard method body in the skeleton class
1265          */
1266         private void writeStdMethodBodyJavaSkeleton(List<String> methParams, String methodId, String methodType) {
1267
1268                 if (methodType.equals("void"))
1269                         print("mainObj." + methodId + "(");
1270                 else
1271                         print("return mainObj." + methodId + "(");
1272                 for (int i = 0; i < methParams.size(); i++) {
1273
1274                         print(getSimpleIdentifier(methParams.get(i)));
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(");");
1281         }
1282
1283
1284         /**
1285          * HELPER: writeInitCallbackJavaSkeleton() writes the init callback method for skeleton class
1286          */
1287         private void writeInitCallbackJavaSkeleton(boolean callbackSkeleton) {
1288
1289                 // This is a callback skeleton generation
1290                 if (callbackSkeleton)
1291                         println("public void ___regCB(IoTRMIObject rmiObj) throws IOException {");
1292                 else
1293                         println("public void ___regCB() throws IOException {");
1294                 println("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class, String.class, int.class },");
1295                 println("\tnew Class<?>[] { null, null, null });");
1296                 println("rmiCall = new IoTRMICall((int) paramObj[0], (String) paramObj[1], (int) paramObj[2]);");
1297                 println("}\n");
1298         }
1299
1300
1301         /**
1302          * HELPER: writeMethodJavaSkeleton() writes the method of the skeleton class
1303          */
1304         private void writeMethodJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses, 
1305                         boolean callbackSkeleton) {
1306
1307                 for (String method : methods) {
1308
1309                         List<String> methParams = intDecl.getMethodParams(method);
1310                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1311                         String methodId = intDecl.getMethodId(method);
1312                         print("public " + intDecl.getMethodType(method) + " " + methodId + "(");
1313                         boolean isCallbackMethod = false;
1314                         String callbackType = null;
1315                         for (int i = 0; i < methParams.size(); i++) {
1316
1317                                 String origParamType = methPrmTypes.get(i);
1318                                 String paramType = checkAndGetParamClass(origParamType);
1319                                 if (callbackClasses.contains(origParamType)) { // Check if this has callback object
1320                                         isCallbackMethod = true;
1321                                         callbackType = origParamType;   
1322                                 }
1323                                 print(paramType + " " + methParams.get(i));
1324                                 // Check if this is the last element (don't print a comma)
1325                                 if (i != methParams.size() - 1) {
1326                                         print(", ");
1327                                 }
1328                         }
1329                         println(") {");
1330                         // Now, write the body of skeleton!
1331                         writeStdMethodBodyJavaSkeleton(methParams, methodId, intDecl.getMethodType(method));
1332                         println("}\n");
1333                         if (isCallbackMethod)
1334                                 writeInitCallbackJavaSkeleton(callbackSkeleton);
1335                 }
1336         }
1337
1338
1339         /**
1340          * HELPER: writeCallbackJavaStubGeneration() writes the callback stub generation part
1341          */
1342         private Map<Integer,String> writeCallbackJavaStubGeneration(List<String> methParams, List<String> methPrmTypes, 
1343                         String callbackType) {
1344
1345                 Map<Integer,String> mapStubParam = new HashMap<Integer,String>();
1346                 // Iterate over callback objects
1347                 for (int i = 0; i < methParams.size(); i++) {
1348                         String paramType = methPrmTypes.get(i);
1349                         String param = methParams.get(i);
1350                         //if (callbackType.equals(paramType)) {
1351                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1352                                 println("try {");
1353                                 String exchParamType = checkAndGetParamClass(paramType);
1354                                 // Print array if this is array or list if this is a list of callback objects
1355                                 if (isArray(param)) {
1356                                         println("int numStubs" + i + " = (int) paramObj[" + i + "];");
1357                                         println(exchParamType + "[] stub" + i + " = new " + exchParamType + "[numStubs" + i + "];");
1358                                 } else if (isList(paramType)) {
1359                                         println("int numStubs" + i + " = (int) paramObj[" + i + "];");
1360                                         println("List<" + exchParamType + "> stub" + i + " = new ArrayList<" + exchParamType + ">();");
1361                                 } else {
1362                                         println(exchParamType + " stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
1363                                         println("objIdCnt++;");
1364                                 }
1365                         }
1366                         // Generate a loop if needed
1367                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1368                                 String exchParamType = checkAndGetParamClass(paramType);
1369                                 if (isArray(param)) {
1370                                         println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
1371                                         println("stub" + i + "[objId] = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
1372                                         println("objIdCnt++;");
1373                                         println("}");
1374                                 } else if (isList(paramType)) {
1375                                         println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
1376                                         println("stub" + i + ".add(new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt));");
1377                                         println("objIdCnt++;");
1378                                         println("}");
1379                                 }
1380                                 mapStubParam.put(i, "stub" + i);        // List of all stub parameters
1381                         }
1382                 }
1383                 return mapStubParam;
1384         }
1385
1386
1387         /**
1388          * HELPER: checkAndWriteEnumTypeJavaSkeleton() writes the enum type (convert from enum to int)
1389          */
1390         private void checkAndWriteEnumTypeJavaSkeleton(List<String> methParams, List<String> methPrmTypes) {
1391
1392                 // Iterate and find enum declarations
1393                 for (int i = 0; i < methParams.size(); i++) {
1394                         String paramType = methPrmTypes.get(i);
1395                         String param = methParams.get(i);
1396                         String simpleType = getSimpleType(paramType);
1397                         if (isEnumClass(simpleType)) {
1398                         // Check if this is enum type
1399                                 println("int paramInt" + i + "[] = (int[]) paramObj[" + i + "];");
1400                                 println(simpleType + "[] enumVals = " + simpleType + ".values();");
1401                                 if (isArray(param)) {   // An array
1402                                         println("int len" + i + " = paramInt" + i + ".length;");
1403                                         println(simpleType + "[] paramEnum = new " + simpleType + "[len];");
1404                                         println("for (int i = 0; i < len" + i + "; i++) {");
1405                                         println("paramEnum[i] = enumVals[paramInt" + i + "[i]];");
1406                                         println("}");
1407                                 } else if (isList(paramType)) { // A list
1408                                         println("int len" + i + " = paramInt" + i + ".length;");
1409                                         println("List<" + simpleType + "> paramEnum = new ArrayList<" + simpleType + ">();");
1410                                         println("for (int i = 0; i < len" + i + "; i++) {");
1411                                         println("paramEnum.add(enumVals[paramInt" + i + "[i]]);");
1412                                         println("}");
1413                                 } else {        // Just one element
1414                                         println(simpleType + " paramEnum" + i + " = enumVals[paramInt" + i + "[0]];");
1415                                 }
1416                         }
1417                 }
1418         }
1419
1420
1421         /**
1422          * HELPER: checkAndWriteEnumRetTypeJavaSkeleton() writes the enum return type (convert from enum to int)
1423          */
1424         private void checkAndWriteEnumRetTypeJavaSkeleton(String retType, String methodId) {
1425
1426                 // Strips off array "[]" for return type
1427                 String pureType = getSimpleArrayType(getSimpleType(retType));
1428                 // Take the inner type of generic
1429                 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
1430                         pureType = getTypeOfGeneric(retType)[0];
1431                 if (isEnumClass(pureType)) {
1432                 // Check if this is enum type
1433                         // Enum decoder
1434                         if (isArray(retType)) {                 // An array
1435                                 print(pureType + "[] retEnum = " + methodId + "(");
1436                         } else if (isList(retType)) {   // A list
1437                                 print("List<" + pureType + "> retEnum = " + methodId + "(");
1438                         } else {        // Just one element
1439                                 print(pureType + " retEnum = " + methodId + "(");
1440                         }
1441                 }
1442         }
1443
1444
1445         /**
1446          * HELPER: checkAndWriteEnumRetConvJavaSkeleton() writes the enum return type (convert from enum to int)
1447          */
1448         private void checkAndWriteEnumRetConvJavaSkeleton(String retType) {
1449
1450                 // Strips off array "[]" for return type
1451                 String pureType = getSimpleArrayType(getSimpleType(retType));
1452                 // Take the inner type of generic
1453                 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
1454                         pureType = getTypeOfGeneric(retType)[0];
1455                 if (isEnumClass(pureType)) {
1456                 // Check if this is enum type
1457                         if (isArray(retType)) { // An array
1458                                 println("int retLen = retEnum.length;");
1459                                 println("int[] retEnumVal = new int[retLen];");
1460                                 println("for (int i = 0; i < retLen; i++) {");
1461                                 println("retEnumVal[i] = retEnum[i].ordinal();");
1462                                 println("}");
1463                         } else if (isList(retType)) {   // A list
1464                                 println("int retLen = retEnum.size();");
1465                                 println("List<" + pureType + "> retEnumVal = new ArrayList<" + pureType + ">();");
1466                                 println("for (int i = 0; i < retLen; i++) {");
1467                                 println("retEnumVal.add(retEnum[i].ordinal());");
1468                                 println("}");
1469                         } else {        // Just one element
1470                                 println("int[] retEnumVal = new int[1];");
1471                                 println("retEnumVal[0] = retEnum.ordinal();");
1472                         }
1473                         println("Object retObj = retEnumVal;");
1474                 }
1475         }
1476         
1477         
1478         /**
1479          * HELPER: writeLengthStructParamClassSkeleton() writes lengths of params
1480          */
1481         private void writeLengthStructParamClassSkeleton(List<String> methParams, List<String> methPrmTypes, 
1482                         String method, InterfaceDecl intDecl) {
1483
1484                 // Iterate and find struct declarations - count number of params
1485                 for (int i = 0; i < methParams.size(); i++) {
1486                         String paramType = methPrmTypes.get(i);
1487                         String param = methParams.get(i);
1488                         String simpleType = getGenericType(paramType);
1489                         if (isStructClass(simpleType)) {
1490                                 int members = getNumOfMembers(simpleType);
1491                                 print(Integer.toString(members) + "*");
1492                                 int methodNumId = intDecl.getMethodNumId(method);
1493                                 print("struct" + methodNumId + "Size" + i);
1494                         } else
1495                                 print("1");
1496                         if (i != methParams.size() - 1) {
1497                                 print("+");
1498                         }
1499                 }
1500         }
1501
1502         
1503         /**
1504          * HELPER: writeStructMembersJavaSkeleton() writes member parameters of struct
1505          */
1506         private void writeStructMembersJavaSkeleton(String simpleType, String paramType, 
1507                         String param, String method, InterfaceDecl intDecl, int iVar) {
1508
1509                 // Get the struct declaration for this struct and generate initialization code
1510                 StructDecl structDecl = getStructDecl(simpleType);
1511                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
1512                 List<String> members = structDecl.getMembers(simpleType);
1513                 if (isArrayOrList(param, paramType)) {  // An array or list
1514                         int methodNumId = intDecl.getMethodNumId(method);
1515                         String counter = "struct" + methodNumId + "Size" + iVar;
1516                         println("for(int i = 0; i < " + counter + "; i++) {");
1517                 }
1518                 println("int pos = 0;");
1519                 if (isArrayOrList(param, paramType)) {  // An array or list
1520                         println("for(int i = 0; i < retLen; i++) {");
1521                         for (int i = 0; i < members.size(); i++) {
1522                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
1523                                 println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
1524                                 println("paramClsGen[pos++] = null;");
1525                         }
1526                         println("}");
1527                 } else {        // Just one struct element
1528                         for (int i = 0; i < members.size(); i++) {
1529                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
1530                                 println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
1531                                 println("paramClsGen[pos++] = null;");
1532                         }
1533                 }
1534         }
1535
1536
1537         /**
1538          * HELPER: writeStructMembersInitJavaSkeleton() writes member parameters initialization of struct
1539          */
1540         private void writeStructMembersInitJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
1541                         List<String> methPrmTypes, String method) {
1542
1543                 for (int i = 0; i < methParams.size(); i++) {
1544                         String paramType = methPrmTypes.get(i);
1545                         String param = methParams.get(i);
1546                         String simpleType = getGenericType(paramType);
1547                         if (isStructClass(simpleType)) {
1548                                 int methodNumId = intDecl.getMethodNumId(method);
1549                                 String counter = "struct" + methodNumId + "Size" + i;
1550                                 // Declaration
1551                                 if (isArray(param)) {                   // An array
1552                                         println(simpleType + "[] paramStruct" + i + " = new " + simpleType + "[" + counter + "];");
1553                                         println("for(int i = 0; i < " + counter + "; i++) {");
1554                                         println("paramStruct" + i + "[i] = new " + simpleType + "();");
1555                                         println("}");
1556                                 } else if (isList(paramType)) { // A list
1557                                         println("List<" + simpleType + "> paramStruct" + i + " = new ArrayList<" + simpleType + ">();");
1558                                 } else
1559                                         println(simpleType + " paramStruct" + i + " = new " + simpleType + "();");
1560                                 println("int objPos = 0;");
1561                                 // Initialize members
1562                                 StructDecl structDecl = getStructDecl(simpleType);
1563                                 List<String> members = structDecl.getMembers(simpleType);
1564                                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
1565                                 if (isArrayOrList(param, paramType)) {  // An array or list
1566                                         println("for(int i = 0; i < " + counter + "; i++) {");
1567                                 }
1568                                 if (isArray(param)) {   // An array
1569                                         for (int j = 0; j < members.size(); j++) {
1570                                                 String prmType = checkAndGetArray(memTypes.get(j), members.get(j));
1571                                                 print("paramStruct" + i + "[i]." + getSimpleIdentifier(members.get(j)));
1572                                                 println(" = (" + getSimpleType(getEnumType(prmType)) + ") paramObj[objPos++];");
1573                                         }
1574                                         println("}");
1575                                 } else if (isList(paramType)) { // A list
1576                                         println(simpleType + " paramStructMem = new " + simpleType + "();");
1577                                         for (int j = 0; j < members.size(); j++) {
1578                                                 String prmType = checkAndGetArray(memTypes.get(j), members.get(j));
1579                                                 print("paramStructMem." + getSimpleIdentifier(members.get(j)));
1580                                                 println(" = (" + getSimpleType(getEnumType(prmType)) + ") paramObj[objPos++];");
1581                                         }
1582                                         println("paramStruct" + i + ".add(paramStructMem);");
1583                                         println("}");
1584                                 } else {        // Just one struct element
1585                                         for (int j = 0; j < members.size(); j++) {
1586                                                 String prmType = checkAndGetArray(memTypes.get(j), members.get(j));
1587                                                 print("paramStruct" + i + "." + getSimpleIdentifier(members.get(j)));
1588                                                 println(" = (" + getSimpleType(getEnumType(prmType)) + ") paramObj[objPos++];");
1589                                         }
1590                                 }
1591                         } else {
1592                                 // Take offsets of parameters
1593                                 println("int offset" + i +" = objPos;");
1594                         }
1595                 }
1596         }
1597
1598
1599         /**
1600          * HELPER: writeStructReturnJavaSkeleton() writes struct for return statement
1601          */
1602         private void writeStructReturnJavaSkeleton(String simpleType, String retType) {
1603
1604                 // Minimum retLen is 1 if this is a single struct object
1605                 if (isArray(retType))
1606                         println("int retLen = retStruct.length;");
1607                 else if (isList(retType))
1608                         println("int retLen = retStruct.size();");
1609                 else    // Just single struct object
1610                         println("int retLen = 1;");
1611                 println("Object retLenObj = retLen;");
1612                 println("rmiObj.sendReturnObj(retLenObj);");
1613                 int numMem = getNumOfMembers(simpleType);
1614                 println("Class<?>[] retCls = new Class<?>[" + numMem + "*retLen];");
1615                 println("Object[] retObj = new Object[" + numMem + "*retLen];");
1616                 println("int retPos = 0;");
1617                 // Get the struct declaration for this struct and generate initialization code
1618                 StructDecl structDecl = getStructDecl(simpleType);
1619                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
1620                 List<String> members = structDecl.getMembers(simpleType);
1621                 if (isArrayOrList(retType, retType)) {  // An array or list
1622                         println("for(int i = 0; i < retLen; i++) {");
1623                         for (int i = 0; i < members.size(); i++) {
1624                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
1625                                 println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
1626                                 print("retObj[retPos++] = retStruct[i].");
1627                                 print(getEnumParam(memTypes.get(i), getSimpleIdentifier(members.get(i)), i));
1628                                 println(";");
1629                         }
1630                         println("}");
1631                 } else {        // Just one struct element
1632                         for (int i = 0; i < members.size(); i++) {
1633                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
1634                                 println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
1635                                 print("retObj[retPos++] = retStruct.");
1636                                 print(getEnumParam(memTypes.get(i), getSimpleIdentifier(members.get(i)), i));
1637                                 println(";");
1638                         }
1639                 }
1640
1641         }
1642
1643
1644         /**
1645          * HELPER: writeMethodHelperReturnJavaSkeleton() writes return statement part in skeleton
1646          */
1647         private void writeMethodHelperReturnJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
1648                         List<String> methPrmTypes, String method, boolean isCallbackMethod, String callbackType,
1649                         boolean isStructMethod) {
1650
1651                 checkAndWriteEnumTypeJavaSkeleton(methParams, methPrmTypes);
1652                 Map<Integer,String> mapStubParam = null;
1653                 if (isCallbackMethod)
1654                         mapStubParam = writeCallbackJavaStubGeneration(methParams, methPrmTypes, callbackType);
1655                 // Check if this is "void"
1656                 String retType = intDecl.getMethodType(method);
1657                 if (retType.equals("void")) {
1658                         print(intDecl.getMethodId(method) + "(");
1659                 } else if (isEnumClass(getSimpleArrayType(getSimpleType(retType)))) {   // Enum type
1660                         checkAndWriteEnumRetTypeJavaSkeleton(retType, intDecl.getMethodId(method));
1661                 } else if (isStructClass(getSimpleArrayType(getSimpleType(retType)))) { // Struct type
1662                         print(retType + " retStruct = " + intDecl.getMethodId(method) + "(");
1663                 } else { // We do have a return value
1664                         print("Object retObj = " + intDecl.getMethodId(method) + "(");
1665                 }
1666                 for (int i = 0; i < methParams.size(); i++) {
1667
1668                         if (isCallbackMethod) {
1669                                 print(mapStubParam.get(i));     // Get the callback parameter
1670                         } else if (isEnumClass(getSimpleType(methPrmTypes.get(i)))) { // Enum class
1671                                 print(getEnumParam(methPrmTypes.get(i), methParams.get(i), i));
1672                         } else if (isStructClass(getSimpleType(methPrmTypes.get(i)))) {
1673                                 print("paramStruct" + i);
1674                         } else {
1675                                 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
1676                                 if (isStructMethod)
1677                                         print("(" + prmType + ") paramObj[offset" + i + "]");
1678                                 else
1679                                         print("(" + prmType + ") paramObj[" + i + "]");
1680                         }
1681                         if (i != methParams.size() - 1)
1682                                 print(", ");
1683                 }
1684                 println(");");
1685                 if (!retType.equals("void")) {
1686                         if (isEnumClass(getSimpleArrayType(getSimpleType(retType)))) { // Enum type
1687                                 checkAndWriteEnumRetConvJavaSkeleton(retType);
1688                                 println("rmiObj.sendReturnObj(retObj);");
1689                         } else if (isStructClass(getSimpleArrayType(getSimpleType(retType)))) { // Struct type
1690                                 writeStructReturnJavaSkeleton(getSimpleArrayType(getSimpleType(retType)), retType);
1691                                 println("rmiObj.sendReturnObj(retCls, retObj);");
1692                         } else
1693                                 println("rmiObj.sendReturnObj(retObj);");
1694                 }
1695                 if (isCallbackMethod) { // Catch exception if this is callback
1696                         print("}");
1697                         println(" catch(Exception ex) {");
1698                         println("ex.printStackTrace();");
1699                         println("throw new Error(\"Exception from callback object instantiation!\");");
1700                         println("}");
1701                 }
1702         }
1703
1704
1705         /**
1706          * HELPER: writeMethodHelperStructJavaSkeleton() writes the struct in skeleton
1707          */
1708         private void writeMethodHelperStructJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
1709                         List<String> methPrmTypes, String method, Set<String> callbackClasses) {
1710
1711                 // Generate array of parameter objects
1712                 boolean isCallbackMethod = false;
1713                 String callbackType = null;
1714                 print("int paramLen = ");
1715                 writeLengthStructParamClassSkeleton(methParams, methPrmTypes, method, intDecl);
1716                 println(";");
1717                 println("Class<?>[] paramCls = new Class<?>[paramLen];");
1718                 println("Class<?>[] paramClsGen = new Class<?>[paramLen];");
1719                 // Iterate again over the parameters
1720                 for (int i = 0; i < methParams.size(); i++) {
1721                         String paramType = methPrmTypes.get(i);
1722                         String param = methParams.get(i);
1723                         String simpleType = getGenericType(paramType);
1724                         if (isStructClass(simpleType)) {
1725                                 writeStructMembersJavaSkeleton(simpleType, paramType, param, method, intDecl, i);
1726                         } else {
1727                                 String prmType = returnGenericCallbackType(methPrmTypes.get(i));
1728                                 if (callbackClasses.contains(prmType)) {
1729                                         isCallbackMethod = true;
1730                                         callbackType = prmType;
1731                                         println("paramCls[pos] = int.class;");
1732                                         println("paramClsGen[pos++] = null;");
1733                                 } else {        // Generate normal classes if it's not a callback object
1734                                         String paramTypeOth = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
1735                                         println("paramCls[pos] = " + getSimpleType(getEnumType(paramTypeOth)) + ".class;");
1736                                         print("paramClsGen[pos++] = ");
1737                                         String prmTypeOth = methPrmTypes.get(i);
1738                                         if (getParamCategory(prmTypeOth) == ParamCategory.NONPRIMITIVES)
1739                                                 println(getTypeOfGeneric(prmType)[0] + ".class;");
1740                                         else
1741                                                 println("null;");
1742                                 }
1743                         }
1744                 }
1745                 println("Object[] paramObj = rmiObj.getMethodParams(paramCls, paramClsGen);");
1746                 writeStructMembersInitJavaSkeleton(intDecl, methParams, methPrmTypes, method);
1747                 // Write the return value part
1748                 writeMethodHelperReturnJavaSkeleton(intDecl, methParams, methPrmTypes, method, isCallbackMethod, callbackType, true);
1749         }
1750
1751
1752         /**
1753          * HELPER: writeStdMethodHelperBodyJavaSkeleton() writes the standard method body helper in the skeleton class
1754          */
1755         private void writeStdMethodHelperBodyJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
1756                         List<String> methPrmTypes, String method, Set<String> callbackClasses) {
1757
1758                 // Generate array of parameter objects
1759                 boolean isCallbackMethod = false;
1760                 String callbackType = null;
1761                 print("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { ");
1762                 for (int i = 0; i < methParams.size(); i++) {
1763
1764                         String paramType = returnGenericCallbackType(methPrmTypes.get(i));
1765                         if (callbackClasses.contains(paramType)) {
1766                                 isCallbackMethod = true;
1767                                 callbackType = paramType;
1768                                 print("int.class");
1769                         } else {        // Generate normal classes if it's not a callback object
1770                                 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
1771                                 print(getSimpleType(getEnumType(prmType)) + ".class");
1772                         }
1773                         if (i != methParams.size() - 1)
1774                                 print(", ");
1775                 }
1776                 println(" }, ");
1777                 // Generate generic class if it's a generic type.. null otherwise
1778                 print("new Class<?>[] { ");
1779                 for (int i = 0; i < methParams.size(); i++) {
1780                         String prmType = methPrmTypes.get(i);
1781                         if (getParamCategory(prmType) == ParamCategory.NONPRIMITIVES)
1782                                 print(getTypeOfGeneric(prmType)[0] + ".class");
1783                         else
1784                                 print("null");
1785                         if (i != methParams.size() - 1)
1786                                 print(", ");
1787                 }
1788                 println(" });");
1789                 // Write the return value part
1790                 writeMethodHelperReturnJavaSkeleton(intDecl, methParams, methPrmTypes, method, isCallbackMethod, callbackType, false);
1791         }
1792
1793
1794         /**
1795          * HELPER: writeMethodHelperJavaSkeleton() writes the method helper of the skeleton class
1796          */
1797         private void writeMethodHelperJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1798
1799                 // Use this set to handle two same methodIds
1800                 Set<String> uniqueMethodIds = new HashSet<String>();
1801                 for (String method : methods) {
1802
1803                         List<String> methParams = intDecl.getMethodParams(method);
1804                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1805                         if (isStructPresent(methParams, methPrmTypes)) {        // Treat struct differently
1806                                 String methodId = intDecl.getMethodId(method);
1807                                 print("public void ___");
1808                                 String helperMethod = methodId;
1809                                 if (uniqueMethodIds.contains(methodId))
1810                                         helperMethod = helperMethod + intDecl.getMethodNumId(method);
1811                                 else
1812                                         uniqueMethodIds.add(methodId);
1813                                 String retType = intDecl.getMethodType(method);
1814                                 print(helperMethod + "(");
1815                                 boolean begin = true;
1816                                 for (int i = 0; i < methParams.size(); i++) { // Print size variables
1817                                         String paramType = methPrmTypes.get(i);
1818                                         String param = methParams.get(i);
1819                                         String simpleType = getSimpleType(paramType);
1820                                         if (isStructClass(simpleType)) {
1821                                                 if (!begin) {   // Generate comma for not the beginning variable
1822                                                         print(", "); begin = false;
1823                                                 }
1824                                                 int methodNumId = intDecl.getMethodNumId(method);
1825                                                 print("int struct" + methodNumId + "Size" + i);
1826                                         }
1827                                 }
1828                                 // Check if this is "void"
1829                                 if (retType.equals("void"))
1830                                         println(") {");
1831                                 else
1832                                         println(") throws IOException {");
1833                                 writeMethodHelperStructJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
1834                                 println("}\n");
1835                         } else {
1836                                 String methodId = intDecl.getMethodId(method);
1837                                 print("public void ___");
1838                                 String helperMethod = methodId;
1839                                 if (uniqueMethodIds.contains(methodId))
1840                                         helperMethod = helperMethod + intDecl.getMethodNumId(method);
1841                                 else
1842                                         uniqueMethodIds.add(methodId);
1843                                 // Check if this is "void"
1844                                 String retType = intDecl.getMethodType(method);
1845                                 if (retType.equals("void"))
1846                                         println(helperMethod + "() {");
1847                                 else
1848                                         println(helperMethod + "() throws IOException {");
1849                                 // Now, write the helper body of skeleton!
1850                                 writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
1851                                 println("}\n");
1852                         }
1853                 }
1854                 // Write method helper for structs
1855                 writeMethodHelperStructSetupJavaSkeleton(methods, intDecl);
1856         }
1857
1858
1859         /**
1860          * HELPER: writeMethodHelperStructSetupJavaSkeleton() writes the method helper of struct setup in skeleton class
1861          */
1862         private void writeMethodHelperStructSetupJavaSkeleton(Collection<String> methods, 
1863                         InterfaceDecl intDecl) {
1864
1865                 // Use this set to handle two same methodIds
1866                 for (String method : methods) {
1867
1868                         List<String> methParams = intDecl.getMethodParams(method);
1869                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1870                         // Check for params with structs
1871                         for (int i = 0; i < methParams.size(); i++) {
1872                                 String paramType = methPrmTypes.get(i);
1873                                 String param = methParams.get(i);
1874                                 String simpleType = getSimpleType(paramType);
1875                                 if (isStructClass(simpleType)) {
1876                                         int methodNumId = intDecl.getMethodNumId(method);
1877                                         print("public int ___");
1878                                         String helperMethod = methodNumId + "struct" + i;
1879                                         println(helperMethod + "() {");
1880                                         // Now, write the helper body of skeleton!
1881                                         println("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, new Class<?>[] { null });");
1882                                         println("return (int) paramObj[0];");
1883                                         println("}\n");
1884                                 }
1885                         }
1886                 }
1887         }
1888
1889
1890         /**
1891          * HELPER: writeMethodHelperStructSetupJavaCallbackSkeleton() writes the method helper of struct setup in callback skeleton class
1892          */
1893         private void writeMethodHelperStructSetupJavaCallbackSkeleton(Collection<String> methods, 
1894                         InterfaceDecl intDecl) {
1895
1896                 // Use this set to handle two same methodIds
1897                 for (String method : methods) {
1898
1899                         List<String> methParams = intDecl.getMethodParams(method);
1900                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1901                         // Check for params with structs
1902                         for (int i = 0; i < methParams.size(); i++) {
1903                                 String paramType = methPrmTypes.get(i);
1904                                 String param = methParams.get(i);
1905                                 String simpleType = getSimpleType(paramType);
1906                                 if (isStructClass(simpleType)) {
1907                                         int methodNumId = intDecl.getMethodNumId(method);
1908                                         print("public int ___");
1909                                         String helperMethod = methodNumId + "struct" + i;
1910                                         println(helperMethod + "(IoTRMIObject rmiObj) {");
1911                                         // Now, write the helper body of skeleton!
1912                                         println("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, new Class<?>[] { null });");
1913                                         println("return (int) paramObj[0];");
1914                                         println("}\n");
1915                                 }
1916                         }
1917                 }
1918         }
1919
1920
1921         /**
1922          * HELPER: writeCountVarStructSkeleton() writes counter variable of struct for skeleton
1923          */
1924         private void writeCountVarStructSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
1925
1926                 // Use this set to handle two same methodIds
1927                 for (String method : methods) {
1928
1929                         List<String> methParams = intDecl.getMethodParams(method);
1930                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1931                         // Check for params with structs
1932                         for (int i = 0; i < methParams.size(); i++) {
1933                                 String paramType = methPrmTypes.get(i);
1934                                 String param = methParams.get(i);
1935                                 String simpleType = getSimpleType(paramType);
1936                                 if (isStructClass(simpleType)) {
1937                                         int methodNumId = intDecl.getMethodNumId(method);
1938                                         println("int struct" + methodNumId + "Size" + i + " = 0;");
1939                                 }
1940                         }
1941                 }
1942         }
1943         
1944         
1945         /**
1946          * HELPER: writeInputCountVarStructSkeleton() writes input counter variable of struct for skeleton
1947          */
1948         private boolean writeInputCountVarStructSkeleton(String method, InterfaceDecl intDecl) {
1949
1950                 List<String> methParams = intDecl.getMethodParams(method);
1951                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1952                 boolean structExist = false;
1953                 // Check for params with structs
1954                 for (int i = 0; i < methParams.size(); i++) {
1955                         String paramType = methPrmTypes.get(i);
1956                         String param = methParams.get(i);
1957                         String simpleType = getSimpleType(paramType);
1958                         boolean begin = true;
1959                         if (isStructClass(simpleType)) {
1960                                 structExist = true;
1961                                 if (!begin) {
1962                                         print(", "); begin = false;
1963                                 }
1964                                 int methodNumId = intDecl.getMethodNumId(method);
1965                                 print("struct" + methodNumId + "Size" + i);
1966                         }
1967                 }
1968                 return structExist;
1969         }
1970
1971
1972         /**
1973          * HELPER: writeMethodCallStructSkeleton() writes method call for wait invoke in skeleton
1974          */
1975         private void writeMethodCallStructSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
1976
1977                 // Use this set to handle two same methodIds
1978                 for (String method : methods) {
1979
1980                         List<String> methParams = intDecl.getMethodParams(method);
1981                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1982                         // Check for params with structs
1983                         for (int i = 0; i < methParams.size(); i++) {
1984                                 String paramType = methPrmTypes.get(i);
1985                                 String param = methParams.get(i);
1986                                 String simpleType = getSimpleType(paramType);
1987                                 if (isStructClass(simpleType)) {
1988                                         int methodNumId = intDecl.getMethodNumId(method);
1989                                         print("case ");
1990                                         String helperMethod = methodNumId + "struct" + i;
1991                                         String tempVar = "struct" + methodNumId + "Size" + i;
1992                                         print(intDecl.getHelperMethodNumId(helperMethod) + ": ");
1993                                         print(tempVar + " = ___");
1994                                         println(helperMethod + "(); break;");
1995                                 }
1996                         }
1997                 }
1998         }
1999
2000
2001         /**
2002          * HELPER: writeMethodCallStructCallbackSkeleton() writes method call for wait invoke in skeleton
2003          */
2004         private void writeMethodCallStructCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
2005
2006                 // Use this set to handle two same methodIds
2007                 for (String method : methods) {
2008
2009                         List<String> methParams = intDecl.getMethodParams(method);
2010                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2011                         // Check for params with structs
2012                         for (int i = 0; i < methParams.size(); i++) {
2013                                 String paramType = methPrmTypes.get(i);
2014                                 String param = methParams.get(i);
2015                                 String simpleType = getSimpleType(paramType);
2016                                 if (isStructClass(simpleType)) {
2017                                         int methodNumId = intDecl.getMethodNumId(method);
2018                                         print("case ");
2019                                         String helperMethod = methodNumId + "struct" + i;
2020                                         String tempVar = "struct" + methodNumId + "Size" + i;
2021                                         print(intDecl.getHelperMethodNumId(helperMethod) + ": ");
2022                                         print(tempVar + " = ___");
2023                                         println(helperMethod + "(rmiObj); break;");
2024                                 }
2025                         }
2026                 }
2027         }
2028
2029
2030         /**
2031          * HELPER: writeJavaMethodPermission() writes permission checks in skeleton
2032          */
2033         private void writeJavaMethodPermission(String intface) {
2034
2035                 // Get all the different stubs
2036                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
2037                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
2038                         String newIntface = intMeth.getKey();
2039                         int newObjectId = getNewIntfaceObjectId(newIntface);
2040                         println("if (_objectId == object" + newObjectId + "Id) {");
2041                         println("if (!set" + newObjectId + "Allowed.contains(methodId)) {");
2042                         println("throw new Error(\"Object with object Id: \" + _objectId + \"  is not allowed to access method: \" + methodId);");
2043                         println("}");
2044                         println("}");
2045                         println("else {");
2046                         println("throw new Error(\"Object Id: \" + _objectId + \" not recognized!\");");
2047                         println("}");
2048                 }
2049         }
2050
2051
2052         /**
2053          * HELPER: writeJavaWaitRequestInvokeMethod() writes the main loop of the skeleton class
2054          */
2055         private void writeJavaWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist, String intface) {
2056
2057                 // Use this set to handle two same methodIds
2058                 Set<String> uniqueMethodIds = new HashSet<String>();
2059                 println("private void ___waitRequestInvokeMethod() throws IOException {");
2060                 // Write variables here if we have callbacks or enums or structs
2061                 writeCountVarStructSkeleton(methods, intDecl);
2062                 println("while (true) {");
2063                 println("rmiObj.getMethodBytes();");
2064                 println("int _objectId = rmiObj.getObjectId();");
2065                 println("int methodId = rmiObj.getMethodId();");
2066                 // Generate permission check
2067                 writeJavaMethodPermission(intface);
2068                 println("switch (methodId) {");
2069                 // Print methods and method Ids
2070                 for (String method : methods) {
2071                         String methodId = intDecl.getMethodId(method);
2072                         int methodNumId = intDecl.getMethodNumId(method);
2073                         print("case " + methodNumId + ": ___");
2074                         String helperMethod = methodId;
2075                         if (uniqueMethodIds.contains(methodId))
2076                                 helperMethod = helperMethod + methodNumId;
2077                         else
2078                                 uniqueMethodIds.add(methodId);
2079                         print(helperMethod + "(");
2080                         writeInputCountVarStructSkeleton(method, intDecl);
2081                         println("); break;");
2082                 }
2083                 String method = "___initCallBack()";
2084                 // Print case -9999 (callback handler) if callback exists
2085                 if (callbackExist) {
2086                         int methodId = intDecl.getHelperMethodNumId(method);
2087                         println("case " + methodId + ": ___regCB(); break;");
2088                 }
2089                 writeMethodCallStructSkeleton(methods, intDecl);
2090                 println("default: ");
2091                 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
2092                 println("}");
2093                 println("}");
2094                 println("}\n");
2095         }
2096
2097
2098         /**
2099          * generateJavaSkeletonClass() generate skeletons based on the methods list in Java
2100          */
2101         public void generateJavaSkeletonClass() throws IOException {
2102
2103                 // Create a new directory
2104                 String path = createDirectories(dir, subdir);
2105                 for (String intface : mapIntfacePTH.keySet()) {
2106                         // Open a new file to write into
2107                         String newSkelClass = intface + "_Skeleton";
2108                         FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
2109                         pw = new PrintWriter(new BufferedWriter(fw));
2110                         // Pass in set of methods and get import classes
2111                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2112                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2113                         List<String> methods = intDecl.getMethods();
2114                         Set<String> importClasses = getImportClasses(methods, intDecl);
2115                         List<String> stdImportClasses = getStandardJavaImportClasses();
2116                         List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
2117                         printImportStatements(allImportClasses);
2118                         // Find out if there are callback objects
2119                         Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
2120                         boolean callbackExist = !callbackClasses.isEmpty();
2121                         // Write class header
2122                         println("");
2123                         println("public class " + newSkelClass  + " implements " + intface + " {\n");
2124                         // Write properties
2125                         writePropertiesJavaSkeleton(intface, callbackExist, intDecl);
2126                         // Write constructor
2127                         writeConstructorJavaSkeleton(newSkelClass, intface, intDecl, methods);
2128                         // Write methods
2129                         writeMethodJavaSkeleton(methods, intDecl, callbackClasses, false);
2130                         // Write method helper
2131                         writeMethodHelperJavaSkeleton(methods, intDecl, callbackClasses);
2132                         // Write waitRequestInvokeMethod() - main loop
2133                         writeJavaWaitRequestInvokeMethod(methods, intDecl, callbackExist, intface);
2134                         println("}");
2135                         pw.close();
2136                         System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".java...");
2137                 }
2138         }
2139
2140
2141         /**
2142          * HELPER: writePropertiesJavaCallbackSkeleton() writes the properties of the callback skeleton class
2143          */
2144         private void writePropertiesJavaCallbackSkeleton(String intface, boolean callbackExist) {
2145
2146                 println("private " + intface + " mainObj;");
2147                 // For callback skeletons, this is its own object Id
2148                 println("private static int objectId = 0;");
2149                 // Callback
2150                 if (callbackExist) {
2151                         println("private static int objIdCnt = 0;");
2152                         println("private IoTRMICall rmiCall;");
2153                 }
2154                 println("\n");
2155         }
2156
2157
2158         /**
2159          * HELPER: writeConstructorJavaCallbackSkeleton() writes the constructor of the skeleton class
2160          */
2161         private void writeConstructorJavaCallbackSkeleton(String newSkelClass, String intface, InterfaceDecl intDecl, Collection<String> methods) {
2162
2163                 println("public " + newSkelClass + "(" + intface + " _mainObj, int _objectId) throws Exception {");
2164                 println("mainObj = _mainObj;");
2165                 println("objectId = _objectId;");
2166                 writeStructPermissionJavaSkeleton(methods, intDecl, intface);
2167                 println("}\n");
2168         }
2169
2170
2171         /**
2172          * HELPER: writeMethodHelperJavaCallbackSkeleton() writes the method helper of the callback skeleton class
2173          */
2174         private void writeMethodHelperJavaCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
2175
2176                 // Use this set to handle two same methodIds
2177                 Set<String> uniqueMethodIds = new HashSet<String>();
2178                 for (String method : methods) {
2179
2180                         List<String> methParams = intDecl.getMethodParams(method);
2181                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2182                         if (isStructPresent(methParams, methPrmTypes)) {        // Treat struct differently
2183                                 String methodId = intDecl.getMethodId(method);
2184                                 print("public void ___");
2185                                 String helperMethod = methodId;
2186                                 if (uniqueMethodIds.contains(methodId))
2187                                         helperMethod = helperMethod + intDecl.getMethodNumId(method);
2188                                 else
2189                                         uniqueMethodIds.add(methodId);
2190                                 String retType = intDecl.getMethodType(method);
2191                                 print(helperMethod + "(");
2192                                 boolean begin = true;
2193                                 for (int i = 0; i < methParams.size(); i++) { // Print size variables
2194                                         String paramType = methPrmTypes.get(i);
2195                                         String param = methParams.get(i);
2196                                         String simpleType = getSimpleType(paramType);
2197                                         if (isStructClass(simpleType)) {
2198                                                 if (!begin) {   // Generate comma for not the beginning variable
2199                                                         print(", "); begin = false;
2200                                                 }
2201                                                 int methodNumId = intDecl.getMethodNumId(method);
2202                                                 print("int struct" + methodNumId + "Size" + i);
2203                                         }
2204                                 }
2205                                 // Check if this is "void"
2206                                 if (retType.equals("void"))
2207                                         println(", IoTRMIObject rmiObj) {");
2208                                 else
2209                                         println(", IoTRMIObject rmiObj) throws IOException {");
2210                                 writeMethodHelperStructJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
2211                                 println("}\n");
2212                         } else {
2213                                 String methodId = intDecl.getMethodId(method);
2214                                 print("public void ___");
2215                                 String helperMethod = methodId;
2216                                 if (uniqueMethodIds.contains(methodId))
2217                                         helperMethod = helperMethod + intDecl.getMethodNumId(method);
2218                                 else
2219                                         uniqueMethodIds.add(methodId);
2220                                 // Check if this is "void"
2221                                 String retType = intDecl.getMethodType(method);
2222                                 if (retType.equals("void"))
2223                                         println(helperMethod + "(IoTRMIObject rmiObj) {");
2224                                 else
2225                                         println(helperMethod + "(IoTRMIObject rmiObj) throws IOException {");
2226                                 // Now, write the helper body of skeleton!
2227                                 writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
2228                                 println("}\n");
2229                         }
2230                 }
2231                 // Write method helper for structs
2232                 writeMethodHelperStructSetupJavaCallbackSkeleton(methods, intDecl);
2233         }
2234
2235
2236         /**
2237          * HELPER: writeJavaCallbackWaitRequestInvokeMethod() writes the request invoke method of the callback skeleton class
2238          */
2239         private void writeJavaCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist) {
2240
2241                 // Use this set to handle two same methodIds
2242                 Set<String> uniqueMethodIds = new HashSet<String>();
2243                 println("public void invokeMethod(IoTRMIObject rmiObj) throws IOException {");
2244                 // Write variables here if we have callbacks or enums or structs
2245                 writeCountVarStructSkeleton(methods, intDecl);
2246                 // Write variables here if we have callbacks or enums or structs
2247                 println("int methodId = rmiObj.getMethodId();");
2248                 // TODO: code the permission check here!
2249                 println("switch (methodId) {");
2250                 // Print methods and method Ids
2251                 for (String method : methods) {
2252                         String methodId = intDecl.getMethodId(method);
2253                         int methodNumId = intDecl.getMethodNumId(method);
2254                         print("case " + methodNumId + ": ___");
2255                         String helperMethod = methodId;
2256                         if (uniqueMethodIds.contains(methodId))
2257                                 helperMethod = helperMethod + methodNumId;
2258                         else
2259                                 uniqueMethodIds.add(methodId);
2260                         print(helperMethod + "(");
2261                         if (writeInputCountVarStructSkeleton(method, intDecl))
2262                                 println(", rmiObj); break;");
2263                         else
2264                                 println("rmiObj); break;");
2265                 }
2266                 String method = "___initCallBack()";
2267                 // Print case -9999 (callback handler) if callback exists
2268                 if (callbackExist) {
2269                         int methodId = intDecl.getHelperMethodNumId(method);
2270                         println("case " + methodId + ": ___regCB(rmiObj); break;");
2271                 }
2272                 writeMethodCallStructCallbackSkeleton(methods, intDecl);
2273                 println("default: ");
2274                 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
2275                 println("}");
2276                 println("}\n");
2277         }
2278
2279
2280         /**
2281          * generateJavaCallbackSkeletonClass() generate callback skeletons based on the methods list in Java
2282          */
2283         public void generateJavaCallbackSkeletonClass() throws IOException {
2284
2285                 // Create a new directory
2286                 String path = createDirectories(dir, subdir);
2287                 for (String intface : mapIntfacePTH.keySet()) {
2288                         // Open a new file to write into
2289                         String newSkelClass = intface + "_CallbackSkeleton";
2290                         FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
2291                         pw = new PrintWriter(new BufferedWriter(fw));
2292                         // Pass in set of methods and get import classes
2293                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2294                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2295                         List<String> methods = intDecl.getMethods();
2296                         Set<String> importClasses = getImportClasses(methods, intDecl);
2297                         List<String> stdImportClasses = getStandardJavaImportClasses();
2298                         List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
2299                         printImportStatements(allImportClasses);
2300                         // Find out if there are callback objects
2301                         Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
2302                         boolean callbackExist = !callbackClasses.isEmpty();
2303                         // Write class header
2304                         println("");
2305                         println("public class " + newSkelClass  + " implements " + intface + " {\n");
2306                         // Write properties
2307                         writePropertiesJavaCallbackSkeleton(intface, callbackExist);
2308                         // Write constructor
2309                         writeConstructorJavaCallbackSkeleton(newSkelClass, intface, intDecl, methods);
2310                         // Write methods
2311                         writeMethodJavaSkeleton(methods, intDecl, callbackClasses, true);
2312                         // Write method helper
2313                         writeMethodHelperJavaCallbackSkeleton(methods, intDecl, callbackClasses);
2314                         // Write waitRequestInvokeMethod() - main loop
2315                         writeJavaCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist);
2316                         println("}");
2317                         pw.close();
2318                         System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".java...");
2319                 }
2320         }
2321
2322
2323         /**
2324          * HELPER: writeMethodCplusLocalInterface() writes the method of the local interface
2325          */
2326         private void writeMethodCplusLocalInterface(Collection<String> methods, InterfaceDecl intDecl) {
2327
2328                 for (String method : methods) {
2329
2330                         List<String> methParams = intDecl.getMethodParams(method);
2331                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2332                         print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
2333                                 intDecl.getMethodId(method) + "(");
2334                         for (int i = 0; i < methParams.size(); i++) {
2335                                 // Check for params with driver class types and exchange it 
2336                                 //              with its remote interface
2337                                 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
2338                                 paramType = checkAndGetCplusType(paramType);
2339                                 // Check for arrays - translate into vector in C++
2340                                 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
2341                                 print(paramComplete);
2342                                 // Check if this is the last element (don't print a comma)
2343                                 if (i != methParams.size() - 1) {
2344                                         print(", ");
2345                                 }
2346                         }
2347                         println(") = 0;");
2348                 }
2349         }
2350
2351
2352         /**
2353          * HELPER: writeMethodCplusInterface() writes the method of the interface
2354          */
2355         private void writeMethodCplusInterface(Collection<String> methods, InterfaceDecl intDecl) {
2356
2357                 for (String method : methods) {
2358
2359                         List<String> methParams = intDecl.getMethodParams(method);
2360                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2361                         print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
2362                                 intDecl.getMethodId(method) + "(");
2363                         for (int i = 0; i < methParams.size(); i++) {
2364                                 // Check for params with driver class types and exchange it 
2365                                 //              with its remote interface
2366                                 String paramType = methPrmTypes.get(i);
2367                                 paramType = checkAndGetCplusType(paramType);
2368                                 // Check for arrays - translate into vector in C++
2369                                 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
2370                                 print(paramComplete);
2371                                 // Check if this is the last element (don't print a comma)
2372                                 if (i != methParams.size() - 1) {
2373                                         print(", ");
2374                                 }
2375                         }
2376                         println(") = 0;");
2377                 }
2378         }
2379
2380
2381         /**
2382          * HELPER: generateEnumCplus() writes the enumeration declaration
2383          */
2384         public void generateEnumCplus() throws IOException {
2385
2386                 // Create a new directory
2387                 createDirectory(dir);
2388                 for (String intface : mapIntfacePTH.keySet()) {
2389                         // Get the right StructDecl
2390                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2391                         EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface);
2392                         Set<String> enumTypes = enumDecl.getEnumDeclarations();
2393                         // Iterate over enum declarations
2394                         for (String enType : enumTypes) {
2395                                 // Open a new file to write into
2396                                 FileWriter fw = new FileWriter(dir + "/" + enType + ".hpp");
2397                                 pw = new PrintWriter(new BufferedWriter(fw));
2398                                 // Write file headers
2399                                 println("#ifndef _" + enType.toUpperCase() + "_HPP__");
2400                                 println("#define _" + enType.toUpperCase() + "_HPP__");
2401                                 println("enum " + enType + " {");
2402                                 List<String> enumMembers = enumDecl.getMembers(enType);
2403                                 for (int i = 0; i < enumMembers.size(); i++) {
2404
2405                                         String member = enumMembers.get(i);
2406                                         print(member);
2407                                         // Check if this is the last element (don't print a comma)
2408                                         if (i != enumMembers.size() - 1)
2409                                                 println(",");
2410                                         else
2411                                                 println("");
2412                                 }
2413                                 println("};\n");
2414                                 println("#endif");
2415                                 pw.close();
2416                                 System.out.println("IoTCompiler: Generated enum " + enType + ".hpp...");
2417                         }
2418                 }
2419         }
2420
2421
2422         /**
2423          * HELPER: generateStructCplus() writes the struct declaration
2424          */
2425         public void generateStructCplus() throws IOException {
2426
2427                 // Create a new directory
2428                 createDirectory(dir);
2429                 for (String intface : mapIntfacePTH.keySet()) {
2430                         // Get the right StructDecl
2431                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2432                         StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
2433                         List<String> structTypes = structDecl.getStructTypes();
2434                         // Iterate over enum declarations
2435                         for (String stType : structTypes) {
2436                                 // Open a new file to write into
2437                                 FileWriter fw = new FileWriter(dir + "/" + stType + ".hpp");
2438                                 pw = new PrintWriter(new BufferedWriter(fw));
2439                                 // Write file headers
2440                                 println("#ifndef _" + stType.toUpperCase() + "_HPP__");
2441                                 println("#define _" + stType.toUpperCase() + "_HPP__");
2442                                 println("struct " + stType + " {");
2443                                 List<String> structMemberTypes = structDecl.getMemberTypes(stType);
2444                                 List<String> structMembers = structDecl.getMembers(stType);
2445                                 for (int i = 0; i < structMembers.size(); i++) {
2446
2447                                         String memberType = structMemberTypes.get(i);
2448                                         String member = structMembers.get(i);
2449                                         String structTypeC = checkAndGetCplusType(memberType);
2450                                         String structComplete = checkAndGetCplusArray(structTypeC, member);
2451                                         println(structComplete + ";");
2452                                 }
2453                                 println("};\n");
2454                                 println("#endif");
2455                                 pw.close();
2456                                 System.out.println("IoTCompiler: Generated struct " + stType + ".hpp...");
2457                         }
2458                 }
2459         }
2460
2461
2462         /**
2463          * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking.
2464          * <p>
2465          * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
2466          * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
2467          * The local interface has to be the input parameter for the stub and the stub 
2468          * interface has to be the input parameter for the local class.
2469          */
2470         public void generateCplusLocalInterfaces() throws IOException {
2471
2472                 // Create a new directory
2473                 createDirectory(dir);
2474                 for (String intface : mapIntfacePTH.keySet()) {
2475                         // Open a new file to write into
2476                         FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
2477                         pw = new PrintWriter(new BufferedWriter(fw));
2478                         // Write file headers
2479                         println("#ifndef _" + intface.toUpperCase() + "_HPP__");
2480                         println("#define _" + intface.toUpperCase() + "_HPP__");
2481                         println("#include <iostream>");
2482                         // Pass in set of methods and get include classes
2483                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2484                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2485                         List<String> methods = intDecl.getMethods();
2486                         Set<String> includeClasses = getIncludeClasses(methods, intDecl, intface, true);
2487                         printIncludeStatements(includeClasses); println("");
2488                         println("using namespace std;\n");
2489                         //writeStructCplus(structDecl);
2490                         println("class " + intface); println("{");
2491                         println("public:");
2492                         // Write methods
2493                         writeMethodCplusLocalInterface(methods, intDecl);
2494                         println("};");
2495                         println("#endif");
2496                         pw.close();
2497                         System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
2498                 }
2499         }
2500
2501
2502         /**
2503          * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
2504          * <p>
2505          * For C++ we use virtual classe as interface
2506          */
2507         public void generateCPlusInterfaces() throws IOException {
2508
2509                 // Create a new directory
2510                 String path = createDirectories(dir, subdir);
2511                 for (String intface : mapIntfacePTH.keySet()) {
2512
2513                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
2514                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
2515
2516                                 // Open a new file to write into
2517                                 String newIntface = intMeth.getKey();
2518                                 FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp");
2519                                 pw = new PrintWriter(new BufferedWriter(fw));
2520                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2521                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2522                                 // Write file headers
2523                                 println("#ifndef _" + newIntface.toUpperCase() + "_HPP__");
2524                                 println("#define _" + newIntface.toUpperCase() + "_HPP__");
2525                                 println("#include <iostream>");
2526                                 // Pass in set of methods and get import classes
2527                                 Set<String> includeClasses = getIncludeClasses(intMeth.getValue(), intDecl, intface, false);
2528                                 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
2529                                 List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
2530                                 printIncludeStatements(allIncludeClasses); println("");                 
2531                                 println("using namespace std;\n");
2532                                 println("class " + newIntface);
2533                                 println("{");
2534                                 println("public:");
2535                                 // Write methods
2536                                 writeMethodCplusInterface(intMeth.getValue(), intDecl);
2537                                 println("};");
2538                                 println("#endif");
2539                                 pw.close();
2540                                 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
2541                         }
2542                 }
2543         }
2544
2545
2546         /**
2547          * HELPER: writeMethodCplusStub() writes the methods of the stub
2548          */
2549         private void writeMethodCplusStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
2550
2551                 for (String method : methods) {
2552
2553                         List<String> methParams = intDecl.getMethodParams(method);
2554                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2555
2556                         //System.out.println("\n\nMethod return type: " + checkAndGetCplusType(intDecl.getMethodType(method)) + "\n\n");
2557
2558                         print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
2559                                 intDecl.getMethodId(method) + "(");
2560                         boolean isCallbackMethod = false;
2561                         String callbackType = null;
2562                         for (int i = 0; i < methParams.size(); i++) {
2563
2564                                 String paramType = methPrmTypes.get(i);
2565                                 // Check if this has callback object
2566                                 if (callbackClasses.contains(paramType)) {
2567                                         isCallbackMethod = true;
2568                                         callbackType = paramType;       
2569                                         // Even if there're 2 callback arguments, we expect them to be of the same interface
2570                                 }
2571                                 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
2572                                 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
2573                                 print(methParamComplete);
2574                                 // Check if this is the last element (don't print a comma)
2575                                 if (i != methParams.size() - 1) {
2576                                         print(", ");
2577                                 }
2578                         }
2579                         println(") { ");
2580                         if (isCallbackMethod)
2581                                 writeCallbackMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method, callbackType);
2582                         else
2583                                 writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method);
2584                         println("}\n");
2585                         // Write the init callback helper method
2586                         if (isCallbackMethod) {
2587                                 writeInitCallbackCplusStub(callbackType, intDecl);
2588                                 writeInitCallbackSendInfoCplusStub(intDecl);
2589                         }
2590                 }
2591         }
2592
2593
2594         /**
2595          * HELPER: writeCallbackMethodBodyCplusStub() writes the callback method of the stub class
2596          */
2597         private void writeCallbackMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
2598                         List<String> methPrmTypes, String method, String callbackType) {
2599
2600                 // Check if this is single object, array, or list of objects
2601                 boolean isArrayOrList = false;
2602                 String callbackParam = null;
2603                 for (int i = 0; i < methParams.size(); i++) {
2604
2605                         String paramType = methPrmTypes.get(i);
2606                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
2607                                 String param = methParams.get(i);
2608                                 if (isArrayOrList(paramType, param)) {  // Generate loop
2609                                         println("for (" + paramType + "* cb : " + getSimpleIdentifier(param) + ") {");
2610                                         println(callbackType + "_CallbackSkeleton* skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);");
2611                                         isArrayOrList = true;
2612                                         callbackParam = getSimpleIdentifier(param);
2613                                 } else
2614                                         println(callbackType + "_CallbackSkeleton* skel = new " + callbackType + "_CallbackSkeleton(" +
2615                                                 getSimpleIdentifier(param) + ", objIdCnt++);");
2616                                 println("vecCallbackObj.push_back(skel);");
2617                                 if (isArrayOrList(paramType, param))
2618                                         println("}");
2619                         }
2620                 }
2621                 println("int numParam = " + methParams.size() + ";");
2622                 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
2623                 String retType = intDecl.getMethodType(method);
2624                 //String retTypeC = checkAndGetCplusType(retType);
2625                 //println("string retType = \"" + checkAndGetCplusArrayType(getStructType(getEnumType(retTypeC))) + "\";");
2626                 println("string retType = \"" + checkAndGetCplusRetClsType(getStructType(getEnumType(retType))) + "\";");
2627                 // Generate array of parameter types
2628                 print("string paramCls[] = { ");
2629                 for (int i = 0; i < methParams.size(); i++) {
2630                         String paramType = methPrmTypes.get(i);
2631                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
2632                                 print("\"int\"");
2633                         } else { // Generate normal classes if it's not a callback object
2634                                 //String paramTypeC = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
2635                                 //String prmType = getSimpleType(getEnumType(paramTypeC));
2636                                 String paramTypeC = checkAndGetCplusArgClsType(methPrmTypes.get(i), methParams.get(i));
2637                                 String prmType = getEnumCplusClsType(paramTypeC);
2638                                 print("\"" + prmType + "\"");
2639                         }
2640                         if (i != methParams.size() - 1) // Check if this is the last element
2641                                 print(", ");
2642                 }
2643                 println(" };");
2644                 print("int ___paramCB = ");
2645                 if (isArrayOrList)
2646                         println(callbackParam + ".size();");
2647                 else
2648                         println("1;");
2649                 // Generate array of parameter objects
2650                 print("void* paramObj[] = { ");
2651                 for (int i = 0; i < methParams.size(); i++) {
2652                         String paramType = methPrmTypes.get(i);
2653                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
2654                                 print("&___paramCB");
2655                         } else
2656                                 print(getSimpleIdentifier(methParams.get(i)));
2657                         if (i != methParams.size() - 1)
2658                                 print(", ");
2659                 }
2660                 println(" };");
2661                 // Check if this is "void"
2662                 if (retType.equals("void")) {
2663                         println("void* retObj = NULL;");
2664                         println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
2665                 } else { // We do have a return value
2666                         if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
2667                                 println(checkAndGetCplusType(retType) + " retVal;");
2668                         else
2669                                 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
2670                         println("void* retObj = &retVal;");
2671                         println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
2672                         println("return retVal;");
2673                 }
2674         }
2675
2676
2677         /**
2678          * HELPER: checkAndWriteEnumTypeCplusStub() writes the enum type (convert from enum to int)
2679          */
2680         private void checkAndWriteEnumTypeCplusStub(List<String> methParams, List<String> methPrmTypes) {
2681
2682                 // Iterate and find enum declarations
2683                 for (int i = 0; i < methParams.size(); i++) {
2684                         String paramType = methPrmTypes.get(i);
2685                         String param = methParams.get(i);
2686                         String simpleType = getSimpleType(paramType);
2687                         if (isEnumClass(simpleType)) {
2688                         // Check if this is enum type
2689                                 if (isArrayOrList(paramType, param)) {  // An array or vector
2690                                         println("int len" + i + " = " + param + ".size();");
2691                                         println("vector<int> paramEnum" + i + "(len);");
2692                                         println("for (int i = 0; i < len" + i + "; i++) {");
2693                                         println("paramEnum" + i + "[i] = (int) " + param + "[i];");
2694                                         println("}");
2695                                 } else {        // Just one element
2696                                         println("vector<int> paramEnum" + i + "(1);");
2697                                         println("paramEnum" + i + "[0] = (int) " + param + ";");
2698                                 }
2699                         }
2700                 }
2701         }
2702
2703
2704         /**
2705          * HELPER: checkAndWriteEnumRetTypeCplusStub() writes the enum return type (convert from enum to int)
2706          */
2707         private void checkAndWriteEnumRetTypeCplusStub(String retType) {
2708
2709                 // Strips off array "[]" for return type
2710                 String pureType = getSimpleArrayType(getSimpleType(retType));
2711                 // Take the inner type of generic
2712                 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
2713                         pureType = getTypeOfGeneric(retType)[0];
2714                 if (isEnumClass(pureType)) {
2715                 // Check if this is enum type
2716                         println("vector<int> retEnumInt;");
2717                         println("void* retObj = &retEnumInt;");
2718                         println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
2719                         if (isArrayOrList(retType, retType)) {  // An array or vector
2720                                 println("int retLen = retEnumInt.size();");
2721                                 println("vector<" + pureType + "> retVal(retLen);");
2722                                 println("for (int i = 0; i < retLen; i++) {");
2723                                 println("retVal[i] = (" + pureType + ") retEnumInt[i];");
2724                                 println("}");
2725                         } else {        // Just one element
2726                                 println(pureType + " retVal = (" + pureType + ") retEnumInt[0];");
2727                         }
2728                         println("return retVal;");
2729                 }
2730         }
2731
2732
2733         /**
2734          * HELPER: checkAndWriteStructSetupCplusStub() writes the struct type setup
2735          */
2736         private void checkAndWriteStructSetupCplusStub(List<String> methParams, List<String> methPrmTypes, 
2737                         InterfaceDecl intDecl, String method) {
2738                 
2739                 // Iterate and find struct declarations
2740                 for (int i = 0; i < methParams.size(); i++) {
2741                         String paramType = methPrmTypes.get(i);
2742                         String param = methParams.get(i);
2743                         String simpleType = getSimpleType(paramType);
2744                         if (isStructClass(simpleType)) {
2745                         // Check if this is enum type
2746                                 println("int numParam" + i + " = 1;");
2747                                 int methodNumId = intDecl.getMethodNumId(method);
2748                                 String helperMethod = methodNumId + "struct" + i;
2749                                 println("int methodIdStruct" + i + " = " + intDecl.getHelperMethodNumId(helperMethod) + ";");
2750                                 println("string retTypeStruct" + i + " = \"void\";");
2751                                 println("string paramClsStruct" + i + "[] = { \"int\" };");
2752                                 print("int structLen" + i + " = ");
2753                                 if (isArrayOrList(param, paramType)) {  // An array
2754                                         println(getSimpleArrayType(param) + ".size();");
2755                                 } else {        // Just one element
2756                                         println("1;");
2757                                 }
2758                                 println("void* paramObjStruct" + i + "[] = { &structLen" + i + " };");
2759                                 println("void* retStructLen" + i + " = NULL;");
2760                                 println("rmiCall->remoteCall(objectId, methodIdStruct" + i + 
2761                                                 ", retTypeStruct" + i + ", paramClsStruct" + i + ", paramObjStruct" + i + 
2762                                                 ", numParam" + i + ", retStructLen" + i + ");\n");
2763                         }
2764                 }
2765         }
2766
2767
2768         /**
2769          * HELPER: writeLengthStructParamClassCplusStub() writes lengths of params
2770          */
2771         private void writeLengthStructParamClassCplusStub(List<String> methParams, List<String> methPrmTypes) {
2772
2773                 // Iterate and find struct declarations - count number of params
2774                 for (int i = 0; i < methParams.size(); i++) {
2775                         String paramType = methPrmTypes.get(i);
2776                         String param = methParams.get(i);
2777                         String simpleType = getGenericType(paramType);
2778                         if (isStructClass(simpleType)) {
2779                                 int members = getNumOfMembers(simpleType);
2780                                 if (isArrayOrList(param, paramType)) {                  // An array
2781                                         String structLen = param + ".size()";
2782                                         print(members + "*" + structLen);
2783                                 } else
2784                                         print(Integer.toString(members));
2785                         } else
2786                                 print("1");
2787                         if (i != methParams.size() - 1) {
2788                                 print("+");
2789                         }
2790                 }
2791         }
2792
2793
2794         /**
2795          * HELPER: writeStructMembersCplusStub() writes member parameters of struct
2796          */
2797         private void writeStructMembersCplusStub(String simpleType, String paramType, String param) {
2798
2799                 // Get the struct declaration for this struct and generate initialization code
2800                 StructDecl structDecl = getStructDecl(simpleType);
2801                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
2802                 List<String> members = structDecl.getMembers(simpleType);
2803                 if (isArrayOrList(param, paramType)) {  // An array or list
2804                         println("for(int i = 0; i < " + param + ".size(); i++) {");
2805                 }
2806                 if (isArrayOrList(param, paramType)) {  // An array or list
2807                         for (int i = 0; i < members.size(); i++) {
2808                                 String prmTypeC = checkAndGetCplusType(memTypes.get(i));
2809                                 String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i));
2810                                 println("paramCls[pos] = \"" + getSimpleType(getEnumType(prmType)) + "\";");
2811                                 print("paramObj[pos++] = &" + param + "[i].");
2812                                 print(getSimpleIdentifier(members.get(i)));
2813                                 println(";");
2814                         }
2815                         println("}");
2816                 } else {        // Just one struct element
2817                         for (int i = 0; i < members.size(); i++) {
2818                                 String prmTypeC = checkAndGetCplusType(memTypes.get(i));
2819                                 String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i));
2820                                 println("paramCls[pos] = \"" + getSimpleType(getEnumType(prmType)) + "\";");
2821                                 print("paramObj[pos++] = &" + param + ".");
2822                                 print(getSimpleIdentifier(members.get(i)));
2823                                 println(";");
2824                         }
2825                 }
2826         }
2827
2828
2829         /**
2830          * HELPER: writeStructParamClassCplusStub() writes member parameters of struct
2831          */
2832         private void writeStructParamClassCplusStub(List<String> methParams, List<String> methPrmTypes) {
2833
2834                 print("int numParam = ");
2835                 writeLengthStructParamClassCplusStub(methParams, methPrmTypes);
2836                 println(";");
2837                 println("void* paramObj[numParam];");
2838                 println("string paramCls[numParam];");
2839                 println("int pos = 0;");
2840                 // Iterate again over the parameters
2841                 for (int i = 0; i < methParams.size(); i++) {
2842                         String paramType = methPrmTypes.get(i);
2843                         String param = methParams.get(i);
2844                         String simpleType = getGenericType(paramType);
2845                         if (isStructClass(simpleType)) {
2846                                 writeStructMembersCplusStub(simpleType, paramType, param);
2847                         } else {
2848                                 String prmTypeC = checkAndGetCplusType(methPrmTypes.get(i));
2849                                 String prmType = checkAndGetCplusArrayType(prmTypeC, methParams.get(i));
2850                                 println("paramCls[pos] = \"" + getSimpleType(getEnumType(prmType)) + "\";");
2851                                 print("paramObj[pos++] = &");
2852                                 print(getEnumParam(methPrmTypes.get(i), getSimpleIdentifier(methParams.get(i)), i));
2853                                 println(";");
2854                         }
2855                 }
2856                 
2857         }
2858
2859
2860         /**
2861          * HELPER: writeStructRetMembersCplusStub() writes member parameters of struct for return statement
2862          */
2863         private void writeStructRetMembersCplusStub(String simpleType, String retType) {
2864
2865                 // Get the struct declaration for this struct and generate initialization code
2866                 StructDecl structDecl = getStructDecl(simpleType);
2867                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
2868                 List<String> members = structDecl.getMembers(simpleType);
2869                 if (isArrayOrList(retType, retType)) {  // An array or list
2870                         println("for(int i = 0; i < retLen; i++) {");
2871                 }
2872                 if (isArrayOrList(retType, retType)) {  // An array or list
2873                         for (int i = 0; i < members.size(); i++) {
2874                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
2875                                 print("structRet[i]." + getSimpleIdentifier(members.get(i)));
2876                                 println(" = retParam" + i + "[i];");
2877                         }
2878                         println("}");
2879                 } else {        // Just one struct element
2880                         for (int i = 0; i < members.size(); i++) {
2881                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
2882                                 print("structRet." + getSimpleIdentifier(members.get(i)));
2883                                 println(" = retParam" + i + ";");
2884                         }
2885                 }
2886                 println("return structRet;");
2887         }
2888
2889
2890         /**
2891          * HELPER: writeStructReturnCplusStub() writes member parameters of struct for return statement
2892          */
2893         private void writeStructReturnCplusStub(String simpleType, String retType) {
2894
2895                 // Minimum retLen is 1 if this is a single struct object
2896                 println("int retLen = 0;");
2897                 println("void* retLenObj = { &retLen };");
2898                 // Handle the returned struct!!!
2899                 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retLenObj);");
2900                 int numMem = getNumOfMembers(simpleType);
2901                 println("int numRet = " + numMem + "*retLen;");
2902                 println("string retCls[numRet];");
2903                 println("void* retObj[numRet];");
2904                 StructDecl structDecl = getStructDecl(simpleType);
2905                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
2906                 List<String> members = structDecl.getMembers(simpleType);
2907                 // Set up variables
2908                 if (isArrayOrList(retType, retType)) {  // An array or list
2909                         for (int i = 0; i < members.size(); i++) {
2910                                 String prmTypeC = checkAndGetCplusType(memTypes.get(i));
2911                                 String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i));
2912                                 println(getSimpleType(getEnumType(prmType)) + " retParam" + i + "[retLen];");
2913                         }
2914                 } else {        // Just one struct element
2915                         for (int i = 0; i < members.size(); i++) {
2916                                 String prmTypeC = checkAndGetCplusType(memTypes.get(i));
2917                                 String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i));
2918                                 println(getSimpleType(getEnumType(prmType)) + " retParam" + i + ";");
2919                         }
2920                 }
2921                 println("int retPos = 0;");
2922                 // Get the struct declaration for this struct and generate initialization code
2923                 if (isArrayOrList(retType, retType)) {  // An array or list
2924                         println("for(int i = 0; i < retLen; i++) {");
2925                         for (int i = 0; i < members.size(); i++) {
2926                                 String prmTypeC = checkAndGetCplusType(memTypes.get(i));
2927                                 String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i));
2928                                 println("retCls[retPos] = \"" + getSimpleType(getEnumType(prmType)) + "\";");
2929                                 println("retObj[retPos++] = &retParam" + i + "[i];");
2930                         }
2931                         println("}");
2932                 } else {        // Just one struct element
2933                         for (int i = 0; i < members.size(); i++) {
2934                                 String prmTypeC = checkAndGetCplusType(memTypes.get(i));
2935                                 String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i));
2936                                 println("retCls[retPos] = \"" + getSimpleType(getEnumType(prmType)) + "\";");
2937                                 println("retObj[retPos++] = &retParam" + i + ";");
2938                         }
2939                 }
2940                 println("rmiCall->getStructObjects(retCls, numRet, retObj);");
2941                 if (isArrayOrList(retType, retType)) {  // An array or list
2942                         println("vector<" + simpleType + "> structRet(retLen);");
2943                 } else
2944                         println(simpleType + " structRet;");
2945                 writeStructRetMembersCplusStub(simpleType, retType);
2946         }
2947
2948
2949         /**
2950          * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class
2951          */
2952         private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
2953                         List<String> methPrmTypes, String method) {
2954
2955                 checkAndWriteStructSetupCplusStub(methParams, methPrmTypes, intDecl, method);
2956                 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
2957                 String retType = intDecl.getMethodType(method);
2958                 //String retTypeC = checkAndGetCplusType(retType);
2959                 //println("string retType = \"" + checkAndGetCplusArrayType(getStructType(getEnumType(retTypeC))) + "\";");
2960                 println("string retType = \"" + checkAndGetCplusRetClsType(getStructType(getEnumType(retType))) + "\";");
2961                 // Generate array of parameter types
2962                 if (isStructPresent(methParams, methPrmTypes)) {
2963                         writeStructParamClassCplusStub(methParams, methPrmTypes);
2964                 } else {
2965                         println("int numParam = " + methParams.size() + ";");
2966                         print("string paramCls[] = { ");
2967                         for (int i = 0; i < methParams.size(); i++) {
2968                                 //String paramTypeC = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
2969                                 //String prmType = getSimpleType(getEnumType(paramTypeC));
2970                                 String paramTypeC = checkAndGetCplusArgClsType(methPrmTypes.get(i), methParams.get(i));
2971                                 String prmType = getEnumCplusClsType(paramTypeC);
2972                                 print("\"" + prmType + "\"");
2973                                 // Check if this is the last element (don't print a comma)
2974                                 if (i != methParams.size() - 1) {
2975                                         print(", ");
2976                                 }
2977                         }
2978                         println(" };");
2979                         checkAndWriteEnumTypeCplusStub(methParams, methPrmTypes);
2980                         // Generate array of parameter objects
2981                         print("void* paramObj[] = { ");
2982                         for (int i = 0; i < methParams.size(); i++) {
2983                                 print("&" + getEnumParam(methPrmTypes.get(i), getSimpleIdentifier(methParams.get(i)), i));
2984                                 // Check if this is the last element (don't print a comma)
2985                                 if (i != methParams.size() - 1) {
2986                                         print(", ");
2987                                 }
2988                         }
2989                         println(" };");
2990                 }
2991                 // Check if this is "void"
2992                 if (retType.equals("void")) {
2993                         println("void* retObj = NULL;");
2994                         println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
2995                 } else { // We do have a return value
2996                         // Generate array of parameter types
2997                         if (isStructClass(getGenericType(getSimpleArrayType(retType)))) {
2998                                 writeStructReturnCplusStub(getGenericType(getSimpleArrayType(retType)), retType);
2999                         } else {
3000                         // Check if the return value NONPRIMITIVES
3001                                 if (getParamCategory(retType) == ParamCategory.ENUM) {
3002                                         checkAndWriteEnumRetTypeCplusStub(retType);
3003                                 } else {
3004                                         //if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
3005                                         if (isArrayOrList(retType,retType))
3006                                                 println(checkAndGetCplusType(retType) + " retVal;");
3007                                         else {
3008                                                 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
3009                                         }
3010                                         println("void* retObj = &retVal;");
3011                                         println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
3012                                         println("return retVal;");
3013                                 }
3014                         }
3015                 }
3016         }
3017
3018
3019         /**
3020          * HELPER: writePropertiesCplusStub() writes the properties of the stub class
3021          */
3022         private void writePropertiesCplusPermission(String intface) {
3023
3024                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
3025                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
3026                         String newIntface = intMeth.getKey();
3027                         int newObjectId = getNewIntfaceObjectId(newIntface);
3028                         println("const static int object" + newObjectId + "Id = " + newObjectId + ";\t//" + newIntface);
3029                         println("static set<int> set" + newObjectId + "Allowed;");
3030                 }
3031         }       
3032
3033         /**
3034          * HELPER: writePropertiesCplusStub() writes the properties of the stub class
3035          */
3036         private void writePropertiesCplusStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
3037
3038                 println("IoTRMICall *rmiCall;");
3039                 //println("IoTRMIObject\t\t\t*rmiObj;");
3040                 println("string address;");
3041                 println("vector<int> ports;\n");
3042                 // Get the object Id
3043                 Integer objId = mapIntfaceObjId.get(intface);
3044                 println("const static int objectId = " + objId + ";");
3045                 mapNewIntfaceObjId.put(newIntface, objId);
3046                 mapIntfaceObjId.put(intface, objId++);
3047                 if (callbackExist) {
3048                 // We assume that each class only has one callback interface for now
3049                         Iterator it = callbackClasses.iterator();
3050                         String callbackType = (String) it.next();
3051                         println("// Callback properties");
3052                         println("IoTRMIObject *rmiObj;");
3053                         println("vector<" + callbackType + "*> vecCallbackObj;");
3054                         println("static int objIdCnt;");
3055                         // Generate permission stuff for callback stubs
3056                         writePropertiesCplusPermission(callbackType);
3057                 }
3058                 println("\n");
3059         }
3060
3061
3062         /**
3063          * HELPER: writeConstructorCplusStub() writes the constructor of the stub class
3064          */
3065         private void writeConstructorCplusStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
3066
3067                 println(newStubClass + 
3068                         "(int _port, const char* _address, int _rev, bool* _bResult, vector<int> _ports) {");
3069                 println("address = _address;");
3070                 println("ports = _ports;");
3071                 println("rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);");
3072                 if (callbackExist) {
3073                         Iterator it = callbackClasses.iterator();
3074                         String callbackType = (String) it.next();
3075                         println("thread th1 (&" + newStubClass + "::___initCallBack, this);");
3076                         println("th1.detach();");
3077                         println("___regCB();");
3078                 }
3079                 println("}\n");
3080         }
3081
3082
3083         /**
3084          * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
3085          */
3086         private void writeDeconstructorCplusStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
3087
3088                 println("~" + newStubClass + "() {");
3089                 println("if (rmiCall != NULL) {");
3090                 println("delete rmiCall;");
3091                 println("rmiCall = NULL;");
3092                 println("}");
3093                 if (callbackExist) {
3094                 // We assume that each class only has one callback interface for now
3095                         println("if (rmiObj != NULL) {");
3096                         println("delete rmiObj;");
3097                         println("rmiObj = NULL;");
3098                         println("}");
3099                         Iterator it = callbackClasses.iterator();
3100                         String callbackType = (String) it.next();
3101                         println("for(" + callbackType + "* cb : vecCallbackObj) {");
3102                         println("delete cb;");
3103                         println("cb = NULL;");
3104                         println("}");
3105                 }
3106                 println("}");
3107                 println("");
3108         }
3109
3110
3111         /**
3112          * HELPER: writeCplusMethodCallbackPermission() writes permission checks in stub for callbacks
3113          */
3114         private void writeCplusMethodCallbackPermission(String intface) {
3115
3116                 println("int methodId = IoTRMIObject::getMethodId(method);");
3117                 // Get all the different stubs
3118                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
3119                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
3120                         String newIntface = intMeth.getKey();
3121                         int newObjectId = getNewIntfaceObjectId(newIntface);
3122                         println("if (set" + newObjectId + "Allowed.find(methodId) == set" + newObjectId + "Allowed.end()) {");
3123                         println("cerr << \"Callback object for " + intface + " is not allowed to access method: \" << methodId;");
3124                         println("exit(-1);");
3125                         println("}");
3126                 }
3127         }
3128
3129
3130         /**
3131          * HELPER: writeInitCallbackCplusStub() writes the initialization of callback
3132          */
3133         private void writeInitCallbackCplusStub(String intface, InterfaceDecl intDecl) {
3134
3135                 println("void ___initCallBack() {");
3136                 println("bool bResult = false;");
3137                 println("rmiObj = new IoTRMIObject(ports[0], &bResult);");
3138                 println("while (true) {");
3139                 println("char* method = rmiObj->getMethodBytes();");
3140                 writeCplusMethodCallbackPermission(intface);
3141                 println("int objId = IoTRMIObject::getObjectId(method);");
3142                 println("if (objId < vecCallbackObj.size()) {   // Check if still within range");
3143                 println(intface + "_CallbackSkeleton* skel = dynamic_cast<" + intface + 
3144                         "_CallbackSkeleton*> (vecCallbackObj.at(objId));");
3145                 println("skel->invokeMethod(rmiObj);");
3146                 print("}");
3147                 println(" else {");
3148                 println("cerr << \"Illegal object Id: \" << to_string(objId);");
3149                 // TODO: perhaps need to change this into "throw" to make it cleaner (allow stack unfolding)
3150                 println("exit(-1);");
3151                 println("}");
3152                 println("}");
3153                 println("}\n");
3154         }
3155
3156
3157         /**
3158          * HELPER: writeCplusInitCallbackPermission() writes the permission for callback
3159          */
3160         private void writeCplusInitCallbackPermission(String intface, InterfaceDecl intDecl) {
3161
3162                 String method = "___initCallBack()";
3163                 int methodNumId = intDecl.getHelperMethodNumId(method);
3164                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
3165                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
3166                         String newIntface = intMeth.getKey();
3167                         int newObjectId = getNewIntfaceObjectId(newIntface);
3168                         println("set" + newObjectId + "Allowed.insert(" + methodNumId + ");");
3169                 }
3170         }
3171
3172
3173         /**
3174          * HELPER: writeInitCallbackSendInfoCplusStub() writes the initialization (send info part) of callback
3175          */
3176         private void writeInitCallbackSendInfoCplusStub(InterfaceDecl intDecl) {
3177
3178                 // Generate info sending part
3179                 println("void ___regCB() {");
3180                 println("int numParam = 3;");
3181                 String method = "___initCallBack()";
3182                 int methodNumId = intDecl.getHelperMethodNumId(method);
3183                 println("int methodId = " + methodNumId + ";");
3184                 //writeCplusCallbackPermission(intface, methodNumId);
3185                 println("string retType = \"void\";");
3186                 println("string paramCls[] = { \"int\", \"string\", \"int\" };");
3187                 println("int rev = 0;");
3188                 println("void* paramObj[] = { &ports[0], &address, &rev };");
3189                 println("void* retObj = NULL;");
3190                 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
3191                 println("}\n");
3192         }
3193
3194
3195         /**
3196          * generateCPlusStubClasses() generate stubs based on the methods list in C++
3197          */
3198         public void generateCPlusStubClasses() throws IOException {
3199
3200                 // Create a new directory
3201                 String path = createDirectories(dir, subdir);
3202                 for (String intface : mapIntfacePTH.keySet()) {
3203
3204                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
3205                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
3206                                 // Open a new file to write into
3207                                 String newIntface = intMeth.getKey();
3208                                 String newStubClass = newIntface + "_Stub";
3209                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
3210                                 pw = new PrintWriter(new BufferedWriter(fw));
3211                                 // Write file headers
3212                                 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
3213                                 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
3214                                 println("#include <iostream>");
3215                                 // Find out if there are callback objects
3216                                 Set<String> methods = intMeth.getValue();
3217                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
3218                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
3219                                 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
3220                                 boolean callbackExist = !callbackClasses.isEmpty();
3221                                 if (callbackExist)      // Need thread library if this has callback
3222                                         println("#include <thread>");
3223                                 println("#include \"" + newIntface + ".hpp\""); println("");            
3224                                 println("using namespace std;"); println("");
3225                                 println("class " + newStubClass + " : public " + newIntface); println("{");
3226                                 println("private:\n");
3227                                 writePropertiesCplusStub(intface, newIntface, callbackExist, callbackClasses);
3228                                 println("public:\n");
3229                                 // Add default constructor and destructor
3230                                 println(newStubClass + "() { }"); println("");
3231                                 writeConstructorCplusStub(newStubClass, callbackExist, callbackClasses);
3232                                 writeDeconstructorCplusStub(newStubClass, callbackExist, callbackClasses);
3233                                 // Write methods
3234                                 writeMethodCplusStub(methods, intDecl, callbackClasses);
3235                                 print("}"); println(";");
3236                                 if (callbackExist)
3237                                         writePermissionInitializationCplus(intface, newStubClass, intDecl);
3238                                 writeObjectIdCountInitializationCplus(newStubClass, callbackExist);
3239                                 println("#endif");
3240                                 pw.close();
3241                                 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".hpp...");
3242                         }
3243                 }
3244         }
3245
3246
3247         /**
3248          * HELPER: writePropertiesCplusCallbackStub() writes the properties of the stub class
3249          */
3250         private void writePropertiesCplusCallbackStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
3251
3252                 println("IoTRMICall *rmiCall;");
3253                 // Get the object Id
3254                 println("int objectId;");
3255                 if (callbackExist) {
3256                 // We assume that each class only has one callback interface for now
3257                         Iterator it = callbackClasses.iterator();
3258                         String callbackType = (String) it.next();
3259                         println("// Callback properties");
3260                         println("IoTRMIObject *rmiObj;");
3261                         println("vector<" + callbackType + "*> vecCallbackObj;");
3262                         println("static int objIdCnt;");
3263                         // TODO: Need to initialize address and ports if we want to have callback-in-callback
3264                         println("string address;");
3265                         println("vector<int> ports;\n");
3266                         writePropertiesCplusPermission(callbackType);
3267                 }
3268                 println("\n");
3269         }
3270
3271
3272         /**
3273          * HELPER: writeConstructorCplusCallbackStub() writes the constructor of the stub class
3274          */
3275         private void writeConstructorCplusCallbackStub(String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
3276
3277                 println(newStubClass + "(IoTRMICall* _rmiCall, int _objectId) {");
3278                 println("objectId = _objectId;");
3279                 println("rmiCall = _rmiCall;");
3280                 if (callbackExist) {
3281                         Iterator it = callbackClasses.iterator();
3282                         String callbackType = (String) it.next();
3283                         println("thread th1 (&" + newStubClass + "::___initCallBack, this);");
3284                         println("th1.detach();");
3285                         println("___regCB();");
3286                 }
3287                 println("}\n");
3288         }
3289
3290
3291         /**
3292          * generateCPlusCallbackStubClasses() generate callback stubs based on the methods list in C++
3293          */
3294         public void generateCPlusCallbackStubClasses() throws IOException {
3295
3296                 // Create a new directory
3297                 String path = createDirectories(dir, subdir);
3298                 for (String intface : mapIntfacePTH.keySet()) {
3299
3300                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
3301                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
3302                                 // Open a new file to write into
3303                                 String newIntface = intMeth.getKey();
3304                                 String newStubClass = newIntface + "_CallbackStub";
3305                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
3306                                 pw = new PrintWriter(new BufferedWriter(fw));
3307                                 // Find out if there are callback objects
3308                                 Set<String> methods = intMeth.getValue();
3309                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
3310                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
3311                                 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
3312                                 boolean callbackExist = !callbackClasses.isEmpty();
3313                                 // Write file headers
3314                                 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
3315                                 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
3316                                 println("#include <iostream>");
3317                                 if (callbackExist)
3318                                         println("#include <thread>");
3319                                 println("#include \"" + newIntface + ".hpp\""); println("");            
3320                                 println("using namespace std;"); println("");
3321                                 println("class " + newStubClass + " : public " + newIntface); println("{");
3322                                 println("private:\n");
3323                                 writePropertiesCplusCallbackStub(intface, newIntface, callbackExist, callbackClasses);
3324                                 println("public:\n");
3325                                 // Add default constructor and destructor
3326                                 println(newStubClass + "() { }"); println("");
3327                                 writeConstructorCplusCallbackStub(newStubClass, callbackExist, callbackClasses);
3328                                 writeDeconstructorCplusStub(newStubClass, callbackExist, callbackClasses);
3329                                 // Write methods
3330                                 writeMethodCplusStub(methods, intDecl, callbackClasses);
3331                                 println("};");
3332                                 if (callbackExist)
3333                                         writePermissionInitializationCplus(intface, newStubClass, intDecl);
3334                                 writeObjectIdCountInitializationCplus(newStubClass, callbackExist);
3335                                 println("#endif");
3336                                 pw.close();
3337                                 System.out.println("IoTCompiler: Generated callback stub class " + newIntface + ".hpp...");
3338                         }
3339                 }
3340         }
3341
3342
3343         /**
3344          * HELPER: writePropertiesCplusSkeleton() writes the properties of the skeleton class
3345          */
3346         private void writePropertiesCplusSkeleton(String intface, boolean callbackExist, Set<String> callbackClasses) {
3347
3348                 println(intface + " *mainObj;");
3349                 // Callback
3350                 if (callbackExist) {
3351                         Iterator it = callbackClasses.iterator();
3352                         String callbackType = (String) it.next();
3353                         String exchangeType = checkAndGetParamClass(callbackType);
3354                         println("// Callback properties");
3355                         println("static int objIdCnt;");
3356                         println("vector<" + exchangeType + "*> vecCallbackObj;");
3357                         println("IoTRMICall *rmiCall;");
3358                 }
3359                 println("IoTRMIObject *rmiObj;\n");
3360                 // Keep track of object Ids of all stubs registered to this interface
3361                 writePropertiesCplusPermission(intface);
3362                 println("\n");
3363         }
3364
3365
3366         /**
3367          * HELPER: writeObjectIdCountInitializationCplus() writes the initialization of objIdCnt variable
3368          */
3369         private void writeObjectIdCountInitializationCplus(String newSkelClass, boolean callbackExist) {
3370
3371                 if (callbackExist)
3372                         println("int " + newSkelClass + "::objIdCnt = 0;");
3373         }
3374
3375
3376         /**
3377          * HELPER: writePermissionInitializationCplus() writes the initialization of permission set
3378          */
3379         private void writePermissionInitializationCplus(String intface, String newSkelClass, InterfaceDecl intDecl) {
3380
3381                 // Keep track of object Ids of all stubs registered to this interface
3382                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
3383                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
3384                         String newIntface = intMeth.getKey();
3385                         int newObjectId = getNewIntfaceObjectId(newIntface);
3386                         print("set<int> " + newSkelClass + "::set" + newObjectId + "Allowed {");
3387                         Set<String> methodIds = intMeth.getValue();
3388                         int i = 0;
3389                         for (String methodId : methodIds) {
3390                                 int methodNumId = intDecl.getMethodNumId(methodId);
3391                                 print(Integer.toString(methodNumId));
3392                                 // Check if this is the last element (don't print a comma)
3393                                 if (i != methodIds.size() - 1) {
3394                                         print(", ");
3395                                 }
3396                                 i++;
3397                         }
3398                         println(" };");
3399                 }       
3400         }
3401
3402
3403         /**
3404          * HELPER: writeStructPermissionCplusSkeleton() writes permission for struct helper
3405          */
3406         private void writeStructPermissionCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl, String intface) {
3407
3408                 // Use this set to handle two same methodIds
3409                 for (String method : methods) {
3410                         List<String> methParams = intDecl.getMethodParams(method);
3411                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
3412                         // Check for params with structs
3413                         for (int i = 0; i < methParams.size(); i++) {
3414                                 String paramType = methPrmTypes.get(i);
3415                                 String param = methParams.get(i);
3416                                 String simpleType = getSimpleType(paramType);
3417                                 if (isStructClass(simpleType)) {
3418                                         int methodNumId = intDecl.getMethodNumId(method);
3419                                         // Iterate over interfaces to give permissions to
3420                                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
3421                                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
3422                                                 String newIntface = intMeth.getKey();
3423                                                 int newObjectId = getNewIntfaceObjectId(newIntface);
3424                                                 println("set" + newObjectId + "Allowed.insert(" + methodNumId + ");");
3425                                         }
3426                                 }
3427                         }
3428                 }
3429         }
3430
3431
3432         /**
3433          * HELPER: writeConstructorCplusSkeleton() writes the constructor of the skeleton class
3434          */
3435         private void writeConstructorCplusSkeleton(String newSkelClass, String intface, boolean callbackExist, InterfaceDecl intDecl, Collection<String> methods) {
3436
3437                 println(newSkelClass + "(" + intface + " *_mainObj, int _port) {");
3438                 println("bool _bResult = false;");
3439                 println("mainObj = _mainObj;");
3440                 println("rmiObj = new IoTRMIObject(_port, &_bResult);");
3441                 writeCplusInitCallbackPermission(intface, intDecl);
3442                 writeStructPermissionCplusSkeleton(methods, intDecl, intface);
3443                 println("___waitRequestInvokeMethod();");
3444                 println("}\n");
3445         }
3446
3447
3448         /**
3449          * HELPER: writeDeconstructorCplusSkeleton() writes the deconstructor of the skeleton class
3450          */
3451         private void writeDeconstructorCplusSkeleton(String newSkelClass, boolean callbackExist, Set<String> callbackClasses) {
3452
3453                 println("~" + newSkelClass + "() {");
3454                 println("if (rmiObj != NULL) {");
3455                 println("delete rmiObj;");
3456                 println("rmiObj = NULL;");
3457                 println("}");
3458                 if (callbackExist) {
3459                 // We assume that each class only has one callback interface for now
3460                         println("if (rmiCall != NULL) {");
3461                         println("delete rmiCall;");
3462                         println("rmiCall = NULL;");
3463                         println("}");
3464                         Iterator it = callbackClasses.iterator();
3465                         String callbackType = (String) it.next();
3466                         String exchangeType = checkAndGetParamClass(callbackType);
3467                         println("for(" + exchangeType + "* cb : vecCallbackObj) {");
3468                         println("delete cb;");
3469                         println("cb = NULL;");
3470                         println("}");
3471                 }
3472                 println("}");
3473                 println("");
3474         }
3475
3476
3477         /**
3478          * HELPER: writeStdMethodBodyCplusSkeleton() writes the standard method body in the skeleton class
3479          */
3480         private void writeStdMethodBodyCplusSkeleton(List<String> methParams, String methodId, String methodType) {
3481
3482                 if (methodType.equals("void"))
3483                         print("mainObj->" + methodId + "(");
3484                 else
3485                         print("return mainObj->" + methodId + "(");
3486                 for (int i = 0; i < methParams.size(); i++) {
3487
3488                         print(getSimpleIdentifier(methParams.get(i)));
3489                         // Check if this is the last element (don't print a comma)
3490                         if (i != methParams.size() - 1) {
3491                                 print(", ");
3492                         }
3493                 }
3494                 println(");");
3495         }
3496
3497
3498         /**
3499          * HELPER: writeInitCallbackCplusSkeleton() writes the init callback method for skeleton class
3500          */
3501         private void writeInitCallbackCplusSkeleton(boolean callbackSkeleton) {
3502
3503                 // This is a callback skeleton generation
3504                 if (callbackSkeleton)
3505                         println("void ___regCB(IoTRMIObject* rmiObj) {");
3506                 else
3507                         println("void ___regCB() {");
3508                 println("int numParam = 3;");
3509                 println("int param1 = 0;");
3510                 println("string param2 = \"\";");
3511                 println("int param3 = 0;");
3512                 println("string paramCls[] = { \"int\", \"string\", \"int\" };");
3513                 println("void* paramObj[] = { &param1, &param2, &param3 };");
3514                 println("rmiObj->getMethodParams(paramCls, numParam, paramObj);");
3515                 println("bool bResult = false;");
3516                 println("rmiCall = new IoTRMICall(param1, param2.c_str(), param3, &bResult);");
3517                 println("}\n");
3518         }
3519
3520
3521         /**
3522          * HELPER: writeMethodCplusSkeleton() writes the method of the skeleton class
3523          */
3524         private void writeMethodCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl, 
3525                         Set<String> callbackClasses, boolean callbackSkeleton) {
3526
3527                 for (String method : methods) {
3528
3529                         List<String> methParams = intDecl.getMethodParams(method);
3530                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
3531                         String methodId = intDecl.getMethodId(method);
3532                         String methodType = checkAndGetCplusType(intDecl.getMethodType(method));
3533                         print(methodType + " " + methodId + "(");
3534                         boolean isCallbackMethod = false;
3535                         String callbackType = null;
3536                         for (int i = 0; i < methParams.size(); i++) {
3537
3538                                 String origParamType = methPrmTypes.get(i);
3539                                 if (callbackClasses.contains(origParamType)) { // Check if this has callback object
3540                                         isCallbackMethod = true;
3541                                         callbackType = origParamType;   
3542                                 }
3543                                 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
3544                                 String methPrmType = checkAndGetCplusType(paramType);
3545                                 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
3546                                 print(methParamComplete);
3547                                 // Check if this is the last element (don't print a comma)
3548                                 if (i != methParams.size() - 1) {
3549                                         print(", ");
3550                                 }
3551                         }
3552                         println(") {");
3553                         // Now, write the body of skeleton!
3554                         writeStdMethodBodyCplusSkeleton(methParams, methodId, intDecl.getMethodType(method));
3555                         println("}\n");
3556                         if (isCallbackMethod)
3557                                 writeInitCallbackCplusSkeleton(callbackSkeleton);
3558                 }
3559         }
3560
3561
3562         /**
3563          * HELPER: writeCallbackCplusNumStubs() writes the numStubs variable
3564          */
3565         private void writeCallbackCplusNumStubs(List<String> methParams, List<String> methPrmTypes, String callbackType) {
3566
3567                 for (int i = 0; i < methParams.size(); i++) {
3568                         String paramType = methPrmTypes.get(i);
3569                         String param = methParams.get(i);
3570                         //if (callbackType.equals(paramType)) {
3571                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
3572                                 String exchParamType = checkAndGetParamClass(paramType);
3573                                 // Print array if this is array or list if this is a list of callback objects
3574                                 println("int numStubs" + i + " = 0;");
3575                         }
3576                 }
3577         }
3578
3579
3580         /**
3581          * HELPER: writeCallbackCplusStubGeneration() writes the callback stub generation part
3582          */
3583         private void writeCallbackCplusStubGeneration(List<String> methParams, List<String> methPrmTypes, String callbackType) {
3584
3585                 // Iterate over callback objects
3586                 for (int i = 0; i < methParams.size(); i++) {
3587                         String paramType = methPrmTypes.get(i);
3588                         String param = methParams.get(i);
3589                         // Generate a loop if needed
3590                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
3591                                 String exchParamType = checkAndGetParamClass(paramType);
3592                                 if (isArrayOrList(paramType, param)) {
3593                                         println("vector<" + exchParamType + "> stub;");
3594                                         println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
3595                                         println(exchParamType + "* cb" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
3596                                         println("stub" + i + ".push_back(cb);");
3597                                         println("vecCallbackObj.push_back(cb);");
3598                                         println("objIdCnt++;");
3599                                         println("}");
3600                                 } else {
3601                                         println(exchParamType + "* stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
3602                                         println("vecCallbackObj.push_back(stub" + i + ");");
3603                                         println("objIdCnt++;");
3604                                 }
3605                         }
3606                 }
3607         }
3608
3609
3610         /**
3611          * HELPER: checkAndWriteEnumTypeCplusSkeleton() writes the enum type (convert from enum to int)
3612          */
3613         private void checkAndWriteEnumTypeCplusSkeleton(List<String> methParams, List<String> methPrmTypes) {
3614
3615                 // Iterate and find enum declarations
3616                 for (int i = 0; i < methParams.size(); i++) {
3617                         String paramType = methPrmTypes.get(i);
3618                         String param = methParams.get(i);
3619                         String simpleType = getSimpleType(paramType);
3620                         if (isEnumClass(simpleType)) {
3621                         // Check if this is enum type
3622                                 if (isArrayOrList(paramType, param)) {  // An array
3623                                         println("int len" + i + " = paramEnumInt" + i + ".size();");
3624                                         println("vector<" + simpleType + "> paramEnum" + i + "(len" + i + ");");
3625                                         println("for (int i=0; i < len" + i + "; i++) {");
3626                                         println("paramEnum" + i + "[i] = (" + simpleType + ") paramEnumInt" + i + "[i];");
3627                                         println("}");
3628                                 } else {        // Just one element
3629                                         println(simpleType + " paramEnum" + i + ";");
3630                                         println("paramEnum" + i + " = (" + simpleType + ") paramEnumInt" + i + "[0];");
3631                                 }
3632                         }
3633                 }
3634         }
3635
3636
3637         /**
3638          * HELPER: checkAndWriteEnumRetTypeCplusSkeleton() writes the enum return type (convert from enum to int)
3639          */
3640         private void checkAndWriteEnumRetTypeCplusSkeleton(String retType) {
3641
3642                 // Strips off array "[]" for return type
3643                 String pureType = getSimpleArrayType(getSimpleType(retType));
3644                 // Take the inner type of generic
3645                 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
3646                         pureType = getTypeOfGeneric(retType)[0];
3647                 if (isEnumClass(pureType)) {
3648                 // Check if this is enum type
3649                         // Enum decoder
3650                         if (isArrayOrList(retType, retType)) {  // An array
3651                                 println("int retLen = retEnum.size();");
3652                                 println("vector<int> retEnumInt(retLen);");
3653                                 println("for (int i=0; i < retLen; i++) {");
3654                                 println("retEnumInt[i] = (int) retEnum[i];");
3655                                 println("}");
3656                         } else {        // Just one element
3657                                 println("vector<int> retEnumInt(1);");
3658                                 println("retEnumInt[0] = (int) retEnum;");
3659                         }
3660                 }
3661         }
3662
3663
3664         /**
3665          * HELPER: writeMethodHelperReturnCplusSkeleton() writes the return statement part in skeleton
3666          */
3667         private void writeMethodInputParameters(List<String> methParams, List<String> methPrmTypes, 
3668                         Set<String> callbackClasses, String methodId) {
3669
3670                 print(methodId + "(");
3671                 for (int i = 0; i < methParams.size(); i++) {
3672                         String paramType = returnGenericCallbackType(methPrmTypes.get(i));
3673                         if (callbackClasses.contains(paramType))
3674                                 print("stub" + i);
3675                         else if (isEnumClass(getSimpleType(paramType))) // Check if this is enum type
3676                                 print("paramEnum" + i);
3677                         else if (isStructClass(getSimpleType(paramType)))       // Struct type
3678                                 print("paramStruct" + i);
3679                         else
3680                                 print(getSimpleIdentifier(methParams.get(i)));
3681                         if (i != methParams.size() - 1) {
3682                                 print(", ");
3683                         }
3684                 }
3685                 println(");");
3686         }
3687
3688
3689         /**
3690          * HELPER: writeMethodHelperReturnCplusSkeleton() writes the return statement part in skeleton
3691          */
3692         private void writeMethodHelperReturnCplusSkeleton(InterfaceDecl intDecl, List<String> methParams,
3693                         List<String> methPrmTypes, String method, boolean isCallbackMethod, String callbackType,
3694                         String methodId, Set<String> callbackClasses) {
3695
3696                 println("rmiObj->getMethodParams(paramCls, numParam, paramObj);");
3697                 if (isCallbackMethod)
3698                         writeCallbackCplusStubGeneration(methParams, methPrmTypes, callbackType);
3699                 checkAndWriteEnumTypeCplusSkeleton(methParams, methPrmTypes);
3700                 writeStructMembersInitCplusSkeleton(intDecl, methParams, methPrmTypes, method);
3701                 // Check if this is "void"
3702                 String retType = intDecl.getMethodType(method);
3703                 // Check if this is "void"
3704                 if (retType.equals("void")) {
3705                         writeMethodInputParameters(methParams, methPrmTypes, callbackClasses, methodId);
3706                 } else { // We do have a return value
3707                         if (isEnumClass(getSimpleArrayType(getSimpleType(retType)))) // Enum type
3708                                 print(checkAndGetCplusType(retType) + " retEnum = ");
3709                         else if (isStructClass(getSimpleArrayType(getSimpleType(retType)))) // Struct type
3710                                 print(checkAndGetCplusType(retType) + " retStruct = ");
3711                         else
3712                                 print(checkAndGetCplusType(retType) + " retVal = ");
3713                         writeMethodInputParameters(methParams, methPrmTypes, callbackClasses, methodId);
3714                         checkAndWriteEnumRetTypeCplusSkeleton(retType);
3715                         if (isStructClass(getSimpleArrayType(getSimpleType(retType)))) // Struct type
3716                                 writeStructReturnCplusSkeleton(getSimpleArrayType(getSimpleType(retType)), retType);
3717                         if (isEnumClass(getSimpleArrayType(getSimpleType(retType)))) // Enum type
3718                                 println("void* retObj = &retEnumInt;");
3719                         else
3720                                 if (!isStructClass(getSimpleArrayType(getSimpleType(retType)))) // Struct type
3721                                         println("void* retObj = &retVal;");
3722                         String retTypeC = checkAndGetCplusType(retType);
3723                         if (isStructClass(getSimpleArrayType(getSimpleType(retType)))) // Struct type
3724                                 println("rmiObj->sendReturnObj(retObj, retCls, numRetObj);");
3725                         else
3726                                 println("rmiObj->sendReturnObj(retObj, \"" + checkAndGetCplusRetClsType(getEnumType(retType)) + "\");");
3727                 }
3728         }
3729
3730
3731         /**
3732          * HELPER: writeStdMethodHelperBodyCplusSkeleton() writes the standard method body helper in the skeleton class
3733          */
3734         private void writeStdMethodHelperBodyCplusSkeleton(InterfaceDecl intDecl, List<String> methParams,
3735                         List<String> methPrmTypes, String method, String methodId, Set<String> callbackClasses) {
3736
3737                 // Generate array of parameter types
3738                 boolean isCallbackMethod = false;
3739                 String callbackType = null;
3740                 print("string paramCls[] = { ");
3741                 for (int i = 0; i < methParams.size(); i++) {
3742                         String paramType = returnGenericCallbackType(methPrmTypes.get(i));
3743                         if (callbackClasses.contains(paramType)) {
3744                                 isCallbackMethod = true;
3745                                 callbackType = paramType;
3746                                 print("\"int\"");
3747                         } else {        // Generate normal classes if it's not a callback object
3748                                 //String paramTypeC = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
3749                                 //String prmType = getSimpleType(getEnumType(paramTypeC));
3750                                 String paramTypeC = checkAndGetCplusArgClsType(methPrmTypes.get(i), methParams.get(i));
3751                                 String prmType = getEnumCplusClsType(paramTypeC);
3752                                 print("\"" + prmType + "\"");
3753                         }
3754                         if (i != methParams.size() - 1) {
3755                                 print(", ");
3756                         }
3757                 }
3758                 println(" };");
3759                 println("int numParam = " + methParams.size() + ";");
3760                 if (isCallbackMethod)
3761                         writeCallbackCplusNumStubs(methParams, methPrmTypes, callbackType);
3762                 // Generate parameters
3763                 for (int i = 0; i < methParams.size(); i++) {
3764                         String paramType = returnGenericCallbackType(methPrmTypes.get(i));
3765                         if (!callbackClasses.contains(paramType)) {
3766                                 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
3767                                 if (isEnumClass(getSimpleType(methPrmType))) {  // Check if this is enum type
3768                                         println("vector<int> paramEnumInt" + i + ";");
3769                                 } else {
3770                                         String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
3771                     println(methParamComplete + ";");
3772                                 }
3773                         }
3774                 }
3775                 // Generate array of parameter objects
3776                 print("void* paramObj[] = { ");
3777                 for (int i = 0; i < methParams.size(); i++) {
3778                         String paramType = returnGenericCallbackType(methPrmTypes.get(i));
3779                         if (callbackClasses.contains(paramType))
3780                                 print("&numStubs" + i);
3781                         else if (isEnumClass(getSimpleType(paramType))) // Check if this is enum type
3782                                 print("&paramEnumInt" + i);
3783                         else
3784                                 print("&" + getSimpleIdentifier(methParams.get(i)));
3785                         if (i != methParams.size() - 1) {
3786                                 print(", ");
3787                         }
3788                 }
3789                 println(" };");
3790                 // Write the return value part
3791                 writeMethodHelperReturnCplusSkeleton(intDecl, methParams, methPrmTypes, method, isCallbackMethod, 
3792                         callbackType, methodId, callbackClasses);
3793         }
3794
3795
3796         /**
3797          * HELPER: writeStructMembersCplusSkeleton() writes member parameters of struct
3798          */
3799         private void writeStructMembersCplusSkeleton(String simpleType, String paramType, 
3800                         String param, String method, InterfaceDecl intDecl, int iVar) {
3801
3802                 // Get the struct declaration for this struct and generate initialization code
3803                 StructDecl structDecl = getStructDecl(simpleType);
3804                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
3805                 List<String> members = structDecl.getMembers(simpleType);
3806                 int methodNumId = intDecl.getMethodNumId(method);
3807                 String counter = "struct" + methodNumId + "Size" + iVar;
3808                 if (isArrayOrList(param, paramType)) {  // An array or list
3809                         println("for(int i = 0; i < " + counter + "; i++) {");
3810                 }
3811                 // Set up variables
3812                 if (isArrayOrList(param, paramType)) {  // An array or list
3813                         for (int i = 0; i < members.size(); i++) {
3814                                 String prmTypeC = checkAndGetCplusType(memTypes.get(i));
3815                                 String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i));
3816                                 println(getSimpleType(getEnumType(prmType)) + " param" + i + "[" + counter + "];");
3817                         }
3818                 } else {        // Just one struct element
3819                         for (int i = 0; i < members.size(); i++) {
3820                                 String prmTypeC = checkAndGetCplusType(memTypes.get(i));
3821                                 String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i));
3822                                 println(getSimpleType(getEnumType(prmType)) + " param" + i + ";");
3823                         }
3824                 }
3825                 println("int pos = 0;");
3826                 if (isArrayOrList(param, paramType)) {  // An array or list
3827                         println("for(int i = 0; i < retLen; i++) {");
3828                         for (int i = 0; i < members.size(); i++) {
3829                                 String prmTypeC = checkAndGetCplusType(memTypes.get(i));
3830                                 String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i));
3831                                 println("paramCls[pos] = \"" + getSimpleType(getEnumType(prmType)) + "\";");
3832                                 println("paramObj[pos++] = &param" + i + "[i];");
3833                         }
3834                         println("}");
3835                 } else {        // Just one struct element
3836                         for (int i = 0; i < members.size(); i++) {
3837                                 String prmTypeC = checkAndGetCplusType(memTypes.get(i));
3838                                 String prmType = checkAndGetCplusArrayType(prmTypeC, members.get(i));
3839                                 println("paramCls[pos] = \"" + getSimpleType(getEnumType(prmType)) + "\";");
3840                                 println("paramObj[pos++] = &param" + i + ";");
3841                         }
3842                 }
3843         }
3844
3845
3846         /**
3847          * HELPER: writeStructMembersInitCplusSkeleton() writes member parameters initialization of struct
3848          */
3849         private void writeStructMembersInitCplusSkeleton(InterfaceDecl intDecl, List<String> methParams,
3850                         List<String> methPrmTypes, String method) {
3851
3852                 for (int i = 0; i < methParams.size(); i++) {
3853                         String paramType = methPrmTypes.get(i);
3854                         String param = methParams.get(i);
3855                         String simpleType = getGenericType(paramType);
3856                         if (isStructClass(simpleType)) {
3857                                 int methodNumId = intDecl.getMethodNumId(method);
3858                                 String counter = "struct" + methodNumId + "Size" + i;
3859                                 // Declaration
3860                                 if (isArrayOrList(param, paramType)) {  // An array or list
3861                                         println("vector<" + simpleType + "> paramStruct" + i + ";");
3862                                 } else
3863                                         println(simpleType + " paramStruct" + i + ";");
3864                                 // Initialize members
3865                                 StructDecl structDecl = getStructDecl(simpleType);
3866                                 List<String> members = structDecl.getMembers(simpleType);
3867                                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
3868                                 if (isArrayOrList(param, paramType)) {  // An array or list
3869                                         println("for(int i = 0; i < " + counter + "; i++) {");
3870                                         for (int j = 0; j < members.size(); j++) {
3871                                                 print("paramStruct" + i + "[i]." + getSimpleIdentifier(members.get(j)));
3872                                                 println(" = param" + j + "[i];");
3873                                         }
3874                                         println("}");
3875                                 } else {        // Just one struct element
3876                                         for (int j = 0; j < members.size(); j++) {
3877                                                 print("paramStruct" + i + "." + getSimpleIdentifier(members.get(j)));
3878                                                 println(" = param" + j + ";");
3879                                         }
3880                                 }
3881                         }
3882                 }
3883         }
3884
3885
3886         /**
3887          * HELPER: writeStructReturnCplusSkeleton() writes parameters of struct for return statement
3888          */
3889         private void writeStructReturnCplusSkeleton(String simpleType, String retType) {
3890
3891                 // Minimum retLen is 1 if this is a single struct object
3892                 if (isArrayOrList(retType, retType))
3893                         println("int retLen = retStruct.size();");
3894                 else    // Just single struct object
3895                         println("int retLen = 1;");
3896                 println("void* retLenObj = &retLen;");
3897                 println("rmiObj->sendReturnObj(retLenObj, \"int\");");
3898                 int numMem = getNumOfMembers(simpleType);
3899                 println("int numRetObj = " + numMem + "*retLen;");
3900                 println("string retCls[numRetObj];");
3901                 println("void* retObj[numRetObj];");
3902                 println("int retPos = 0;");
3903                 // Get the struct declaration for this struct and generate initialization code
3904                 StructDecl structDecl = getStructDecl(simpleType);
3905                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
3906                 List<String> members = structDecl.getMembers(simpleType);
3907                 if (isArrayOrList(retType, retType)) {  // An array or list
3908                         println("for(int i = 0; i < retLen; i++) {");
3909                         for (int i = 0; i < members.size(); i++) {
3910                                 String paramTypeC = checkAndGetCplusType(memTypes.get(i));
3911                                 String prmType = checkAndGetCplusArrayType(paramTypeC, members.get(i));
3912                                 println("retCls[retPos] = \"" + getSimpleType(getEnumType(prmType)) + "\";");
3913                                 print("retObj[retPos++] = &retStruct[i].");
3914                                 print(getEnumParam(memTypes.get(i), getSimpleIdentifier(members.get(i)), i));
3915                                 println(";");
3916                         }
3917                         println("}");
3918                 } else {        // Just one struct element
3919                         for (int i = 0; i < members.size(); i++) {
3920                                 String paramTypeC = checkAndGetCplusType(memTypes.get(i));
3921                                 String prmType = checkAndGetCplusArrayType(paramTypeC, members.get(i));
3922                                 println("retCls[retPos] = \"" + getSimpleType(getEnumType(prmType)) + "\";");
3923                                 print("retObj[retPos++] = &retStruct.");
3924                                 print(getEnumParam(memTypes.get(i), getSimpleIdentifier(members.get(i)), i));
3925                                 println(";");
3926                         }
3927                 }
3928
3929         }
3930
3931
3932         /**
3933          * HELPER: writeMethodHelperStructCplusSkeleton() writes the struct in skeleton
3934          */
3935         private void writeMethodHelperStructCplusSkeleton(InterfaceDecl intDecl, List<String> methParams,
3936                         List<String> methPrmTypes, String method, String methodId, Set<String> callbackClasses) {
3937
3938                 // Generate array of parameter objects
3939                 boolean isCallbackMethod = false;
3940                 String callbackType = null;
3941                 print("int numParam = ");
3942                 writeLengthStructParamClassSkeleton(methParams, methPrmTypes, method, intDecl);
3943                 println(";");
3944                 println("string paramCls[numParam];");
3945                 println("void* paramObj[numParam];");
3946                 // Iterate again over the parameters
3947                 for (int i = 0; i < methParams.size(); i++) {
3948                         String paramType = methPrmTypes.get(i);
3949                         String param = methParams.get(i);
3950                         String simpleType = getGenericType(paramType);
3951                         if (isStructClass(simpleType)) {
3952                                 writeStructMembersCplusSkeleton(simpleType, paramType, param, method, intDecl, i);
3953                         } else {
3954                                 String prmType = returnGenericCallbackType(methPrmTypes.get(i));
3955                                 if (callbackClasses.contains(prmType)) {
3956                                         isCallbackMethod = true;
3957                                         callbackType = paramType;
3958                                         writeCallbackCplusNumStubs(methParams, methPrmTypes, callbackType);
3959                                         println("paramCls[pos] = \"int\";");
3960                                         println("paramObj[pos++] = &numStubs" + i + ";");
3961                                 } else {        // Generate normal classes if it's not a callback object
3962                                         String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
3963                                         String prmTypeC = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
3964                                         if (isEnumClass(getSimpleType(paramTypeC))) {   // Check if this is enum type
3965                                                 println("vector<int> paramEnumInt" + i + ";");
3966                                         } else {
3967                                                 String methParamComplete = checkAndGetCplusArray(paramTypeC, methParams.get(i));
3968                                                 println(methParamComplete + ";");
3969                                         }
3970                                         println("paramCls[pos] = \"" + getEnumType(prmTypeC) + "\";");
3971                                         if (isEnumClass(getSimpleType(paramType)))      // Check if this is enum type
3972                                                 println("paramObj[pos++] = &paramEnumInt" + i);
3973                                         else
3974                                                 println("paramObj[pos++] = &" + getSimpleIdentifier(methParams.get(i)) + ";");
3975                                 }
3976                         }
3977                 }
3978                 // Write the return value part
3979                 writeMethodHelperReturnCplusSkeleton(intDecl, methParams, methPrmTypes, method, isCallbackMethod, 
3980                         callbackType, methodId, callbackClasses);
3981         }
3982
3983
3984         /**
3985          * HELPER: writeMethodHelperCplusSkeleton() writes the method helper of the skeleton class
3986          */
3987         private void writeMethodHelperCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
3988
3989                 // Use this set to handle two same methodIds
3990                 Set<String> uniqueMethodIds = new HashSet<String>();
3991                 for (String method : methods) {
3992
3993                         List<String> methParams = intDecl.getMethodParams(method);
3994                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
3995                         if (isStructPresent(methParams, methPrmTypes)) {        // Treat struct differently
3996                                 String methodId = intDecl.getMethodId(method);
3997                                 print("void ___");
3998                                 String helperMethod = methodId;
3999                                 if (uniqueMethodIds.contains(methodId))
4000                                         helperMethod = helperMethod + intDecl.getMethodNumId(method);
4001                                 else
4002                                         uniqueMethodIds.add(methodId);
4003                                 String retType = intDecl.getMethodType(method);
4004                                 print(helperMethod + "(");
4005                                 boolean begin = true;
4006                                 for (int i = 0; i < methParams.size(); i++) { // Print size variables
4007                                         String paramType = methPrmTypes.get(i);
4008                                         String param = methParams.get(i);
4009                                         String simpleType = getSimpleType(paramType);
4010                                         if (isStructClass(simpleType)) {
4011                                                 if (!begin) {   // Generate comma for not the beginning variable
4012                                                         print(", "); begin = false;
4013                                                 }
4014                                                 int methodNumId = intDecl.getMethodNumId(method);
4015                                                 print("int struct" + methodNumId + "Size" + i);
4016                                         }
4017                                 }
4018                                 println(") {");
4019                                 writeMethodHelperStructCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses);
4020                                 println("}\n");
4021                         } else {
4022                                 String methodId = intDecl.getMethodId(method);
4023                                 print("void ___");
4024                                 String helperMethod = methodId;
4025                                 if (uniqueMethodIds.contains(methodId))
4026                                         helperMethod = helperMethod + intDecl.getMethodNumId(method);
4027                                 else
4028                                         uniqueMethodIds.add(methodId);
4029                                 // Check if this is "void"
4030                                 String retType = intDecl.getMethodType(method);
4031                                 println(helperMethod + "() {");
4032                                 // Now, write the helper body of skeleton!
4033                                 writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses);
4034                                 println("}\n");
4035                         }
4036                 }
4037                 // Write method helper for structs
4038                 writeMethodHelperStructSetupCplusSkeleton(methods, intDecl);
4039         }
4040
4041
4042         /**
4043          * HELPER: writeMethodHelperStructSetupCplusSkeleton() writes the method helper of struct in skeleton class
4044          */
4045         private void writeMethodHelperStructSetupCplusSkeleton(Collection<String> methods, 
4046                         InterfaceDecl intDecl) {
4047
4048                 // Use this set to handle two same methodIds
4049                 for (String method : methods) {
4050
4051                         List<String> methParams = intDecl.getMethodParams(method);
4052                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
4053                         // Check for params with structs
4054                         for (int i = 0; i < methParams.size(); i++) {
4055                                 String paramType = methPrmTypes.get(i);
4056                                 String param = methParams.get(i);
4057                                 String simpleType = getSimpleType(paramType);
4058                                 if (isStructClass(simpleType)) {
4059                                         int methodNumId = intDecl.getMethodNumId(method);
4060                                         print("int ___");
4061                                         String helperMethod = methodNumId + "struct" + i;
4062                                         println(helperMethod + "() {");
4063                                         // Now, write the helper body of skeleton!
4064                                         println("string paramCls[] = { \"int\" };");
4065                                         println("int numParam = 1;");
4066                                         println("int param0 = 0;");
4067                                         println("void* paramObj[] = { &param0 };");
4068                                         println("rmiObj->getMethodParams(paramCls, numParam, paramObj);");
4069                                         println("return param0;");
4070                                         println("}\n");
4071                                 }
4072                         }
4073                 }
4074         }
4075
4076
4077         /**
4078          * HELPER: writeMethodHelperStructSetupCplusCallbackSkeleton() writes the method helper of struct in skeleton class
4079          */
4080         private void writeMethodHelperStructSetupCplusCallbackSkeleton(Collection<String> methods, 
4081                         InterfaceDecl intDecl) {
4082
4083                 // Use this set to handle two same methodIds
4084                 for (String method : methods) {
4085
4086                         List<String> methParams = intDecl.getMethodParams(method);
4087                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
4088                         // Check for params with structs
4089                         for (int i = 0; i < methParams.size(); i++) {
4090                                 String paramType = methPrmTypes.get(i);
4091                                 String param = methParams.get(i);
4092                                 String simpleType = getSimpleType(paramType);
4093                                 if (isStructClass(simpleType)) {
4094                                         int methodNumId = intDecl.getMethodNumId(method);
4095                                         print("int ___");
4096                                         String helperMethod = methodNumId + "struct" + i;
4097                                         println(helperMethod + "(IoTRMIObject* rmiObj) {");
4098                                         // Now, write the helper body of skeleton!
4099                                         println("string paramCls[] = { \"int\" };");
4100                                         println("int numParam = 1;");
4101                                         println("int param0 = 0;");
4102                                         println("void* paramObj[] = { &param0 };");
4103                                         println("rmiObj->getMethodParams(paramCls, numParam, paramObj);");
4104                                         println("return param0;");
4105                                         println("}\n");
4106                                 }
4107                         }
4108                 }
4109         }
4110
4111
4112         /**
4113          * HELPER: writeCplusMethodPermission() writes permission checks in skeleton
4114          */
4115         private void writeCplusMethodPermission(String intface) {
4116
4117                 // Get all the different stubs
4118                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
4119                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
4120                         String newIntface = intMeth.getKey();
4121                         int newObjectId = getNewIntfaceObjectId(newIntface);
4122                         println("if (_objectId == object" + newObjectId + "Id) {");
4123                         println("if (set" + newObjectId + "Allowed.find(methodId) == set" + newObjectId + "Allowed.end()) {");
4124                         println("cerr << \"Object with object Id: \" << _objectId << \"  is not allowed to access method: \" << methodId << endl;");
4125                         println("exit(-1);");
4126                         println("}");
4127                         println("}");
4128                         println("else {");
4129                         println("cerr << \"Object Id: \" << _objectId << \" not recognized!\" << endl;");
4130                         println("exit(-1);");
4131                         println("}");
4132                 }
4133         }
4134
4135
4136         /**
4137          * HELPER: writeCplusWaitRequestInvokeMethod() writes the main loop of the skeleton class
4138          */
4139         private void writeCplusWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist, String intface) {
4140
4141                 // Use this set to handle two same methodIds
4142                 Set<String> uniqueMethodIds = new HashSet<String>();
4143                 println("void ___waitRequestInvokeMethod() {");
4144                 // Write variables here if we have callbacks or enums or structs
4145                 writeCountVarStructSkeleton(methods, intDecl);
4146                 println("while (true) {");
4147                 println("rmiObj->getMethodBytes();");
4148                 println("int _objectId = rmiObj->getObjectId();");
4149                 println("int methodId = rmiObj->getMethodId();");
4150                 // Generate permission check
4151                 writeCplusMethodPermission(intface);
4152                 println("switch (methodId) {");
4153                 // Print methods and method Ids
4154                 for (String method : methods) {
4155                         String methodId = intDecl.getMethodId(method);
4156                         int methodNumId = intDecl.getMethodNumId(method);
4157                         print("case " + methodNumId + ": ___");
4158                         String helperMethod = methodId;
4159                         if (uniqueMethodIds.contains(methodId))
4160                                 helperMethod = helperMethod + methodNumId;
4161                         else
4162                                 uniqueMethodIds.add(methodId);
4163                         print(helperMethod + "(");
4164                         writeInputCountVarStructSkeleton(method, intDecl);
4165                         println("); break;");
4166                 }
4167                 String method = "___initCallBack()";
4168                 // Print case -9999 (callback handler) if callback exists
4169                 if (callbackExist) {
4170                         int methodId = intDecl.getHelperMethodNumId(method);
4171                         println("case " + methodId + ": ___regCB(); break;");
4172                 }
4173                 writeMethodCallStructSkeleton(methods, intDecl);
4174                 println("default: ");
4175                 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
4176                 println("throw exception();");
4177                 println("}");
4178                 println("}");
4179                 println("}\n");
4180         }
4181
4182
4183         /**
4184          * generateCplusSkeletonClass() generate skeletons based on the methods list in C++
4185          */
4186         public void generateCplusSkeletonClass() throws IOException {
4187
4188                 // Create a new directory
4189                 String path = createDirectories(dir, subdir);
4190                 for (String intface : mapIntfacePTH.keySet()) {
4191                         // Open a new file to write into
4192                         String newSkelClass = intface + "_Skeleton";
4193                         FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp");
4194                         pw = new PrintWriter(new BufferedWriter(fw));
4195                         // Write file headers
4196                         println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
4197                         println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
4198                         println("#include <iostream>");
4199                         println("#include \"" + intface + ".hpp\"\n");
4200                         // Pass in set of methods and get import classes
4201                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
4202                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
4203                         List<String> methods = intDecl.getMethods();
4204                         Set<String> includeClasses = getIncludeClasses(methods, intDecl, intface, true);
4205                         List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
4206                         List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
4207                         printIncludeStatements(allIncludeClasses); println("");
4208                         println("using namespace std;\n");
4209                         // Find out if there are callback objects
4210                         Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
4211                         boolean callbackExist = !callbackClasses.isEmpty();
4212                         // Write class header
4213                         println("class " + newSkelClass + " : public " + intface); println("{");
4214                         println("private:\n");
4215                         // Write properties
4216                         writePropertiesCplusSkeleton(intface, callbackExist, callbackClasses);
4217                         println("public:\n");
4218                         // Write constructor
4219                         writeConstructorCplusSkeleton(newSkelClass, intface, callbackExist, intDecl, methods);
4220                         // Write deconstructor
4221                         writeDeconstructorCplusSkeleton(newSkelClass, callbackExist, callbackClasses);
4222                         // Write methods
4223                         writeMethodCplusSkeleton(methods, intDecl, callbackClasses, false);
4224                         // Write method helper
4225                         writeMethodHelperCplusSkeleton(methods, intDecl, callbackClasses);
4226                         // Write waitRequestInvokeMethod() - main loop
4227                         writeCplusWaitRequestInvokeMethod(methods, intDecl, callbackExist, intface);
4228                         println("};");
4229                         writePermissionInitializationCplus(intface, newSkelClass, intDecl);
4230                         writeObjectIdCountInitializationCplus(newSkelClass, callbackExist);
4231                         println("#endif");
4232                         pw.close();
4233                         System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".hpp...");
4234                 }
4235         }
4236
4237
4238         /**
4239          * HELPER: writePropertiesCplusCallbackSkeleton() writes the properties of the callback skeleton class
4240          */
4241         private void writePropertiesCplusCallbackSkeleton(String intface, boolean callbackExist, Set<String> callbackClasses) {
4242
4243                 println(intface + " *mainObj;");
4244                 // Keep track of object Ids of all stubs registered to this interface
4245                 println("int objectId;");
4246                 // Callback
4247                 if (callbackExist) {
4248                         Iterator it = callbackClasses.iterator();
4249                         String callbackType = (String) it.next();
4250                         String exchangeType = checkAndGetParamClass(callbackType);
4251                         println("// Callback properties");
4252                         println("IoTRMICall* rmiCall;");
4253                         println("vector<" + exchangeType + "*> vecCallbackObj;");
4254                         println("static int objIdCnt;");
4255                 }
4256                 println("\n");
4257         }
4258
4259
4260         /**
4261          * HELPER: writeConstructorCplusCallbackSkeleton() writes the constructor of the skeleton class
4262          */
4263         private void writeConstructorCplusCallbackSkeleton(String newSkelClass, String intface, boolean callbackExist, InterfaceDecl intDecl, Collection<String> methods) {
4264
4265                 println(newSkelClass + "(" + intface + " *_mainObj, int _objectId) {");
4266                 println("mainObj = _mainObj;");
4267                 println("objectId = _objectId;");
4268                 writeStructPermissionCplusSkeleton(methods, intDecl, intface);
4269                 println("}\n");
4270         }
4271
4272
4273         /**
4274          * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
4275          */
4276         private void writeDeconstructorCplusCallbackSkeleton(String newStubClass, boolean callbackExist, 
4277                         Set<String> callbackClasses) {
4278
4279                 println("~" + newStubClass + "() {");
4280                 if (callbackExist) {
4281                 // We assume that each class only has one callback interface for now
4282                         println("if (rmiCall != NULL) {");
4283                         println("delete rmiCall;");
4284                         println("rmiCall = NULL;");
4285                         println("}");
4286                         Iterator it = callbackClasses.iterator();
4287                         String callbackType = (String) it.next();
4288                         String exchangeType = checkAndGetParamClass(callbackType);
4289                         println("for(" + exchangeType + "* cb : vecCallbackObj) {");
4290                         println("delete cb;");
4291                         println("cb = NULL;");
4292                         println("}");
4293                 }
4294                 println("}");
4295                 println("");
4296         }
4297
4298
4299         /**
4300          * HELPER: writeMethodHelperCplusCallbackSkeleton() writes the method helper of callback skeleton class
4301          */
4302         private void writeMethodHelperCplusCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl, 
4303                         Set<String> callbackClasses) {
4304
4305                 // Use this set to handle two same methodIds
4306                 Set<String> uniqueMethodIds = new HashSet<String>();
4307                 for (String method : methods) {
4308
4309                         List<String> methParams = intDecl.getMethodParams(method);
4310                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
4311                         if (isStructPresent(methParams, methPrmTypes)) {        // Treat struct differently
4312                                 String methodId = intDecl.getMethodId(method);
4313                                 print("void ___");
4314                                 String helperMethod = methodId;
4315                                 if (uniqueMethodIds.contains(methodId))
4316                                         helperMethod = helperMethod + intDecl.getMethodNumId(method);
4317                                 else
4318                                         uniqueMethodIds.add(methodId);
4319                                 String retType = intDecl.getMethodType(method);
4320                                 print(helperMethod + "(");
4321                                 boolean begin = true;
4322                                 for (int i = 0; i < methParams.size(); i++) { // Print size variables
4323                                         String paramType = methPrmTypes.get(i);
4324                                         String param = methParams.get(i);
4325                                         String simpleType = getSimpleType(paramType);
4326                                         if (isStructClass(simpleType)) {
4327                                                 if (!begin) {   // Generate comma for not the beginning variable
4328                                                         print(", "); begin = false;
4329                                                 }
4330                                                 int methodNumId = intDecl.getMethodNumId(method);
4331                                                 print("int struct" + methodNumId + "Size" + i);
4332                                         }
4333                                 }
4334                                 println(", IoTRMIObject* rmiObj) {");
4335                                 writeMethodHelperStructCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses);
4336                                 println("}\n");
4337                         } else {
4338                                 String methodId = intDecl.getMethodId(method);
4339                                 print("void ___");
4340                                 String helperMethod = methodId;
4341                                 if (uniqueMethodIds.contains(methodId))
4342                                         helperMethod = helperMethod + intDecl.getMethodNumId(method);
4343                                 else
4344                                         uniqueMethodIds.add(methodId);
4345                                 // Check if this is "void"
4346                                 String retType = intDecl.getMethodType(method);
4347                                 println(helperMethod + "(IoTRMIObject* rmiObj) {");
4348                                 // Now, write the helper body of skeleton!
4349                                 writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId, callbackClasses);
4350                                 println("}\n");
4351                         }
4352                 }
4353                 // Write method helper for structs
4354                 writeMethodHelperStructSetupCplusCallbackSkeleton(methods, intDecl);
4355         }
4356
4357
4358         /**
4359          * HELPER: writeCplusCallbackWaitRequestInvokeMethod() writes the request invoke method of the skeleton callback class
4360          */
4361         private void writeCplusCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, 
4362                         boolean callbackExist) {
4363
4364                 // Use this set to handle two same methodIds
4365                 Set<String> uniqueMethodIds = new HashSet<String>();
4366                 println("void invokeMethod(IoTRMIObject* rmiObj) {");
4367                 // Write variables here if we have callbacks or enums or structs
4368                 writeCountVarStructSkeleton(methods, intDecl);
4369                 // Write variables here if we have callbacks or enums or structs
4370                 println("int methodId = rmiObj->getMethodId();");
4371                 // TODO: code the permission check here!
4372                 println("switch (methodId) {");
4373                 // Print methods and method Ids
4374                 for (String method : methods) {
4375                         String methodId = intDecl.getMethodId(method);
4376                         int methodNumId = intDecl.getMethodNumId(method);
4377                         print("case " + methodNumId + ": ___");
4378                         String helperMethod = methodId;
4379                         if (uniqueMethodIds.contains(methodId))
4380                                 helperMethod = helperMethod + methodNumId;
4381                         else
4382                                 uniqueMethodIds.add(methodId);
4383                         print(helperMethod + "(");
4384                         if (writeInputCountVarStructSkeleton(method, intDecl))
4385                                 println(", rmiObj); break;");
4386                         else
4387                                 println("rmiObj); break;");
4388                 }
4389                 String method = "___initCallBack()";
4390                 // Print case -9999 (callback handler) if callback exists
4391                 if (callbackExist) {
4392                         int methodId = intDecl.getHelperMethodNumId(method);
4393                         println("case " + methodId + ": ___regCB(rmiObj); break;");
4394                 }
4395                 writeMethodCallStructCallbackSkeleton(methods, intDecl);
4396                 println("default: ");
4397                 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
4398                 println("throw exception();");
4399                 println("}");
4400                 println("}\n");
4401         }
4402
4403
4404         /**
4405          * generateCplusCallbackSkeletonClass() generate callback skeletons based on the methods list in C++
4406          */
4407         public void generateCplusCallbackSkeletonClass() throws IOException {
4408
4409                 // Create a new directory
4410                 String path = createDirectories(dir, subdir);
4411                 for (String intface : mapIntfacePTH.keySet()) {
4412                         // Open a new file to write into
4413                         String newSkelClass = intface + "_CallbackSkeleton";
4414                         FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp");
4415                         pw = new PrintWriter(new BufferedWriter(fw));
4416                         // Write file headers
4417                         println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
4418                         println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
4419                         println("#include <iostream>");
4420                         println("#include \"" + intface + ".hpp\"\n");
4421                         // Pass in set of methods and get import classes
4422                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
4423                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
4424                         List<String> methods = intDecl.getMethods();
4425                         Set<String> includeClasses = getIncludeClasses(methods, intDecl, intface, true);
4426                         List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
4427                         List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
4428                         printIncludeStatements(allIncludeClasses); println("");                 
4429                         // Find out if there are callback objects
4430                         Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
4431                         boolean callbackExist = !callbackClasses.isEmpty();
4432                         println("using namespace std;\n");
4433                         // Write class header
4434                         println("class " + newSkelClass + " : public " + intface); println("{");
4435                         println("private:\n");
4436                         // Write properties
4437                         writePropertiesCplusCallbackSkeleton(intface, callbackExist, callbackClasses);
4438                         println("public:\n");
4439                         // Write constructor
4440                         writeConstructorCplusCallbackSkeleton(newSkelClass, intface, callbackExist, intDecl, methods);
4441                         // Write deconstructor
4442                         writeDeconstructorCplusCallbackSkeleton(newSkelClass, callbackExist, callbackClasses);
4443                         // Write methods
4444                         writeMethodCplusSkeleton(methods, intDecl, callbackClasses, true);
4445                         // Write method helper
4446                         writeMethodHelperCplusCallbackSkeleton(methods, intDecl, callbackClasses);
4447                         // Write waitRequestInvokeMethod() - main loop
4448                         writeCplusCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist);
4449                         println("};");
4450                         writeObjectIdCountInitializationCplus(newSkelClass, callbackExist);
4451                         println("#endif");
4452                         pw.close();
4453                         System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".hpp...");
4454                 }
4455         }
4456
4457
4458         /**
4459          * generateInitializer() generate initializer based on type
4460          */
4461         public String generateCplusInitializer(String type) {
4462
4463                 // Generate dummy returns for now
4464                 if (type.equals("short")||
4465                         type.equals("int")      ||
4466                         type.equals("long") ||
4467                         type.equals("float")||
4468                         type.equals("double")) {
4469
4470                         return "0";
4471                 } else if ( type.equals("String") ||
4472                                         type.equals("string")) {
4473   
4474                         return "\"\"";
4475                 } else if ( type.equals("char") ||
4476                                         type.equals("byte")) {
4477
4478                         return "\' \'";
4479                 } else if ( type.equals("boolean")) {
4480
4481                         return "false";
4482                 } else {
4483                         return "NULL";
4484                 }
4485         }
4486
4487
4488         /**
4489          * setDirectory() sets a new directory for stub files
4490          */
4491         public void setDirectory(String _subdir) {
4492
4493                 subdir = _subdir;
4494         }
4495
4496
4497         /**
4498          * printUsage() prints the usage of this compiler
4499          */
4500         public static void printUsage() {
4501
4502                 System.out.println();
4503                 System.out.println("Sentinel interface and stub compiler version 1.0");
4504                 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
4505                 System.out.println("All rights reserved.");
4506                 System.out.println("Usage:");
4507                 System.out.println("\tjava IoTCompiler -help / --help / -h\n");
4508                 System.out.println("\t\tDisplay this help texts\n\n");
4509                 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>]");
4510                 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>] [options]\n");
4511                 System.out.println("\t\tTake one or more pairs of main-req policy files, and generate Java and/or C++ files\n");
4512                 System.out.println("Options:");
4513                 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
4514                 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
4515                 System.out.println();
4516         }
4517
4518
4519         /**
4520          * parseFile() prepares Lexer and Parser objects, then parses the file
4521          */
4522         public static ParseNode parseFile(String file) {
4523
4524                 ParseNode pn = null;
4525                 try {
4526                         ComplexSymbolFactory csf = new ComplexSymbolFactory();
4527                         ScannerBuffer lexer = 
4528                                 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf));
4529                         Parser parse = new Parser(lexer,csf);
4530                         pn = (ParseNode) parse.parse().value;
4531                 } catch (Exception e) {
4532                         e.printStackTrace();
4533                         throw new Error("IoTCompiler: ERROR parsing policy file or wrong command line option: " + file + "\n");
4534                 }
4535
4536                 return pn;
4537         }
4538
4539
4540         /**================
4541          * Basic helper functions
4542          **================
4543          */
4544         boolean newline=true;
4545         int tablevel=0;
4546
4547         private void print(String str) {
4548                 if (newline) {
4549                         int tab=tablevel;
4550                         if (str.equals("}"))
4551                                 tab--;
4552                         for(int i=0; i<tab; i++)
4553                                 pw.print("\t");
4554                 }
4555                 pw.print(str);
4556                 updatetabbing(str);
4557                 newline=false;
4558         }
4559
4560
4561         /**
4562          * This function converts Java to C++ type for compilation
4563          */
4564         private String convertType(String jType) {
4565
4566                 return mapPrimitives.get(jType);
4567         }
4568
4569
4570         /**
4571          * A collection of methods with print-to-file functionality
4572          */
4573         private void println(String str) {
4574                 if (newline) {
4575                         int tab = tablevel;
4576                         if (str.contains("}") && !str.contains("{"))
4577                                 tab--;
4578                         for(int i=0; i<tab; i++)
4579                                 pw.print("\t");
4580                 }
4581                 pw.println(str);
4582                 updatetabbing(str);
4583                 newline = true;
4584         }
4585
4586
4587         private void updatetabbing(String str) {
4588
4589                 tablevel+=count(str,'{')-count(str,'}');
4590         }
4591
4592
4593         private int count(String str, char key) {
4594                 char[] array = str.toCharArray();
4595                 int count = 0;
4596                 for(int i=0; i<array.length; i++) {
4597                         if (array[i] == key)
4598                                 count++;
4599                 }
4600                 return count;
4601         }
4602
4603
4604         private void createDirectory(String dirName) {
4605
4606                 File file = new File(dirName);
4607                 if (!file.exists()) {
4608                         if (file.mkdir()) {
4609                                 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
4610                         } else {
4611                                 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
4612                         }
4613                 } else {
4614                         System.out.println("IoTCompiler: Directory " + dirName + " exists...");
4615                 }
4616         }
4617
4618
4619         // Create a directory and possibly a sub directory
4620         private String createDirectories(String dir, String subdir) {
4621
4622                 String path = dir;
4623                 createDirectory(path);
4624                 if (subdir != null) {
4625                         path = path + "/" + subdir;
4626                         createDirectory(path);
4627                 }
4628                 return path;
4629         }
4630
4631
4632         // Inserting array members into a Map object
4633         // that maps arrKey to arrVal objects
4634         private void arraysToMap(Map map, Object[] arrKey, Object[] arrVal) {
4635
4636                 for(int i = 0; i < arrKey.length; i++) {
4637
4638                         map.put(arrKey[i], arrVal[i]);
4639                 }
4640         }
4641
4642
4643         // Check and find object Id for new interface in mapNewIntfaceObjId (callbacks)
4644         // Throw an error if the new interface is not found!
4645         // Basically the compiler needs to parse the policy (and requires) files for callback class first
4646         private int getNewIntfaceObjectId(String newIntface) {
4647
4648                 if (!mapNewIntfaceObjId.containsKey(newIntface)) {
4649                         throw new Error("IoTCompiler: Need to parse policy and requires files for callback class first! " +
4650                                                         "Please place the two files for callback class in front...\n");
4651                 } else {
4652                         int retObjId = mapNewIntfaceObjId.get(newIntface);
4653                         return retObjId;
4654                 }
4655         }
4656
4657
4658         // Return parameter category, i.e. PRIMITIVES, NONPRIMITIVES, USERDEFINED, ENUM, or STRUCT
4659         private ParamCategory getParamCategory(String paramType) {
4660
4661                 if (mapPrimitives.containsKey(paramType)) {
4662                         return ParamCategory.PRIMITIVES;
4663                 // We can either use mapNonPrimitivesJava or mapNonPrimitivesCplus here
4664                 } else if (mapNonPrimitivesJava.containsKey(getSimpleType(paramType))) {
4665                         return ParamCategory.NONPRIMITIVES;
4666                 } else if (isEnumClass(paramType)) {
4667                         return ParamCategory.ENUM;
4668                 } else if (isStructClass(paramType)) {
4669                         return ParamCategory.STRUCT;
4670                 } else
4671                         return ParamCategory.USERDEFINED;
4672         }
4673
4674
4675         // Return full class name for non-primitives to generate Java import statements
4676         // e.g. java.util.Set for Set
4677         private String getNonPrimitiveJavaClass(String paramNonPrimitives) {
4678
4679                 return mapNonPrimitivesJava.get(paramNonPrimitives);
4680         }
4681
4682
4683         // Return full class name for non-primitives to generate Cplus include statements
4684         // e.g. #include <set> for Set
4685         private String getNonPrimitiveCplusClass(String paramNonPrimitives) {
4686
4687                 return mapNonPrimitivesCplus.get(paramNonPrimitives);
4688         }
4689
4690
4691         // Get simple types, e.g. HashSet for HashSet<...>
4692         // Basically strip off the "<...>"
4693         private String getSimpleType(String paramType) {
4694
4695                 // Check if this is generics
4696                 if(paramType.contains("<")) {
4697                         String[] type = paramType.split("<");
4698                         return type[0];
4699                 } else
4700                         return paramType;
4701         }
4702
4703
4704         // Generate a set of standard classes for import statements
4705         private List<String> getStandardJavaIntfaceImportClasses() {
4706
4707                 List<String> importClasses = new ArrayList<String>();
4708                 // Add the standard list first
4709                 importClasses.add("java.util.List");
4710                 importClasses.add("java.util.ArrayList");
4711
4712                 return importClasses;
4713         }
4714
4715
4716         // Generate a set of standard classes for import statements
4717         private List<String> getStandardJavaImportClasses() {
4718
4719                 List<String> importClasses = new ArrayList<String>();
4720                 // Add the standard list first
4721                 importClasses.add("java.io.IOException");
4722                 importClasses.add("java.util.List");
4723                 importClasses.add("java.util.ArrayList");
4724                 importClasses.add("java.util.Arrays");
4725                 importClasses.add("iotrmi.Java.IoTRMICall");
4726                 importClasses.add("iotrmi.Java.IoTRMIObject");
4727
4728                 return importClasses;
4729         }
4730
4731
4732         // Generate a set of standard classes for import statements
4733         private List<String> getStandardCplusIncludeClasses() {
4734
4735                 List<String> importClasses = new ArrayList<String>();
4736                 // Add the standard list first
4737                 importClasses.add("<vector>");
4738                 importClasses.add("<set>");
4739                 importClasses.add("\"IoTRMICall.hpp\"");
4740                 importClasses.add("\"IoTRMIObject.hpp\"");
4741
4742                 return importClasses;
4743         }
4744
4745
4746         // Combine all classes for import statements
4747         private List<String> getAllLibClasses(Collection<String> stdLibClasses, Collection<String> libClasses) {
4748
4749                 List<String> allLibClasses = new ArrayList<String>(stdLibClasses);
4750                 // Iterate over the list of import classes
4751                 for (String str : libClasses) {
4752                         if (!allLibClasses.contains(str)) {
4753                                 allLibClasses.add(str);
4754                         }
4755                 }
4756                 return allLibClasses;
4757         }
4758
4759
4760
4761         // Generate a set of classes for import statements
4762         private Set<String> getImportClasses(Collection<String> methods, InterfaceDecl intDecl) {
4763
4764                 Set<String> importClasses = new HashSet<String>();
4765                 for (String method : methods) {
4766                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
4767                         for (String paramType : methPrmTypes) {
4768
4769                                 String simpleType = getSimpleType(paramType);
4770                                 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
4771                                         importClasses.add(getNonPrimitiveJavaClass(simpleType));
4772                                 }
4773                         }
4774                 }
4775                 return importClasses;
4776         }
4777
4778
4779         // Handle and return the correct enum declaration
4780         // In Java, if we declare enum in Camera interface, then it becomes "Camera.<enum>"
4781         private String getEnumParamDecl(String type, InterfaceDecl intDecl) {
4782
4783                 // Strips off array "[]" for return type
4784                 String pureType = getSimpleArrayType(type);
4785                 // Take the inner type of generic
4786                 if (getParamCategory(type) == ParamCategory.NONPRIMITIVES)
4787                         pureType = getTypeOfGeneric(type)[0];
4788                 if (isEnumClass(pureType)) {
4789                         String enumType = intDecl.getInterface() + "." + type;
4790                         return enumType;
4791                 } else
4792                         return type;
4793         }
4794
4795
4796         // Handle and return the correct type
4797         private String getEnumParam(String type, String param, int i) {
4798
4799                 // Strips off array "[]" for return type
4800                 String pureType = getSimpleArrayType(type);
4801                 // Take the inner type of generic
4802                 if (getParamCategory(type) == ParamCategory.NONPRIMITIVES)
4803                         pureType = getTypeOfGeneric(type)[0];
4804                 if (isEnumClass(pureType)) {
4805                         String enumParam = "paramEnum" + i;
4806                         return enumParam;
4807                 } else
4808                         return param;
4809         }
4810
4811
4812         // Handle and return the correct enum declaration translate into int[]
4813         private String getEnumType(String type) {
4814
4815                 // Strips off array "[]" for return type
4816                 String pureType = getSimpleArrayType(type);
4817                 // Take the inner type of generic
4818                 if (getParamCategory(type) == ParamCategory.NONPRIMITIVES)
4819                         pureType = getTypeOfGeneric(type)[0];
4820                 if (isEnumClass(pureType)) {
4821                         String enumType = "int[]";
4822                         return enumType;
4823                 } else
4824                         return type;
4825         }
4826
4827         // Handle and return the correct enum declaration translate into int* for C
4828         private String getEnumCplusClsType(String type) {
4829
4830                 // Strips off array "[]" for return type
4831                 String pureType = getSimpleArrayType(type);
4832                 // Take the inner type of generic
4833                 if (getParamCategory(type) == ParamCategory.NONPRIMITIVES)
4834                         pureType = getTypeOfGeneric(type)[0];
4835                 if (isEnumClass(pureType)) {
4836                         String enumType = "int*";
4837                         return enumType;
4838                 } else
4839                         return type;
4840         }
4841
4842
4843         // Handle and return the correct struct declaration
4844         private String getStructType(String type) {
4845
4846                 // Strips off array "[]" for return type
4847                 String pureType = getSimpleArrayType(type);
4848                 // Take the inner type of generic
4849                 if (getParamCategory(type) == ParamCategory.NONPRIMITIVES)
4850                         pureType = getTypeOfGeneric(type)[0];
4851                 if (isStructClass(pureType)) {
4852                         String structType = "int";
4853                         return structType;
4854                 } else
4855                         return type;
4856         }
4857
4858
4859         // Check if this an enum declaration
4860         private boolean isEnumClass(String type) {
4861
4862                 // Just iterate over the set of interfaces
4863                 for (String intface : mapIntfacePTH.keySet()) {
4864                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
4865                         EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface);
4866                         Set<String> setEnumDecl = enumDecl.getEnumDeclarations();
4867                         if (setEnumDecl.contains(type))
4868                                 return true;
4869                 }
4870                 return false;
4871         }
4872
4873
4874         // Check if this an struct declaration
4875         private boolean isStructClass(String type) {
4876
4877                 // Just iterate over the set of interfaces
4878                 for (String intface : mapIntfacePTH.keySet()) {
4879                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
4880                         StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
4881                         List<String> listStructDecl = structDecl.getStructTypes();
4882                         if (listStructDecl.contains(type))
4883                                 return true;
4884                 }
4885                 return false;
4886         }
4887
4888
4889         // Return a struct declaration
4890         private StructDecl getStructDecl(String type) {
4891
4892                 // Just iterate over the set of interfaces
4893                 for (String intface : mapIntfacePTH.keySet()) {
4894                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
4895                         StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
4896                         List<String> listStructDecl = structDecl.getStructTypes();
4897                         if (listStructDecl.contains(type))
4898                                 return structDecl;
4899                 }
4900                 return null;
4901         }
4902
4903
4904         // Return number of members (-1 if not found)
4905         private int getNumOfMembers(String type) {
4906
4907                 // Just iterate over the set of interfaces
4908                 for (String intface : mapIntfacePTH.keySet()) {
4909                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
4910                         StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
4911                         List<String> listStructDecl = structDecl.getStructTypes();
4912                         if (listStructDecl.contains(type))
4913                                 return structDecl.getNumOfMembers(type);
4914                 }
4915                 return -1;
4916         }
4917
4918
4919         // Generate a set of classes for include statements
4920         private Set<String> getIncludeClasses(Collection<String> methods, InterfaceDecl intDecl, String intface, boolean needExchange) {
4921
4922                 Set<String> includeClasses = new HashSet<String>();
4923                 for (String method : methods) {
4924
4925                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
4926                         List<String> methParams = intDecl.getMethodParams(method);
4927                         for (int i = 0; i < methPrmTypes.size(); i++) {
4928
4929                                 String simpleType = getSimpleType(methPrmTypes.get(i));
4930                                 String param = methParams.get(i);
4931                                 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
4932                                         includeClasses.add("<" + getNonPrimitiveCplusClass(simpleType) + ">");
4933                                 } else if (getParamCategory(simpleType) == ParamCategory.USERDEFINED) {
4934                                         // For original interface, we need it exchanged... not for stub interfaces
4935                                         if (needExchange) {
4936                                                 includeClasses.add("\"" + exchangeParamType(simpleType) + ".hpp\"");
4937                                                 includeClasses.add("\"" + exchangeParamType(simpleType) + "_CallbackStub.hpp\"");
4938                                         } else {
4939                                                 includeClasses.add("\"" + simpleType + ".hpp\"");
4940                                                 includeClasses.add("\"" + simpleType + "_CallbackSkeleton.hpp\"");
4941                                         }
4942                                 } else if (getParamCategory(getSimpleArrayType(simpleType)) == ParamCategory.ENUM) {
4943                                         includeClasses.add("\"" + simpleType + ".hpp\"");
4944                                 } else if (getParamCategory(getSimpleArrayType(simpleType)) == ParamCategory.STRUCT) {
4945                                         includeClasses.add("\"" + simpleType + ".hpp\"");
4946                                 } else if (param.contains("[]")) {
4947                                 // Check if this is array for C++; translate into vector
4948                                         includeClasses.add("<vector>");
4949                                 }
4950                         }
4951                 }
4952                 return includeClasses;
4953         }
4954
4955
4956         // Generate a set of callback classes
4957         private Set<String> getCallbackClasses(Collection<String> methods, InterfaceDecl intDecl) {
4958
4959                 Set<String> callbackClasses = new HashSet<String>();
4960                 for (String method : methods) {
4961
4962                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
4963                         List<String> methParams = intDecl.getMethodParams(method);
4964                         for (int i = 0; i < methPrmTypes.size(); i++) {
4965
4966                                 String type = methPrmTypes.get(i);
4967                                 if (getParamCategory(type) == ParamCategory.USERDEFINED) {
4968                                         callbackClasses.add(type);
4969                                 } else if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) {
4970                                 // Can be a List<...> of callback objects ...
4971                                         String genericType = getTypeOfGeneric(type)[0];
4972                                         if (getParamCategory(type) == ParamCategory.USERDEFINED) {
4973                                                 callbackClasses.add(type);
4974                                         }
4975                                 }
4976                         }
4977                 }
4978                 return callbackClasses;
4979         }
4980
4981
4982         // Print import statements into file
4983         private void printImportStatements(Collection<String> importClasses) {
4984
4985                 for(String cls : importClasses) {
4986                         println("import " + cls + ";");
4987                 }
4988         }
4989
4990
4991         // Print include statements into file
4992         private void printIncludeStatements(Collection<String> includeClasses) {
4993
4994                 for(String cls : includeClasses) {
4995                         println("#include " + cls);
4996                 }
4997         }
4998
4999
5000         // Get the C++ version of a non-primitive type
5001         // e.g. set for Set and map for Map
5002         // Input nonPrimitiveType has to be generics in format
5003         private String[] getTypeOfGeneric(String nonPrimitiveType) {
5004
5005                 // Handle <, >, and , for 2-type generic/template
5006                 String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(",");
5007                 return substr;
5008         }
5009
5010
5011         // Gets generic type inside "<" and ">"
5012         private String getGenericType(String type) {
5013
5014                 // Handle <, >, and , for 2-type generic/template
5015                 if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) {
5016                         String[] substr = type.split("<")[1].split(">")[0].split(",");
5017                         return substr[0];
5018                 } else
5019                         return type;
5020         }
5021
5022
5023         // This helper function strips off array declaration, e.g. int[] becomes int
5024         private String getSimpleArrayType(String type) {
5025
5026                 // Handle [ for array declaration
5027                 String substr = type;
5028                 if (type.contains("[]")) {
5029                         substr = type.split("\\[\\]")[0];
5030                 }
5031                 return substr;
5032         }
5033
5034
5035         // This helper function strips off array declaration, e.g. D[] becomes D
5036         private String getSimpleIdentifier(String ident) {
5037
5038                 // Handle [ for array declaration
5039                 String substr = ident;
5040                 if (ident.contains("[]")) {
5041                         substr = ident.split("\\[\\]")[0];
5042                 }
5043                 return substr;
5044         }
5045
5046
5047         // Checks and gets type in C++
5048         private String checkAndGetCplusType(String paramType) {
5049
5050                 if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
5051                         return convertType(paramType);
5052                 } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) {
5053
5054                         // Check for generic/template format
5055                         if (paramType.contains("<") && paramType.contains(">")) {
5056
5057                                 String genericClass = getSimpleType(paramType);
5058                                 String[] genericType = getTypeOfGeneric(paramType);
5059                                 String cplusTemplate = null;
5060                                 if (genericType.length == 1) // Generic/template with one type
5061                                         cplusTemplate = getNonPrimitiveCplusClass(genericClass) + 
5062                                                 "<" + convertType(genericType[0]) + ">";
5063                                 else // Generic/template with two types
5064                                         cplusTemplate = getNonPrimitiveCplusClass(genericClass) + 
5065                                                 "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">";
5066                                 return cplusTemplate;
5067                         } else
5068                                 return getNonPrimitiveCplusClass(paramType);
5069                 } else if(paramType.contains("[]")) {   // Array type (used for return type only)
5070                         String cArray = "vector<" + convertType(getSimpleArrayType(paramType)) + ">";
5071                         return cArray;
5072                 } else if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
5073                         return paramType + "*";
5074                 } else
5075                         // Just return it as is if it's not non-primitives
5076                         return paramType;
5077                         //return checkAndGetParamClass(paramType, true);
5078         }
5079
5080
5081         // Detect array declaration, e.g. int A[],
5082         //              then generate "int A[]" in C++ as "vector<int> A"
5083         private String checkAndGetCplusArray(String paramType, String param) {
5084
5085                 String paramComplete = null;
5086                 // Check for array declaration
5087                 if (param.contains("[]")) {
5088                         paramComplete = "vector<" + paramType + "> " + param.replace("[]","");
5089                 } else
5090                         // Just return it as is if it's not an array
5091                         paramComplete = paramType + " " + param;
5092
5093                 return paramComplete;
5094         }
5095         
5096
5097         // Detect array declaration, e.g. int A[],
5098         //              then generate "int A[]" in C++ as "vector<int> A"
5099         // This method just returns the type
5100         private String checkAndGetCplusArrayType(String paramType) {
5101
5102                 String paramTypeRet = null;
5103                 // Check for array declaration
5104                 if (paramType.contains("[]")) {
5105                         String type = paramType.split("\\[\\]")[0];
5106                         paramTypeRet = checkAndGetCplusType(type) + "[]";
5107                 } else if (paramType.contains("vector")) {
5108                         // Just return it as is if it's not an array
5109                         String type = paramType.split("<")[1].split(">")[0];
5110                         paramTypeRet = checkAndGetCplusType(type) + "[]";
5111                 } else
5112                         paramTypeRet = paramType;
5113
5114                 return paramTypeRet;
5115         }
5116         
5117         
5118         // Detect array declaration, e.g. int A[],
5119         //              then generate "int A[]" in C++ as "vector<int> A"
5120         // This method just returns the type
5121         private String checkAndGetCplusArrayType(String paramType, String param) {
5122
5123                 String paramTypeRet = null;
5124                 // Check for array declaration
5125                 if (param.contains("[]")) {
5126                         paramTypeRet = checkAndGetCplusType(paramType) + "[]";
5127                 } else if (paramType.contains("vector")) {
5128                         // Just return it as is if it's not an array
5129                         String type = paramType.split("<")[1].split(">")[0];
5130                         paramTypeRet = checkAndGetCplusType(type) + "[]";
5131                 } else
5132                         paramTypeRet = paramType;
5133
5134                 return paramTypeRet;
5135         }
5136
5137
5138         // Return the class type for class resolution (for return value)
5139         // - Check and return C++ array class, e.g. int A[] into int*
5140         // - Check and return C++ vector class, e.g. List<Integer> A into vector<int>
5141         private String checkAndGetCplusRetClsType(String paramType) {
5142
5143                 String paramTypeRet = null;
5144                 // Check for array declaration
5145                 if (paramType.contains("[]")) {
5146                         String type = paramType.split("\\[\\]")[0];
5147                         paramTypeRet = getSimpleArrayType(type) + "*";
5148                 } else if (paramType.contains("<") && paramType.contains(">")) {
5149                         // Just return it as is if it's not an array
5150                         String type = paramType.split("<")[1].split(">")[0];
5151                         paramTypeRet = "vector<" + getGenericType(type) + ">";
5152                 } else
5153                         paramTypeRet = paramType;
5154
5155                 return paramTypeRet;
5156         }
5157
5158
5159         // Return the class type for class resolution (for method arguments)
5160         // - Check and return C++ array class, e.g. int A[] into int*
5161         // - Check and return C++ vector class, e.g. List<Integer> A into vector<int>
5162         private String checkAndGetCplusArgClsType(String paramType, String param) {
5163
5164                 String paramTypeRet = null;
5165                 // Check for array declaration
5166                 if (param.contains("[]")) {
5167                         paramTypeRet = getSimpleArrayType(paramType) + "*";
5168                 } else if (paramType.contains("<") && paramType.contains(">")) {
5169                         // Just return it as is if it's not an array
5170                         String type = paramType.split("<")[1].split(">")[0];
5171                         paramTypeRet = "vector<" + getGenericType(type) + ">";
5172                 } else
5173                         paramTypeRet = paramType;
5174
5175                 return paramTypeRet;
5176         }
5177
5178
5179         // Detect array declaration, e.g. int A[],
5180         //              then generate type "int[]"
5181         private String checkAndGetArray(String paramType, String param) {
5182
5183                 String paramTypeRet = null;
5184                 // Check for array declaration
5185                 if (param.contains("[]")) {
5186                         paramTypeRet = paramType + "[]";
5187                 } else
5188                         // Just return it as is if it's not an array
5189                         paramTypeRet = paramType;
5190
5191                 return paramTypeRet;
5192         }
5193
5194
5195         // Is array or list?
5196         private boolean isArrayOrList(String paramType, String param) {
5197
5198                 // Check for array declaration
5199                 if (isArray(param))
5200                         return true;
5201                 else if (isList(paramType))
5202                         return true;
5203                 else
5204                         return false;
5205         }
5206
5207
5208         // Is array? 
5209         // For return type we use retType as input parameter
5210         private boolean isArray(String param) {
5211
5212                 // Check for array declaration
5213                 if (param.contains("[]"))
5214                         return true;
5215                 else
5216                         return false;
5217         }
5218
5219
5220         // Is list?
5221         private boolean isList(String paramType) {
5222
5223                 // Check for array declaration
5224                 if (paramType.contains("List"))
5225                         return true;
5226                 else
5227                         return false;
5228         }
5229
5230
5231         // Get the right type for a callback object
5232         private String checkAndGetParamClass(String paramType) {
5233
5234                 // Check if this is generics
5235                 if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
5236                         return exchangeParamType(paramType);
5237                 } else
5238                         return paramType;
5239         }
5240
5241
5242         // Returns the other interface for type-checking purposes for USERDEFINED
5243         //              classes based on the information provided in multiple policy files
5244         // e.g. return CameraWithXXX instead of Camera
5245         private String exchangeParamType(String intface) {
5246
5247                 // Param type that's passed is the interface name we need to look for
5248                 //              in the map of interfaces, based on available policy files.
5249                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
5250                 if (decHandler != null) {
5251                 // We've found the required interface policy files
5252                         RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(intface);
5253                         Set<String> setExchInt = reqDecl.getInterfaces();
5254                         if (setExchInt.size() == 1) {
5255                                 Iterator iter = setExchInt.iterator();
5256                                 return (String) iter.next();
5257                         } else {
5258                                 throw new Error("IoTCompiler: Ambiguous stub interfaces: " + setExchInt.toString() + 
5259                                         ". Only one new interface can be declared if the object " + intface +
5260                                         " needs to be passed in as an input parameter!\n");
5261                         }
5262                 } else {
5263                 // NULL value - this means policy files missing
5264                         throw new Error("IoTCompiler: Parameter type lookup failed for " + intface +
5265                                 "... Please provide the necessary policy files for user-defined types." +
5266                                 " If this is an array please type the brackets after the variable name," +
5267                                 " e.g. \"String str[]\", not \"String[] str\"." +
5268                                 " If this is a Collections (Java) / STL (C++) type, this compiler only" +
5269                                 " supports List/ArrayList (Java) or list (C++).\n");
5270                 }
5271         }
5272
5273
5274         public static void main(String[] args) throws Exception {
5275
5276                 // If there is no argument or just "--help" or "-h", then invoke printUsage()
5277                 if ((args[0].equals("-help") ||
5278                          args[0].equals("--help")||
5279                          args[0].equals("-h"))   ||
5280                         (args.length == 0)) {
5281
5282                         IoTCompiler.printUsage();
5283
5284                 } else if (args.length > 1) {
5285
5286                         IoTCompiler comp = new IoTCompiler();
5287                         int i = 0;                              
5288                         do {
5289                                 // Parse main policy file
5290                                 ParseNode pnPol = IoTCompiler.parseFile(args[i]);
5291                                 // Parse "requires" policy file
5292                                 ParseNode pnReq = IoTCompiler.parseFile(args[i+1]);
5293                                 // Get interface name
5294                                 String intface = ParseTreeHandler.getOrigIntface(pnPol);
5295                                 comp.setDataStructures(intface, pnPol, pnReq);
5296                                 comp.getMethodsForIntface(intface);
5297                                 i = i + 2;
5298                         // 1) Check if this is the last option before "-java" or "-cplus"
5299                         // 2) Check if this is really the last option (no "-java" or "-cplus")
5300                         } while(!args[i].equals("-java") &&
5301                                         !args[i].equals("-cplus") &&
5302                                         (i < args.length));
5303
5304                         // Generate everything if we don't see "-java" or "-cplus"
5305                         if (i == args.length) {
5306                                 comp.generateEnumJava();
5307                                 comp.generateStructJava();
5308                                 comp.generateJavaLocalInterfaces();
5309                                 comp.generateJavaInterfaces();
5310                                 comp.generateJavaStubClasses();
5311                                 comp.generateJavaCallbackStubClasses();
5312                                 comp.generateJavaSkeletonClass();
5313                                 comp.generateJavaCallbackSkeletonClass();
5314                                 comp.generateEnumCplus();
5315                                 comp.generateStructCplus();
5316                                 comp.generateCplusLocalInterfaces();
5317                                 comp.generateCPlusInterfaces();
5318                                 comp.generateCPlusStubClasses();
5319                                 comp.generateCPlusCallbackStubClasses();
5320                                 comp.generateCplusSkeletonClass();
5321                                 comp.generateCplusCallbackSkeletonClass();
5322                         } else {
5323                         // Check other options
5324                                 while(i < args.length) {
5325                                         // Error checking
5326                                         if (!args[i].equals("-java") &&
5327                                                 !args[i].equals("-cplus")) {
5328                                                 throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i] + "\n");
5329                                         } else {
5330                                                 if (i + 1 < args.length) {
5331                                                         comp.setDirectory(args[i+1]);
5332                                                 } else
5333                                                         throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i] + "\n");
5334
5335                                                 if (args[i].equals("-java")) {
5336                                                         comp.generateEnumJava();
5337                                                         comp.generateStructJava();
5338                                                         comp.generateJavaLocalInterfaces();
5339                                                         comp.generateJavaInterfaces();
5340                                                         comp.generateJavaStubClasses();
5341                                                         comp.generateJavaCallbackStubClasses();
5342                                                         comp.generateJavaSkeletonClass();
5343                                                         comp.generateJavaCallbackSkeletonClass();
5344                                                 } else {
5345                                                         comp.generateEnumCplus();
5346                                                         comp.generateStructCplus();
5347                                                         comp.generateCplusLocalInterfaces();
5348                                                         comp.generateCPlusInterfaces();
5349                                                         comp.generateCPlusStubClasses();
5350                                                         comp.generateCPlusCallbackStubClasses();
5351                                                         comp.generateCplusSkeletonClass();
5352                                                         comp.generateCplusCallbackSkeletonClass();
5353                                                 }
5354                                         }
5355                                         i = i + 2;
5356                                 }
5357                         }
5358                 } else {
5359                 // Need to at least have exactly 2 parameters, i.e. main policy file and requires file
5360                         IoTCompiler.printUsage();
5361                         throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!\n");
5362                 }
5363         }
5364 }
5365
5366