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