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