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