c11d32f8bfd84470625ba0fad9032da2e507868b
[iot2.git] / iotjava / iotpolicy / IoTStubCompiler.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.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import iotpolicy.parser.Lexer;
13 import iotpolicy.parser.Parser;
14 import iotpolicy.tree.ParseNode;
15 import iotpolicy.tree.ParseNodeVector;
16 import iotpolicy.tree.ParseTreeHandler;
17 import iotpolicy.tree.CapabilityDecl;
18 import iotpolicy.tree.InterfaceDecl;
19 import iotpolicy.tree.RequiresDecl;
20
21 /** Class IoTStubCompiler is the main stub compiler for
22  *  stub files generation. This class calls helper classes
23  *  such as Parser, Lexer, InterfaceDecl, CapabilityDecl,
24  *  RequiresDecl, ParseTreeHandler, etc.
25  *
26  * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
27  * @version     1.0
28  * @since       2016-09-22
29  */
30 public final class IoTStubCompiler {
31
32         /**
33          * Class properties
34          */
35         private String origInt;
36         private ParseTreeHandler ptHandler;
37         private InterfaceDecl intDecl;
38         private CapabilityDecl capDecl;
39         private RequiresDecl reqDecl;
40         private Map<String,Set<String>> mapCapabMethods;
41         private PrintWriter pw;
42         private String dir;
43
44         /**
45          * Class constants
46          */
47         private final static String OUTPUT_DIRECTORY = "stubfiles";
48
49         /**
50          * Class constructors
51          */
52         public IoTStubCompiler() {
53
54                 origInt = null;
55                 ptHandler = new ParseTreeHandler();
56                 intDecl = null;
57                 capDecl = null;
58                 capDecl = null;
59                 mapCapabMethods = new HashMap<String,Set<String>>();
60                 pw = null;
61                 dir = OUTPUT_DIRECTORY;
62         }
63
64
65         public IoTStubCompiler(String _origInt, ParseNode _pn) {
66
67                 origInt = _origInt;
68                 ptHandler = new ParseTreeHandler(_origInt, _pn);
69                 intDecl = null;
70                 capDecl = null;
71                 reqDecl = null;
72                 mapCapabMethods = new HashMap<String,Set<String>>();
73                 pw = null;
74                 dir = OUTPUT_DIRECTORY;
75         }
76
77
78         /**
79          * parsePolicyFile() parses policy file
80          * <p>
81          * It also generates parse tree and
82          * copies useful information from parse tree into
83          * InterfaceDecl, CapabilityDecl, and RequiresDecl 
84          * data structures.
85          * Additionally, the data structure handles are
86          * returned from tree-parsing for further process.
87          *
88          */
89         public void parsePolicyFile() {
90
91                 ptHandler.processInterfaceDecl();
92                 intDecl = ptHandler.getInterfaceDecl();
93
94                 ptHandler.processCapabilityDecl();
95                 capDecl = ptHandler.getCapabilityDecl();
96
97                 ptHandler.processRequiresDecl();
98                 reqDecl = ptHandler.getRequiresDecl();
99         }
100
101
102         /**
103          * getMethodsForIntface() reads for methods in the data structure
104          * <p>
105          * It is going to give list of methods for a certain interface
106          *              based on the declaration of capabilities.
107          */
108         public void getMethodsForIntface() {
109
110                 // Get set of new interfaces, e.g. CameraWithCaptureAndData
111                 // Generate this new interface with all the methods it needs
112                 //              from different capabilities it declares
113                 Set<String> setIntfaces = reqDecl.getInterfaces();
114                 for (String strInt : setIntfaces) {
115
116                         // Initialize a set of methods
117                         Set<String> setMethods = new HashSet<String>();
118                         // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc.
119                         List<String> listCapab = reqDecl.getCapabList(strInt);
120                         for (String strCap : listCapab) {
121
122                                 // Get list of methods for each capability
123                                 List<String> listCapabMeth = capDecl.getMethods(strCap);
124                                 for (String strMeth : listCapabMeth) {
125
126                                         // Add methods into setMethods
127                                         // This is to also handle redundancies (say two capabilities
128                                         //              share the same methods)
129                                         setMethods.add(strMeth);
130                                 }
131                         }
132                         // Add interface and methods information into map
133                         mapCapabMethods.put(strInt, setMethods);
134                 }
135         }
136
137
138         /**
139          * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
140          */
141         public void generateJavaInterfaces() throws IOException {
142
143                 // Create a new directory
144                 createDirectory(dir);
145                 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
146
147                         // Open a new file to write into
148                         String newIntface = intMeth.getKey();
149                         FileWriter fw = new FileWriter(dir + "/" + newIntface + ".java");
150                         pw = new PrintWriter(new BufferedWriter(fw));
151                         // Write interface header
152                         println("");
153                         println("public interface " + newIntface + " {");
154                         // Write methods
155                         for (String method : intMeth.getValue()) {
156
157                                 List<String> methParams = intDecl.getMethodParams(method);
158                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
159                                 print("public " + intDecl.getMethodType(method) + " " +
160                                         method + "(");
161                                 for (int i = 0; i < methParams.size(); i++) {
162                                          print(methPrmTypes.get(i) + " " + methParams.get(i));
163                                         // Check if this is the last element (don't print a comma)
164                                         if (i != methParams.size() - 1) {
165                                                 print(", ");
166                                         }
167                                 }
168                                 println(");");
169                         }
170                         println("}");
171                         pw.close();
172                         System.out.println("IoTStubCompiler: Generated interface " + newIntface + ".java...");
173                 }
174         }
175
176
177         /**
178          * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
179          * <p>
180          * For C++ we use virtual classe as interface
181          */
182         public void generateCPlusInterfaces() throws IOException {
183
184                 // Create a new directory
185                 createDirectory(dir);
186                 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
187
188                         // Open a new file to write into
189                         String newIntface = intMeth.getKey();
190                         FileWriter fw = new FileWriter(dir + "/" + newIntface + ".hpp");
191                         pw = new PrintWriter(new BufferedWriter(fw));
192                         // Write file headers
193                         println("#include<iostream>");
194                         println("");
195                         println("using namespace std;");
196                         println("");
197                         println("class " + newIntface);
198                         println("{");
199                         println("public:");
200                         // Write methods
201                         for (String method : intMeth.getValue()) {
202
203                                 List<String> methParams = intDecl.getMethodParams(method);
204                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
205                                 print("virtual " + convertType(intDecl.getMethodType(method)) + " " +
206                                         method + "(");
207                                 for (int i = 0; i < methParams.size(); i++) {
208                                          print(convertType(methPrmTypes.get(i)) + " " + methParams.get(i));
209                                         // Check if this is the last element (don't print a comma)
210                                         if (i != methParams.size() - 1) {
211                                                 print(", ");
212                                         }
213                                 }
214                                 println(") = 0;");
215                         }
216                         print("}");
217                         println(";");
218                         pw.close();
219                         System.out.println("IoTStubCompiler: Generated interface " + newIntface + ".hpp...");
220                 }
221         }
222
223
224         /**
225          * generateJavaStubClasses() generate stubs based on the methods list in Java
226          */
227         public void generateJavaStubClasses() throws IOException {
228
229                 // Create a new directory
230                 createDirectory(dir);
231                 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
232
233                         // Open a new file to write into
234                         String newIntface = intMeth.getKey();
235                         String newStubClass = newIntface + "_Stub";
236                         FileWriter fw = new FileWriter(dir + "/" + newStubClass + ".java");
237                         pw = new PrintWriter(new BufferedWriter(fw));
238                         // Write interface header
239                         println("");
240                         println("public class " + newStubClass + " implements " + newIntface + " {");
241                         println("");
242                         // Write methods
243                         for (String method : intMeth.getValue()) {
244
245                                 List<String> methParams = intDecl.getMethodParams(method);
246                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
247                                 print("public " + intDecl.getMethodType(method) + " " +
248                                         method + "(");
249                                 for (int i = 0; i < methParams.size(); i++) {
250                                          print(methPrmTypes.get(i) + " " + methParams.get(i));
251                                         // Check if this is the last element (don't print a comma)
252                                         if (i != methParams.size() - 1) {
253                                                 print(", ");
254                                         }
255                                 }
256                                 println(") {");
257                                 // Check if this is not "void"
258                                 if (!intDecl.getMethodType(method).equals("void")) {
259                                         String retStmt = generateReturnStmt(intDecl.getMethodType(method));
260                                         println("return " + retStmt + ";");
261                                 }
262                                 println("}");
263                                 println("");
264                         }
265                         println("}");
266                         pw.close();
267                         System.out.println("IoTStubCompiler: Generated stub class " + newStubClass + ".java...");
268                 }
269         }
270
271
272         /**
273          * generateCPlusStubClasses() generate stubs based on the methods list in C++
274          */
275         public void generateCPlusStubClasses() throws IOException {
276
277                 // Create a new directory
278                 createDirectory(dir);
279                 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
280
281                         // Open a new file to write into
282                         String newIntface = intMeth.getKey();
283                         String newStubClass = newIntface + "_Stub";
284                         FileWriter fw = new FileWriter(dir + "/" + newStubClass + ".hpp");
285                         pw = new PrintWriter(new BufferedWriter(fw));
286                         // Write file headers
287                         println("#include<iostream>");
288                         println("#include \"" + newIntface + ".hpp\""); println("");            
289                         println("using namespace std;"); println("");
290                         println("class " + newStubClass + " : public " + newIntface);
291                         println("{");
292                         println("public:"); println("");
293                         // Add default constructor and destructor
294                         println(newStubClass + "() { }"); println("");
295                         println("~" + newStubClass + "() { }"); println("");            
296                         // Write methods
297                         for (String method : intMeth.getValue()) {
298
299                                 List<String> methParams = intDecl.getMethodParams(method);
300                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
301                                 print(convertType(intDecl.getMethodType(method)) + " " +
302                                         method + "(");
303                                 for (int i = 0; i < methParams.size(); i++) {
304                                          print(convertType(methPrmTypes.get(i)) + " " + methParams.get(i));
305                                         // Check if this is the last element (don't print a comma)
306                                         if (i != methParams.size() - 1) {
307                                                 print(", ");
308                                         }
309                                 }
310                                 println(") { ");
311                                 // Check if this is not "void"
312                                 if (!intDecl.getMethodType(method).equals("void")) {
313                                         String retStmt = generateReturnStmt(intDecl.getMethodType(method));
314                                         if (retStmt.equals("null")) { // null = NULL in C++
315                                                 retStmt = "NULL";
316                                         }
317                                         println("return " + retStmt + ";");
318                                 }
319                                 println("}"); println("");
320                         }
321                         print("}"); println(";");
322                         pw.close();
323                         System.out.println("IoTStubCompiler: Generated stub class " + newIntface + ".hpp...");
324                 }
325         }
326
327
328         /**
329          * generateReturnStmt() generate return statement based on methType
330          */
331         public String generateReturnStmt(String methType) {
332
333                 // Generate dummy returns for now
334                 if (methType.equals("short")||
335                         methType.equals("int")  ||
336                         methType.equals("long") ||
337                         methType.equals("float")||
338                         methType.equals("double")) {
339
340                         return "1";
341                 } else if ( methType.equals("String") ||
342                                         methType.equals("byte")) {
343   
344                         return "\"a\"";
345                 } else if ( methType.equals("char")) {
346
347                         return "\'a\'";
348                 } else if ( methType.equals("boolean")) {
349
350                         return "true";
351                 } else {
352                         return "null";
353                 }
354         }
355
356
357         /**
358          * setDirectory() set a new directory for stub files
359          */
360         public void setDirectory(String _dir) {
361
362                 dir = _dir;
363         }
364
365
366         /**
367          * printUsage() prints the usage of this compiler
368          */
369         public static void printUsage() {
370
371                 System.out.println();
372                 System.out.println("Sentinel stub compiler version 1.0");
373                 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
374                 System.out.println("All rights reserved.");
375                 System.out.println("Usage:");
376                 System.out.println("\tjava IoTStubCompiler --help\t\t\tDisplay this help texts");
377                 System.out.println("\tjava IoTStubCompiler <policy-file>\t\tGenerate both Java and C++ stub files");
378                 System.out.println("\tjava IoTStubCompiler <policy-file> [options]");
379                 System.out.println("Options:");
380                 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
381                 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
382                 System.out.println();
383         }
384
385
386         /**================================================
387          * Helper functions to write stub codes into files
388          **================================================
389          */
390         boolean newline=true;
391         int tablevel=0;
392
393         private void print(String str) {
394                 if (newline) {
395                         int tab=tablevel;
396                         if (str.equals("}"))
397                                 tab--;
398                         for(int i=0; i<tab; i++)
399                                 pw.print("\t");
400                 }
401                 pw.print(str);
402                 updatetabbing(str);
403                 newline=false;
404         }
405
406         /**
407          * This function converts Java to C++ type for compilation
408          */
409         private String convertType(String jType) {
410
411                 // Generate dummy returns for now
412                 if (jType.equals("short")||
413                         jType.equals("int")  ||
414                         jType.equals("long") ||
415                         jType.equals("char") ||
416                         jType.equals("float")||
417                         jType.equals("double")) {
418
419                         return jType;
420                 } else if ( jType.equals("String")) {
421   
422                         return "string";
423                 } else if ( jType.equals("byte")) {
424
425                         return "char";
426                 } else if ( jType.equals("boolean")) {
427
428                         return "bool";
429                 } else {
430                         return jType;
431                 }       
432         }
433
434
435         private void println(String str) {
436                 if (newline) {
437                         int tab = tablevel;
438                         if (str.equals("}"))
439                                 tab--;
440                         for(int i=0; i<tab; i++)
441                                 pw.print("\t");
442                 }
443                 pw.println(str);
444                 updatetabbing(str);
445                 newline = true;
446         }
447
448
449         private void updatetabbing(String str) {
450                 tablevel+=count(str,'{')-count(str,'}');
451         }
452
453
454         private int count(String str, char key) {
455                 char[] array = str.toCharArray();
456                 int count = 0;
457                 for(int i=0; i<array.length; i++) {
458                         if (array[i] == key)
459                                 count++;
460                 }
461                 return count;
462         }
463
464
465         private void createDirectory(String dirName) {
466
467                 File file = new File(dirName);
468                 if (!file.exists()) {
469                         if (file.mkdir()) {
470                                 System.out.println("IoTStubCompiler: Directory " + dirName + "has been created!");
471                         } else {
472                                 System.out.println("IoTStubCompiler: Failed to create directory " + dirName + "!");
473                         }
474                 } else {
475                         System.out.println("IoTStubCompiler: Directory " + dirName + " exists...");
476                 }
477         }
478
479
480         public static void main(String[] args) throws Exception {
481
482                 // Runtime options
483                 if (args.length != 0) {
484                         // Display help
485                         if (args[0].equals("--help")) {
486                                 IoTStubCompiler.printUsage();
487                         } else {
488                                 // Initialize the symbol factory
489                                 ComplexSymbolFactory csf = new ComplexSymbolFactory();
490                                 // Create a buffering scanner wrapper
491                                 ScannerBuffer lexer = 
492                                         new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(args[0])),csf));
493                                 // Start parsing
494                                 Parser p = new Parser(lexer,csf);
495                                 ParseNode pn = (ParseNode) p.parse().value;
496                                 // Handle parse-tree and process it
497                                 String intFace = ParseTreeHandler.getOrigIntface(pn);
498                                 //System.out.println("IoTStubCompiler: Original interface: " + intFace);
499                                 IoTStubCompiler stubComp = new IoTStubCompiler(intFace, pn);
500                                 // Generate all policy files if just policy file is provided
501                                 stubComp.parsePolicyFile();
502                                 stubComp.getMethodsForIntface();
503                                 if (args.length == 1) {
504                                         stubComp.generateJavaInterfaces();
505                                         stubComp.generateJavaStubClasses();
506                                         stubComp.generateCPlusInterfaces();
507                                         stubComp.generateCPlusStubClasses();
508                                 } else {
509                                 // Check other options
510                                         int i = 1;
511                                         while(i < args.length) {
512                                                 // Check whether <directory> is provided
513                                                 if ((i + 1) < args.length) {
514                                                         stubComp.setDirectory(args[i+1]);
515                                                 } else
516                                                         throw new Error("IoTStubCompiler: ERROR - please provide <directory> after option: " + args[i]);
517                                                 if (args[i].equals("-java")) {
518                                                         stubComp.generateJavaInterfaces();
519                                                         stubComp.generateJavaStubClasses();
520                                                 } else if (args[i].equals("-cplus")) {
521                                                         stubComp.generateCPlusInterfaces();
522                                                         stubComp.generateCPlusStubClasses();
523                                                 } else
524                                                         throw new Error("IoTStubCompiler: ERROR - unrecognized command line option: " + args[i]);
525                                                 i = i + 2;
526                                         }
527                                 }
528                         }
529
530                 } else {
531                 // Need at least the policy file name
532                         IoTStubCompiler.printUsage();
533                         throw new Error("IoTStubCompiler: At least one argument (policy file) has to be provided!");
534                 }
535         }
536 }
537
538
539
540