Adding skeleton generation for Java and C++; excluding specific features for now...
[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
28 import iotrmi.Java.IoTRMITypes;
29
30
31 /** Class IoTCompiler is the main interface/stub compiler for
32  *  files generation. This class calls helper classes
33  *  such as Parser, Lexer, InterfaceDecl, CapabilityDecl,
34  *  RequiresDecl, ParseTreeHandler, etc.
35  *
36  * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
37  * @version     1.0
38  * @since       2016-09-22
39  */
40 public class IoTCompiler {
41
42         /**
43          * Class properties
44          */
45         // Maps multiple interfaces to multiple objects of ParseTreeHandler
46         private Map<String,ParseTreeHandler> mapIntfacePTH;
47         private Map<String,DeclarationHandler> mapIntDeclHand;
48         private Map<String,Map<String,Set<String>>> mapInt2NewInts;
49         // Data structure to store our types (primitives and non-primitives) for compilation
50         private Map<String,String> mapPrimitives;
51         private Map<String,String> mapNonPrimitivesJava;
52         private Map<String,String> mapNonPrimitivesCplus;
53         // Other data structures
54         private Map<String,Integer> mapIntfaceObjId;            // Maps interface name to object Id
55         private Map<String,Integer> mapNewIntfaceObjId;         // Maps new interface name to its object Id (keep track of stubs)
56         private PrintWriter pw;
57         private String dir;
58         private String subdir;
59
60         /**
61          * Class constants
62          */
63         private final static String OUTPUT_DIRECTORY = "output_files";
64
65         private enum ParamCategory {
66
67                 PRIMITIVES,             // All the primitive types, e.g. byte, short, int, long, etc.
68                 NONPRIMITIVES,  // Non-primitive types, e.g. Set, Map, List, etc.
69                 USERDEFINED             // Non-supported type by default; assumed as driver classes
70         }
71
72         /**
73          * Class constructors
74          */
75         public IoTCompiler() {
76
77                 mapIntfacePTH = new HashMap<String,ParseTreeHandler>();
78                 mapIntDeclHand = new HashMap<String,DeclarationHandler>();
79                 mapInt2NewInts = new HashMap<String,Map<String,Set<String>>>();
80                 mapIntfaceObjId = new HashMap<String,Integer>();
81                 mapNewIntfaceObjId = new HashMap<String,Integer>();
82                 mapPrimitives = new HashMap<String,String>();
83                         arraysToMap(mapPrimitives, IoTRMITypes.primitivesJava, IoTRMITypes.primitivesCplus);
84                 mapNonPrimitivesJava = new HashMap<String,String>();
85                         arraysToMap(mapNonPrimitivesJava, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitiveJavaLibs);
86                 mapNonPrimitivesCplus = new HashMap<String,String>();
87                         arraysToMap(mapNonPrimitivesCplus, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitivesCplus);
88                 pw = null;
89                 dir = OUTPUT_DIRECTORY;
90                 subdir = null;
91         }
92
93
94         /**
95          * setDataStructures() sets parse tree and other data structures based on policy files.
96          * <p>
97          * It also generates parse tree (ParseTreeHandler) and
98          * copies useful information from parse tree into
99          * InterfaceDecl, CapabilityDecl, and RequiresDecl 
100          * data structures.
101          * Additionally, the data structure handles are
102          * returned from tree-parsing for further process.
103          *
104          */
105         public void setDataStructures(String origInt, ParseNode pnPol, ParseNode pnReq) {
106
107                 ParseTreeHandler ptHandler = new ParseTreeHandler(origInt, pnPol, pnReq);
108                 DeclarationHandler decHandler = new DeclarationHandler();
109                 // Process ParseNode and generate Declaration objects
110                 ptHandler.processInterfaceDecl();
111                 InterfaceDecl intDecl = ptHandler.getInterfaceDecl();
112                 decHandler.addInterfaceDecl(origInt, intDecl);
113                 ptHandler.processCapabilityDecl();
114                 CapabilityDecl capDecl = ptHandler.getCapabilityDecl();
115                 decHandler.addCapabilityDecl(origInt, capDecl);
116                 ptHandler.processRequiresDecl();
117                 RequiresDecl reqDecl = ptHandler.getRequiresDecl();
118                 decHandler.addRequiresDecl(origInt, reqDecl);
119
120                 mapIntfacePTH.put(origInt, ptHandler);
121                 mapIntDeclHand.put(origInt, decHandler);
122                 // Set object Id counter to 0 for each interface
123                 mapIntfaceObjId.put(origInt, new Integer(0));
124         }
125
126
127         /**
128          * getMethodsForIntface() reads for methods in the data structure
129          * <p>
130          * It is going to give list of methods for a certain interface
131          *              based on the declaration of capabilities.
132          */
133         public void getMethodsForIntface(String origInt) {
134
135                 ParseTreeHandler ptHandler = mapIntfacePTH.get(origInt);
136                 Map<String,Set<String>> mapNewIntMethods = new HashMap<String,Set<String>>();
137                 // Get set of new interfaces, e.g. CameraWithCaptureAndData
138                 // Generate this new interface with all the methods it needs
139                 //              from different capabilities it declares
140                 DeclarationHandler decHandler = mapIntDeclHand.get(origInt);
141                 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(origInt);
142                 Set<String> setIntfaces = reqDecl.getInterfaces();
143                 for (String strInt : setIntfaces) {
144
145                         // Initialize a set of methods
146                         Set<String> setMethods = new HashSet<String>();
147                         // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc.
148                         List<String> listCapab = reqDecl.getCapabList(strInt);
149                         for (String strCap : listCapab) {
150
151                                 // Get list of methods for each capability
152                                 CapabilityDecl capDecl = (CapabilityDecl) decHandler.getCapabilityDecl(origInt);
153                                 List<String> listCapabMeth = capDecl.getMethods(strCap);
154                                 for (String strMeth : listCapabMeth) {
155
156                                         // Add methods into setMethods
157                                         // This is to also handle redundancies (say two capabilities
158                                         //              share the same methods)
159                                         setMethods.add(strMeth);
160                                 }
161                         }
162                         // Add interface and methods information into map
163                         mapNewIntMethods.put(strInt, setMethods);
164                 }
165                 // Map the map of interface-methods to the original interface
166                 mapInt2NewInts.put(origInt, mapNewIntMethods);
167         }
168
169
170         /**
171          * HELPER: writeMethodJavaInterface() writes the method of the interface
172          */
173         private void writeMethodJavaInterface(Collection<String> methods, InterfaceDecl intDecl) {
174
175                 for (String method : methods) {
176
177                         List<String> methParams = intDecl.getMethodParams(method);
178                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
179                         print("public " + intDecl.getMethodType(method) + " " +
180                                 intDecl.getMethodId(method) + "(");
181                         for (int i = 0; i < methParams.size(); i++) {
182                                 // Check for params with driver class types and exchange it 
183                                 //              with its remote interface
184                                 String paramType = checkAndGetParamClass(methPrmTypes.get(i), false);
185                                 print(paramType + " " + methParams.get(i));
186                                 // Check if this is the last element (don't print a comma)
187                                 if (i != methParams.size() - 1) {
188                                         print(", ");
189                                 }
190                         }
191                         println(");");
192                 }
193         }
194
195
196         /**
197          * generateJavaLocalInterface() writes the local interface and provides type-checking.
198          * <p>
199          * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
200          * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
201          * The local interface has to be the input parameter for the stub and the stub 
202          * interface has to be the input parameter for the local class.
203          */
204         public void generateJavaLocalInterfaces() throws IOException {
205
206                 // Create a new directory
207                 createDirectory(dir);
208                 for (String intface : mapIntfacePTH.keySet()) {
209                         // Open a new file to write into
210                         FileWriter fw = new FileWriter(dir + "/" + intface + ".java");
211                         pw = new PrintWriter(new BufferedWriter(fw));
212                         // Pass in set of methods and get import classes
213                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
214                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
215                         List<String> methods = intDecl.getMethods();
216                         Set<String> importClasses = getImportClasses(methods, intDecl);
217                         printImportStatements(importClasses);
218                         // Write interface header
219                         println("");
220                         println("public interface " + intface + " {");
221                         // Write methods
222                         writeMethodJavaInterface(methods, intDecl);
223                         println("}");
224                         pw.close();
225                         System.out.println("IoTCompiler: Generated local interface " + intface + ".java...");
226                 }
227         }
228
229
230         /**
231          * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
232          */
233         public void generateJavaInterfaces() throws IOException {
234
235                 // Create a new directory
236                 String path = createDirectories(dir, subdir);
237                 for (String intface : mapIntfacePTH.keySet()) {
238
239                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
240                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
241
242                                 // Open a new file to write into
243                                 String newIntface = intMeth.getKey();
244                                 FileWriter fw = new FileWriter(path + "/" + newIntface + ".java");
245                                 pw = new PrintWriter(new BufferedWriter(fw));
246                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
247                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
248                                 // Pass in set of methods and get import classes
249                                 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
250                                 printImportStatements(importClasses);
251                                 // Write interface header
252                                 println("");
253                                 println("public interface " + newIntface + " {");
254                                 // Write methods
255                                 writeMethodJavaInterface(intMeth.getValue(), intDecl);
256                                 println("}");
257                                 pw.close();
258                                 System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
259                         }
260                 }
261         }
262
263
264         /**
265          * HELPER: writePropertiesJavaStub() writes the properties of the stub class
266          */
267         private void writePropertiesJavaStub(String intface, String newIntface) {
268
269                 println("private IoTRMICall rmiCall;");
270                 //println("private IoTRMIObject rmiObj;");
271                 println("private String address;");
272                 println("private int[] ports;\n");
273                 // Get the object Id
274                 Integer objId = mapIntfaceObjId.get(intface);
275                 println("private final static int objectId = " + objId + ";");
276                 mapNewIntfaceObjId.put(newIntface, objId);
277                 mapIntfaceObjId.put(intface, objId++);
278                 println("\n");
279         }
280
281
282         /**
283          * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
284          */
285         private void writeConstructorJavaStub(String intface) {
286
287                 println("public " + intface + "(int _port, String _address, int _rev, int[] _ports) throws Exception {");
288                 println("address = _address;");
289                 println("ports = _ports;");
290                 println("rmiCall = new IoTRMICall(_port, _address, _rev);");
291                 println("}\n");
292         }
293
294
295         /**
296          * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class
297          */
298         private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
299                         List<String> methPrmTypes, String method) {
300
301                 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
302                 String retType = intDecl.getMethodType(method);
303                 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
304                 // Generate array of parameter types
305                 print("Class<?>[] paramCls = new Class<?>[] { ");
306                 for (int i = 0; i < methParams.size(); i++) {
307                         String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
308                         print(getSimpleType(paramType) + ".class");
309                         // Check if this is the last element (don't print a comma)
310                         if (i != methParams.size() - 1) {
311                                 print(", ");
312                         }
313                 }
314                 println(" };");
315                 // Generate array of parameter objects
316                 print("Object[] paramObj = new Object[] { ");
317                 for (int i = 0; i < methParams.size(); i++) {
318                         print(getSimpleIdentifier(methParams.get(i)));
319                         // Check if this is the last element (don't print a comma)
320                         if (i != methParams.size() - 1) {
321                                 print(", ");
322                         }
323                 }
324                 println(" };");
325                 // Check if this is "void"
326                 if (retType.equals("void")) {
327                         println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
328                 } else { // We do have a return value
329                 // Check if the return value NONPRIMITIVES
330                         if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
331                                 String[] retGenValType = getTypeOfGeneric(retType);
332                                 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
333                                 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
334                                 println("return (" + retType + ")retObj;");
335                         } else {
336                                 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
337                                 println("return (" + retType + ")retObj;");
338                         }
339                 }
340         }
341
342
343         /**
344          * HELPER: writeMethodJavaStub() writes the method of the stub class
345          */
346         private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl) {
347
348                 for (String method : methods) {
349
350                         List<String> methParams = intDecl.getMethodParams(method);
351                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
352                         print("public " + intDecl.getMethodType(method) + " " +
353                                 intDecl.getMethodId(method) + "(");
354                         for (int i = 0; i < methParams.size(); i++) {
355
356                                 print(methPrmTypes.get(i) + " " + methParams.get(i));
357                                 // Check if this is the last element (don't print a comma)
358                                 if (i != methParams.size() - 1) {
359                                         print(", ");
360                                 }
361                         }
362                         println(") {");
363                         // Now, write the body of stub!
364                         writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
365                         println("}\n");
366                 }
367         }
368
369
370         /**
371          * generateJavaStubClasses() generate stubs based on the methods list in Java
372          */
373         public void generateJavaStubClasses() throws IOException {
374
375                 // Create a new directory
376                 String path = createDirectories(dir, subdir);
377                 for (String intface : mapIntfacePTH.keySet()) {
378
379                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
380                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
381
382                                 // Open a new file to write into
383                                 String newIntface = intMeth.getKey();
384                                 String newStubClass = newIntface + "_Stub";
385                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
386                                 pw = new PrintWriter(new BufferedWriter(fw));
387                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
388                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
389                                 // Pass in set of methods and get import classes
390                                 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
391                                 List<String> stdImportClasses = getStandardJavaImportClasses();
392                                 List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
393                                 printImportStatements(allImportClasses); println("");
394                                 // Write class header
395                                 println("public class " + newStubClass + " implements " + newIntface + " {\n");
396                                 // Write properties
397                                 writePropertiesJavaStub(intface, newIntface);
398                                 // Write constructor
399                                 writeConstructorJavaStub(newStubClass);
400                                 // Write methods
401                                 writeMethodJavaStub(intMeth.getValue(), intDecl);
402                                 println("}");
403                                 pw.close();
404                                 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
405                         }
406                 }
407         }
408
409
410         /**
411          * HELPER: writePropertiesJavaSkeleton() writes the properties of the skeleton class
412          */
413         private void writePropertiesJavaSkeleton(String intface) {
414
415                 println("private " + intface + " mainObj;");
416                 //println("private int ports;");
417                 //println("private IoTRMICall rmiCall;");
418                 println("private IoTRMIObject rmiObj;\n");
419                 // Keep track of object Ids of all stubs registered to this interface
420                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
421                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
422                         String newIntface = intMeth.getKey();
423                         int newObjectId = mapNewIntfaceObjId.get(newIntface);
424                         println("private final static int object" + newObjectId + "Id = " + 
425                                 newObjectId + ";\t//" + newIntface);
426                 }
427                 println("\n");
428         }
429
430
431         /**
432          * HELPER: writeConstructorJavaSkeleton() writes the constructor of the skeleton class
433          */
434         private void writeConstructorJavaSkeleton(String newSkelClass, String intface) {
435
436                 println("public " + newSkelClass + "(" + intface + " _mainObj, int _port) throws Exception {");
437                 println("mainObj = _mainObj;");
438                 println("rmiObj = new IoTRMIObject(_port);");
439                 //println("set0Allowed = Arrays.asList(object0Permission);");
440                 println("___waitRequestInvokeMethod();");
441                 println("}\n");
442         }
443
444
445         /**
446          * HELPER: writeStdMethodBodyJavaSkeleton() writes the standard method body in the skeleton class
447          */
448         private void writeStdMethodBodyJavaSkeleton(List<String> methParams, String methodId, String methodType) {
449
450                 if (methodType.equals("void"))
451                         print("mainObj." + methodId + "(");
452                 else
453                         print("return mainObj." + methodId + "(");
454                 for (int i = 0; i < methParams.size(); i++) {
455
456                         print(getSimpleIdentifier(methParams.get(i)));
457                         // Check if this is the last element (don't print a comma)
458                         if (i != methParams.size() - 1) {
459                                 print(", ");
460                         }
461                 }
462                 println(");");
463         }
464
465
466         /**
467          * HELPER: writeMethodJavaSkeleton() writes the method of the skeleton class
468          */
469         private void writeMethodJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
470
471                 for (String method : methods) {
472
473                         List<String> methParams = intDecl.getMethodParams(method);
474                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
475                         String methodId = intDecl.getMethodId(method);
476                         print("public " + intDecl.getMethodType(method) + " " + methodId + "(");
477                         for (int i = 0; i < methParams.size(); i++) {
478
479                                 print(methPrmTypes.get(i) + " " + methParams.get(i));
480                                 // Check if this is the last element (don't print a comma)
481                                 if (i != methParams.size() - 1) {
482                                         print(", ");
483                                 }
484                         }
485                         println(") {");
486                         // Now, write the body of skeleton!
487                         writeStdMethodBodyJavaSkeleton(methParams, methodId, intDecl.getMethodType(method));
488                         println("}\n");
489                 }
490         }
491
492
493         /**
494          * HELPER: writeStdMethodHelperBodyJavaSkeleton() writes the standard method body helper in the skeleton class
495          */
496         private void writeStdMethodHelperBodyJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
497                         List<String> methPrmTypes, String method) {
498                 // Generate array of parameter objects
499                 print("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { ");
500                 for (int i = 0; i < methParams.size(); i++) {
501                         String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
502                         print(getSimpleType(paramType) + ".class");
503                         // Check if this is the last element (don't print a comma)
504                         if (i != methParams.size() - 1)
505                                 print(", ");
506                 }
507                 println(" }, ");
508                 // Generate generic class if it's a generic type.. null otherwise
509                 print("new Class<?>[] { ");
510                 for (int i = 0; i < methParams.size(); i++) {
511                         String prmType = methPrmTypes.get(i);
512                         if (getParamCategory(prmType) == ParamCategory.NONPRIMITIVES)
513                                 print(getTypeOfGeneric(prmType)[0] + ".class");
514                         else
515                                 print("null");
516                         if (i != methParams.size() - 1)
517                                 print(", ");
518                 }
519                 println(" });");
520                 // Check if this is "void"
521                 String retType = intDecl.getMethodType(method);
522                 if (retType.equals("void")) {
523                         print(intDecl.getMethodId(method) + "(");
524                 } else { // We do have a return value
525                         print("Object retObj = " + intDecl.getMethodId(method) + "(");
526                 }
527                 for (int i = 0; i < methParams.size(); i++) {
528                         String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
529                         print("(" + paramType + ") paramObj[" + i + "]");
530                         if (i != methParams.size() - 1)
531                                 print(", ");
532                 }
533                 println(");");
534                 if (!retType.equals("void"))
535                         println("rmiObj.sendReturnObj(retObj);");
536         }
537
538
539         /**
540          * HELPER: writeMethodHelperJavaSkeleton() writes the method helper of the skeleton class
541          */
542         private void writeMethodHelperJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
543
544                 // Use this set to handle two same methodIds
545                 Set<String> uniqueMethodIds = new HashSet<String>();
546                 for (String method : methods) {
547
548                         List<String> methParams = intDecl.getMethodParams(method);
549                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
550                         String methodId = intDecl.getMethodId(method);
551                         print("public void ___");
552                         String helperMethod = methodId;
553                         if (uniqueMethodIds.contains(methodId))
554                                 helperMethod = helperMethod + intDecl.getMethodNumId(method);
555                         else
556                                 uniqueMethodIds.add(methodId);
557                         // Check if this is "void"
558                         String retType = intDecl.getMethodType(method);
559                         if (retType.equals("void"))
560                                 println(helperMethod + "() {");
561                         else
562                                 println(helperMethod + "() throws IOException {");
563                         // Now, write the helper body of skeleton!
564                         writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method);
565                         println("}\n");
566                 }
567         }
568
569
570         /**
571          * HELPER: writeJavaWaitRequestInvokeMethod() writes the main loop of the skeleton class
572          */
573         private void writeJavaWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl) {
574
575                 // Use this set to handle two same methodIds
576                 Set<String> uniqueMethodIds = new HashSet<String>();
577                 println("private void ___waitRequestInvokeMethod() throws IOException {");
578                 // Write variables here if we have callbacks or enums or structs
579                 println("while (true) {");
580                 println("rmiObj.getMethodBytes();");
581                 println("int _objectId = rmiObj.getObjectId();");
582                 println("int methodId = rmiObj.getMethodId();");
583                 // TODO: code the permission check here!
584                 println("switch (methodId) {");
585                 // Print methods and method Ids
586                 for (String method : methods) {
587                         String methodId = intDecl.getMethodId(method);
588                         int methodNumId = intDecl.getMethodNumId(method);
589                         print("case " + methodNumId + ": ___");
590                         String helperMethod = methodId;
591                         if (uniqueMethodIds.contains(methodId))
592                                 helperMethod = helperMethod + methodNumId;
593                         else
594                                 uniqueMethodIds.add(methodId);
595                         println(helperMethod + "(); break;");
596                 }
597                 println("default: ");
598                 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
599                 println("}");
600                 println("}");
601                 println("}\n");
602         }
603
604
605         /**
606          * generateJavaSkeletonClass() generate skeletons based on the methods list in Java
607          */
608         public void generateJavaSkeletonClass() throws IOException {
609
610                 // Create a new directory
611                 createDirectory(dir);
612                 for (String intface : mapIntfacePTH.keySet()) {
613                         // Open a new file to write into
614                         String newSkelClass = intface + "_Skeleton";
615                         FileWriter fw = new FileWriter(dir + "/" + newSkelClass + ".java");
616                         pw = new PrintWriter(new BufferedWriter(fw));
617                         // Pass in set of methods and get import classes
618                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
619                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
620                         List<String> methods = intDecl.getMethods();
621                         Set<String> importClasses = getImportClasses(methods, intDecl);
622                         List<String> stdImportClasses = getStandardJavaImportClasses();
623                         List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
624                         printImportStatements(allImportClasses);
625                         // Write class header
626                         println("");
627                         println("public class " + newSkelClass  + " implements " + intface + " {\n");
628                         // Write properties
629                         writePropertiesJavaSkeleton(intface);
630                         // Write constructor
631                         writeConstructorJavaSkeleton(newSkelClass, intface);
632                         // Write methods
633                         writeMethodJavaSkeleton(methods, intDecl);
634                         // Write method helper
635                         writeMethodHelperJavaSkeleton(methods, intDecl);
636                         // Write waitRequestInvokeMethod() - main loop
637                         writeJavaWaitRequestInvokeMethod(methods, intDecl);
638                         println("}");
639                         pw.close();
640                         System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".java...");
641                 }
642         }
643
644
645         /**
646          * HELPER: writeMethodCplusInterface() writes the method of the interface
647          */
648         private void writeMethodCplusInterface(Collection<String> methods, InterfaceDecl intDecl) {
649
650                 for (String method : methods) {
651
652                         List<String> methParams = intDecl.getMethodParams(method);
653                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
654                         print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
655                                 intDecl.getMethodId(method) + "(");
656                         for (int i = 0; i < methParams.size(); i++) {
657                                 // Check for params with driver class types and exchange it 
658                                 //              with its remote interface
659                                 String paramType = checkAndGetParamClass(methPrmTypes.get(i), true);
660                                 paramType = checkAndGetCplusType(paramType);
661                                 // Check for arrays - translate into vector in C++
662                                 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
663                                 print(paramComplete);
664                                 // Check if this is the last element (don't print a comma)
665                                 if (i != methParams.size() - 1) {
666                                         print(", ");
667                                 }
668                         }
669                         println(") = 0;");
670                 }
671         }
672
673
674         /**
675          * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking.
676          * <p>
677          * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
678          * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
679          * The local interface has to be the input parameter for the stub and the stub 
680          * interface has to be the input parameter for the local class.
681          */
682         public void generateCplusLocalInterfaces() throws IOException {
683
684                 // Create a new directory
685                 createDirectory(dir);
686                 for (String intface : mapIntfacePTH.keySet()) {
687                         // Open a new file to write into
688                         FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
689                         pw = new PrintWriter(new BufferedWriter(fw));
690                         // Write file headers
691                         println("#ifndef _" + intface.toUpperCase() + "_HPP__");
692                         println("#define _" + intface.toUpperCase() + "_HPP__");
693                         println("#include <iostream>");
694                         // Pass in set of methods and get include classes
695                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
696                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
697                         List<String> methods = intDecl.getMethods();
698                         Set<String> includeClasses = getIncludeClasses(methods, intDecl);
699                         printIncludeStatements(includeClasses); println("");
700                         println("using namespace std;\n");
701                         println("class " + intface); println("{");
702                         println("public:");
703                         // Write methods
704                         writeMethodCplusInterface(methods, intDecl);
705                         println("};");
706                         println("#endif");
707                         pw.close();
708                         System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
709                 }
710         }
711
712
713         /**
714          * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
715          * <p>
716          * For C++ we use virtual classe as interface
717          */
718         public void generateCPlusInterfaces() throws IOException {
719
720                 // Create a new directory
721                 String path = createDirectories(dir, subdir);
722                 for (String intface : mapIntfacePTH.keySet()) {
723
724                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
725                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
726
727                                 // Open a new file to write into
728                                 String newIntface = intMeth.getKey();
729                                 FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp");
730                                 pw = new PrintWriter(new BufferedWriter(fw));
731                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
732                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
733                                 // Write file headers
734                                 println("#ifndef _" + newIntface.toUpperCase() + "_HPP__");
735                                 println("#define _" + newIntface.toUpperCase() + "_HPP__");
736                                 println("#include <iostream>");
737                                 // Pass in set of methods and get import classes
738                                 Set<String> includeClasses = getIncludeClasses(intMeth.getValue(), intDecl);
739                                 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
740                                 List<String> allIncludeClasses = getAllImportClasses(stdIncludeClasses, includeClasses);
741                                 printIncludeStatements(allIncludeClasses); println("");                 
742                                 println("using namespace std;\n");
743                                 println("class " + newIntface);
744                                 println("{");
745                                 println("public:");
746                                 // Write methods
747                                 writeMethodCplusInterface(intMeth.getValue(), intDecl);
748                                 println("};");
749                                 println("#endif");
750                                 pw.close();
751                                 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
752                         }
753                 }
754         }
755
756
757         /**
758          * HELPER: writeMethodCplusStub() writes the method of the stub
759          */
760         private void writeMethodCplusStub(Collection<String> methods, InterfaceDecl intDecl) {
761
762                 for (String method : methods) {
763
764                         List<String> methParams = intDecl.getMethodParams(method);
765                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
766                         print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
767                                 intDecl.getMethodId(method) + "(");
768                         for (int i = 0; i < methParams.size(); i++) {
769                                 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
770                                 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
771                                 print(methParamComplete);
772                                 // Check if this is the last element (don't print a comma)
773                                 if (i != methParams.size() - 1) {
774                                         print(", ");
775                                 }
776                         }
777                         println(") { ");
778                         writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method);
779                         println("}\n");
780                 }
781         }
782
783
784         /**
785          * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class
786          */
787         private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
788                         List<String> methPrmTypes, String method) {
789
790                 println("int numParam = " + methParams.size() + ";");
791                 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
792                 String retType = intDecl.getMethodType(method);
793                 String retTypeC = checkAndGetCplusType(retType);
794                 println("string retType = \"" + checkAndGetCplusArrayType(retTypeC) + "\";");
795                 // Generate array of parameter types
796                 print("string paramCls[] = { ");
797                 for (int i = 0; i < methParams.size(); i++) {
798                         String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
799                         String paramType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
800                         print("\"" + paramType + "\"");
801                         // Check if this is the last element (don't print a comma)
802                         if (i != methParams.size() - 1) {
803                                 print(", ");
804                         }
805                 }
806                 println(" };");
807                 // Generate array of parameter objects
808                 print("void* paramObj[] = { ");
809                 for (int i = 0; i < methParams.size(); i++) {
810                         print("&" + checkAndGetCplusType(getSimpleIdentifier(methParams.get(i))));
811                         // Check if this is the last element (don't print a comma)
812                         if (i != methParams.size() - 1) {
813                                 print(", ");
814                         }
815                 }
816                 println(" };");
817                 // Check if this is "void"
818                 if (retType.equals("void")) {
819                         println("void* retObj = NULL;");
820                         println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
821                 } else { // We do have a return value
822                         if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
823                                 println(checkAndGetCplusType(retType) + " retVal;");
824                         else
825                                 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
826                         println("void* retObj = &retVal;");
827                         println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
828                         println("return retVal;");
829                 }
830         }
831
832
833         /**
834          * HELPER: writePropertiesCplusStub() writes the properties of the stub class
835          */
836         private void writePropertiesCplusStub(String intface, String newIntface) {
837
838                 println("IoTRMICall\t\t\t*rmiCall;");
839                 //println("IoTRMIObject\t\t\t*rmiObj;");
840                 println("string\t\t\t\taddress;");
841                 println("vector<int>\t\t\tports;\n");
842                 // Get the object Id
843                 Integer objId = mapIntfaceObjId.get(intface);
844                 println("const static int\tobjectId = " + objId + ";");
845                 mapNewIntfaceObjId.put(newIntface, objId);
846                 mapIntfaceObjId.put(intface, objId++);
847                 println("\n");
848         }
849
850
851         /**
852          * HELPER: writeConstructorCplusStub() writes the constructor of the stub class
853          */
854         private void writeConstructorCplusStub(String newStubClass) {
855
856                 println(newStubClass + 
857                         "(int _port, const char* _address, int _rev, bool* _bResult, vector<int> _ports) {");
858                 println("address = _address;");
859                 println("ports = _ports;");
860                 println("rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);");
861                 println("}\n");
862         }
863
864
865         /**
866          * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
867          */
868         private void writeDeconstructorCplusStub(String newStubClass) {
869
870                 println("~" + newStubClass + "() {");
871                 println("if (rmiCall != NULL) {");
872                 println("delete rmiCall;");
873                 println("rmiCall = NULL;");
874                 println("}");
875                 println("}");
876                 println("");
877                 // Check if this is callback!!! and print "delete rmiObj and vecCBObj"
878         }
879
880
881         /**
882          * generateCPlusStubClasses() generate stubs based on the methods list in C++
883          */
884         public void generateCPlusStubClasses() throws IOException {
885
886                 // Create a new directory
887                 String path = createDirectories(dir, subdir);
888                 for (String intface : mapIntfacePTH.keySet()) {
889
890                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
891                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
892                                 // Open a new file to write into
893                                 String newIntface = intMeth.getKey();
894                                 String newStubClass = newIntface + "_Stub";
895                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
896                                 pw = new PrintWriter(new BufferedWriter(fw));
897                                 // Write file headers
898                                 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
899                                 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
900                                 println("#include <iostream>");
901                                 println("#include \"" + newIntface + ".hpp\""); println("");            
902                                 println("using namespace std;"); println("");
903                                 println("class " + newStubClass + " : public " + newIntface); println("{");
904                                 println("private:\n");
905                                 writePropertiesCplusStub(intface, newIntface);
906                                 println("public:\n");
907                                 // Add default constructor and destructor
908                                 println(newStubClass + "() { }"); println("");
909                                 writeConstructorCplusStub(newStubClass);
910                                 writeDeconstructorCplusStub(newStubClass);
911                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
912                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
913                                 // Write methods
914                                 writeMethodCplusStub(intMeth.getValue(), intDecl);
915                                 print("}"); println(";");
916                                 println("#endif");
917                                 pw.close();
918                                 System.out.println("IoTCompiler: Generated stub class " + newIntface + ".hpp...");
919                         }
920                 }
921         }
922
923
924         /**
925          * HELPER: writePropertiesCplusSkeleton() writes the properties of the skeleton class
926          */
927         private void writePropertiesCplusSkeleton(String intface) {
928
929                 println(intface + " *mainObj;");
930                 //println("private int ports;");
931                 //println("private IoTRMICall rmiCall;");
932                 println("IoTRMIObject *rmiObj;\n");
933                 // Keep track of object Ids of all stubs registered to this interface
934                 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
935                 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
936                         String newIntface = intMeth.getKey();
937                         int newObjectId = mapNewIntfaceObjId.get(newIntface);
938 //                      println("const static int object" + newObjectId + "Id = " + 
939 //                              newObjectId + ";\t//" + newIntface);
940                 }
941                 // TODO: CALLBACKS!
942                 // TODO: code the set of allowed functions here
943                 println("\n");
944         }
945
946
947         /**
948          * HELPER: writeConstructorCplusSkeleton() writes the constructor of the skeleton class
949          */
950         private void writeConstructorCplusSkeleton(String newSkelClass, String intface) {
951
952                 println(newSkelClass + "(" + intface + " *_mainObj, int _port) {");
953                 println("bool _bResult = false;");
954                 println("mainObj = _mainObj;");
955                 println("rmiObj = new IoTRMIObject(_port, &_bResult);");
956                 //println("set0Allowed = Arrays.asList(object0Permission);");
957                 //println("___waitRequestInvokeMethod();");
958                 println("}\n");
959         }
960
961
962         /**
963          * HELPER: writeDeconstructorCplusSkeleton() writes the deconstructor of the skeleton class
964          */
965         private void writeDeconstructorCplusSkeleton(String newSkelClass) {
966
967                 println("~" + newSkelClass + "() {");
968                 println("if (rmiObj != NULL) {");
969                 println("delete rmiObj;");
970                 println("rmiObj = NULL;");
971                 println("}");
972                 println("}");
973                 println("");
974                 // Check if this is callback!!! and print "delete rmiObj and vecCBObj"
975         }
976
977
978         /**
979          * HELPER: writeStdMethodBodyCplusSkeleton() writes the standard method body in the skeleton class
980          */
981         private void writeStdMethodBodyCplusSkeleton(List<String> methParams, String methodId, String methodType) {
982
983                 if (methodType.equals("void"))
984                         print("mainObj->" + methodId + "(");
985                 else
986                         print("return mainObj->" + methodId + "(");
987                 for (int i = 0; i < methParams.size(); i++) {
988
989                         print(getSimpleIdentifier(methParams.get(i)));
990                         // Check if this is the last element (don't print a comma)
991                         if (i != methParams.size() - 1) {
992                                 print(", ");
993                         }
994                 }
995                 println(");");
996         }
997
998
999         /**
1000          * HELPER: writeMethodCplusSkeleton() writes the method of the skeleton class
1001          */
1002         private void writeMethodCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
1003
1004                 for (String method : methods) {
1005
1006                         List<String> methParams = intDecl.getMethodParams(method);
1007                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1008                         String methodId = intDecl.getMethodId(method);
1009                         String methodType = checkAndGetCplusType(intDecl.getMethodType(method));
1010                         print(methodType + " " + methodId + "(");
1011                         for (int i = 0; i < methParams.size(); i++) {
1012                                 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
1013                                 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
1014                                 print(methParamComplete);
1015                                 // Check if this is the last element (don't print a comma)
1016                                 if (i != methParams.size() - 1) {
1017                                         print(", ");
1018                                 }
1019                         }
1020                         println(") {");
1021                         // Now, write the body of skeleton!
1022                         writeStdMethodBodyCplusSkeleton(methParams, methodId, intDecl.getMethodType(method));
1023                         println("}\n");
1024                 }
1025         }
1026
1027
1028         /**
1029          * HELPER: writeStdMethodHelperBodyCplusSkeleton() writes the standard method body helper in the skeleton class
1030          */
1031         private void writeStdMethodHelperBodyCplusSkeleton(InterfaceDecl intDecl, List<String> methParams,
1032                         List<String> methPrmTypes, String method, String methodId) {
1033
1034                 // Generate array of parameter types
1035                 print("string paramCls[] = { ");
1036                 for (int i = 0; i < methParams.size(); i++) {
1037                         String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
1038                         String paramType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
1039                         print("\"" + paramType + "\"");
1040                         if (i != methParams.size() - 1) {
1041                                 print(", ");
1042                         }
1043                 }
1044                 println(" };");
1045                 println("int numParam = " + methParams.size() + ";");
1046                 // Generate parameters
1047                 for (int i = 0; i < methParams.size(); i++) {
1048                         String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
1049                         String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
1050                         println(methParamComplete + ";");
1051                 }
1052                 // Generate array of parameter objects
1053                 print("void* paramObj[] = { ");
1054                 for (int i = 0; i < methParams.size(); i++) {
1055                         print("&" + getSimpleIdentifier(methParams.get(i)));
1056                         if (i != methParams.size() - 1) {
1057                                 print(", ");
1058                         }
1059                 }
1060                 println(" };");
1061                 println("rmiObj->getMethodParams(paramCls, numParam, paramObj);");
1062                 String retType = intDecl.getMethodType(method);
1063                 // Check if this is "void"
1064                 if (retType.equals("void")) {
1065                         print(methodId + "(");
1066                         for (int i = 0; i < methParams.size(); i++) {
1067                                 print(getSimpleIdentifier(methParams.get(i)));
1068                                 if (i != methParams.size() - 1) {
1069                                         print(", ");
1070                                 }
1071                         }
1072                         println(");");
1073                 } else { // We do have a return value
1074                         print(checkAndGetCplusType(retType) + " retVal = " + methodId + "(");
1075                         for (int i = 0; i < methParams.size(); i++) {
1076                                 print(getSimpleIdentifier(methParams.get(i)));
1077                                 if (i != methParams.size() - 1) {
1078                                         print(", ");
1079                                 }
1080                         }
1081                         println(");");
1082                         println("void* retObj = &retVal;");
1083                         String retTypeC = checkAndGetCplusType(retType);
1084                         println("rmiObj->sendReturnObj(retObj, \"" + checkAndGetCplusArrayType(retTypeC) + "\");");
1085                 }
1086         }
1087
1088
1089         /**
1090          * HELPER: writeMethodHelperCplusSkeleton() writes the method helper of the skeleton class
1091          */
1092         private void writeMethodHelperCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
1093
1094                 // Use this set to handle two same methodIds
1095                 Set<String> uniqueMethodIds = new HashSet<String>();
1096                 for (String method : methods) {
1097
1098                         List<String> methParams = intDecl.getMethodParams(method);
1099                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1100                         String methodId = intDecl.getMethodId(method);
1101                         print("void ___");
1102                         String helperMethod = methodId;
1103                         if (uniqueMethodIds.contains(methodId))
1104                                 helperMethod = helperMethod + intDecl.getMethodNumId(method);
1105                         else
1106                                 uniqueMethodIds.add(methodId);
1107                         // Check if this is "void"
1108                         String retType = intDecl.getMethodType(method);
1109                         println(helperMethod + "() {");
1110                         // Now, write the helper body of skeleton!
1111                         writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId);
1112                         println("}\n");
1113                 }
1114         }
1115
1116
1117         /**
1118          * HELPER: writeCplusWaitRequestInvokeMethod() writes the main loop of the skeleton class
1119          */
1120         private void writeCplusWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl) {
1121
1122                 // Use this set to handle two same methodIds
1123                 Set<String> uniqueMethodIds = new HashSet<String>();
1124                 println("void ___waitRequestInvokeMethod() {");
1125                 // Write variables here if we have callbacks or enums or structs
1126                 println("while (true) {");
1127                 println("rmiObj->getMethodBytes();");
1128                 println("int _objectId = rmiObj->getObjectId();");
1129                 println("int methodId = rmiObj->getMethodId();");
1130                 // TODO: code the permission check here!
1131                 println("switch (methodId) {");
1132                 // Print methods and method Ids
1133                 for (String method : methods) {
1134                         String methodId = intDecl.getMethodId(method);
1135                         int methodNumId = intDecl.getMethodNumId(method);
1136                         print("case " + methodNumId + ": ___");
1137                         String helperMethod = methodId;
1138                         if (uniqueMethodIds.contains(methodId))
1139                                 helperMethod = helperMethod + methodNumId;
1140                         else
1141                                 uniqueMethodIds.add(methodId);
1142                         println(helperMethod + "(); break;");
1143                 }
1144                 println("default: ");
1145                 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
1146                 println("throw exception();");
1147                 println("}");
1148                 println("}");
1149                 println("}\n");
1150         }
1151
1152
1153         /**
1154          * generateCplusSkeletonClass() generate skeletons based on the methods list in C++
1155          */
1156         public void generateCplusSkeletonClass() throws IOException {
1157
1158                 // Create a new directory
1159                 createDirectory(dir);
1160                 for (String intface : mapIntfacePTH.keySet()) {
1161                         // Open a new file to write into
1162                         String newSkelClass = intface + "_Skeleton";
1163                         FileWriter fw = new FileWriter(dir + "/" + newSkelClass + ".hpp");
1164                         pw = new PrintWriter(new BufferedWriter(fw));
1165                         // Write file headers
1166                         println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
1167                         println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
1168                         println("#include <iostream>");
1169                         println("#include \"" + intface + ".hpp\"\n");
1170                         // Pass in set of methods and get import classes
1171                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1172                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1173                         List<String> methods = intDecl.getMethods();
1174                         Set<String> includeClasses = getIncludeClasses(methods, intDecl);
1175                         List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
1176                         List<String> allIncludeClasses = getAllImportClasses(stdIncludeClasses, includeClasses);
1177                         printIncludeStatements(allIncludeClasses); println("");                 
1178                         println("using namespace std;\n");
1179                         // Write class header
1180                         println("class " + newSkelClass + " : public " + intface); println("{");
1181                         println("private:\n");
1182                         // Write properties
1183                         writePropertiesCplusSkeleton(intface);
1184                         println("public:\n");
1185                         // Write constructor
1186                         writeConstructorCplusSkeleton(newSkelClass, intface);
1187                         // Write deconstructor
1188                         writeDeconstructorCplusSkeleton(newSkelClass);
1189                         // Write methods
1190                         writeMethodCplusSkeleton(methods, intDecl);
1191                         // Write method helper
1192                         writeMethodHelperCplusSkeleton(methods, intDecl);
1193                         // Write waitRequestInvokeMethod() - main loop
1194                         writeCplusWaitRequestInvokeMethod(methods, intDecl);
1195                         println("};");
1196                         println("#endif");
1197                         pw.close();
1198                         System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".hpp...");
1199                 }
1200         }
1201
1202
1203         /**
1204          * generateInitializer() generate initializer based on type
1205          */
1206         public String generateCplusInitializer(String type) {
1207
1208                 // Generate dummy returns for now
1209                 if (type.equals("short")||
1210                         type.equals("int")      ||
1211                         type.equals("long") ||
1212                         type.equals("float")||
1213                         type.equals("double")) {
1214
1215                         return "0";
1216                 } else if ( type.equals("String") ||
1217                                         type.equals("string")) {
1218   
1219                         return "\"\"";
1220                 } else if ( type.equals("char") ||
1221                                         type.equals("byte")) {
1222
1223                         return "\' \'";
1224                 } else if ( type.equals("boolean")) {
1225
1226                         return "false";
1227                 } else {
1228                         return "NULL";
1229                 }
1230         }
1231
1232
1233         /**
1234          * generateReturnStmt() generate return statement based on methType
1235          */
1236         public String generateReturnStmt(String methType) {
1237
1238                 // Generate dummy returns for now
1239                 if (methType.equals("short")||
1240                         methType.equals("int")  ||
1241                         methType.equals("long") ||
1242                         methType.equals("float")||
1243                         methType.equals("double")) {
1244
1245                         return "1";
1246                 } else if ( methType.equals("String")) {
1247   
1248                         return "\"a\"";
1249                 } else if ( methType.equals("char") ||
1250                                         methType.equals("byte")) {
1251
1252                         return "\'a\'";
1253                 } else if ( methType.equals("boolean")) {
1254
1255                         return "true";
1256                 } else {
1257                         return "null";
1258                 }
1259         }
1260
1261
1262         /**
1263          * setDirectory() sets a new directory for stub files
1264          */
1265         public void setDirectory(String _subdir) {
1266
1267                 subdir = _subdir;
1268         }
1269
1270
1271         /**
1272          * printUsage() prints the usage of this compiler
1273          */
1274         public static void printUsage() {
1275
1276                 System.out.println();
1277                 System.out.println("Sentinel interface and stub compiler version 1.0");
1278                 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
1279                 System.out.println("All rights reserved.");
1280                 System.out.println("Usage:");
1281                 System.out.println("\tjava IoTCompiler -help / --help / -h\n");
1282                 System.out.println("\t\tDisplay this help texts\n\n");
1283                 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>]");
1284                 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>] [options]\n");
1285                 System.out.println("\t\tTake one or more pairs of main-req policy files, and generate Java and/or C++ files\n");
1286                 System.out.println("Options:");
1287                 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
1288                 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
1289                 System.out.println();
1290         }
1291
1292
1293         /**
1294          * parseFile() prepares Lexer and Parser objects, then parses the file
1295          */
1296         public static ParseNode parseFile(String file) {
1297
1298                 ParseNode pn = null;
1299                 try {
1300                         ComplexSymbolFactory csf = new ComplexSymbolFactory();
1301                         ScannerBuffer lexer = 
1302                                 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf));
1303                         Parser parse = new Parser(lexer,csf);
1304                         pn = (ParseNode) parse.parse().value;
1305                 } catch (Exception e) {
1306                         e.printStackTrace();
1307                         throw new Error("IoTCompiler: ERROR parsing policy file or wrong command line option: " + file);
1308                 }
1309
1310                 return pn;
1311         }
1312
1313
1314         /**================
1315          * Helper functions
1316          **================
1317          */
1318         boolean newline=true;
1319         int tablevel=0;
1320
1321         private void print(String str) {
1322                 if (newline) {
1323                         int tab=tablevel;
1324                         if (str.equals("}"))
1325                                 tab--;
1326                         for(int i=0; i<tab; i++)
1327                                 pw.print("\t");
1328                 }
1329                 pw.print(str);
1330                 updatetabbing(str);
1331                 newline=false;
1332         }
1333
1334
1335         /**
1336          * This function converts Java to C++ type for compilation
1337          */
1338         private String convertType(String jType) {
1339
1340                 return mapPrimitives.get(jType);
1341         }
1342
1343
1344         private void println(String str) {
1345                 if (newline) {
1346                         int tab = tablevel;
1347                         if (str.equals("}"))
1348                                 tab--;
1349                         for(int i=0; i<tab; i++)
1350                                 pw.print("\t");
1351                 }
1352                 pw.println(str);
1353                 updatetabbing(str);
1354                 newline = true;
1355         }
1356
1357
1358         private void updatetabbing(String str) {
1359                 tablevel+=count(str,'{')-count(str,'}');
1360         }
1361
1362
1363         private int count(String str, char key) {
1364                 char[] array = str.toCharArray();
1365                 int count = 0;
1366                 for(int i=0; i<array.length; i++) {
1367                         if (array[i] == key)
1368                                 count++;
1369                 }
1370                 return count;
1371         }
1372
1373
1374         private void createDirectory(String dirName) {
1375
1376                 File file = new File(dirName);
1377                 if (!file.exists()) {
1378                         if (file.mkdir()) {
1379                                 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
1380                         } else {
1381                                 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
1382                         }
1383                 } else {
1384                         System.out.println("IoTCompiler: Directory " + dirName + " exists...");
1385                 }
1386         }
1387
1388
1389         // Create a directory and possibly a sub directory
1390         private String createDirectories(String dir, String subdir) {
1391
1392                 String path = dir;
1393                 createDirectory(path);
1394                 if (subdir != null) {
1395                         path = path + "/" + subdir;
1396                         createDirectory(path);
1397                 }
1398                 return path;
1399         }
1400
1401
1402         // Inserting array members into a Map object
1403         // that maps arrKey to arrVal objects
1404         private void arraysToMap(Map map, Object[] arrKey, Object[] arrVal) {
1405
1406                 for(int i = 0; i < arrKey.length; i++) {
1407
1408                         map.put(arrKey[i], arrVal[i]);
1409                 }
1410         }
1411
1412
1413         // Return parameter category, i.e. PRIMITIVES, NONPRIMITIVES, or USERDEFINED
1414         private ParamCategory getParamCategory(String paramType) {
1415
1416                 if (mapPrimitives.containsKey(paramType)) {
1417                         return ParamCategory.PRIMITIVES;
1418                 // We can either use mapNonPrimitivesJava or mapNonPrimitivesCplus here
1419                 } else if (mapNonPrimitivesJava.containsKey(getSimpleType(paramType))) {
1420                         return ParamCategory.NONPRIMITIVES;
1421                 } else
1422                         return ParamCategory.USERDEFINED;
1423         }
1424
1425
1426         // Return full class name for non-primitives to generate Java import statements
1427         // e.g. java.util.Set for Set, java.util.Map for Map
1428         private String getNonPrimitiveJavaClass(String paramNonPrimitives) {
1429
1430                 return mapNonPrimitivesJava.get(paramNonPrimitives);
1431         }
1432
1433
1434         // Return full class name for non-primitives to generate Cplus include statements
1435         // e.g. #include <set> for Set, #include <map> for Map
1436         private String getNonPrimitiveCplusClass(String paramNonPrimitives) {
1437
1438                 return mapNonPrimitivesCplus.get(paramNonPrimitives);
1439         }
1440
1441
1442         // Get simple types, e.g. HashSet for HashSet<...>
1443         // Basically strip off the "<...>"
1444         private String getSimpleType(String paramType) {
1445
1446                 // Check if this is generics
1447                 if(paramType.contains("<")) {
1448                         String[] type = paramType.split("<");
1449                         return type[0];
1450                 } else
1451                         return paramType;
1452         }
1453
1454
1455         // Generate a set of standard classes for import statements
1456         private List<String> getStandardJavaImportClasses() {
1457
1458                 List<String> importClasses = new ArrayList<String>();
1459                 // Add the standard list first
1460                 importClasses.add("java.io.IOException");
1461                 importClasses.add("java.util.List");
1462                 importClasses.add("java.util.ArrayList");
1463                 importClasses.add("iotrmi.Java.IoTRMICall");
1464                 importClasses.add("iotrmi.Java.IoTRMIObject");
1465
1466                 return importClasses;
1467         }
1468
1469
1470         // Generate a set of standard classes for import statements
1471         private List<String> getStandardCplusIncludeClasses() {
1472
1473                 List<String> importClasses = new ArrayList<String>();
1474                 // Add the standard list first
1475                 importClasses.add("<vector>");
1476                 importClasses.add("\"IoTRMICall.hpp\"");
1477                 importClasses.add("\"IoTRMIObject.hpp\"");
1478
1479                 return importClasses;
1480         }
1481
1482
1483         // Generate a set of standard classes for import statements
1484         private List<String> getAllImportClasses(Collection<String> stdImportClasses, Collection<String> importClasses) {
1485
1486                 List<String> allImportClasses = new ArrayList<String>(stdImportClasses);
1487                 // Iterate over the list of import classes
1488                 for (String str : importClasses) {
1489                         if (!stdImportClasses.contains(str)) {
1490                                 stdImportClasses.add(str);
1491                         }
1492                 }
1493
1494                 return allImportClasses;
1495         }
1496
1497
1498
1499         // Generate a set of classes for import statements
1500         private Set<String> getImportClasses(Collection<String> methods, InterfaceDecl intDecl) {
1501
1502                 Set<String> importClasses = new HashSet<String>();
1503                 for (String method : methods) {
1504                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1505                         for (String paramType : methPrmTypes) {
1506
1507                                 String simpleType = getSimpleType(paramType);
1508                                 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
1509                                         importClasses.add(getNonPrimitiveJavaClass(simpleType));
1510                                 }
1511                         }
1512                 }
1513                 return importClasses;
1514         }
1515
1516
1517         // Generate a set of classes for include statements
1518         private Set<String> getIncludeClasses(Collection<String> methods, InterfaceDecl intDecl) {
1519
1520                 Set<String> includeClasses = new HashSet<String>();
1521                 for (String method : methods) {
1522
1523                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1524                         List<String> methParams = intDecl.getMethodParams(method);
1525                         for (int i = 0; i < methPrmTypes.size(); i++) {
1526
1527                                 String simpleType = getSimpleType(methPrmTypes.get(i));
1528                                 String param = methParams.get(i);
1529                                 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
1530                                         includeClasses.add("<" + getNonPrimitiveCplusClass(simpleType) + ">");
1531                                 } else if (getParamCategory(simpleType) == ParamCategory.USERDEFINED) {
1532                                         includeClasses.add("\"" + exchangeParamType(simpleType) + ".hpp\"");
1533                                 } else if (param.contains("[]")) {
1534                                 // Check if this is array for C++; translate into vector
1535                                         includeClasses.add("<vector>");
1536                                 }
1537                         }
1538                 }
1539                 return includeClasses;
1540         }
1541
1542
1543         private void printImportStatements(Collection<String> importClasses) {
1544
1545                 for(String cls : importClasses) {
1546                         println("import " + cls + ";");
1547                 }
1548         }
1549
1550
1551         private void printIncludeStatements(Collection<String> includeClasses) {
1552
1553                 for(String cls : includeClasses) {
1554                         println("#include " + cls);
1555                 }
1556         }
1557
1558
1559         // Get the C++ version of a non-primitive type
1560         // e.g. set for Set and map for Map
1561         // Input nonPrimitiveType has to be generics in format
1562         private String[] getTypeOfGeneric(String nonPrimitiveType) {
1563
1564                 // Handle <, >, and , for 2-type generic/template
1565                 String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(",");
1566                 return substr;
1567         }
1568
1569
1570         // This helper function strips off array declaration, e.g. D[] becomes D
1571         private String getSimpleIdentifier(String ident) {
1572
1573                 // Handle [ for array declaration
1574                 String substr = ident;
1575                 if (ident.contains("[]")) {
1576                         substr = ident.split("\\[\\]")[0];
1577                 }
1578                 return substr;
1579         }
1580
1581
1582         private String checkAndGetCplusType(String paramType) {
1583
1584                 if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
1585                         return convertType(paramType);
1586                 } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) {
1587
1588                         // Check for generic/template format
1589                         if (paramType.contains("<") && paramType.contains(">")) {
1590
1591                                 String genericClass = getSimpleType(paramType);
1592                                 String[] genericType = getTypeOfGeneric(paramType);
1593                                 String cplusTemplate = null;
1594                                 if (genericType.length == 1) // Generic/template with one type
1595                                         cplusTemplate = getNonPrimitiveCplusClass(genericClass) + 
1596                                                 "<" + convertType(genericType[0]) + ">";
1597                                 else // Generic/template with two types
1598                                         cplusTemplate = getNonPrimitiveCplusClass(genericClass) + 
1599                                                 "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">";
1600                                 return cplusTemplate;
1601                         } else
1602                                 return getNonPrimitiveCplusClass(paramType);
1603                 } else
1604                         // Just return it as is if it's not non-primitives
1605                         return paramType;
1606         }
1607
1608
1609         // Detect array declaration, e.g. int A[],
1610         //              then generate "int A[]" in C++ as "vector<int> A"
1611         private String checkAndGetCplusArray(String paramType, String param) {
1612
1613                 String paramComplete = null;
1614                 // Check for array declaration
1615                 if (param.contains("[]")) {
1616                         paramComplete = "vector<" + paramType + "> " + param.replace("[]","");
1617                 } else
1618                         // Just return it as is if it's not an array
1619                         paramComplete = paramType + " " + param;
1620
1621                 return paramComplete;
1622         }
1623         
1624
1625         // Detect array declaration, e.g. int A[],
1626         //              then generate "int A[]" in C++ as "vector<int> A"
1627         // This method just returns the type
1628         private String checkAndGetCplusArrayType(String paramType) {
1629
1630                 String paramTypeRet = null;
1631                 // Check for array declaration
1632                 if (paramType.contains("[]")) {
1633                         String type = paramType.split("\\[\\]")[0];
1634                         paramTypeRet = checkAndGetCplusType(type) + "[]";
1635                 } else if (paramType.contains("vector")) {
1636                         // Just return it as is if it's not an array
1637                         String type = paramType.split("<")[1].split(">")[0];
1638                         paramTypeRet = checkAndGetCplusType(type) + "[]";
1639                 } else
1640                         paramTypeRet = paramType;
1641
1642                 return paramTypeRet;
1643         }
1644         
1645         
1646         // Detect array declaration, e.g. int A[],
1647         //              then generate "int A[]" in C++ as "vector<int> A"
1648         // This method just returns the type
1649         private String checkAndGetCplusArrayType(String paramType, String param) {
1650
1651                 String paramTypeRet = null;
1652                 // Check for array declaration
1653                 if (param.contains("[]")) {
1654                         paramTypeRet = checkAndGetCplusType(paramType) + "[]";
1655                 } else if (paramType.contains("vector")) {
1656                         // Just return it as is if it's not an array
1657                         String type = paramType.split("<")[1].split(">")[0];
1658                         paramTypeRet = checkAndGetCplusType(type) + "[]";
1659                 } else
1660                         paramTypeRet = paramType;
1661
1662                 return paramTypeRet;
1663         }
1664
1665
1666         // Detect array declaration, e.g. int A[],
1667         //              then generate type "int[]"
1668         private String checkAndGetArray(String paramType, String param) {
1669
1670                 String paramTypeRet = null;
1671                 // Check for array declaration
1672                 if (param.contains("[]")) {
1673                         paramTypeRet = paramType + "[]";
1674                 } else
1675                         // Just return it as is if it's not an array
1676                         paramTypeRet = paramType;
1677
1678                 return paramTypeRet;
1679         }
1680
1681
1682         // Get simple types, e.g. HashSet for HashSet<...>
1683         // Basically strip off the "<...>"
1684         private String checkAndGetParamClass(String paramType, boolean needPtr) {
1685
1686                 // Check if this is generics
1687                 if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
1688                         // If true then return with pointer (C++)
1689                         if (needPtr)
1690                                 return exchangeParamType(paramType) + "*";
1691                         else    // Java, so no pointer needed
1692                                 return exchangeParamType(paramType);
1693                 } else
1694                         return paramType;
1695         }
1696
1697
1698         // Returns the other interface for type-checking purposes for USERDEFINED
1699         //              classes based on the information provided in multiple policy files
1700         // e.g. return CameraWithXXX instead of Camera
1701         private String exchangeParamType(String intface) {
1702
1703                 // Param type that's passed is the interface name we need to look for
1704                 //              in the map of interfaces, based on available policy files.
1705                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1706                 if (decHandler != null) {
1707                 // We've found the required interface policy files
1708                         RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(intface);
1709                         Set<String> setExchInt = reqDecl.getInterfaces();
1710                         if (setExchInt.size() == 1) {
1711                                 Iterator iter = setExchInt.iterator();
1712                                 return (String) iter.next();
1713                         } else {
1714                                 throw new Error("IoTCompiler: Ambiguous stub interfaces: " + setExchInt.toString() + 
1715                                         ". Only one new interface can be declared if the object " + intface +
1716                                         " needs to be passed in as an input parameter!");
1717                         }
1718                 } else {
1719                 // NULL value - this means policy files missing
1720                         throw new Error("IoTCompiler: Parameter type lookup failed for " + intface +
1721                                 "... Please provide the necessary policy files for user-defined types." +
1722                                 " If this is an array please type the brackets after the variable name," +
1723                                 " e.g. \"String str[]\", not \"String[] str\"." +
1724                                 " If this is a Collections (Java) / STL (C++) type, this compiler only" +
1725                                 " supports List/ArrayList (Java) or list (C++).");
1726                 }
1727         }
1728
1729
1730         public static void main(String[] args) throws Exception {
1731
1732                 // If there is no argument or just "--help" or "-h", then invoke printUsage()
1733                 if ((args[0].equals("-help") ||
1734                          args[0].equals("--help")||
1735                          args[0].equals("-h"))   ||
1736                         (args.length == 0)) {
1737
1738                         IoTCompiler.printUsage();
1739
1740                 } else if (args.length > 1) {
1741
1742                         IoTCompiler comp = new IoTCompiler();
1743                         int i = 0;                              
1744                         do {
1745                                 // Parse main policy file
1746                                 ParseNode pnPol = IoTCompiler.parseFile(args[i]);
1747                                 // Parse "requires" policy file
1748                                 ParseNode pnReq = IoTCompiler.parseFile(args[i+1]);
1749                                 // Get interface name
1750                                 String intface = ParseTreeHandler.getOrigIntface(pnPol);
1751                                 comp.setDataStructures(intface, pnPol, pnReq);
1752                                 comp.getMethodsForIntface(intface);
1753                                 i = i + 2;
1754                         // 1) Check if this is the last option before "-java" or "-cplus"
1755                         // 2) Check if this is really the last option (no "-java" or "-cplus")
1756                         } while(!args[i].equals("-java") &&
1757                                         !args[i].equals("-cplus") &&
1758                                         (i < args.length));
1759
1760                         // Generate everything if we don't see "-java" or "-cplus"
1761                         if (i == args.length) {
1762                                 comp.generateJavaLocalInterfaces();
1763                                 comp.generateJavaInterfaces();
1764                                 comp.generateJavaStubClasses();
1765                                 comp.generateJavaSkeletonClass();
1766                                 comp.generateCplusLocalInterfaces();
1767                                 comp.generateCPlusInterfaces();
1768                                 comp.generateCPlusStubClasses();
1769                                 comp.generateCplusSkeletonClass();
1770                         } else {
1771                         // Check other options
1772                                 while(i < args.length) {
1773                                         // Error checking
1774                                         if (!args[i].equals("-java") &&
1775                                                 !args[i].equals("-cplus")) {
1776                                                 throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
1777                                         } else {
1778                                                 if (i + 1 < args.length) {
1779                                                         comp.setDirectory(args[i+1]);
1780                                                 } else
1781                                                         throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
1782
1783                                                 if (args[i].equals("-java")) {
1784                                                         comp.generateJavaLocalInterfaces();
1785                                                         comp.generateJavaInterfaces();
1786                                                         comp.generateJavaStubClasses();
1787                                                         comp.generateJavaSkeletonClass();
1788                                                 } else {
1789                                                         comp.generateCplusLocalInterfaces();
1790                                                         comp.generateCPlusInterfaces();
1791                                                         comp.generateCPlusStubClasses();
1792                                                         comp.generateCplusSkeletonClass();
1793                                                 }
1794                                         }
1795                                         i = i + 2;
1796                                 }
1797                         }
1798                 } else {
1799                 // Need to at least have exactly 2 parameters, i.e. main policy file and requires file
1800                         IoTCompiler.printUsage();
1801                         throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");
1802                 }
1803         }
1804 }
1805
1806
1807
1808