e79bea68700701b043b03c44eb90832e8bb5b244
[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.Collection;
7 import java.util.Collections;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Set;
13
14 import iotpolicy.parser.Lexer;
15 import iotpolicy.parser.Parser;
16 import iotpolicy.tree.ParseNode;
17 import iotpolicy.tree.ParseNodeVector;
18 import iotpolicy.tree.ParseTreeHandler;
19 import iotpolicy.tree.CapabilityDecl;
20 import iotpolicy.tree.InterfaceDecl;
21 import iotpolicy.tree.RequiresDecl;
22
23 /** Class IoTCompiler is the main interface/stub compiler for
24  *  files generation. This class calls helper classes
25  *  such as Parser, Lexer, InterfaceDecl, CapabilityDecl,
26  *  RequiresDecl, ParseTreeHandler, etc.
27  *
28  * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
29  * @version     1.0
30  * @since       2016-09-22
31  */
32 public class IoTCompiler {
33
34         /**
35          * Class properties
36          */
37         private ParseTreeHandler ptHandler;
38         private InterfaceDecl intDecl;
39         private CapabilityDecl capDecl;
40         private RequiresDecl reqDecl;
41         private Map<String,Set<String>> mapCapabMethods;
42         // Data structure to store our types (primitives and non-primitives) for compilation
43         //private Set<String> setPrimitives;
44         private Map<String,String> mapPrimitives;
45         private Map<String,String> mapNonPrimitivesJava;
46         private Map<String,String> mapNonPrimitivesCplus;
47         private PrintWriter pw;
48         private String dir;
49         private String subdir;
50
51         /**
52          * Class constants
53          */
54         private final static String OUTPUT_DIRECTORY = "output_files";
55
56         /**
57          * Primitive data types
58          */
59         private final static String[] primitives = new String[] {
60
61                 "byte",
62                 "Byte",
63                 "short",
64                 "Short",
65                 "int",
66                 "Integer",
67                 "long",
68                 "Long",
69                 "float",
70                 "Float",
71                 "double",
72                 "Double",
73                 "boolean",
74                 "Boolean",
75                 "char",
76                 "Character",
77                 "string",
78                 "String",
79                 "void"
80         };
81
82         /**
83          * Primitive data types in C++ to map the primitives list
84          */
85         private final static String[] primitivesCplus = new String[] {
86
87                 "char",
88                 "char",
89                 "short",
90                 "short",
91                 "int",
92                 "int",
93                 "long",
94                 "long",
95                 "float",
96                 "float",
97                 "double",
98                 "double",
99                 "bool",
100                 "bool",
101                 "char",
102                 "char",
103                 "string",
104                 "string",
105                 "void"
106         };
107
108         /**
109          * Non-primitive data types supported by this compiler
110          */
111         private final static String[] nonPrimitives = new String[] {
112
113                 "Set",
114                 "HashSet",
115                 "Map",
116                 "HashMap",
117                 "List",
118                 "ArrayList"
119         };
120
121         /**
122          * Non-primitive Java libraries based on the list above
123          */
124         private final static String[] nonPrimitiveJavaLibs = new String[] {
125
126                 "java.util.Set",
127                 "java.util.HashSet",
128                 "java.util.Map",
129                 "java.util.HashMap",
130                 "java.util.List",
131                 "java.util.ArrayList"
132         };
133
134         /**
135          * Non-primitive C++ libraries based on the list above
136          */
137         private final static String[] nonPrimitiveCplusLibs = new String[] {
138
139                 "set",
140                 "unordered_set",
141                 "map",
142                 "unordered_map",
143                 "list",
144                 "list"
145         };
146
147         private enum ParamCategory {
148
149                 PRIMITIVES,             // All the primitive types, e.g. byte, short, int, long, etc.
150                 NONPRIMITIVES,  // Non-primitive types, e.g. Set, Map, List, etc.
151                 USERDEFINED             // Non-supported type by default; assumed as driver classes
152         }
153
154         /**
155          * Class constructors
156          */
157         public IoTCompiler() {
158
159                 ptHandler = new ParseTreeHandler();
160                 intDecl = null;
161                 capDecl = null;
162                 capDecl = null;
163                 mapCapabMethods = new HashMap<String,Set<String>>();
164                 mapPrimitives = new HashMap<String,String>();
165                         arraysToMap(mapPrimitives, primitives, primitivesCplus);
166                 mapNonPrimitivesJava = new HashMap<String,String>();
167                         arraysToMap(mapNonPrimitivesJava, nonPrimitives, nonPrimitiveJavaLibs);
168                 mapNonPrimitivesCplus = new HashMap<String,String>();
169                         arraysToMap(mapNonPrimitivesCplus, nonPrimitives, nonPrimitiveCplusLibs);
170                 pw = null;
171                 dir = OUTPUT_DIRECTORY;
172                 subdir = null;
173         }
174
175
176         public IoTCompiler(String _intface, ParseNode _pnPol, ParseNode _pnReq) {
177
178                 ptHandler = new ParseTreeHandler(_intface, _pnPol, _pnReq);
179                 intDecl = null;
180                 capDecl = null;
181                 reqDecl = null;
182                 mapCapabMethods = new HashMap<String,Set<String>>();
183                 mapPrimitives = new HashMap<String,String>();
184                         arraysToMap(mapPrimitives, primitives, primitivesCplus);
185                 mapNonPrimitivesJava = new HashMap<String,String>();
186                         arraysToMap(mapNonPrimitivesJava, nonPrimitives, nonPrimitiveJavaLibs);
187                 mapNonPrimitivesCplus = new HashMap<String,String>();
188                         arraysToMap(mapNonPrimitivesCplus, nonPrimitives, nonPrimitiveCplusLibs);
189                 pw = null;
190                 dir = OUTPUT_DIRECTORY;
191                 subdir = null;
192         }
193
194
195         /**
196          * parsePolicyFile() parses policy file
197          * <p>
198          * It also generates parse tree and
199          * copies useful information from parse tree into
200          * InterfaceDecl, CapabilityDecl, and RequiresDecl 
201          * data structures.
202          * Additionally, the data structure handles are
203          * returned from tree-parsing for further process.
204          *
205          */
206         public void parsePolicyFile() {
207
208                 ptHandler.processInterfaceDecl();
209                 intDecl = ptHandler.getInterfaceDecl();
210
211                 ptHandler.processCapabilityDecl();
212                 capDecl = ptHandler.getCapabilityDecl();
213
214                 ptHandler.processRequiresDecl();
215                 reqDecl = ptHandler.getRequiresDecl();
216         }
217
218
219         /**
220          * getMethodsForIntface() reads for methods in the data structure
221          * <p>
222          * It is going to give list of methods for a certain interface
223          *              based on the declaration of capabilities.
224          */
225         public void getMethodsForIntface() {
226
227                 // Get set of new interfaces, e.g. CameraWithCaptureAndData
228                 // Generate this new interface with all the methods it needs
229                 //              from different capabilities it declares
230                 Set<String> setIntfaces = reqDecl.getInterfaces();
231                 for (String strInt : setIntfaces) {
232
233                         // Initialize a set of methods
234                         Set<String> setMethods = new HashSet<String>();
235                         // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc.
236                         List<String> listCapab = reqDecl.getCapabList(strInt);
237                         for (String strCap : listCapab) {
238
239                                 // Get list of methods for each capability
240                                 List<String> listCapabMeth = capDecl.getMethods(strCap);
241                                 for (String strMeth : listCapabMeth) {
242
243                                         // Add methods into setMethods
244                                         // This is to also handle redundancies (say two capabilities
245                                         //              share the same methods)
246                                         setMethods.add(strMeth);
247                                 }
248                         }
249                         // Add interface and methods information into map
250                         mapCapabMethods.put(strInt, setMethods);
251                 }
252         }
253
254
255         /**
256          * generateJavaLocalInterface() writes the local interface to provide type-checking
257          * <p>
258          * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
259          * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
260          * The local interface has to be the input parameter for the stub and the stub 
261          * interface has to be the input parameter for the local class.
262          */
263         public void generateJavaLocalInterface(String _intface) throws IOException {
264
265                 // Create a new directory
266                 createDirectory(dir);
267                 // Open a new file to write into
268                 String intface = _intface;
269                 FileWriter fw = new FileWriter(dir + "/" + intface + ".java");
270                 pw = new PrintWriter(new BufferedWriter(fw));
271                 // Pass in set of methods and get import classes
272                 List<String> methods = intDecl.getMethods();
273                 Set<String> importClasses = getImportClasses(methods);
274                 printImportStatements(importClasses);
275                 // Write interface header
276                 println("");
277                 println("public interface " + intface + " {");
278                 // Write methods
279                 for (String method : methods) {
280
281                         List<String> methParams = intDecl.getMethodParams(method);
282                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
283                         print("public " + intDecl.getMethodType(method) + " " +
284                                 intDecl.getMethodId(method) + "(");
285                         for (int i = 0; i < methParams.size(); i++) {
286                                 // Check for params with driver class types and exchange it 
287                                 //              with its remote interface
288                                 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
289                                 print(paramType + " " + methParams.get(i));
290                                 // Check if this is the last element (don't print a comma)
291                                 if (i != methParams.size() - 1) {
292                                         print(", ");
293                                 }
294                         }
295                         println(");");
296                 }
297                 println("}");
298                 pw.close();
299                 System.out.println("IoTCompiler: Generated local interface " + intface + ".java...");
300         }
301
302
303         /**
304          * generateCplusLocalInterface() writes the local interface to provide type-checking
305          * <p>
306          * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
307          * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
308          * The local interface has to be the input parameter for the stub and the stub 
309          * interface has to be the input parameter for the local class.
310          */
311         public void generateCplusLocalInterface(String _intface) throws IOException {
312
313                 // Create a new directory
314                 createDirectory(dir);
315                 // Open a new file to write into
316                 String intface = _intface;
317                 FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
318                 pw = new PrintWriter(new BufferedWriter(fw));
319                 // Write file headers
320                 println("#include <iostream>");
321                 // Pass in set of methods and get import classes
322                 List<String> methods = intDecl.getMethods();
323                 Set<String> includeClasses = getIncludeClasses(methods);
324                 printIncludeStatements(includeClasses);
325                 println("");
326                 println("using namespace std;");
327                 println("");
328                 println("class " + intface);
329                 println("{");
330                 println("public:");
331                 // Write methods
332                 for (String method : methods) {
333
334                         List<String> methParams = intDecl.getMethodParams(method);
335                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
336                         print("virtual " + convertType(intDecl.getMethodType(method)) + " " +
337                                 intDecl.getMethodId(method) + "(");
338                         for (int i = 0; i < methParams.size(); i++) {
339                                 // Check for params with driver class types and exchange it 
340                                 //              with its remote interface
341                                 String paramType = checkAndGetParamClass(methPrmTypes.get(i));
342                                 paramType = checkAndGetCplusType(paramType);
343                                 print(paramType + " " + methParams.get(i));
344                                 // Check if this is the last element (don't print a comma)
345                                 if (i != methParams.size() - 1) {
346                                         print(", ");
347                                 }
348                         }
349                         println(") = 0;");
350                 }
351                 print("}");
352                 println(";");
353                 pw.close();
354                 System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
355         }
356
357
358         /**
359          * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
360          */
361         public void generateJavaInterfaces() throws IOException {
362
363                 // Create a new directory
364                 createDirectories(dir, subdir);
365                 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
366
367                         // Open a new file to write into
368                         String newIntface = intMeth.getKey();
369                         FileWriter fw = new FileWriter(dir + "/" + subdir + "/" + newIntface + ".java");
370                         pw = new PrintWriter(new BufferedWriter(fw));
371                         // Pass in set of methods and get import classes
372                         Set<String> importClasses = getImportClasses(intMeth.getValue());
373                         printImportStatements(importClasses);
374                         // Write interface header
375                         println("");
376                         println("public interface " + newIntface + " {");
377                         List<String> meths = intDecl.getMethods();
378                         // Write methods
379                         for (String method : intMeth.getValue()) {
380
381                                 List<String> methParams = intDecl.getMethodParams(method);
382                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
383                                 print("public " + intDecl.getMethodType(method) + " " +
384                                         intDecl.getMethodId(method) + "(");
385                                 for (int i = 0; i < methParams.size(); i++) {
386                                         print(methPrmTypes.get(i) + " " + 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                         }
394                         println("}");
395                         pw.close();
396                         System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
397                 }
398         }
399
400
401         /**
402          * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
403          * <p>
404          * For C++ we use virtual classe as interface
405          */
406         public void generateCPlusInterfaces() throws IOException {
407
408                 // Create a new directory
409                 createDirectories(dir, subdir);
410                 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
411
412                         // Open a new file to write into
413                         String newIntface = intMeth.getKey();
414                         FileWriter fw = new FileWriter(dir + "/" + subdir + "/" + newIntface + ".hpp");
415                         pw = new PrintWriter(new BufferedWriter(fw));
416                         // Write file headers
417                         println("#include <iostream>");
418                         // Pass in set of methods and get import classes
419                         Set<String> includeClasses = getIncludeClasses(intMeth.getValue());
420                         printIncludeStatements(includeClasses);
421                         println("");
422                         println("using namespace std;");
423                         println("");
424                         println("class " + newIntface);
425                         println("{");
426                         println("public:");
427                         // Write methods
428                         for (String method : intMeth.getValue()) {
429
430                                 List<String> methParams = intDecl.getMethodParams(method);
431                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
432                                 print("virtual " + convertType(intDecl.getMethodType(method)) + " " +
433                                         intDecl.getMethodId(method) + "(");
434                                 for (int i = 0; i < methParams.size(); i++) {
435
436                                         String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
437                                         print(methPrmType + " " + methParams.get(i));
438                                         // Check if this is the last element (don't print a comma)
439                                         if (i != methParams.size() - 1) {
440                                                 print(", ");
441                                         }
442                                 }
443                                 println(") = 0;");
444                         }
445                         print("}");
446                         println(";");
447                         pw.close();
448                         System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
449                 }
450         }
451
452
453         /**
454          * generateJavaStubClasses() generate stubs based on the methods list in Java
455          */
456         public void generateJavaStubClasses() throws IOException {
457
458                 // Create a new directory
459                 createDirectories(dir, subdir);
460                 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
461
462                         // Open a new file to write into
463                         String newIntface = intMeth.getKey();
464                         String newStubClass = newIntface + "_Stub";
465                         FileWriter fw = new FileWriter(dir + "/" + subdir + "/" + newStubClass + ".java");
466                         pw = new PrintWriter(new BufferedWriter(fw));
467                         // Pass in set of methods and get import classes
468                         Set<String> importClasses = getImportClasses(intMeth.getValue());
469                         printImportStatements(importClasses);
470                         // Write interface header
471                         println("");
472                         println("public class " + newStubClass + " implements " + newIntface + " {");
473                         println("");
474                         // Write methods
475                         for (String method : intMeth.getValue()) {
476
477                                 List<String> methParams = intDecl.getMethodParams(method);
478                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
479                                 print("public " + intDecl.getMethodType(method) + " " +
480                                         intDecl.getMethodId(method) + "(");
481                                 for (int i = 0; i < methParams.size(); i++) {
482
483                                         print(methPrmTypes.get(i) + " " + methParams.get(i));
484                                         // Check if this is the last element (don't print a comma)
485                                         if (i != methParams.size() - 1) {
486                                                 print(", ");
487                                         }
488                                 }
489                                 println(") {");
490                                 // Check if this is not "void"
491                                 if (!intDecl.getMethodType(method).equals("void")) {
492                                         String retStmt = generateReturnStmt(intDecl.getMethodType(method));
493                                         println("return " + retStmt + ";");
494                                 }
495                                 println("}"); println("");
496                         }
497                         println("}");
498                         pw.close();
499                         System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
500                 }
501         }
502
503
504         /**
505          * generateCPlusStubClasses() generate stubs based on the methods list in C++
506          */
507         public void generateCPlusStubClasses() throws IOException {
508
509                 // Create a new directory
510                 createDirectories(dir, subdir);
511                 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
512
513                         // Open a new file to write into
514                         String newIntface = intMeth.getKey();
515                         String newStubClass = newIntface + "_Stub";
516                         FileWriter fw = new FileWriter(dir + "/" + subdir + "/" + newStubClass + ".hpp");
517                         pw = new PrintWriter(new BufferedWriter(fw));
518                         // Write file headers
519                         println("#include <iostream>");
520                         println("#include \"" + newIntface + ".hpp\""); println("");            
521                         println("using namespace std;"); println("");
522                         println("class " + newStubClass + " : public " + newIntface);
523                         println("{");
524                         println("public:"); println("");
525                         // Add default constructor and destructor
526                         println(newStubClass + "() { }"); println("");
527                         println("~" + newStubClass + "() { }"); println("");            
528                         // Write methods
529                         for (String method : intMeth.getValue()) {
530
531                                 List<String> methParams = intDecl.getMethodParams(method);
532                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
533                                 print(convertType(intDecl.getMethodType(method)) + " " +
534                                         intDecl.getMethodId(method) + "(");
535                                 for (int i = 0; i < methParams.size(); i++) {
536
537                                         String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
538                                         print(methPrmType + " " + methParams.get(i));
539                                         // Check if this is the last element (don't print a comma)
540                                         if (i != methParams.size() - 1) {
541                                                 print(", ");
542                                         }
543                                 }
544                                 println(") { ");
545                                 // Check if this is not "void"
546                                 if (!intDecl.getMethodType(method).equals("void")) {
547                                         String retStmt = generateReturnStmt(intDecl.getMethodType(method));
548                                         if (retStmt.equals("null")) { // null = NULL in C++
549                                                 retStmt = "NULL";
550                                         }
551                                         println("return " + retStmt + ";");
552                                 }
553                                 println("}"); println("");
554                         }
555                         print("}"); println(";");
556                         pw.close();
557                         System.out.println("IoTCompiler: Generated stub class " + newIntface + ".hpp...");
558                 }
559         }
560
561
562         /**
563          * generateReturnStmt() generate return statement based on methType
564          */
565         public String generateReturnStmt(String methType) {
566
567                 // Generate dummy returns for now
568                 if (methType.equals("short")||
569                         methType.equals("int")  ||
570                         methType.equals("long") ||
571                         methType.equals("float")||
572                         methType.equals("double")) {
573
574                         return "1";
575                 } else if ( methType.equals("String") ||
576                                         methType.equals("byte")) {
577   
578                         return "\"a\"";
579                 } else if ( methType.equals("char")) {
580
581                         return "\'a\'";
582                 } else if ( methType.equals("boolean")) {
583
584                         return "true";
585                 } else {
586                         return "null";
587                 }
588         }
589
590
591         /**
592          * setDirectory() set a new directory for stub files
593          */
594         public void setDirectory(String _subdir) {
595
596                 subdir = _subdir;
597         }
598
599
600         /**
601          * printUsage() prints the usage of this compiler
602          */
603         public static void printUsage() {
604
605                 System.out.println();
606                 System.out.println("Sentinel interface and stub compiler version 1.0");
607                 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
608                 System.out.println("All rights reserved.");
609                 System.out.println("Usage:");
610                 System.out.println("\tjava IoTCompiler --help / -h\t\t\t\t\tDisplay this help texts");
611                 System.out.println("\tjava IoTCompiler <main-policy-file> <req-policy-file>\t\tGenerate both Java and C++ stub files");
612                 System.out.println("\tjava IoTCompiler <main-policy-file> <req-policy-file> [options]");
613                 System.out.println("Options:");
614                 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
615                 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
616                 System.out.println();
617         }
618
619
620         /**
621          * parseFile() prepares Lexer and Parser objects, then parses the file
622          */
623         public static ParseNode parseFile(String file) {
624
625                 ParseNode pn = null;
626                 try {
627                         ComplexSymbolFactory csf = new ComplexSymbolFactory();
628                         ScannerBuffer lexer = 
629                                 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf));
630                         Parser parse = new Parser(lexer,csf);
631                         pn = (ParseNode) parse.parse().value;
632                 } catch (Exception e) {
633                         System.out.println("IoTCompiler: ERROR parsing policy file!");
634                         e.printStackTrace();
635                 }
636
637                 return pn;
638         }
639
640
641         /**================================================
642          * Helper functions to write stub codes into files
643          **================================================
644          */
645         boolean newline=true;
646         int tablevel=0;
647
648         private void print(String str) {
649                 if (newline) {
650                         int tab=tablevel;
651                         if (str.equals("}"))
652                                 tab--;
653                         for(int i=0; i<tab; i++)
654                                 pw.print("\t");
655                 }
656                 pw.print(str);
657                 updatetabbing(str);
658                 newline=false;
659         }
660
661         /**
662          * This function converts Java to C++ type for compilation
663          */
664         private String convertType(String jType) {
665
666                 return mapPrimitives.get(jType);
667         }
668
669
670         private void println(String str) {
671                 if (newline) {
672                         int tab = tablevel;
673                         if (str.equals("}"))
674                                 tab--;
675                         for(int i=0; i<tab; i++)
676                                 pw.print("\t");
677                 }
678                 pw.println(str);
679                 updatetabbing(str);
680                 newline = true;
681         }
682
683
684         private void updatetabbing(String str) {
685                 tablevel+=count(str,'{')-count(str,'}');
686         }
687
688
689         private int count(String str, char key) {
690                 char[] array = str.toCharArray();
691                 int count = 0;
692                 for(int i=0; i<array.length; i++) {
693                         if (array[i] == key)
694                                 count++;
695                 }
696                 return count;
697         }
698
699
700         private void createDirectory(String dirName) {
701
702                 File file = new File(dirName);
703                 if (!file.exists()) {
704                         if (file.mkdir()) {
705                                 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
706                         } else {
707                                 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
708                         }
709                 } else {
710                         System.out.println("IoTCompiler: Directory " + dirName + " exists...");
711                 }
712         }
713
714
715         // Create a directory and possibly a sub directory
716         private void createDirectories(String dir, String subdir) {
717
718                 createDirectory(dir);
719                 if (subdir != null) {
720                         createDirectory(dir + "/" + subdir);
721                 }
722         }
723
724
725         // Inserting array members into a Map object
726         // that maps arrKey to arrVal objects
727         private void arraysToMap(Map map, Object[] arrKey, Object[] arrVal) {
728
729                 for(int i = 0; i < arrKey.length; i++) {
730
731                         map.put(arrKey[i], arrVal[i]);
732                 }
733         }
734
735
736         // Return parameter category, i.e. PRIMITIVES, NONPRIMITIVES, or USERDEFINED
737         private ParamCategory getParamCategory(String paramType) {
738
739                 if (mapPrimitives.containsKey(paramType)) {
740                         return ParamCategory.PRIMITIVES;
741                 // We can either use mapNonPrimitivesJava or mapNonPrimitivesCplus here
742                 } else if (mapNonPrimitivesJava.containsKey(getSimpleType(paramType))) {
743                         return ParamCategory.NONPRIMITIVES;
744                 } else
745                         return ParamCategory.USERDEFINED;
746         }
747
748
749         // Return full class name for non-primitives to generate Java import statements
750         // e.g. java.util.Set for Set, java.util.Map for Map
751         private String getNonPrimitiveJavaClass(String paramNonPrimitives) {
752
753                 return mapNonPrimitivesJava.get(paramNonPrimitives);
754         }
755
756
757         // Return full class name for non-primitives to generate Cplus include statements
758         // e.g. #include <set> for Set, #include <map> for Map
759         private String getNonPrimitiveCplusClass(String paramNonPrimitives) {
760
761                 return mapNonPrimitivesCplus.get(paramNonPrimitives);
762         }
763
764
765         // Get simple types, e.g. HashSet for HashSet<...>
766         // Basically strip off the "<...>"
767         private String getSimpleType(String paramType) {
768
769                 // Check if this is generics
770                 if(paramType.contains("<")) {
771                         String[] type = paramType.split("<");
772                         return type[0];
773                 } else
774                         return paramType;
775         }
776
777
778         // Generate a set of classes for import statements
779         private Set<String> getImportClasses(Collection<String> methods) {
780
781                 Set<String> importClasses = new HashSet<String>();
782                 for (String method : methods) {
783                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
784                         for (String paramType : methPrmTypes) {
785
786                                 String simpleType = getSimpleType(paramType);
787                                 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
788                                         importClasses.add(getNonPrimitiveJavaClass(simpleType));
789                                 }
790                         }
791                 }
792                 return importClasses;
793         }
794
795
796         // Generate a set of classes for include statements
797         private Set<String> getIncludeClasses(Collection<String> methods) {
798
799                 Set<String> includeClasses = new HashSet<String>();
800                 for (String method : methods) {
801
802                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
803                         for (String paramType : methPrmTypes) {
804
805                                 String simpleType = getSimpleType(paramType);
806                                 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
807                                         includeClasses.add(getNonPrimitiveCplusClass(simpleType));
808                                 }
809                         }
810                 }
811                 return includeClasses;
812         }
813
814
815         private void printImportStatements(Set<String> importClasses) {
816
817                 for(String cls : importClasses) {
818                         println("import " + cls + ";");
819                 }
820         }
821
822
823         private void printIncludeStatements(Set<String> includeClasses) {
824
825                 for(String cls : includeClasses) {
826                         println("#include <" + cls + ">");
827                 }
828         }
829
830
831         // Get the C++ version of a non-primitive type
832         // e.g. set for Set and map for Map
833         // Input nonPrimitiveType has to be generics in format
834         private String[] getTypeOfGeneric(String nonPrimitiveType) {
835
836                 // Handle <, >, and , for 2-type generic/template
837                 String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(",");
838                 return substr;
839         }
840
841
842         private String checkAndGetCplusType(String paramType) {
843
844                 if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
845                         return convertType(paramType);
846                 } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) {
847
848                         // Check for generic/template format
849                         if (paramType.contains("<") && paramType.contains(">")) {
850
851                                 String genericClass = getSimpleType(paramType);
852                                 String[] genericType = getTypeOfGeneric(paramType);
853                                 String cplusTemplate = null;
854                                 if (genericType.length == 1) // Generic/template with one type
855                                         cplusTemplate = getNonPrimitiveCplusClass(genericClass) + 
856                                                 "<" + convertType(genericType[0]) + ">";
857                                 else // Generic/template with two types
858                                         cplusTemplate = getNonPrimitiveCplusClass(genericClass) + 
859                                                 "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">";
860                                 return cplusTemplate;
861                         } else
862                                 return getNonPrimitiveCplusClass(paramType);
863                 } else
864                         // Just return it as is if it's not non-primitives
865                         return paramType;
866         }
867
868
869         // Get simple types, e.g. HashSet for HashSet<...>
870         // Basically strip off the "<...>"
871         private String checkAndGetParamClass(String paramType) {
872
873                 // Check if this is generics
874                 if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
875                         // TODO: replace this with the proper stub interface name
876                         return paramType + "Remote";
877                 } else
878                         return paramType;
879         }
880
881
882         public static void main(String[] args) throws Exception {
883
884                 // Runtime options
885                 if (args.length > 1) {
886                         // Display help
887                         if ((args[0].equals("--help") ||
888                                 (args[0].equals("-h")))) {
889                                 IoTCompiler.printUsage();
890                         } else {
891                                 // Parse main policy file
892                                 ParseNode pnPol = IoTCompiler.parseFile(args[0]);
893                                 // Parse "requires" policy file
894                                 ParseNode pnReq = IoTCompiler.parseFile(args[1]);
895                                 // Get interface name
896                                 String intface = ParseTreeHandler.getOrigIntface(pnPol);
897                                 IoTCompiler comp = new IoTCompiler(intface, pnPol, pnReq);
898                                 // Generate all policy files if just policy file is provided
899                                 comp.parsePolicyFile();
900                                 comp.getMethodsForIntface();
901                                 if (args.length == 2) {
902                                         comp.generateJavaLocalInterface(intface);
903                                         comp.generateJavaInterfaces();
904                                         comp.generateJavaStubClasses();
905                                         comp.generateCplusLocalInterface(intface);
906                                         comp.generateCPlusInterfaces();
907                                         comp.generateCPlusStubClasses();
908                                 } else {
909                                 // Check other options
910                                         int i = 2;
911                                         while(i < args.length) {
912                                                 // Check whether <directory> is provided
913                                                 if ((i + 1) < args.length) {
914                                                         comp.setDirectory(args[i+1]);
915                                                 } else
916                                                         throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
917                                                 if (args[i].equals("-java")) {
918                                                         comp.generateJavaLocalInterface(intface);
919                                                         comp.generateJavaInterfaces();
920                                                         comp.generateJavaStubClasses();
921                                                 } else if (args[i].equals("-cplus")) {
922                                                         comp.generateCplusLocalInterface(intface);
923                                                         comp.generateCPlusInterfaces();
924                                                         comp.generateCPlusStubClasses();
925                                                 } else
926                                                         throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
927                                                 i = i + 2;
928                                         }
929                                 }
930                         }
931
932                 } else {
933                 // Need at least the policy file name
934                         IoTCompiler.printUsage();
935                         throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");
936                 }
937         }
938 }
939
940
941
942