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