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