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