cd6b0f7b8aa7ce1471b0ca9df04be8948f82e646
[iot2.git] / iotjava / iotruntime / brillo / IoTBrilloWeaveCodeGenerator.java
1 package iotruntime.brillo;
2
3 // Java libraries
4 import java.io.BufferedWriter;
5 import java.io.PrintWriter;
6 import java.io.FileWriter;
7 import java.io.IOException;
8 import java.net.HttpURLConnection;
9 import java.net.MalformedURLException;
10 import java.net.ProtocolException;
11 import java.net.URL;
12 import java.lang.Class;
13 import java.lang.reflect.*;
14 import java.util.Map;
15
16 // Google APIs
17 import com.google.api.services.clouddevices.model.CommandDefNew;
18 import com.google.api.services.clouddevices.model.Device;
19
20
21 /** IoTBrilloWeaveCodeGenerator class that connects to
22  *  Google Brillo/Weave server based on user's credentials
23  *  and creates user's class and interface
24  *  <p>
25  *  Steps:
26  *  0) Compile iotruntime
27  *  1) Run this code generator
28  *     - go to $(IOTJAVA_CLASSPATH)/iot/bin/iotruntime/brillo/
29  *     - run this class with this command line: 
30  *       java -cp .:../../:../../../jars/brillo/*:../../../jars/brillo/libs/* iotruntime.brillo.IoTBrilloWeaveCodeGenerator -help
31  *     - follow the instructions to generate codes
32  *  2) If credentials_cache.json hasn't been created then one will be created
33  *  3) Both interface and implementation java API source files will be created
34  *  4) We can move them to the right directories with the credentials_cache.json
35  *     - move the interface java file into folder "interfaces"
36  *     - create a folder in "iot/benchmarks/drivers" with the class name and put
37  *       the class java file there; don't forget to create <class>.config file
38  *       and modify the Makefile
39  *  5) A device driver can be created based on the created API's
40  *
41  * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
42  * @version     1.0
43  * @since       2016-06-09
44  */
45 public class IoTBrilloWeaveCodeGenerator {
46
47         /**
48          * IoTBrilloWeaveCodeGenerator properties
49          */
50         private PrintWriter pw;
51         private String strInterfaceName;
52         private String strClassName;
53         private IoTBrilloWeaveCloudConnection iotBrillo;
54
55         /**
56          * Constructor
57          */
58         public IoTBrilloWeaveCodeGenerator(String[] strArgs) {
59
60                 this.strInterfaceName = strArgs[0];
61                 this.strClassName = strArgs[1];
62                 this.iotBrillo = new IoTBrilloWeaveCloudConnection(strArgs[2], strArgs[3], strArgs[4]);
63                 this.iotBrillo.connectionSetup(strArgs[5]);
64         }
65
66
67         /**
68          * Generate interface
69          *
70          * @return      void
71          */
72         public void generateInterface() throws IOException {
73
74                 // Initialize FileWriter and PrintWriter
75                 FileWriter fwInterface = new FileWriter(strInterfaceName + ".java");
76                 this.pw = new PrintWriter(new BufferedWriter(fwInterface));
77                 // Write the interface header
78                 generateInterfaceImports();
79                 println("");
80                 println("public interface " + strInterfaceName + " extends Remote {");
81                 println("");
82                 generateInterfaceBody(this.iotBrillo.getDeviceObject());
83                 println("");
84                 //Close interface
85                 println("}");
86                 pw.close();
87         }
88
89
90         /**
91          * Generate interface import statements
92          *
93          * @return      void
94          */
95         public void generateInterfaceInit() {
96                 println("public void init() throws RemoteException;");
97         }
98
99
100         /**
101          * Generate interface init method
102          *
103          * @return      void
104          */
105         public void generateInterfaceImports() {
106                 println("package iotcode.interfaces;");
107                 println("");    
108                 println("import java.rmi.Remote;");
109                 println("import java.rmi.RemoteException;");
110         }
111
112
113         /**
114          * Generate interface body
115          *
116          * @param       device  Device object that contains JSON parameters
117          * @return      void
118          */
119         private void generateInterfaceBody(Device device) {
120
121                 generateInterfaceInit();
122                 Map<String,Map<String,CommandDefNew>> mapCommand = device.getCommandDefs();
123                 for(String strCmd : mapCommand.keySet()) {
124                         Map<String,CommandDefNew> mapSubCommand = mapCommand.get(strCmd);
125                         for(String strSubCmd : mapSubCommand.keySet()) {
126                                 print("public void " + strCmd + "_" + strSubCmd + "(");
127                                 CommandDefNew cmd = mapSubCommand.get(strSubCmd);
128                                 if (cmd.getParameters() != null) {
129                                 // If we have parameters ...
130                                         int iParamCount = 0;
131                                         Map<String,Map<String,Object>> mapParam = cmd.getParameters();
132                                         for (String strParamName : mapParam.keySet()) {
133                                                 iParamCount++;
134                                                 Map<String,Object> mapParamProp = mapParam.get(strParamName);
135                                                 for (String strParamProp : mapParamProp.keySet()) {
136                                                         if (strParamProp.equals("type")) {
137                                                                 print(getJavaType(mapParamProp.get(strParamProp).toString()) + " ");
138                                                                 if (iParamCount == mapParam.size())
139                                                                         println(strParamName + ") throws RemoteException;");
140                                                                 else
141                                                                         print(strParamName + ", ");
142                                                         }
143                                                 }
144                                         }
145                                 } else {
146                                 // If we don't have parameters ...
147                                         println(") throws RemoteException;");
148                                 }
149                         }
150                 }
151         }
152
153
154         /**
155          * Type translator from JSON syntax to Java
156          *
157          * @return      String
158          */
159         private String getJavaType(String strJsonType) {
160
161                 if (strJsonType.equals("string")) {
162                         return "String";
163                 } else if (strJsonType.equals("integer")) {
164                         return "Integer";
165                 } else if (strJsonType.equals("boolean")) {
166                         return "Boolean";
167                 } else if (strJsonType.equals("number")) {
168                         return "Float";
169                 } else { // NULL is returned when type is not recognized
170                         return null;
171                 }
172         }
173
174
175         /**
176          * Generate class
177          *
178          * @return      void
179          */
180         public void generateClass() throws IOException {
181
182                 // Initialize FileWriter and PrintWriter
183                 FileWriter fwClass = new FileWriter(strClassName + ".java");
184                 this.pw = new PrintWriter(new BufferedWriter(fwClass));
185                 // Write the import statements
186                 generateImports();
187                 println("");
188                 println("public class " + strClassName + 
189                                 " extends IoTBrilloWeave" +
190                                 " implements " + strInterfaceName + " {");
191                 println("");
192                 generateAtConfigs();            
193                 println("");
194                 generateConstructor();
195                 println("");
196                 generateInit();
197                 println("");
198                 generateClassAPIs(this.iotBrillo.getDeviceObject());
199                 //Close class
200                 println("}");
201                 pw.close();
202         }
203
204
205         /**
206          * Generate @config statements for IoTDeviceAddress
207          *
208          * @return      void
209          */
210         public void generateAtConfigs() {
211
212                 println("@config private IoTSet<IoTAddress> GoogleAccountAddress;");
213                 println("@config private IoTSet<IoTAddress> GoogleAPIsAddress;");
214         }
215
216
217         /**
218          * Generate init method
219          *
220          * @return      void
221          */
222         public void generateInit() {
223
224                 println("public void init() {");
225                 println("Iterator itr = GoogleAccountAddress.iterator();");
226                 println("IoTAddress address = (IoTAddress)itr.next();");
227                 println("super.setAuthScope(address.getHostName());");
228                 println("}");
229         }
230
231
232         /**
233          * Generate class APIs
234          *
235          * @param       device  Device object that contains JSON parameters
236          * @return      void
237          */
238         private void generateClassAPIs(Device device) {
239
240                 // Generate method header
241                 Map<String,Map<String,CommandDefNew>> mapCommand = device.getCommandDefs();
242                 for(String strCmd : mapCommand.keySet()) {
243                         Map<String,CommandDefNew> mapSubCommand = mapCommand.get(strCmd);
244                         for(String strSubCmd : mapSubCommand.keySet()) {
245                                 print("public void " + strCmd + "_" + strSubCmd + "(");
246                                 CommandDefNew cmd = mapSubCommand.get(strSubCmd);
247                                 boolean doesParamExist = false;
248                                 if (cmd.getParameters() != null) {
249                                 // If we have parameters ...
250                                         doesParamExist = true;
251                                         int iParamCount = 0;
252                                         Map<String,Map<String,Object>> mapParam = cmd.getParameters();
253                                         for (String strParamName : mapParam.keySet()) {
254                                                 iParamCount++;
255                                                 Map<String,Object> mapParamProp = mapParam.get(strParamName);
256                                                 for (String strParamProp : mapParamProp.keySet()) {
257                                                         if (strParamProp.equals("type")) {
258                                                                 print(getJavaType(mapParamProp.get(strParamProp).toString()) + " ");
259                                                                 if (iParamCount == mapParam.size())
260                                                                         println(strParamName + ") {");
261                                                                 else
262                                                                         print(strParamName + ", ");
263                                                         }
264                                                 }
265                                         }
266                                 } else {
267                                 // If we don't have parameters ...
268                                         println(") {");
269                                 }
270                                 generateMethodBody(cmd, doesParamExist, strCmd, strSubCmd);
271                                 generateCommandInsertionAndException();
272                                 println("}");
273                                 println("");
274                         }
275                 }
276         }
277
278
279         /**
280          * Generate method body
281          *
282          * @param       cmd                     Object CommandDefNew that contains information about the command
283          * @param       doesParamExist  Boolean that tracks if the method has parameters
284          * @param       strCmd                  String that contains the main command name
285          * @param       strSubCmd               String that contains the sub command name
286          * @return      void
287          */
288         private void generateMethodBody(CommandDefNew cmd, boolean doesParamExist, String strCmd, String strSubCmd) {
289
290                 if (doesParamExist) {
291                 // If we have parameters ...
292                         //int iParamCount = 0;
293                         println("Map<String, Object> parameters = new HashMap<String, Object>();");
294                         Map<String,Map<String,Object>> mapParam = cmd.getParameters();
295                         for (String strParamName : mapParam.keySet()) {
296                                 //iParamCount++;
297                                 Map<String,Object> mapParamProp = mapParam.get(strParamName);
298                                 for (String strParamProp : mapParamProp.keySet()) {
299                                         if (strParamProp.equals("type")) {
300                                                 //print(getJavaType(mapParamProp.get(strParamProp).toString()) + " ");
301                                                 println("parameters.put(\"" + strParamName + "\", " + strParamName + ");");
302                                         }
303                                 }
304                         }
305                 }
306                 println("Command command = new Command()");
307                 println("\t.setName(\"" + strCmd + "." + strSubCmd + "\")");
308                 if (doesParamExist)
309                         println("\t.setParameters(parameters)");
310                 println("\t.setDeviceId(device.getId());");
311         }
312
313
314         /**
315          * Generate command insertion and exception statements
316          *
317          * @return      void
318          */
319         private void generateCommandInsertionAndException() {
320                 println("try {");
321                 println("command = apiClient.commands().insert(command).execute(); }");
322                 println("catch (IOException e) {");
323                 println("throw new RuntimeException(\"Could not insert command\", e); }");
324                 println("");
325                 println("try {");
326                 println("System.out.println(\"Sent command to the device:\" + jsonFactory.toPrettyString(command)); }");
327                 println("catch (IOException e) {");
328                 println("throw new RuntimeException(e); }");
329         }
330
331
332         /**
333          * Generate import statements
334          *
335          * @return      void
336          */
337         private void generateImports() {
338
339                 println("package iotcode." + strClassName + ";");
340                 println("");    
341                 println("import com.google.api.client.json.jackson2.JacksonFactory;");
342                 println("import com.google.api.services.clouddevices.CloudDevices;");
343                 println("import com.google.api.services.clouddevices.model.Command;");
344                 println("import com.google.api.services.clouddevices.model.Device;");
345                 println("");
346                 println("import java.io.IOException;");
347                 println("import java.util.HashMap;");
348                 println("import java.util.Iterator;");
349                 println("import java.util.Map;");
350                 println("");
351                 println("import iotcode.interfaces.LEDFlasher;");
352                 println("import iotruntime.brillo.IoTBrilloWeave;");
353                 println("import iotruntime.brillo.IoTBrilloWeaveCloudConnection;");
354                 println("import iotruntime.slave.IoTAddress;");
355                 println("import iotruntime.slave.IoTSet;");
356                 println("import iotchecker.qual.*;");
357         }
358
359
360         /**
361          * Generate constructor
362          *
363          * @return      void
364          */
365         private void generateConstructor() {
366                 // Write the constructor
367                 println("public " + strClassName + 
368                         "(String _clientId, String _clientSecret, String _apiKey, String _deviceId) {");
369                 println("super(_clientId, _clientSecret, _apiKey, _deviceId);");
370                 println("}");
371         }
372
373
374         /**
375          * Display help message
376          *
377          * @return      void
378          */
379         public static void displayHelpMessage() {
380                 System.out.println();
381                 System.out.println("Please use this code generator in the following syntax:");
382                 System.out.print("java -cp <classpath> IoTBrilloWeaveCodeGenerator <interface_name> ");
383                 System.out.println("<class_name> <client_id> <client_secret> <api_key> <device_id>");
384                 System.out.println("e.g.");
385                 System.out.print("java -cp .:../clouddevices/*:../clouddevices/libs/* IoTBrilloWeaveCodeGenerator ");
386                 System.out.print("LEDFlasherTest LEDFlasherTestImplementation 627170482755-4l2gd5m3lf6ej674vqr8sdc14gmeva3e.apps.googleusercontent.com ");
387                 System.out.println("Yhj6QzCxeO2B0i25JHqYShsi AIzaSyDcYp9RQAV2ELZWxVIjPBAzIPGiXAAORs0 77173ed5-3303-4c54-f852-b8f51fb7b31f");
388                 System.out.println();
389                 System.out.println("To show this help message: java IoTBrilloWeaveCodeGenerator --help");
390                 System.out.println();
391         }
392
393
394         /**
395          * Helper functions that help print to files
396          */
397         boolean newline=true;
398         int tablevel=0;
399
400         private void print(String str) {
401                 if (newline) {
402                         int tab=tablevel;
403                         if (str.equals("}"))
404                                 tab--;
405                         for(int i=0; i<tab; i++)
406                                 pw.print("\t");
407                 }
408                 pw.print(str);
409                 updatetabbing(str);
410                 newline=false;
411         }
412
413         private void println(String str) {
414                 if (newline) {
415                         int tab = tablevel;
416                         if (str.equals("}"))
417                                 tab--;
418                         for(int i=0; i<tab; i++)
419                                 pw.print("\t");
420                 }
421                 pw.println(str);
422                 updatetabbing(str);
423                 newline = true;
424         }
425
426         private void updatetabbing(String str) {
427                 tablevel += count(str,'{') - count(str,'}');
428         }
429
430         private int count(String str, char key) {
431                 char[] array = str.toCharArray();
432                 int count = 0;
433                 for(int i=0; i<array.length; i++) {
434                         if (array[i] == key)
435                                 count++;
436                 }
437                 return count;
438         }
439
440
441         /**
442          * Call main function for file generations
443          * 
444          * @param       args[0]         Interface name
445          * @param       args[1]         Class name
446          * @param       args[2]         Client ID
447          * @param       args[3]         Client secret
448          * @param       args[4]         API key
449          * @param       args[5]         Device ID
450          */
451         public static void main(String[] args) throws IOException {
452
453                 if(args.length < 6 || args[0].contains("help")) {
454                         displayHelpMessage();
455                 } else {
456                         IoTBrilloWeaveCodeGenerator iotBrilloCodeGen = new IoTBrilloWeaveCodeGenerator(args);
457                         iotBrilloCodeGen.generateInterface();
458                         iotBrilloCodeGen.generateClass();
459                 }
460         }
461 }