Porting and compiling SmartLightsController
[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          * HELPER: updateIntfaceObjIdMap() updates the mapping between new interface and object Id
347          */
348         private void updateIntfaceObjIdMap(String intface, String newIntface) {
349
350                 Integer objId = mapIntfaceObjId.get(intface);
351                 mapNewIntfaceObjId.put(newIntface, objId);
352                 mapIntfaceObjId.put(intface, objId++);
353         }
354
355
356         /**
357          * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
358          */
359         public void generateJavaInterfaces() throws IOException {
360
361                 // Create a new directory
362                 String path = createDirectories(dir, subdir);
363                 for (String intface : mapIntfacePTH.keySet()) {
364
365                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
366                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
367
368                                 // Open a new file to write into
369                                 String newIntface = intMeth.getKey();
370                                 FileWriter fw = new FileWriter(path + "/" + newIntface + ".java");
371                                 pw = new PrintWriter(new BufferedWriter(fw));
372                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
373                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
374                                 // Pass in set of methods and get import classes
375                                 Set<String> methods = intMeth.getValue();
376                                 Set<String> importClasses = getImportClasses(methods, intDecl);
377                                 List<String> stdImportClasses = getStandardJavaIntfaceImportClasses();
378                                 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
379                                 printImportStatements(allImportClasses);
380                                 // Write interface header
381                                 println("");
382                                 println("public interface " + newIntface + " {\n");
383                                 updateIntfaceObjIdMap(intface, newIntface);
384                                 // Write methods
385                                 writeMethodJavaInterface(methods, intDecl);
386                                 println("}");
387                                 pw.close();
388                                 System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
389                         }
390                 }
391         }
392
393
394         /**
395          * HELPER: writePropertiesJavaPermission() writes the permission in properties
396          */
397         private void writePropertiesJavaPermission(String intface, InterfaceDecl intDecl) {
398
399                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
400                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
401                         String newIntface = intMeth.getKey();
402                         int newObjectId = getNewIntfaceObjectId(newIntface);
403                         println("private final static int object" + newObjectId + "Id = " + 
404                                 newObjectId + ";\t//" + newIntface);
405                         Set<String> methodIds = intMeth.getValue();
406                         print("private static Integer[] object" + newObjectId + "Permission = { ");
407                         int i = 0;
408                         for (String methodId : methodIds) {
409                                 int methodNumId = intDecl.getMethodNumId(methodId);
410                                 print(Integer.toString(methodNumId));
411                                 // Check if this is the last element (don't print a comma)
412                                 if (i != methodIds.size() - 1) {
413                                         print(", ");
414                                 }
415                                 i++;
416                         }
417                         println(" };");
418                         println("private static List<Integer> set" + newObjectId + "Allowed;");
419                 }
420         }
421
422
423         /**
424          * HELPER: writePropertiesJavaStub() writes the properties of the stub class
425          */
426         private void writePropertiesJavaStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
427
428                 println("private IoTRMICall rmiCall;");
429                 println("private String callbackAddress;");
430                 println("private int[] ports;\n");
431                 // Get the object Id
432                 Integer objId = mapIntfaceObjId.get(intface);
433                 println("private final static int objectId = " + objId + ";");
434                 //mapNewIntfaceObjId.put(newIntface, objId);
435                 //mapIntfaceObjId.put(intface, objId++);
436                 if (callbackExist) {
437                 // We assume that each class only has one callback interface for now
438                         Iterator it = callbackClasses.iterator();
439                         String callbackType = (String) it.next();
440                         println("// Callback properties");
441                         println("private IoTRMIObject rmiObj;");
442                         println("List<" + callbackType + "> listCallbackObj;");
443                         println("private static int objIdCnt = 0;");
444                         // Generate permission stuff for callback stubs
445                         DeclarationHandler decHandler = mapIntDeclHand.get(callbackType);
446                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(callbackType);
447                         writePropertiesJavaPermission(callbackType, intDecl);
448                 }
449                 println("\n");
450         }
451
452
453         /**
454          * HELPER: writeConstructorJavaPermission() writes the permission in constructor
455          */
456         private void writeConstructorJavaPermission(String intface) {
457
458                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
459                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
460                         String newIntface = intMeth.getKey();
461                         int newObjectId = getNewIntfaceObjectId(newIntface);
462                         println("set" + newObjectId + "Allowed = new ArrayList<Integer>(Arrays.asList(object" + newObjectId +"Permission));");
463                 }
464         }
465
466
467         /**
468          * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
469          */
470         private void writeConstructorJavaStub(String intface, String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
471
472                 println("public " + newStubClass + "(int _port, String _skeletonAddress, String _callbackAddress, int _rev, int[] _ports) throws Exception {");
473                 println("callbackAddress = _callbackAddress;");
474                 println("ports = _ports;");
475                 println("rmiCall = new IoTRMICall(_port, _skeletonAddress, _rev);");
476                 if (callbackExist) {
477                         Iterator it = callbackClasses.iterator();
478                         String callbackType = (String) it.next();
479                         writeConstructorJavaPermission(intface);
480                         println("listCallbackObj = new ArrayList<" + callbackType + ">();");
481                         println("___initCallBack();");
482                 }
483                 println("}\n");
484         }
485
486
487         /**
488          * HELPER: writeJavaMethodCallbackPermission() writes permission checks in stub for callbacks
489          */
490         private void writeJavaMethodCallbackPermission(String intface) {
491
492                 println("int methodId = IoTRMIObject.getMethodId(method);");
493                 // Get all the different stubs
494                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
495                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
496                         String newIntface = intMeth.getKey();
497                         int newObjectId = getNewIntfaceObjectId(newIntface);
498                         println("if (!set" + newObjectId + "Allowed.contains(methodId)) {");
499                         println("throw new Error(\"Callback object for " + intface + " is not allowed to access method: \" + methodId);");
500                         println("}");
501                 }
502         }
503
504
505         /**
506          * HELPER: writeJavaInitCallbackPermission() writes the permission for callback
507          */
508         private void writeJavaInitCallbackPermission(String intface, InterfaceDecl intDecl, boolean callbackExist) {
509
510                 if (callbackExist) {
511                         String method = "___initCallBack()";
512                         int methodNumId = intDecl.getHelperMethodNumId(method);
513                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
514                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
515                                 String newIntface = intMeth.getKey();
516                                 int newObjectId = getNewIntfaceObjectId(newIntface);
517                                 println("set" + newObjectId + "Allowed.add(" + methodNumId + ");");
518                         }
519                 }
520         }
521
522
523         /**
524          * HELPER: writeInitCallbackJavaStub() writes callback initialization in stub
525          */
526         private void writeInitCallbackJavaStub(String intface, InterfaceDecl intDecl, boolean isGenCallbackStub) {
527
528                 println("public void ___initCallBack() {");
529                 // Generate main thread for callbacks
530                 println("Thread thread = new Thread() {");
531                 println("public void run() {");
532                 println("try {");
533                 if (isGenCallbackStub)  // Use the second port for a _CallbackStub class (callback in callback)
534                         println("rmiObj = new IoTRMIObject(ports[1]);");
535                 else
536                         println("rmiObj = new IoTRMIObject(ports[0]);");
537                 println("while (true) {");
538                 println("byte[] method = rmiObj.getMethodBytes();");
539                 writeJavaMethodCallbackPermission(intface);
540                 println("int objId = IoTRMIObject.getObjectId(method);");
541                 println(intface + "_CallbackSkeleton skel = (" + intface + "_CallbackSkeleton) listCallbackObj.get(objId);");
542                 println("if (skel != null) {");
543                 println("skel.invokeMethod(rmiObj);");
544                 print("}");
545                 println(" else {");
546                 println("throw new Error(\"" + intface + ": Object with Id \" + objId + \" not found!\");");
547                 println("}");
548                 println("}");
549                 print("}");
550                 println(" catch (Exception ex) {");
551                 println("ex.printStackTrace();");
552                 println("throw new Error(\"Error instantiating class " + intface + "_CallbackSkeleton!\");");
553                 println("}");
554                 println("}");
555                 println("};");
556                 println("thread.start();\n");
557                 // Generate info sending part
558                 String method = "___initCallBack()";
559                 int methodNumId = intDecl.getHelperMethodNumId(method);
560                 println("int methodId = " + methodNumId + ";");
561                 println("Class<?> retType = void.class;");
562                 println("Class<?>[] paramCls = new Class<?>[] { int[].class, String.class, int.class };");
563                 println("Object[] paramObj = new Object[] { ports, callbackAddress, 0 };");
564                 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
565                 println("}\n");
566         }
567
568
569         /**
570          * HELPER: checkAndWriteEnumTypeJavaStub() writes the enum type (convert from enum to int)
571          */
572         private void checkAndWriteEnumTypeJavaStub(List<String> methParams, List<String> methPrmTypes) {
573
574                 // Iterate and find enum declarations
575                 for (int i = 0; i < methParams.size(); i++) {
576                         String paramType = methPrmTypes.get(i);
577                         String param = methParams.get(i);
578                         String simpleType = getGenericType(paramType);
579                         if (isEnumClass(simpleType)) {
580                         // Check if this is enum type
581                                 if (isArray(param)) {   // An array
582                                         println("int len" + i + " = " + getSimpleIdentifier(param) + ".length;");
583                                         println("int paramEnum" + i + "[] = new int[len" + i + "];");
584                                         println("for (int i = 0; i < len" + i + "; i++) {");
585                                         println("paramEnum" + i + "[i] = " + getSimpleIdentifier(param) + "[i].ordinal();");
586                                         println("}");
587                                 } else if (isList(paramType)) { // A list
588                                         println("int len" + i + " = " + getSimpleIdentifier(param) + ".size();");
589                                         println("int paramEnum" + i + "[] = new int[len" + i + "];");
590                                         println("for (int i = 0; i < len" + i + "; i++) {");
591                                         println("paramEnum" + i + "[i] = " + getSimpleIdentifier(param) + ".get(i).ordinal();");
592                                         println("}");
593                                 } else {        // Just one element
594                                         println("int paramEnum" + i + "[] = new int[1];");
595                                         println("paramEnum" + i + "[0] = " + param + ".ordinal();");
596                                 }
597                         }
598                 }
599         }
600
601
602         /**
603          * HELPER: checkAndWriteEnumRetTypeJavaStub() writes the enum return type (convert from enum to int)
604          */
605         private void checkAndWriteEnumRetTypeJavaStub(String retType) {
606
607                 // Strips off array "[]" for return type
608                 String pureType = getSimpleArrayType(getGenericType(retType));
609                 // Take the inner type of generic
610                 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
611                         pureType = getGenericType(retType);
612                 if (isEnumClass(pureType)) {
613                 // Check if this is enum type
614                         // Enum decoder
615                         println("int[] retEnum = (int[]) retObj;");
616                         println(pureType + "[] enumVals = " + pureType + ".values();");
617                         if (isArray(retType)) {                 // An array
618                                 println("int retLen = retEnum.length;");
619                                 println(pureType + "[] enumRetVal = new " + pureType + "[retLen];");
620                                 println("for (int i = 0; i < retLen; i++) {");
621                                 println("enumRetVal[i] = enumVals[retEnum[i]];");
622                                 println("}");
623                         } else if (isList(retType)) {   // A list
624                                 println("int retLen = retEnum.length;");
625                                 println("List<" + pureType + "> enumRetVal = new ArrayList<" + pureType + ">();");
626                                 println("for (int i = 0; i < retLen; i++) {");
627                                 println("enumRetVal.add(enumVals[retEnum[i]]);");
628                                 println("}");
629                         } else {        // Just one element
630                                 println(pureType + " enumRetVal = enumVals[retEnum[0]];");
631                         }
632                         println("return enumRetVal;");
633                 }
634         }
635
636
637         /**
638          * HELPER: checkAndWriteStructSetupJavaStub() writes the struct type setup
639          */
640         private void checkAndWriteStructSetupJavaStub(List<String> methParams, List<String> methPrmTypes, 
641                         InterfaceDecl intDecl, String method) {
642                 
643                 // Iterate and find struct declarations
644                 for (int i = 0; i < methParams.size(); i++) {
645                         String paramType = methPrmTypes.get(i);
646                         String param = methParams.get(i);
647                         String simpleType = getGenericType(paramType);
648                         if (isStructClass(simpleType)) {
649                         // Check if this is enum type
650                                 int methodNumId = intDecl.getMethodNumId(method);
651                                 String helperMethod = methodNumId + "struct" + i;
652                                 println("int methodIdStruct" + i + " = " + intDecl.getHelperMethodNumId(helperMethod) + ";");
653                                 println("Class<?> retTypeStruct" + i + " = void.class;");
654                                 println("Class<?>[] paramClsStruct" + i + " = new Class<?>[] { int.class };");
655                                 if (isArray(param)) {   // An array
656                                         println("Object[] paramObjStruct" + i + " = new Object[] { " + getSimpleArrayType(param) + ".length };");
657                                 } else if (isList(paramType)) { // A list
658                                         println("Object[] paramObjStruct" + i + " = new Object[] { " + getSimpleArrayType(param) + ".size() };");
659                                 } else {        // Just one element
660                                         println("Object[] paramObjStruct" + i + " = new Object[] { new Integer(1) };");
661                                 }
662                                 println("rmiCall.remoteCall(objectId, methodIdStruct" + i + 
663                                                 ", retTypeStruct" + i + ", null, paramClsStruct" + i + 
664                                                 ", paramObjStruct" + i + ");\n");
665                         }
666                 }
667         }
668
669
670         /**
671          * HELPER: isStructPresent() checks presence of struct
672          */
673         private boolean isStructPresent(List<String> methParams, List<String> methPrmTypes) {
674
675                 // Iterate and find enum declarations
676                 for (int i = 0; i < methParams.size(); i++) {
677                         String paramType = methPrmTypes.get(i);
678                         String param = methParams.get(i);
679                         String simpleType = getGenericType(paramType);
680                         if (isStructClass(simpleType))
681                                 return true;
682                 }
683                 return false;
684         }
685
686
687         /**
688          * HELPER: writeLengthStructParamClassJavaStub() writes lengths of parameters
689          */
690         private void writeLengthStructParamClassJavaStub(List<String> methParams, List<String> methPrmTypes) {
691
692                 // Iterate and find struct declarations - count number of params
693                 for (int i = 0; i < methParams.size(); i++) {
694                         String paramType = methPrmTypes.get(i);
695                         String param = methParams.get(i);
696                         String simpleType = getGenericType(paramType);
697                         if (isStructClass(simpleType)) {
698                                 int members = getNumOfMembers(simpleType);
699                                 if (isArray(param)) {                   // An array
700                                         String structLen = getSimpleArrayType(param) + ".length";
701                                         print(members + "*" + structLen);
702                                 } else if (isList(paramType)) { // A list
703                                         String structLen = getSimpleArrayType(param) + ".size()";
704                                         print(members + "*" + structLen);
705                                 } else
706                                         print(Integer.toString(members));
707                         } else
708                                 print("1");
709                         if (i != methParams.size() - 1) {
710                                 print("+");
711                         }
712                 }
713         }
714
715
716         /**
717          * HELPER: writeStructMembersJavaStub() writes parameters of struct
718          */
719         private void writeStructMembersJavaStub(String simpleType, String paramType, String param) {
720
721                 // Get the struct declaration for this struct and generate initialization code
722                 StructDecl structDecl = getStructDecl(simpleType);
723                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
724                 List<String> members = structDecl.getMembers(simpleType);
725                 if (isArray(param)) {                   // An array
726                         println("for(int i = 0; i < " + getSimpleIdentifier(param) + ".length; i++) {");
727                         for (int i = 0; i < members.size(); i++) {
728                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
729                                 println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
730                                 print("paramObj[pos++] = " + getSimpleIdentifier(param) + "[i].");
731                                 print(getSimpleIdentifier(members.get(i)));
732                                 println(";");
733                         }
734                         println("}");
735                 } else if (isList(paramType)) { // A list
736                         println("for(int i = 0; i < " + getSimpleIdentifier(param) + ".size(); i++) {");
737                         for (int i = 0; i < members.size(); i++) {
738                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
739                                 println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
740                                 print("paramObj[pos++] = " + getSimpleIdentifier(param) + ".get(i).");
741                                 print(getSimpleIdentifier(members.get(i)));
742                                 println(";");
743                         }
744                         println("}");
745                 } else {        // Just one struct element
746                         for (int i = 0; i < members.size(); i++) {
747                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
748                                 println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
749                                 print("paramObj[pos++] = " + getSimpleIdentifier(param) + ".");
750                                 print(getSimpleIdentifier(members.get(i)));
751                                 println(";");
752                         }
753                 }
754         }
755
756
757         /**
758          * HELPER: writeStructParamClassJavaStub() writes parameters if struct is present
759          */
760         private void writeStructParamClassJavaStub(List<String> methParams, List<String> methPrmTypes, String callbackType) {
761
762                 print("int paramLen = ");
763                 writeLengthStructParamClassJavaStub(methParams, methPrmTypes);
764                 println(";");
765                 println("Object[] paramObj = new Object[paramLen];");
766                 println("Class<?>[] paramCls = new Class<?>[paramLen];");
767                 println("int pos = 0;");
768                 // Iterate again over the parameters
769                 for (int i = 0; i < methParams.size(); i++) {
770                         String paramType = methPrmTypes.get(i);
771                         String param = methParams.get(i);
772                         String simpleType = getGenericType(paramType);
773                         if (isStructClass(simpleType)) {
774                                 writeStructMembersJavaStub(simpleType, paramType, param);
775                         } else if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
776                                 println("paramCls[pos] = int.class;");
777                                 print("paramObj[pos++] = ");
778                                 if (isArray(methParams.get(i)))
779                                         print(getSimpleIdentifier(methParams.get(i)) + ".length");
780                                 else if (isList(methPrmTypes.get(i)))
781                                         print(getSimpleIdentifier(methParams.get(i)) + ".size()");
782                                 else
783                                         print("new Integer(1)");
784                                 println(";");
785                         } else {
786                                 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
787                                 println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
788                                 print("paramObj[pos++] = ");
789                                 print(getEnumParam(methPrmTypes.get(i), getSimpleIdentifier(methParams.get(i)), i));
790                                 println(";");
791                         }
792                 }
793                 
794         }
795
796
797         /**
798          * HELPER: writeStructRetMembersJavaStub() writes parameters of struct for return statement
799          */
800         private void writeStructRetMembersJavaStub(String simpleType, String retType) {
801
802                 // Get the struct declaration for this struct and generate initialization code
803                 StructDecl structDecl = getStructDecl(simpleType);
804                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
805                 List<String> members = structDecl.getMembers(simpleType);
806                 if (isArrayOrList(retType, retType)) {  // An array or list
807                         println("for(int i = 0; i < retLen; i++) {");
808                 }
809                 if (isArray(retType)) { // An array
810                         for (int i = 0; i < members.size(); i++) {
811                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
812                                 print("structRet[i]." + getSimpleIdentifier(members.get(i)));
813                                 println(" = (" + getSimpleType(getEnumType(prmType)) + ") retObj[retObjPos++];");
814                         }
815                         println("}");
816                 } else if (isList(retType)) {   // A list
817                         println(simpleType + " structRetMem = new " + simpleType + "();");
818                         for (int i = 0; i < members.size(); i++) {
819                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
820                                 print("structRetMem." + getSimpleIdentifier(members.get(i)));
821                                 println(" = (" + getSimpleType(getEnumType(prmType)) + ") retObj[retObjPos++];");
822                         }
823                         println("structRet.add(structRetMem);");
824                         println("}");
825                 } else {        // Just one struct element
826                         for (int i = 0; i < members.size(); i++) {
827                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
828                                 print("structRet." + getSimpleIdentifier(members.get(i)));
829                                 println(" = (" + getSimpleType(getEnumType(prmType)) + ") retObj[retObjPos++];");
830                         }
831                 }
832                 println("return structRet;");
833         }
834
835
836         /**
837          * HELPER: writeStructReturnJavaStub() writes parameters if struct is present for return statement
838          */
839         private void writeStructReturnJavaStub(String simpleType, String retType) {
840
841                 // Handle the returned struct!!!
842                 println("Object retLenObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
843                 // Minimum retLen is 1 if this is a single struct object
844                 println("int retLen = (int) retLenObj;");
845                 int numMem = getNumOfMembers(simpleType);
846                 println("Class<?>[] retCls = new Class<?>[" + numMem + "*retLen];");
847                 println("Class<?>[] retClsVal = new Class<?>[" + numMem + "*retLen];");
848                 println("int retPos = 0;");
849                 // Get the struct declaration for this struct and generate initialization code
850                 StructDecl structDecl = getStructDecl(simpleType);
851                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
852                 List<String> members = structDecl.getMembers(simpleType);
853                 if (isArrayOrList(retType, retType)) {  // An array or list
854                         println("for(int i = 0; i < retLen; i++) {");
855                         for (int i = 0; i < members.size(); i++) {
856                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
857                                 println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
858                                 println("retClsVal[retPos++] = null;");
859                         }
860                         println("}");
861                 } else {        // Just one struct element
862                         for (int i = 0; i < members.size(); i++) {
863                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
864                                 println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
865                                 println("retClsVal[retPos++] = null;");
866                         }
867                 }
868                 println("Object[] retObj = rmiCall.getStructObjects(retCls, retClsVal);");
869                 if (isArray(retType)) {                 // An array
870                         println(simpleType + "[] structRet = new " + simpleType + "[retLen];");
871                         println("for(int i = 0; i < retLen; i++) {");
872                         println("structRet[i] = new " + simpleType + "();");
873                         println("}");
874                 } else if (isList(retType)) {   // A list
875                         println("List<" + simpleType + "> structRet = new ArrayList<" + simpleType + ">();");
876                 } else
877                         println(simpleType + " structRet = new " + simpleType + "();");
878                 println("int retObjPos = 0;");
879                 writeStructRetMembersJavaStub(simpleType, retType);
880         }
881
882
883         /**
884          * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class
885          */
886         private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
887                         List<String> methPrmTypes, String method, String callbackType) {
888
889                 checkAndWriteStructSetupJavaStub(methParams, methPrmTypes, intDecl, method);
890                 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
891                 String retType = intDecl.getMethodType(method);
892                 println("Class<?> retType = " + getSimpleType(getStructType(getEnumType(retType))) + ".class;");
893                 checkAndWriteEnumTypeJavaStub(methParams, methPrmTypes);
894                 // Generate array of parameter types
895                 if (isStructPresent(methParams, methPrmTypes)) {
896                         writeStructParamClassJavaStub(methParams, methPrmTypes, callbackType);
897                 } else {
898                         print("Class<?>[] paramCls = new Class<?>[] { ");
899                         for (int i = 0; i < methParams.size(); i++) {
900                                 String prmType = methPrmTypes.get(i);
901                                 if (checkCallbackType(prmType, callbackType)) { // Check if this has callback object
902                                         print("int.class");
903                                 } else { // Generate normal classes if it's not a callback object
904                                         String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
905                                         print(getSimpleType(getEnumType(paramType)) + ".class");
906                                 }
907                                 // Check if this is the last element (don't print a comma)
908                                 if (i != methParams.size() - 1) {
909                                         print(", ");
910                                 }
911                         }
912                         println(" };");
913                         // Generate array of parameter objects
914                         print("Object[] paramObj = new Object[] { ");
915                         for (int i = 0; i < methParams.size(); i++) {
916                                 String paramType = methPrmTypes.get(i);
917                                 if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
918                                         //if (isArray(methPrmTypes.get(i), methParams.get(i)))
919                                         if (isArray(methParams.get(i)))
920                                                 print(getSimpleIdentifier(methParams.get(i)) + ".length");
921                                         else if (isList(methPrmTypes.get(i)))
922                                                 print(getSimpleIdentifier(methParams.get(i)) + ".size()");
923                                         else
924                                                 print("new Integer(1)");
925                                 } else
926                                         print(getEnumParam(methPrmTypes.get(i), getSimpleIdentifier(methParams.get(i)), i));
927                                 // Check if this is the last element (don't print a comma)
928                                 if (i != methParams.size() - 1) {
929                                         print(", ");
930                                 }
931                         }
932                         println(" };");
933                 }
934                 // Check if this is "void"
935                 if (retType.equals("void")) {
936                         println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
937                 } else { // We do have a return value
938                         // Generate array of parameter types
939                         if (isStructClass(getGenericType(getSimpleArrayType(retType)))) {
940                                 writeStructReturnJavaStub(getGenericType(getSimpleArrayType(retType)), retType);
941                         } else {
942                                 // This is an enum type
943                                 if (getParamCategory(getGenericType(getSimpleArrayType(retType))) == ParamCategory.ENUM) {
944                                         println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
945                                         checkAndWriteEnumRetTypeJavaStub(retType);
946                                 } else if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
947                                 // Check if the return value NONPRIMITIVES
948                                         String retGenValType = getGenericType(retType);
949                                         println("Class<?> retGenValType = " + retGenValType + ".class;");
950                                         println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
951                                         println("return (" + retType + ")retObj;");
952                                 } else {
953                                         println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
954                                         println("return (" + retType + ")retObj;");
955                                 }
956                         }
957                 }
958         }
959
960
961         /**
962          * HELPER: returnGenericCallbackType() returns the callback type
963          */
964         private String returnGenericCallbackType(String paramType) {
965
966                 if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES)
967                         return getGenericType(paramType);
968                 else
969                         return paramType;
970         }
971
972
973         /**
974          * HELPER: checkCallbackType() checks the callback type
975          */
976         private boolean checkCallbackType(String paramType, String callbackType) {
977
978                 String prmType = returnGenericCallbackType(paramType);
979                 if (callbackType == null)       // If there is no callbackType it means not a callback method
980                         return false;
981                 else
982                         return callbackType.equals(prmType);
983         }
984
985
986         /**
987          * HELPER: writeCallbackMethodBodyJavaStub() writes the callback method of the stub class
988          */
989         private void writeCallbackMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
990                         List<String> methPrmTypes, String method, String callbackType) {
991
992                 println("try {");
993                 // Check if this is single object, array, or list of objects
994                 for (int i = 0; i < methParams.size(); i++) {
995                         String paramType = methPrmTypes.get(i);
996                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
997                                 String param = methParams.get(i);
998                                 if (isArrayOrList(paramType, param)) {  // Generate loop
999                                         println("for (" + getGenericType(paramType) + " cb : " + getSimpleIdentifier(param) + ") {");
1000                                         println(callbackType + "_CallbackSkeleton skel" + i + " = new " + callbackType + "_CallbackSkeleton(cb, callbackAddress, objIdCnt++);");
1001                                 } else
1002                                         println(callbackType + "_CallbackSkeleton skel" + i + " = new " + callbackType + "_CallbackSkeleton(" +
1003                                                 getSimpleIdentifier(param) + ", callbackAddress, objIdCnt++);");
1004                                 println("listCallbackObj.add(skel" + i + ");");
1005                                 if (isArrayOrList(paramType, param))
1006                                         println("}");
1007                         }
1008                 }
1009                 print("}");
1010                 println(" catch (Exception ex) {");
1011                 println("ex.printStackTrace();");
1012                 println("throw new Error(\"Exception when generating skeleton objects!\");");
1013                 println("}\n");
1014         }
1015
1016
1017         /**
1018          * HELPER: writeMethodJavaStub() writes the methods of the stub class
1019          */
1020         private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses, boolean isGenCallbackStub) {
1021
1022                 boolean isDefined = false;
1023                 for (String method : methods) {
1024
1025                         List<String> methParams = intDecl.getMethodParams(method);
1026                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1027                         print("public " + intDecl.getMethodType(method) + " " +
1028                                 intDecl.getMethodId(method) + "(");
1029                         boolean isCallbackMethod = false;
1030                         String callbackType = null;
1031                         for (int i = 0; i < methParams.size(); i++) {
1032
1033                                 String paramType = returnGenericCallbackType(methPrmTypes.get(i));
1034                                 // Check if this has callback object
1035                                 if (callbackClasses.contains(paramType)) {
1036                                         isCallbackMethod = true;
1037                                         callbackType = paramType;       
1038                                         // Even if there're 2 callback arguments, we expect them to be of the same interface
1039                                 }
1040                                 print(methPrmTypes.get(i) + " " + methParams.get(i));
1041                                 // Check if this is the last element (don't print a comma)
1042                                 if (i != methParams.size() - 1) {
1043                                         print(", ");
1044                                 }
1045                         }
1046                         println(") {");
1047                         // Now, write the body of stub!
1048                         if (isCallbackMethod)
1049                                 writeCallbackMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method, callbackType);
1050                         //else
1051                         writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method, callbackType);
1052                         println("}\n");
1053                         // Write the init callback helper method
1054                         if (isCallbackMethod && !isDefined) {
1055                                 writeInitCallbackJavaStub(callbackType, intDecl, isGenCallbackStub);
1056                                 isDefined = true;
1057                         }
1058                 }
1059         }
1060
1061
1062         /**
1063          * generateJavaStubClasses() generate stubs based on the methods list in Java
1064          */
1065         public void generateJavaStubClasses() throws IOException {
1066
1067                 // Create a new directory
1068                 String path = createDirectories(dir, subdir);
1069                 for (String intface : mapIntfacePTH.keySet()) {
1070
1071                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1072                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1073
1074                                 // Open a new file to write into
1075                                 String newIntface = intMeth.getKey();
1076                                 String newStubClass = newIntface + "_Stub";
1077                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
1078                                 pw = new PrintWriter(new BufferedWriter(fw));
1079                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1080                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1081                                 // Pass in set of methods and get import classes
1082                                 Set<String> methods = intMeth.getValue();
1083                                 Set<String> importClasses = getImportClasses(methods, intDecl);
1084                                 List<String> stdImportClasses = getStandardJavaImportClasses();
1085                                 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
1086                                 printImportStatements(allImportClasses); println("");
1087                                 // Find out if there are callback objects
1088                                 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1089                                 boolean callbackExist = !callbackClasses.isEmpty();
1090                                 // Write class header
1091                                 println("public class " + newStubClass + " implements " + newIntface + " {\n");
1092                                 // Write properties
1093                                 writePropertiesJavaStub(intface, newIntface, callbackExist, callbackClasses);
1094                                 // Write constructor
1095                                 writeConstructorJavaStub(intface, newStubClass, callbackExist, callbackClasses);
1096                                 // Write methods
1097                                 writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses, false);
1098                                 println("}");
1099                                 pw.close();
1100                                 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
1101                         }
1102                 }
1103         }
1104
1105
1106         /**
1107          * HELPER: writePropertiesJavaCallbackStub() writes the properties of the callback stub class
1108          */
1109         private void writePropertiesJavaCallbackStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
1110
1111                 println("private IoTRMICall rmiCall;");
1112                 println("private String callbackAddress;");
1113                 println("private int[] ports;\n");
1114                 // Get the object Id
1115                 println("private int objectId = 0;");
1116                 if (callbackExist) {
1117                 // We assume that each class only has one callback interface for now
1118                         Iterator it = callbackClasses.iterator();
1119                         String callbackType = (String) it.next();
1120                         println("// Callback properties");
1121                         println("private IoTRMIObject rmiObj;");
1122                         println("List<" + callbackType + "> listCallbackObj;");
1123                         println("private static int objIdCnt = 0;");
1124                         // Generate permission stuff for callback stubs
1125                         DeclarationHandler decHandler = mapIntDeclHand.get(callbackType);
1126                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(callbackType);
1127                         writePropertiesJavaPermission(callbackType, intDecl);
1128                 }
1129                 println("\n");
1130         }
1131
1132
1133         /**
1134          * HELPER: writeConstructorJavaCallbackStub() writes the constructor of the callback stub class
1135          */
1136         private void writeConstructorJavaCallbackStub(String intface, String newStubClass, boolean callbackExist, Set<String> callbackClasses) {
1137
1138                 // TODO: If we want callback in callback, then we need to add address and port initializations
1139                 println("public " + newStubClass + "(IoTRMICall _rmiCall, String _callbackAddress, int _objectId, int[] _ports) throws Exception {");
1140                 println("callbackAddress = _callbackAddress;");
1141                 println("objectId = _objectId;");
1142                 println("rmiCall = _rmiCall;");
1143                 println("ports = _ports;");
1144                 if (callbackExist) {
1145                         Iterator it = callbackClasses.iterator();
1146                         String callbackType = (String) it.next();
1147                         writeConstructorJavaPermission(intface);
1148                         println("listCallbackObj = new ArrayList<" + callbackType + ">();");
1149                         println("___initCallBack();");
1150                 }
1151                 println("}\n");
1152         }
1153
1154
1155         /**
1156          * generateJavaCallbackStubClasses() generate callback stubs based on the methods list in Java
1157          * <p>
1158          * Callback stubs gets the IoTRMICall objects from outside of the class as contructor input
1159          * because all these stubs are populated by the class that takes in this object as a callback
1160          * object. In such a class, we only use one socket, hence one IoTRMICall, for all callback objects.
1161          */
1162         public void generateJavaCallbackStubClasses() throws IOException {
1163
1164                 // Create a new directory
1165                 String path = createDirectories(dir, subdir);
1166                 for (String intface : mapIntfacePTH.keySet()) {
1167
1168                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1169                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1170
1171                                 // Open a new file to write into
1172                                 String newIntface = intMeth.getKey();
1173                                 String newStubClass = newIntface + "_CallbackStub";
1174                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
1175                                 pw = new PrintWriter(new BufferedWriter(fw));
1176                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1177                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1178                                 // Pass in set of methods and get import classes
1179                                 Set<String> methods = intMeth.getValue();
1180                                 Set<String> importClasses = getImportClasses(methods, intDecl);
1181                                 List<String> stdImportClasses = getStandardJavaImportClasses();
1182                                 List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
1183                                 printImportStatements(allImportClasses); println("");
1184                                 // Find out if there are callback objects
1185                                 Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
1186                                 boolean callbackExist = !callbackClasses.isEmpty();
1187                                 // Write class header
1188                                 println("public class " + newStubClass + " implements " + newIntface + " {\n");
1189                                 // Write properties
1190                                 writePropertiesJavaCallbackStub(intface, newIntface, callbackExist, callbackClasses);
1191                                 // Write constructor
1192                                 writeConstructorJavaCallbackStub(intface, newStubClass, callbackExist, callbackClasses);
1193                                 // Write methods
1194                                 // TODO: perhaps need to generate callback for callback
1195                                 writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses, true);
1196                                 println("}");
1197                                 pw.close();
1198                                 System.out.println("IoTCompiler: Generated callback stub class " + newStubClass + ".java...");
1199                         }
1200                 }
1201         }
1202
1203
1204         /**
1205          * HELPER: writePropertiesJavaSkeleton() writes the properties of the skeleton class
1206          */
1207         private void writePropertiesJavaSkeleton(String intface, boolean callbackExist, InterfaceDecl intDecl) {
1208
1209                 println("private " + intface + " mainObj;");
1210                 //println("private int ports;");
1211                 println("private IoTRMIObject rmiObj;\n");
1212                 println("private String callbackAddress;");
1213                 // Callback
1214                 if (callbackExist) {
1215                         println("private static int objIdCnt = 0;");
1216                         println("private IoTRMICall rmiCall;");
1217                         println("private int[] ports;\n");
1218                 }
1219                 writePropertiesJavaPermission(intface, intDecl);
1220                 println("\n");
1221         }
1222
1223
1224         /**
1225          * HELPER: writeStructPermissionJavaSkeleton() writes permission for struct helper
1226          */
1227         private void writeStructPermissionJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, String intface) {
1228
1229                 // Use this set to handle two same methodIds
1230                 for (String method : methods) {
1231                         List<String> methParams = intDecl.getMethodParams(method);
1232                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1233                         // Check for params with structs
1234                         for (int i = 0; i < methParams.size(); i++) {
1235                                 String paramType = methPrmTypes.get(i);
1236                                 String param = methParams.get(i);
1237                                 String simpleType = getGenericType(paramType);
1238                                 if (isStructClass(simpleType)) {
1239                                         int methodNumId = intDecl.getMethodNumId(method);
1240                                         String helperMethod = methodNumId + "struct" + i;
1241                                         int methodHelperNumId = intDecl.getHelperMethodNumId(helperMethod);
1242                                         // Iterate over interfaces to give permissions to
1243                                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1244                                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1245                                                 String newIntface = intMeth.getKey();
1246                                                 int newObjectId = getNewIntfaceObjectId(newIntface);
1247                                                 println("set" + newObjectId + "Allowed.add(" + methodHelperNumId + ");");
1248                                         }
1249                                 }
1250                         }
1251                 }
1252         }
1253
1254
1255         /**
1256          * HELPER: writeConstructorJavaSkeleton() writes the constructor of the skeleton class
1257          */
1258         private void writeConstructorJavaSkeleton(String newSkelClass, String intface, InterfaceDecl intDecl, Collection<String> methods, boolean callbackExist) {
1259
1260                 println("public " + newSkelClass + "(" + intface + " _mainObj, String _callbackAddress, int _port) throws Exception {");
1261                 println("mainObj = _mainObj;");
1262                 println("callbackAddress = _callbackAddress;");
1263                 println("rmiObj = new IoTRMIObject(_port);");
1264                 // Generate permission control initialization
1265                 writeConstructorJavaPermission(intface);
1266                 writeJavaInitCallbackPermission(intface, intDecl, callbackExist);
1267                 writeStructPermissionJavaSkeleton(methods, intDecl, intface);
1268                 println("___waitRequestInvokeMethod();");
1269                 println("}\n");
1270         }
1271
1272
1273         /**
1274          * HELPER: writeStdMethodBodyJavaSkeleton() writes the standard method body in the skeleton class
1275          */
1276         private void writeStdMethodBodyJavaSkeleton(List<String> methParams, String methodId, String methodType) {
1277
1278                 if (methodType.equals("void"))
1279                         print("mainObj." + methodId + "(");
1280                 else
1281                         print("return mainObj." + methodId + "(");
1282                 for (int i = 0; i < methParams.size(); i++) {
1283
1284                         print(getSimpleIdentifier(methParams.get(i)));
1285                         // Check if this is the last element (don't print a comma)
1286                         if (i != methParams.size() - 1) {
1287                                 print(", ");
1288                         }
1289                 }
1290                 println(");");
1291         }
1292
1293
1294         /**
1295          * HELPER: writeInitCallbackJavaSkeleton() writes the init callback method for skeleton class
1296          */
1297         private void writeInitCallbackJavaSkeleton(boolean callbackSkeleton) {
1298
1299                 // This is a callback skeleton generation
1300                 if (callbackSkeleton)
1301                         println("public void ___regCB(IoTRMIObject rmiObj) throws IOException {");
1302                 else
1303                         println("public void ___regCB() throws IOException {");
1304                 print("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { int[].class, String.class, int.class },");
1305                 println("new Class<?>[] { null, null, null });");
1306                 println("ports = (int[]) paramObj[0];");
1307                 if (callbackSkeleton)   // If this is a callback skeleton then use the other port
1308                         println("rmiCall = new IoTRMICall((int) paramObj[0], (String) paramObj[1], ports[1]);");
1309                 else
1310                         println("rmiCall = new IoTRMICall((int) paramObj[0], (String) paramObj[1], ports[0]);");
1311                 println("}\n");
1312         }
1313
1314
1315         /**
1316          * HELPER: writeMethodJavaSkeleton() writes the method of the skeleton class
1317          */
1318         private void writeMethodJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses, 
1319                         boolean callbackSkeleton) {
1320
1321                 boolean isDefined = false;
1322                 for (String method : methods) {
1323
1324                         List<String> methParams = intDecl.getMethodParams(method);
1325                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1326                         String methodId = intDecl.getMethodId(method);
1327                         print("public " + intDecl.getMethodType(method) + " " + methodId + "(");
1328                         boolean isCallbackMethod = false;
1329                         String callbackType = null;
1330                         for (int i = 0; i < methParams.size(); i++) {
1331
1332                                 String origParamType = methPrmTypes.get(i);
1333                                 String paramType = checkAndGetParamClass(origParamType);
1334                                 if (callbackClasses.contains(origParamType)) { // Check if this has callback object
1335                                         isCallbackMethod = true;
1336                                         callbackType = origParamType;   
1337                                 }
1338                                 print(paramType + " " + methParams.get(i));
1339                                 // Check if this is the last element (don't print a comma)
1340                                 if (i != methParams.size() - 1) {
1341                                         print(", ");
1342                                 }
1343                         }
1344                         println(") {");
1345                         // Now, write the body of skeleton!
1346                         writeStdMethodBodyJavaSkeleton(methParams, methodId, intDecl.getMethodType(method));
1347                         println("}\n");
1348                         if (isCallbackMethod && !isDefined) {   // Make sure that this function is only defined once!
1349                                 writeInitCallbackJavaSkeleton(callbackSkeleton);
1350                                 isDefined = true;
1351                         }
1352                 }
1353         }
1354
1355
1356         /**
1357          * HELPER: writeCallbackJavaStubGeneration() writes the callback stub generation part
1358          */
1359         private Map<Integer,String> writeCallbackJavaStubGeneration(List<String> methParams, List<String> methPrmTypes, 
1360                         String callbackType, boolean isStructMethod) {
1361
1362                 Map<Integer,String> mapStubParam = new HashMap<Integer,String>();
1363                 String offsetPfx = "";
1364                 if (isStructMethod)
1365                         offsetPfx = "offset";
1366                 // Iterate over callback objects
1367                 for (int i = 0; i < methParams.size(); i++) {
1368                         String paramType = methPrmTypes.get(i);
1369                         String param = methParams.get(i);
1370                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1371                                 String exchParamType = checkAndGetParamClass(getGenericType(paramType));
1372                                 // Print array if this is array or list if this is a list of callback objects
1373                                 if (isArray(param)) {
1374                                         println("int numStubs" + i + " = (int) paramObj[" + offsetPfx + i + "];");
1375                                         println(exchParamType + "[] stub" + i + " = new " + exchParamType + "[numStubs" + i + "];");
1376                                 } else if (isList(paramType)) {
1377                                         println("int numStubs" + i + " = (int) paramObj[" + offsetPfx + i + "];");
1378                                         println("List<" + exchParamType + "> stub" + i + " = new ArrayList<" + exchParamType + ">();");
1379                                 } else {
1380                                         println(exchParamType + " stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, callbackAddress, objIdCnt, ports);");
1381                                         println("objIdCnt++;");
1382                                 }
1383                         }
1384                         // Generate a loop if needed
1385                         if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
1386                                 String exchParamType = checkAndGetParamClass(getGenericType(paramType));
1387                                 if (isArray(param)) {
1388                                         println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
1389                                         println("stub" + i + "[objId] = new " + exchParamType + "_CallbackStub(rmiCall, callbackAddress, objIdCnt, ports);");
1390                                         println("objIdCnt++;");
1391                                         println("}");
1392                                 } else if (isList(paramType)) {
1393                                         println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
1394                                         println("stub" + i + ".add(new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt, ports));");
1395                                         println("objIdCnt++;");
1396                                         println("}");
1397                                 }
1398                                 mapStubParam.put(i, "stub" + i);        // List of all stub parameters
1399                         }
1400                 }
1401                 return mapStubParam;
1402         }
1403
1404
1405         /**
1406          * HELPER: checkAndWriteEnumTypeJavaSkeleton() writes the enum type (convert from enum to int)
1407          */
1408         private void checkAndWriteEnumTypeJavaSkeleton(List<String> methParams, List<String> methPrmTypes, boolean isStructMethod) {
1409
1410                 String offsetPfx = "";
1411                 if (isStructMethod)
1412                         offsetPfx = "offset";
1413                 // Iterate and find enum declarations
1414                 boolean printed = false;
1415                 for (int i = 0; i < methParams.size(); i++) {
1416                         String paramType = methPrmTypes.get(i);
1417                         String param = methParams.get(i);
1418                         String simpleType = getGenericType(paramType);
1419                         if (isEnumClass(simpleType)) {
1420                         // Check if this is enum type
1421                                 println("int paramInt" + i + "[] = (int[]) paramObj[" + offsetPfx + i + "];");
1422                                 if (!printed) {
1423                                         println(simpleType + "[] enumVals = " + simpleType + ".values();");
1424                                         printed = true;
1425                                 }
1426                                 if (isArray(param)) {   // An array
1427                                         println("int len" + i + " = paramInt" + i + ".length;");
1428                                         println(simpleType + "[] paramEnum" + i + " = new " + simpleType + "[len" + i + "];");
1429                                         println("for (int i = 0; i < len" + i + "; i++) {");
1430                                         println("paramEnum" + i + "[i] = enumVals[paramInt" + i + "[i]];");
1431                                         println("}");
1432                                 } else if (isList(paramType)) { // A list
1433                                         println("int len" + i + " = paramInt" + i + ".length;");
1434                                         println("List<" + simpleType + "> paramEnum" + i + " = new ArrayList<" + simpleType + ">();");
1435                                         println("for (int i = 0; i < len" + i + "; i++) {");
1436                                         println("paramEnum" + i + ".add(enumVals[paramInt" + i + "[i]]);");
1437                                         println("}");
1438                                 } else {        // Just one element
1439                                         println(simpleType + " paramEnum" + i + " = enumVals[paramInt" + i + "[0]];");
1440                                 }
1441                         }
1442                 }
1443         }
1444
1445
1446         /**
1447          * HELPER: checkAndWriteEnumRetTypeJavaSkeleton() writes the enum return type (convert from enum to int)
1448          */
1449         private void checkAndWriteEnumRetTypeJavaSkeleton(String retType, String methodId) {
1450
1451                 // Strips off array "[]" for return type
1452                 String pureType = getSimpleArrayType(getGenericType(retType));
1453                 // Take the inner type of generic
1454                 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
1455                         pureType = getGenericType(retType);
1456                 if (isEnumClass(pureType)) {
1457                 // Check if this is enum type
1458                         // Enum decoder
1459                         if (isArray(retType)) {                 // An array
1460                                 print(pureType + "[] retEnum = " + methodId + "(");
1461                         } else if (isList(retType)) {   // A list
1462                                 print("List<" + pureType + "> retEnum = " + methodId + "(");
1463                         } else {        // Just one element
1464                                 print(pureType + " retEnum = " + methodId + "(");
1465                         }
1466                 }
1467         }
1468
1469
1470         /**
1471          * HELPER: checkAndWriteEnumRetConvJavaSkeleton() writes the enum return type (convert from enum to int)
1472          */
1473         private void checkAndWriteEnumRetConvJavaSkeleton(String retType) {
1474
1475                 // Strips off array "[]" for return type
1476                 String pureType = getSimpleArrayType(getGenericType(retType));
1477                 // Take the inner type of generic
1478                 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
1479                         pureType = getGenericType(retType);
1480                 if (isEnumClass(pureType)) {
1481                 // Check if this is enum type
1482                         if (isArray(retType)) { // An array
1483                                 println("int retLen = retEnum.length;");
1484                                 println("int[] retEnumVal = new int[retLen];");
1485                                 println("for (int i = 0; i < retLen; i++) {");
1486                                 println("retEnumVal[i] = retEnum[i].ordinal();");
1487                                 println("}");
1488                         } else if (isList(retType)) {   // A list
1489                                 println("int retLen = retEnum.size();");
1490                                 println("int[] retEnumVal = new int[retLen];");
1491                                 println("for (int i = 0; i < retLen; i++) {");
1492                                 println("retEnumVal[i] = retEnum.get(i).ordinal();");
1493                                 println("}");
1494                         } else {        // Just one element
1495                                 println("int[] retEnumVal = new int[1];");
1496                                 println("retEnumVal[0] = retEnum.ordinal();");
1497                         }
1498                         println("Object retObj = retEnumVal;");
1499                 }
1500         }
1501         
1502         
1503         /**
1504          * HELPER: writeLengthStructParamClassSkeleton() writes lengths of params
1505          */
1506         private void writeLengthStructParamClassSkeleton(List<String> methParams, List<String> methPrmTypes, 
1507                         String method, InterfaceDecl intDecl) {
1508
1509                 // Iterate and find struct declarations - count number of params
1510                 for (int i = 0; i < methParams.size(); i++) {
1511                         String paramType = methPrmTypes.get(i);
1512                         String param = methParams.get(i);
1513                         String simpleType = getGenericType(paramType);
1514                         if (isStructClass(simpleType)) {
1515                                 int members = getNumOfMembers(simpleType);
1516                                 print(Integer.toString(members) + "*");
1517                                 int methodNumId = intDecl.getMethodNumId(method);
1518                                 print("struct" + methodNumId + "Size" + i);
1519                         } else
1520                                 print("1");
1521                         if (i != methParams.size() - 1) {
1522                                 print("+");
1523                         }
1524                 }
1525         }
1526
1527         
1528         /**
1529          * HELPER: writeStructMembersJavaSkeleton() writes member parameters of struct
1530          */
1531         private void writeStructMembersJavaSkeleton(String simpleType, String paramType, 
1532                         String param, String method, InterfaceDecl intDecl, int iVar) {
1533
1534                 // Get the struct declaration for this struct and generate initialization code
1535                 StructDecl structDecl = getStructDecl(simpleType);
1536                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
1537                 List<String> members = structDecl.getMembers(simpleType);
1538                 if (isArrayOrList(paramType, param)) {  // An array or list
1539                         int methodNumId = intDecl.getMethodNumId(method);
1540                         String counter = "struct" + methodNumId + "Size" + iVar;
1541                         println("for(int i = 0; i < " + counter + "; i++) {");
1542                 }
1543                 if (isArrayOrList(paramType, param)) {  // An array or list
1544                         for (int i = 0; i < members.size(); i++) {
1545                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
1546                                 println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
1547                                 println("paramClsGen[pos++] = null;");
1548                         }
1549                         println("}");
1550                 } else {        // Just one struct element
1551                         for (int i = 0; i < members.size(); i++) {
1552                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
1553                                 println("paramCls[pos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
1554                                 println("paramClsGen[pos++] = null;");
1555                         }
1556                 }
1557         }
1558
1559
1560         /**
1561          * HELPER: writeStructMembersInitJavaSkeleton() writes member parameters initialization of struct
1562          */
1563         private void writeStructMembersInitJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
1564                         List<String> methPrmTypes, String method) {
1565
1566                 println("int objPos = 0;");
1567                 for (int i = 0; i < methParams.size(); i++) {
1568                         String paramType = methPrmTypes.get(i);
1569                         String param = methParams.get(i);
1570                         String simpleType = getGenericType(paramType);
1571                         if (isStructClass(simpleType)) {
1572                                 int methodNumId = intDecl.getMethodNumId(method);
1573                                 String counter = "struct" + methodNumId + "Size" + i;
1574                                 // Declaration
1575                                 if (isArray(param)) {                   // An array
1576                                         println(simpleType + "[] paramStruct" + i + " = new " + simpleType + "[" + counter + "];");
1577                                         println("for(int i = 0; i < " + counter + "; i++) {");
1578                                         println("paramStruct" + i + "[i] = new " + simpleType + "();");
1579                                         println("}");
1580                                 } else if (isList(paramType)) { // A list
1581                                         println("List<" + simpleType + "> paramStruct" + i + " = new ArrayList<" + simpleType + ">();");
1582                                 } else
1583                                         println(simpleType + " paramStruct" + i + " = new " + simpleType + "();");
1584                                 // Initialize members
1585                                 StructDecl structDecl = getStructDecl(simpleType);
1586                                 List<String> members = structDecl.getMembers(simpleType);
1587                                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
1588                                 if (isArrayOrList(paramType, param)) {  // An array or list
1589                                         println("for(int i = 0; i < " + counter + "; i++) {");
1590                                 }
1591                                 if (isArray(param)) {   // An array
1592                                         for (int j = 0; j < members.size(); j++) {
1593                                                 String prmType = checkAndGetArray(memTypes.get(j), members.get(j));
1594                                                 print("paramStruct" + i + "[i]." + getSimpleIdentifier(members.get(j)));
1595                                                 println(" = (" + getSimpleType(getEnumType(prmType)) + ") paramObj[objPos++];");
1596                                         }
1597                                         println("}");
1598                                 } else if (isList(paramType)) { // A list
1599                                         println(simpleType + " paramStructMem = new " + simpleType + "();");
1600                                         for (int j = 0; j < members.size(); j++) {
1601                                                 String prmType = checkAndGetArray(memTypes.get(j), members.get(j));
1602                                                 print("paramStructMem." + getSimpleIdentifier(members.get(j)));
1603                                                 println(" = (" + getSimpleType(getEnumType(prmType)) + ") paramObj[objPos++];");
1604                                         }
1605                                         println("paramStruct" + i + ".add(paramStructMem);");
1606                                         println("}");
1607                                 } else {        // Just one struct element
1608                                         for (int j = 0; j < members.size(); j++) {
1609                                                 String prmType = checkAndGetArray(memTypes.get(j), members.get(j));
1610                                                 print("paramStruct" + i + "." + getSimpleIdentifier(members.get(j)));
1611                                                 println(" = (" + getSimpleType(getEnumType(prmType)) + ") paramObj[objPos++];");
1612                                         }
1613                                 }
1614                         } else {
1615                                 // Take offsets of parameters
1616                                 println("int offset" + i +" = objPos++;");
1617                         }
1618                 }
1619         }
1620
1621
1622         /**
1623          * HELPER: writeStructReturnJavaSkeleton() writes struct for return statement
1624          */
1625         private void writeStructReturnJavaSkeleton(String simpleType, String retType) {
1626
1627                 // Minimum retLen is 1 if this is a single struct object
1628                 if (isArray(retType))
1629                         println("int retLen = retStruct.length;");
1630                 else if (isList(retType))
1631                         println("int retLen = retStruct.size();");
1632                 else    // Just single struct object
1633                         println("int retLen = 1;");
1634                 println("Object retLenObj = retLen;");
1635                 println("rmiObj.sendReturnObj(retLenObj);");
1636                 int numMem = getNumOfMembers(simpleType);
1637                 println("Class<?>[] retCls = new Class<?>[" + numMem + "*retLen];");
1638                 println("Object[] retObj = new Object[" + numMem + "*retLen];");
1639                 println("int retPos = 0;");
1640                 // Get the struct declaration for this struct and generate initialization code
1641                 StructDecl structDecl = getStructDecl(simpleType);
1642                 List<String> memTypes = structDecl.getMemberTypes(simpleType);
1643                 List<String> members = structDecl.getMembers(simpleType);
1644                 if (isArray(retType)) { // An array or list
1645                         println("for(int i = 0; i < retLen; i++) {");
1646                         for (int i = 0; i < members.size(); i++) {
1647                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
1648                                 println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
1649                                 print("retObj[retPos++] = retStruct[i].");
1650                                 print(getEnumParam(memTypes.get(i), getSimpleIdentifier(members.get(i)), i));
1651                                 println(";");
1652                         }
1653                         println("}");
1654                 } else if (isList(retType)) {   // An array or list
1655                         println("for(int i = 0; i < retLen; i++) {");
1656                         for (int i = 0; i < members.size(); i++) {
1657                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
1658                                 println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
1659                                 print("retObj[retPos++] = retStruct.get(i).");
1660                                 print(getEnumParam(memTypes.get(i), getSimpleIdentifier(members.get(i)), i));
1661                                 println(";");
1662                         }
1663                         println("}");
1664                 } else {        // Just one struct element
1665                         for (int i = 0; i < members.size(); i++) {
1666                                 String prmType = checkAndGetArray(memTypes.get(i), members.get(i));
1667                                 println("retCls[retPos] = " + getSimpleType(getEnumType(prmType)) + ".class;");
1668                                 print("retObj[retPos++] = retStruct.");
1669                                 print(getEnumParam(memTypes.get(i), getSimpleIdentifier(members.get(i)), i));
1670                                 println(";");
1671                         }
1672                 }
1673
1674         }
1675
1676
1677         /**
1678          * HELPER: writeMethodHelperReturnJavaSkeleton() writes return statement part in skeleton
1679          */
1680         private void writeMethodHelperReturnJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
1681                         List<String> methPrmTypes, String method, boolean isCallbackMethod, String callbackType,
1682                         boolean isStructMethod) {
1683
1684                 checkAndWriteEnumTypeJavaSkeleton(methParams, methPrmTypes, isStructMethod);
1685                 Map<Integer,String> mapStubParam = null;
1686                 if (isCallbackMethod) {
1687                         println("try {");
1688                         mapStubParam = writeCallbackJavaStubGeneration(methParams, methPrmTypes, callbackType, isStructMethod);
1689                 }
1690                 // Check if this is "void"
1691                 String retType = intDecl.getMethodType(method);
1692                 if (retType.equals("void")) {
1693                         print(intDecl.getMethodId(method) + "(");
1694                 } else if (isEnumClass(getSimpleArrayType(getGenericType(retType)))) {  // Enum type
1695                         checkAndWriteEnumRetTypeJavaSkeleton(retType, intDecl.getMethodId(method));
1696                 } else if (isStructClass(getSimpleArrayType(getGenericType(retType)))) {        // Struct type
1697                         print(retType + " retStruct = " + intDecl.getMethodId(method) + "(");
1698                 } else { // We do have a return value
1699                         print("Object retObj = " + intDecl.getMethodId(method) + "(");
1700                 }
1701                 for (int i = 0; i < methParams.size(); i++) {
1702
1703                         String paramType = methPrmTypes.get(i);
1704                         if (isCallbackMethod && checkCallbackType(paramType, callbackType)) {
1705                                 print(mapStubParam.get(i));     // Get the callback parameter
1706                         } else if (isEnumClass(getGenericType(paramType))) { // Enum class
1707                                 print(getEnumParam(paramType, methParams.get(i), i));
1708                         } else if (isStructClass(getGenericType(paramType))) {
1709                                 print("paramStruct" + i);
1710                         } else {
1711                                 String prmType = checkAndGetArray(paramType, methParams.get(i));
1712                                 if (isStructMethod)
1713                                         print("(" + prmType + ") paramObj[offset" + i + "]");
1714                                 else
1715                                         print("(" + prmType + ") paramObj[" + i + "]");
1716                         }
1717                         if (i != methParams.size() - 1)
1718                                 print(", ");
1719                 }
1720                 println(");");
1721                 if (!retType.equals("void")) {
1722                         if (isEnumClass(getSimpleArrayType(getGenericType(retType)))) { // Enum type
1723                                 checkAndWriteEnumRetConvJavaSkeleton(retType);
1724                                 println("rmiObj.sendReturnObj(retObj);");
1725                         } else if (isStructClass(getSimpleArrayType(getGenericType(retType)))) { // Struct type
1726                                 writeStructReturnJavaSkeleton(getSimpleArrayType(getGenericType(retType)), retType);
1727                                 println("rmiObj.sendReturnObj(retCls, retObj);");
1728                         } else
1729                                 println("rmiObj.sendReturnObj(retObj);");
1730                 }
1731                 if (isCallbackMethod) { // Catch exception if this is callback
1732                         print("}");
1733                         println(" catch(Exception ex) {");
1734                         println("ex.printStackTrace();");
1735                         println("throw new Error(\"Exception from callback object instantiation!\");");
1736                         println("}");
1737                 }
1738         }
1739
1740
1741         /**
1742          * HELPER: writeMethodHelperStructJavaSkeleton() writes the struct in skeleton
1743          */
1744         private void writeMethodHelperStructJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
1745                         List<String> methPrmTypes, String method, Set<String> callbackClasses) {
1746
1747                 // Generate array of parameter objects
1748                 boolean isCallbackMethod = false;
1749                 String callbackType = null;
1750                 print("int paramLen = ");
1751                 writeLengthStructParamClassSkeleton(methParams, methPrmTypes, method, intDecl);
1752                 println(";");
1753                 println("Class<?>[] paramCls = new Class<?>[paramLen];");
1754                 println("Class<?>[] paramClsGen = new Class<?>[paramLen];");
1755                 println("int pos = 0;");
1756                 // Iterate again over the parameters
1757                 for (int i = 0; i < methParams.size(); i++) {
1758                         String paramType = methPrmTypes.get(i);
1759                         String param = methParams.get(i);
1760                         String simpleType = getGenericType(paramType);
1761                         if (isStructClass(simpleType)) {
1762                                 writeStructMembersJavaSkeleton(simpleType, paramType, param, method, intDecl, i);
1763                         } else {
1764                                 String prmType = returnGenericCallbackType(methPrmTypes.get(i));
1765                                 if (callbackClasses.contains(prmType)) {
1766                                         isCallbackMethod = true;
1767                                         callbackType = prmType;
1768                                         println("paramCls[pos] = int.class;");
1769                                         println("paramClsGen[pos++] = null;");
1770                                 } else {        // Generate normal classes if it's not a callback object
1771                                         String paramTypeOth = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
1772                                         println("paramCls[pos] = " + getSimpleType(getEnumType(paramTypeOth)) + ".class;");
1773                                         print("paramClsGen[pos++] = ");
1774                                         String prmTypeOth = methPrmTypes.get(i);
1775                                         if (getParamCategory(prmTypeOth) == ParamCategory.NONPRIMITIVES)
1776                                                 println(getTypeOfGeneric(prmType)[0] + ".class;");
1777                                         else
1778                                                 println("null;");
1779                                 }
1780                         }
1781                 }
1782                 println("Object[] paramObj = rmiObj.getMethodParams(paramCls, paramClsGen);");
1783                 writeStructMembersInitJavaSkeleton(intDecl, methParams, methPrmTypes, method);
1784                 // Write the return value part
1785                 writeMethodHelperReturnJavaSkeleton(intDecl, methParams, methPrmTypes, method, isCallbackMethod, callbackType, true);
1786         }
1787
1788
1789         /**
1790          * HELPER: writeStdMethodHelperBodyJavaSkeleton() writes the standard method body helper in the skeleton class
1791          */
1792         private void writeStdMethodHelperBodyJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
1793                         List<String> methPrmTypes, String method, Set<String> callbackClasses) {
1794
1795                 // Generate array of parameter objects
1796                 boolean isCallbackMethod = false;
1797                 String callbackType = null;
1798                 print("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { ");
1799                 for (int i = 0; i < methParams.size(); i++) {
1800
1801                         String paramType = returnGenericCallbackType(methPrmTypes.get(i));
1802                         if (callbackClasses.contains(paramType)) {
1803                                 isCallbackMethod = true;
1804                                 callbackType = paramType;
1805                                 print("int.class");
1806                         } else {        // Generate normal classes if it's not a callback object
1807                                 String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
1808                                 print(getSimpleType(getEnumType(prmType)) + ".class");
1809                         }
1810                         if (i != methParams.size() - 1)
1811                                 print(", ");
1812                 }
1813                 println(" }, ");
1814                 // Generate generic class if it's a generic type.. null otherwise
1815                 print("new Class<?>[] { ");
1816                 for (int i = 0; i < methParams.size(); i++) {
1817                         String prmType = methPrmTypes.get(i);
1818                         if ((getParamCategory(prmType) == ParamCategory.NONPRIMITIVES) &&
1819                                 !isEnumClass(getGenericType(prmType)) &&
1820                                 !callbackClasses.contains(getGenericType(prmType)))
1821                                         print(getGenericType(prmType) + ".class");
1822                         else
1823                                 print("null");
1824                         if (i != methParams.size() - 1)
1825                                 print(", ");
1826                 }
1827                 println(" });");
1828                 // Write the return value part
1829                 writeMethodHelperReturnJavaSkeleton(intDecl, methParams, methPrmTypes, method, isCallbackMethod, callbackType, false);
1830         }
1831
1832
1833         /**
1834          * HELPER: writeMethodHelperJavaSkeleton() writes the method helper of the skeleton class
1835          */
1836         private void writeMethodHelperJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
1837
1838                 // Use this set to handle two same methodIds
1839                 Set<String> uniqueMethodIds = new HashSet<String>();
1840                 for (String method : methods) {
1841
1842                         List<String> methParams = intDecl.getMethodParams(method);
1843                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1844                         if (isStructPresent(methParams, methPrmTypes)) {        // Treat struct differently
1845                                 String methodId = intDecl.getMethodId(method);
1846                                 print("public void ___");
1847                                 String helperMethod = methodId;
1848                                 if (uniqueMethodIds.contains(methodId))
1849                                         helperMethod = helperMethod + intDecl.getMethodNumId(method);
1850                                 else
1851                                         uniqueMethodIds.add(methodId);
1852                                 String retType = intDecl.getMethodType(method);
1853                                 print(helperMethod + "(");
1854                                 boolean begin = true;
1855                                 for (int i = 0; i < methParams.size(); i++) { // Print size variables
1856                                         String paramType = methPrmTypes.get(i);
1857                                         String param = methParams.get(i);
1858                                         String simpleType = getGenericType(paramType);
1859                                         if (isStructClass(simpleType)) {
1860                                                 if (!begin)     // Generate comma for not the beginning variable
1861                                                         print(", ");
1862                                                 else
1863                                                         begin = false;
1864                                                 int methodNumId = intDecl.getMethodNumId(method);
1865                                                 print("int struct" + methodNumId + "Size" + i);
1866                                         }
1867                                 }
1868                                 // Check if this is "void"
1869                                 if (retType.equals("void"))
1870                                         println(") {");
1871                                 else
1872                                         println(") throws IOException {");
1873                                 writeMethodHelperStructJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
1874                                 println("}\n");
1875                         } else {
1876                                 String methodId = intDecl.getMethodId(method);
1877                                 print("public void ___");
1878                                 String helperMethod = methodId;
1879                                 if (uniqueMethodIds.contains(methodId))
1880                                         helperMethod = helperMethod + intDecl.getMethodNumId(method);
1881                                 else
1882                                         uniqueMethodIds.add(methodId);
1883                                 // Check if this is "void"
1884                                 String retType = intDecl.getMethodType(method);
1885                                 if (retType.equals("void"))
1886                                         println(helperMethod + "() {");
1887                                 else
1888                                         println(helperMethod + "() throws IOException {");
1889                                 // Now, write the helper body of skeleton!
1890                                 writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
1891                                 println("}\n");
1892                         }
1893                 }
1894                 // Write method helper for structs
1895                 writeMethodHelperStructSetupJavaSkeleton(methods, intDecl);
1896         }
1897
1898
1899         /**
1900          * HELPER: writeMethodHelperStructSetupJavaSkeleton() writes the method helper of struct setup in skeleton class
1901          */
1902         private void writeMethodHelperStructSetupJavaSkeleton(Collection<String> methods, 
1903                         InterfaceDecl intDecl) {
1904
1905                 // Use this set to handle two same methodIds
1906                 for (String method : methods) {
1907
1908                         List<String> methParams = intDecl.getMethodParams(method);
1909                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1910                         // Check for params with structs
1911                         for (int i = 0; i < methParams.size(); i++) {
1912                                 String paramType = methPrmTypes.get(i);
1913                                 String param = methParams.get(i);
1914                                 String simpleType = getGenericType(paramType);
1915                                 if (isStructClass(simpleType)) {
1916                                         int methodNumId = intDecl.getMethodNumId(method);
1917                                         print("public int ___");
1918                                         String helperMethod = methodNumId + "struct" + i;
1919                                         println(helperMethod + "() {");
1920                                         // Now, write the helper body of skeleton!
1921                                         println("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, new Class<?>[] { null });");
1922                                         println("return (int) paramObj[0];");
1923                                         println("}\n");
1924                                 }
1925                         }
1926                 }
1927         }
1928
1929
1930         /**
1931          * HELPER: writeMethodHelperStructSetupJavaCallbackSkeleton() writes the method helper of struct setup in callback skeleton class
1932          */
1933         private void writeMethodHelperStructSetupJavaCallbackSkeleton(Collection<String> methods, 
1934                         InterfaceDecl intDecl) {
1935
1936                 // Use this set to handle two same methodIds
1937                 for (String method : methods) {
1938
1939                         List<String> methParams = intDecl.getMethodParams(method);
1940                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1941                         // Check for params with structs
1942                         for (int i = 0; i < methParams.size(); i++) {
1943                                 String paramType = methPrmTypes.get(i);
1944                                 String param = methParams.get(i);
1945                                 String simpleType = getGenericType(paramType);
1946                                 if (isStructClass(simpleType)) {
1947                                         int methodNumId = intDecl.getMethodNumId(method);
1948                                         print("public int ___");
1949                                         String helperMethod = methodNumId + "struct" + i;
1950                                         println(helperMethod + "(IoTRMIObject rmiObj) {");
1951                                         // Now, write the helper body of skeleton!
1952                                         println("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, new Class<?>[] { null });");
1953                                         println("return (int) paramObj[0];");
1954                                         println("}\n");
1955                                 }
1956                         }
1957                 }
1958         }
1959
1960
1961         /**
1962          * HELPER: writeCountVarStructSkeleton() writes counter variable of struct for skeleton
1963          */
1964         private void writeCountVarStructSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
1965
1966                 // Use this set to handle two same methodIds
1967                 for (String method : methods) {
1968
1969                         List<String> methParams = intDecl.getMethodParams(method);
1970                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1971                         // Check for params with structs
1972                         for (int i = 0; i < methParams.size(); i++) {
1973                                 String paramType = methPrmTypes.get(i);
1974                                 String param = methParams.get(i);
1975                                 String simpleType = getGenericType(paramType);
1976                                 if (isStructClass(simpleType)) {
1977                                         int methodNumId = intDecl.getMethodNumId(method);
1978                                         println("int struct" + methodNumId + "Size" + i + " = 0;");
1979                                 }
1980                         }
1981                 }
1982         }
1983         
1984         
1985         /**
1986          * HELPER: writeInputCountVarStructSkeleton() writes input counter variable of struct for skeleton
1987          */
1988         private boolean writeInputCountVarStructSkeleton(String method, InterfaceDecl intDecl) {
1989
1990                 List<String> methParams = intDecl.getMethodParams(method);
1991                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1992                 boolean structExist = false;
1993                 boolean begin = true;
1994                 // Check for params with structs
1995                 for (int i = 0; i < methParams.size(); i++) {
1996                         String paramType = methPrmTypes.get(i);
1997                         String param = methParams.get(i);
1998                         String simpleType = getGenericType(paramType);
1999                         if (isStructClass(simpleType)) {
2000                                 structExist = true;
2001                                 if (!begin)
2002                                         print(", ");
2003                                 else
2004                                         begin = false;
2005                                 int methodNumId = intDecl.getMethodNumId(method);
2006                                 print("struct" + methodNumId + "Size" + i);
2007                         }
2008                 }
2009                 return structExist;
2010         }
2011
2012
2013         /**
2014          * HELPER: writeMethodCallStructSkeleton() writes method call for wait invoke in skeleton
2015          */
2016         private void writeMethodCallStructSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
2017
2018                 // Use this set to handle two same methodIds
2019                 for (String method : methods) {
2020
2021                         List<String> methParams = intDecl.getMethodParams(method);
2022                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2023                         // Check for params with structs
2024                         for (int i = 0; i < methParams.size(); i++) {
2025                                 String paramType = methPrmTypes.get(i);
2026                                 String param = methParams.get(i);
2027                                 String simpleType = getGenericType(paramType);
2028                                 if (isStructClass(simpleType)) {
2029                                         int methodNumId = intDecl.getMethodNumId(method);
2030                                         print("case ");
2031                                         String helperMethod = methodNumId + "struct" + i;
2032                                         String tempVar = "struct" + methodNumId + "Size" + i;
2033                                         print(intDecl.getHelperMethodNumId(helperMethod) + ": ");
2034                                         print(tempVar + " = ___");
2035                                         println(helperMethod + "(); break;");
2036                                 }
2037                         }
2038                 }
2039         }
2040
2041
2042         /**
2043          * HELPER: writeMethodCallStructCallbackSkeleton() writes method call for wait invoke in skeleton
2044          */
2045         private void writeMethodCallStructCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
2046
2047                 // Use this set to handle two same methodIds
2048                 for (String method : methods) {
2049
2050                         List<String> methParams = intDecl.getMethodParams(method);
2051                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2052                         // Check for params with structs
2053                         for (int i = 0; i < methParams.size(); i++) {
2054                                 String paramType = methPrmTypes.get(i);
2055                                 String param = methParams.get(i);
2056                                 String simpleType = getGenericType(paramType);
2057                                 if (isStructClass(simpleType)) {
2058                                         int methodNumId = intDecl.getMethodNumId(method);
2059                                         print("case ");
2060                                         String helperMethod = methodNumId + "struct" + i;
2061                                         String tempVar = "struct" + methodNumId + "Size" + i;
2062                                         print(intDecl.getHelperMethodNumId(helperMethod) + ": ");
2063                                         print(tempVar + " = ___");
2064                                         println(helperMethod + "(rmiObj); break;");
2065                                 }
2066                         }
2067                 }
2068         }
2069
2070
2071         /**
2072          * HELPER: writeJavaMethodPermission() writes permission checks in skeleton
2073          */
2074         private void writeJavaMethodPermission(String intface) {
2075
2076                 // Get all the different stubs
2077                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
2078                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
2079                         String newIntface = intMeth.getKey();
2080                         int newObjectId = getNewIntfaceObjectId(newIntface);
2081                         println("if (_objectId == object" + newObjectId + "Id) {");
2082                         println("if (!set" + newObjectId + "Allowed.contains(methodId)) {");
2083                         println("throw new Error(\"Object with object Id: \" + _objectId + \"  is not allowed to access method: \" + methodId);");
2084                         println("}");
2085                         println("}");
2086                         println("else {");
2087                         println("throw new Error(\"Object Id: \" + _objectId + \" not recognized!\");");
2088                         println("}");
2089                 }
2090         }
2091
2092
2093         /**
2094          * HELPER: writeJavaWaitRequestInvokeMethod() writes the main loop of the skeleton class
2095          */
2096         private void writeJavaWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist, String intface) {
2097
2098                 // Use this set to handle two same methodIds
2099                 Set<String> uniqueMethodIds = new HashSet<String>();
2100                 println("private void ___waitRequestInvokeMethod() throws IOException {");
2101                 // Write variables here if we have callbacks or enums or structs
2102                 writeCountVarStructSkeleton(methods, intDecl);
2103                 println("while (true) {");
2104                 println("rmiObj.getMethodBytes();");
2105                 println("int _objectId = rmiObj.getObjectId();");
2106                 println("int methodId = rmiObj.getMethodId();");
2107                 // Generate permission check
2108                 writeJavaMethodPermission(intface);
2109                 println("switch (methodId) {");
2110                 // Print methods and method Ids
2111                 for (String method : methods) {
2112                         String methodId = intDecl.getMethodId(method);
2113                         int methodNumId = intDecl.getMethodNumId(method);
2114                         print("case " + methodNumId + ": ___");
2115                         String helperMethod = methodId;
2116                         if (uniqueMethodIds.contains(methodId))
2117                                 helperMethod = helperMethod + methodNumId;
2118                         else
2119                                 uniqueMethodIds.add(methodId);
2120                         print(helperMethod + "(");
2121                         writeInputCountVarStructSkeleton(method, intDecl);
2122                         println("); break;");
2123                 }
2124                 String method = "___initCallBack()";
2125                 // Print case -9999 (callback handler) if callback exists
2126                 if (callbackExist) {
2127                         int methodId = intDecl.getHelperMethodNumId(method);
2128                         println("case " + methodId + ": ___regCB(); break;");
2129                 }
2130                 writeMethodCallStructSkeleton(methods, intDecl);
2131                 println("default: ");
2132                 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
2133                 println("}");
2134                 println("}");
2135                 println("}\n");
2136         }
2137
2138
2139         /**
2140          * generateJavaSkeletonClass() generate skeletons based on the methods list in Java
2141          */
2142         public void generateJavaSkeletonClass() throws IOException {
2143
2144                 // Create a new directory
2145                 String path = createDirectories(dir, subdir);
2146                 for (String intface : mapIntfacePTH.keySet()) {
2147                         // Open a new file to write into
2148                         String newSkelClass = intface + "_Skeleton";
2149                         FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
2150                         pw = new PrintWriter(new BufferedWriter(fw));
2151                         // Pass in set of methods and get import classes
2152                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2153                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2154                         List<String> methods = intDecl.getMethods();
2155                         Set<String> importClasses = getImportClasses(methods, intDecl);
2156                         List<String> stdImportClasses = getStandardJavaImportClasses();
2157                         List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
2158                         printImportStatements(allImportClasses);
2159                         // Find out if there are callback objects
2160                         Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
2161                         boolean callbackExist = !callbackClasses.isEmpty();
2162                         // Write class header
2163                         println("");
2164                         println("public class " + newSkelClass  + " implements " + intface + " {\n");
2165                         // Write properties
2166                         writePropertiesJavaSkeleton(intface, callbackExist, intDecl);
2167                         // Write constructor
2168                         writeConstructorJavaSkeleton(newSkelClass, intface, intDecl, methods, callbackExist);
2169                         // Write methods
2170                         writeMethodJavaSkeleton(methods, intDecl, callbackClasses, false);
2171                         // Write method helper
2172                         writeMethodHelperJavaSkeleton(methods, intDecl, callbackClasses);
2173                         // Write waitRequestInvokeMethod() - main loop
2174                         writeJavaWaitRequestInvokeMethod(methods, intDecl, callbackExist, intface);
2175                         println("}");
2176                         pw.close();
2177                         System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".java...");
2178                 }
2179         }
2180
2181
2182         /**
2183          * HELPER: writePropertiesJavaCallbackSkeleton() writes the properties of the callback skeleton class
2184          */
2185         private void writePropertiesJavaCallbackSkeleton(String intface, boolean callbackExist) {
2186
2187                 println("private " + intface + " mainObj;");
2188                 // For callback skeletons, this is its own object Id
2189                 println("private int objectId = 0;");
2190                 println("private String callbackAddress;");
2191                 // Callback
2192                 if (callbackExist) {
2193
2194                         println("private static int objIdCnt = 0;");
2195                         println("private IoTRMICall rmiCall;");
2196                         println("private int[] ports;\n");
2197                 }
2198                 println("\n");
2199         }
2200
2201
2202         /**
2203          * HELPER: writeConstructorJavaCallbackSkeleton() writes the constructor of the skeleton class
2204          */
2205         private void writeConstructorJavaCallbackSkeleton(String newSkelClass, String intface, InterfaceDecl intDecl, Collection<String> methods) {
2206
2207                 println("public " + newSkelClass + "(" + intface + " _mainObj, String _callbackAddress, int _objectId) throws Exception {");
2208                 println("callbackAddress = _callbackAddress;");
2209                 println("mainObj = _mainObj;");
2210                 println("objectId = _objectId;");
2211                 println("}\n");
2212         }
2213
2214
2215         /**
2216          * HELPER: writeMethodHelperJavaCallbackSkeleton() writes the method helper of the callback skeleton class
2217          */
2218         private void writeMethodHelperJavaCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
2219
2220                 // Use this set to handle two same methodIds
2221                 Set<String> uniqueMethodIds = new HashSet<String>();
2222                 for (String method : methods) {
2223
2224                         List<String> methParams = intDecl.getMethodParams(method);
2225                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2226                         if (isStructPresent(methParams, methPrmTypes)) {        // Treat struct differently
2227                                 String methodId = intDecl.getMethodId(method);
2228                                 print("public void ___");
2229                                 String helperMethod = methodId;
2230                                 if (uniqueMethodIds.contains(methodId))
2231                                         helperMethod = helperMethod + intDecl.getMethodNumId(method);
2232                                 else
2233                                         uniqueMethodIds.add(methodId);
2234                                 String retType = intDecl.getMethodType(method);
2235                                 print(helperMethod + "(");
2236                                 boolean begin = true;
2237                                 for (int i = 0; i < methParams.size(); i++) { // Print size variables
2238                                         String paramType = methPrmTypes.get(i);
2239                                         String param = methParams.get(i);
2240                                         String simpleType = getGenericType(paramType);
2241                                         if (isStructClass(simpleType)) {
2242                                                 if (!begin)     // Generate comma for not the beginning variable
2243                                                         print(", ");
2244                                                 else
2245                                                         begin = false;
2246                                                 int methodNumId = intDecl.getMethodNumId(method);
2247                                                 print("int struct" + methodNumId + "Size" + i);
2248                                         }
2249                                 }
2250                                 // Check if this is "void"
2251                                 if (retType.equals("void"))
2252                                         println(", IoTRMIObject rmiObj) {");
2253                                 else
2254                                         println(", IoTRMIObject rmiObj) throws IOException {");
2255                                 writeMethodHelperStructJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
2256                                 println("}\n");
2257                         } else {
2258                                 String methodId = intDecl.getMethodId(method);
2259                                 print("public void ___");
2260                                 String helperMethod = methodId;
2261                                 if (uniqueMethodIds.contains(methodId))
2262                                         helperMethod = helperMethod + intDecl.getMethodNumId(method);
2263                                 else
2264                                         uniqueMethodIds.add(methodId);
2265                                 // Check if this is "void"
2266                                 String retType = intDecl.getMethodType(method);
2267                                 if (retType.equals("void"))
2268                                         println(helperMethod + "(IoTRMIObject rmiObj) {");
2269                                 else
2270                                         println(helperMethod + "(IoTRMIObject rmiObj) throws IOException {");
2271                                 // Now, write the helper body of skeleton!
2272                                 writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
2273                                 println("}\n");
2274                         }
2275                 }
2276                 // Write method helper for structs
2277                 writeMethodHelperStructSetupJavaCallbackSkeleton(methods, intDecl);
2278         }
2279
2280
2281         /**
2282          * HELPER: writeJavaCallbackWaitRequestInvokeMethod() writes the request invoke method of the callback skeleton class
2283          */
2284         private void writeJavaCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist) {
2285
2286                 // Use this set to handle two same methodIds
2287                 Set<String> uniqueMethodIds = new HashSet<String>();
2288                 println("public void invokeMethod(IoTRMIObject rmiObj) throws IOException {");
2289                 // Write variables here if we have callbacks or enums or structs
2290                 writeCountVarStructSkeleton(methods, intDecl);
2291                 // Write variables here if we have callbacks or enums or structs
2292                 println("int methodId = rmiObj.getMethodId();");
2293                 // TODO: code the permission check here!
2294                 println("switch (methodId) {");
2295                 // Print methods and method Ids
2296                 for (String method : methods) {
2297                         String methodId = intDecl.getMethodId(method);
2298                         int methodNumId = intDecl.getMethodNumId(method);
2299                         print("case " + methodNumId + ": ___");
2300                         String helperMethod = methodId;
2301                         if (uniqueMethodIds.contains(methodId))
2302                                 helperMethod = helperMethod + methodNumId;
2303                         else
2304                                 uniqueMethodIds.add(methodId);
2305                         print(helperMethod + "(");
2306                         if (writeInputCountVarStructSkeleton(method, intDecl))
2307                                 println(", rmiObj); break;");
2308                         else
2309                                 println("rmiObj); break;");
2310                 }
2311                 String method = "___initCallBack()";
2312                 // Print case -9999 (callback handler) if callback exists
2313                 if (callbackExist) {
2314                         int methodId = intDecl.getHelperMethodNumId(method);
2315                         println("case " + methodId + ": ___regCB(rmiObj); break;");
2316                 }
2317                 writeMethodCallStructCallbackSkeleton(methods, intDecl);
2318                 println("default: ");
2319                 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
2320                 println("}");
2321                 println("}\n");
2322         }
2323
2324
2325         /**
2326          * generateJavaCallbackSkeletonClass() generate callback skeletons based on the methods list in Java
2327          */
2328         public void generateJavaCallbackSkeletonClass() throws IOException {
2329
2330                 // Create a new directory
2331                 String path = createDirectories(dir, subdir);
2332                 for (String intface : mapIntfacePTH.keySet()) {
2333                         // Open a new file to write into
2334                         String newSkelClass = intface + "_CallbackSkeleton";
2335                         FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
2336                         pw = new PrintWriter(new BufferedWriter(fw));
2337                         // Pass in set of methods and get import classes
2338                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2339                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2340                         List<String> methods = intDecl.getMethods();
2341                         Set<String> importClasses = getImportClasses(methods, intDecl);
2342                         List<String> stdImportClasses = getStandardJavaImportClasses();
2343                         List<String> allImportClasses = getAllLibClasses(stdImportClasses, importClasses);
2344                         printImportStatements(allImportClasses);
2345                         // Find out if there are callback objects
2346                         Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
2347                         boolean callbackExist = !callbackClasses.isEmpty();
2348                         // Write class header
2349                         println("");
2350                         println("public class " + newSkelClass  + " implements " + intface + " {\n");
2351                         // Write properties
2352                         writePropertiesJavaCallbackSkeleton(intface, callbackExist);
2353                         // Write constructor
2354                         writeConstructorJavaCallbackSkeleton(newSkelClass, intface, intDecl, methods);
2355                         // Write methods
2356                         writeMethodJavaSkeleton(methods, intDecl, callbackClasses, true);
2357                         // Write method helper
2358                         writeMethodHelperJavaCallbackSkeleton(methods, intDecl, callbackClasses);
2359                         // Write waitRequestInvokeMethod() - main loop
2360                         writeJavaCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist);
2361                         println("}");
2362                         pw.close();
2363                         System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".java...");
2364                 }
2365         }
2366
2367
2368         /**
2369          * HELPER: writeMethodCplusLocalInterface() writes the method of the local interface
2370          */
2371         private void writeMethodCplusLocalInterface(Collection<String> methods, InterfaceDecl intDecl) {
2372
2373                 for (String method : methods) {
2374
2375                         List<String> methParams = intDecl.getMethodParams(method);
2376                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2377                         print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
2378                                 intDecl.getMethodId(method) + "(");
2379                         for (int i = 0; i < methParams.size(); i++) {
2380                                 // Check for params with driver class types and exchange it 
2381                                 //              with its remote interface
2382                                 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
2383                                 paramType = checkAndGetCplusType(paramType);
2384                                 // Check for arrays - translate into vector in C++
2385                                 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
2386                                 print(paramComplete);
2387                                 // Check if this is the last element (don't print a comma)
2388                                 if (i != methParams.size() - 1) {
2389                                         print(", ");
2390                                 }
2391                         }
2392                         println(") = 0;");
2393                 }
2394         }
2395
2396
2397         /**
2398          * HELPER: writeMethodCplusInterface() writes the method of the interface
2399          */
2400         private void writeMethodCplusInterface(Collection<String> methods, InterfaceDecl intDecl) {
2401
2402                 for (String method : methods) {
2403
2404                         List<String> methParams = intDecl.getMethodParams(method);
2405                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2406                         print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
2407                                 intDecl.getMethodId(method) + "(");
2408                         for (int i = 0; i < methParams.size(); i++) {
2409                                 // Check for params with driver class types and exchange it 
2410                                 //              with its remote interface
2411                                 String paramType = methPrmTypes.get(i);
2412                                 paramType = checkAndGetCplusType(paramType);
2413                                 // Check for arrays - translate into vector in C++
2414                                 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
2415                                 print(paramComplete);
2416                                 // Check if this is the last element (don't print a comma)
2417                                 if (i != methParams.size() - 1) {
2418                                         print(", ");
2419                                 }
2420                         }
2421                         println(") = 0;");
2422                 }
2423         }
2424
2425
2426         /**
2427          * HELPER: generateEnumCplus() writes the enumeration declaration
2428          */
2429         public void generateEnumCplus() throws IOException {
2430
2431                 // Create a new directory
2432                 createDirectory(dir);
2433                 for (String intface : mapIntfacePTH.keySet()) {
2434                         // Get the right StructDecl
2435                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2436                         EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface);
2437                         Set<String> enumTypes = enumDecl.getEnumDeclarations();
2438                         // Iterate over enum declarations
2439                         for (String enType : enumTypes) {
2440                                 // Open a new file to write into
2441                                 FileWriter fw = new FileWriter(dir + "/" + enType + ".hpp");
2442                                 pw = new PrintWriter(new BufferedWriter(fw));
2443                                 // Write file headers
2444                                 println("#ifndef _" + enType.toUpperCase() + "_HPP__");
2445                                 println("#define _" + enType.toUpperCase() + "_HPP__");
2446                                 println("enum " + enType + " {");
2447                                 List<String> enumMembers = enumDecl.getMembers(enType);
2448                                 for (int i = 0; i < enumMembers.size(); i++) {
2449
2450                                         String member = enumMembers.get(i);
2451                                         print(member);
2452                                         // Check if this is the last element (don't print a comma)
2453                                         if (i != enumMembers.size() - 1)
2454                                                 println(",");
2455                                         else
2456                                                 println("");
2457                                 }
2458                                 println("};\n");
2459                                 println("#endif");
2460                                 pw.close();
2461                                 System.out.println("IoTCompiler: Generated enum " + enType + ".hpp...");
2462                         }
2463                 }
2464         }
2465
2466
2467         /**
2468          * HELPER: generateStructCplus() writes the struct declaration
2469          */
2470         public void generateStructCplus() throws IOException {
2471
2472                 // Create a new directory
2473                 createDirectory(dir);
2474                 for (String intface : mapIntfacePTH.keySet()) {
2475                         // Get the right StructDecl
2476                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2477                         StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
2478                         List<String> structTypes = structDecl.getStructTypes();
2479                         // Iterate over enum declarations
2480                         for (String stType : structTypes) {
2481                                 // Open a new file to write into
2482                                 FileWriter fw = new FileWriter(dir + "/" + stType + ".hpp");
2483                                 pw = new PrintWriter(new BufferedWriter(fw));
2484                                 // Write file headers
2485                                 println("#ifndef _" + stType.toUpperCase() + "_HPP__");
2486                                 println("#define _" + stType.toUpperCase() + "_HPP__");
2487                                 println("using namespace std;");
2488                                 println("struct " + stType + " {");
2489                                 List<String> structMemberTypes = structDecl.getMemberTypes(stType);
2490                                 List<String> structMembers = structDecl.getMembers(stType);
2491                                 for (int i = 0; i < structMembers.size(); i++) {
2492
2493                                         String memberType = structMemberTypes.get(i);
2494                                         String member = structMembers.get(i);
2495                                         String structTypeC = checkAndGetCplusType(memberType);
2496                                         String structComplete = checkAndGetCplusArray(structTypeC, member);
2497                                         println(structComplete + ";");
2498                                 }
2499                                 println("};\n");
2500                                 println("#endif");
2501                                 pw.close();
2502                                 System.out.println("IoTCompiler: Generated struct " + stType + ".hpp...");
2503                         }
2504                 }
2505         }
2506
2507
2508         /**
2509          * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking.
2510          * <p>
2511          * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
2512          * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
2513          * The local interface has to be the input parameter for the stub and the stub 
2514          * interface has to be the input parameter for the local class.
2515          */
2516         public void generateCplusLocalInterfaces() throws IOException {
2517
2518                 // Create a new directory
2519                 createDirectory(dir);
2520                 for (String intface : mapIntfacePTH.keySet()) {
2521                         // Open a new file to write into
2522                         FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
2523                         pw = new PrintWriter(new BufferedWriter(fw));
2524                         // Write file headers
2525                         println("#ifndef _" + intface.toUpperCase() + "_HPP__");
2526                         println("#define _" + intface.toUpperCase() + "_HPP__");
2527                         println("#include <iostream>");
2528                         // Pass in set of methods and get include classes
2529                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2530                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2531                         List<String> methods = intDecl.getMethods();
2532                         Set<String> includeClasses = getIncludeClasses(methods, intDecl, intface, true);
2533                         printIncludeStatements(includeClasses); println("");
2534                         println("using namespace std;\n");
2535                         //writeStructCplus(structDecl);
2536                         println("class " + intface); println("{");
2537                         println("public:");
2538                         // Write methods
2539                         writeMethodCplusLocalInterface(methods, intDecl);
2540                         println("};");
2541                         println("#endif");
2542                         pw.close();
2543                         System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
2544                 }
2545         }
2546
2547
2548         /**
2549          * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
2550          * <p>
2551          * For C++ we use virtual classe as interface
2552          */
2553         public void generateCPlusInterfaces() throws IOException {
2554
2555                 // Create a new directory
2556                 String path = createDirectories(dir, subdir);
2557                 for (String intface : mapIntfacePTH.keySet()) {
2558
2559                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
2560                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
2561
2562                                 // Open a new file to write into
2563                                 String newIntface = intMeth.getKey();
2564                                 FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp");
2565                                 pw = new PrintWriter(new BufferedWriter(fw));
2566                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
2567                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
2568                                 // Write file headers
2569                                 println("#ifndef _" + newIntface.toUpperCase() + "_HPP__");
2570                                 println("#define _" + newIntface.toUpperCase() + "_HPP__");
2571                                 println("#include <iostream>");
2572                                 updateIntfaceObjIdMap(intface, newIntface);
2573                                 // Pass in set of methods and get import classes
2574                                 Set<String> methods = intMeth.getValue();
2575                                 Set<String> includeClasses = getIncludeClasses(methods, intDecl, intface, false);
2576                                 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
2577                                 List<String> allIncludeClasses = getAllLibClasses(stdIncludeClasses, includeClasses);
2578                                 printIncludeStatements(allIncludeClasses); println("");                 
2579                                 println("using namespace std;\n");
2580                                 println("class " + newIntface);
2581                                 println("{");
2582                                 println("public:");
2583                                 // Write methods
2584                                 writeMethodCplusInterface(methods, intDecl);
2585                                 println("};");
2586                                 println("#endif");
2587                                 pw.close();
2588                                 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
2589                         }
2590                 }
2591         }
2592
2593
2594         /**
2595          * HELPER: writeMethodCplusStub() writes the methods of the stub
2596          */
2597         private void writeMethodCplusStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses, boolean isGenCallbackStub) {
2598
2599                 boolean isDefined = false;
2600                 for (String method : methods) {
2601
2602                         List<String> methParams = intDecl.getMethodParams(method);
2603                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
2604              &nb