3 import java_cup.runtime.ComplexSymbolFactory;
4 import java_cup.runtime.ScannerBuffer;
6 import java.util.Arrays;
7 import java.util.ArrayList;
8 import java.util.Collection;
9 import java.util.Collections;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Iterator;
13 import java.util.List;
17 import iotpolicy.parser.Lexer;
18 import iotpolicy.parser.Parser;
19 import iotpolicy.tree.ParseNode;
20 import iotpolicy.tree.ParseNodeVector;
21 import iotpolicy.tree.ParseTreeHandler;
22 import iotpolicy.tree.Declaration;
23 import iotpolicy.tree.DeclarationHandler;
24 import iotpolicy.tree.CapabilityDecl;
25 import iotpolicy.tree.InterfaceDecl;
26 import iotpolicy.tree.RequiresDecl;
28 import iotrmi.Java.IoTRMITypes;
31 /** Class IoTCompiler is the main interface/stub compiler for
32 * files generation. This class calls helper classes
33 * such as Parser, Lexer, InterfaceDecl, CapabilityDecl,
34 * RequiresDecl, ParseTreeHandler, etc.
36 * @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
40 public class IoTCompiler {
45 // Maps multiple interfaces to multiple objects of ParseTreeHandler
46 private Map<String,ParseTreeHandler> mapIntfacePTH;
47 private Map<String,DeclarationHandler> mapIntDeclHand;
48 private Map<String,Map<String,Set<String>>> mapInt2NewInts;
49 // Data structure to store our types (primitives and non-primitives) for compilation
50 private Map<String,String> mapPrimitives;
51 private Map<String,String> mapNonPrimitivesJava;
52 private Map<String,String> mapNonPrimitivesCplus;
53 // Other data structures
54 private Map<String,Integer> mapIntfaceObjId; // Maps interface name to object Id
55 private Map<String,Integer> mapNewIntfaceObjId; // Maps new interface name to its object Id (keep track of stubs)
56 private PrintWriter pw;
58 private String subdir;
63 private final static String OUTPUT_DIRECTORY = "output_files";
65 private enum ParamCategory {
67 PRIMITIVES, // All the primitive types, e.g. byte, short, int, long, etc.
68 NONPRIMITIVES, // Non-primitive types, e.g. Set, Map, List, etc.
69 USERDEFINED // Non-supported type by default; assumed as driver classes
75 public IoTCompiler() {
77 mapIntfacePTH = new HashMap<String,ParseTreeHandler>();
78 mapIntDeclHand = new HashMap<String,DeclarationHandler>();
79 mapInt2NewInts = new HashMap<String,Map<String,Set<String>>>();
80 mapIntfaceObjId = new HashMap<String,Integer>();
81 mapNewIntfaceObjId = new HashMap<String,Integer>();
82 mapPrimitives = new HashMap<String,String>();
83 arraysToMap(mapPrimitives, IoTRMITypes.primitivesJava, IoTRMITypes.primitivesCplus);
84 mapNonPrimitivesJava = new HashMap<String,String>();
85 arraysToMap(mapNonPrimitivesJava, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitiveJavaLibs);
86 mapNonPrimitivesCplus = new HashMap<String,String>();
87 arraysToMap(mapNonPrimitivesCplus, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitivesCplus);
89 dir = OUTPUT_DIRECTORY;
95 * setDataStructures() sets parse tree and other data structures based on policy files.
97 * It also generates parse tree (ParseTreeHandler) and
98 * copies useful information from parse tree into
99 * InterfaceDecl, CapabilityDecl, and RequiresDecl
101 * Additionally, the data structure handles are
102 * returned from tree-parsing for further process.
105 public void setDataStructures(String origInt, ParseNode pnPol, ParseNode pnReq) {
107 ParseTreeHandler ptHandler = new ParseTreeHandler(origInt, pnPol, pnReq);
108 DeclarationHandler decHandler = new DeclarationHandler();
109 // Process ParseNode and generate Declaration objects
110 ptHandler.processInterfaceDecl();
111 InterfaceDecl intDecl = ptHandler.getInterfaceDecl();
112 decHandler.addInterfaceDecl(origInt, intDecl);
113 ptHandler.processCapabilityDecl();
114 CapabilityDecl capDecl = ptHandler.getCapabilityDecl();
115 decHandler.addCapabilityDecl(origInt, capDecl);
116 ptHandler.processRequiresDecl();
117 RequiresDecl reqDecl = ptHandler.getRequiresDecl();
118 decHandler.addRequiresDecl(origInt, reqDecl);
120 mapIntfacePTH.put(origInt, ptHandler);
121 mapIntDeclHand.put(origInt, decHandler);
122 // Set object Id counter to 0 for each interface
123 mapIntfaceObjId.put(origInt, new Integer(0));
128 * getMethodsForIntface() reads for methods in the data structure
130 * It is going to give list of methods for a certain interface
131 * based on the declaration of capabilities.
133 public void getMethodsForIntface(String origInt) {
135 ParseTreeHandler ptHandler = mapIntfacePTH.get(origInt);
136 Map<String,Set<String>> mapNewIntMethods = new HashMap<String,Set<String>>();
137 // Get set of new interfaces, e.g. CameraWithCaptureAndData
138 // Generate this new interface with all the methods it needs
139 // from different capabilities it declares
140 DeclarationHandler decHandler = mapIntDeclHand.get(origInt);
141 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(origInt);
142 Set<String> setIntfaces = reqDecl.getInterfaces();
143 for (String strInt : setIntfaces) {
145 // Initialize a set of methods
146 Set<String> setMethods = new HashSet<String>();
147 // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc.
148 List<String> listCapab = reqDecl.getCapabList(strInt);
149 for (String strCap : listCapab) {
151 // Get list of methods for each capability
152 CapabilityDecl capDecl = (CapabilityDecl) decHandler.getCapabilityDecl(origInt);
153 List<String> listCapabMeth = capDecl.getMethods(strCap);
154 for (String strMeth : listCapabMeth) {
156 // Add methods into setMethods
157 // This is to also handle redundancies (say two capabilities
158 // share the same methods)
159 setMethods.add(strMeth);
162 // Add interface and methods information into map
163 mapNewIntMethods.put(strInt, setMethods);
165 // Map the map of interface-methods to the original interface
166 mapInt2NewInts.put(origInt, mapNewIntMethods);
171 * HELPER: writeMethodJavaInterface() writes the method of the interface
173 private void writeMethodJavaInterface(Collection<String> methods, InterfaceDecl intDecl) {
175 for (String method : methods) {
177 List<String> methParams = intDecl.getMethodParams(method);
178 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
179 print("public " + intDecl.getMethodType(method) + " " +
180 intDecl.getMethodId(method) + "(");
181 for (int i = 0; i < methParams.size(); i++) {
182 // Check for params with driver class types and exchange it
183 // with its remote interface
184 String paramType = checkAndGetParamClass(methPrmTypes.get(i), false);
185 print(paramType + " " + methParams.get(i));
186 // Check if this is the last element (don't print a comma)
187 if (i != methParams.size() - 1) {
197 * generateJavaLocalInterface() writes the local interface and provides type-checking.
199 * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
200 * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
201 * The local interface has to be the input parameter for the stub and the stub
202 * interface has to be the input parameter for the local class.
204 public void generateJavaLocalInterfaces() throws IOException {
206 // Create a new directory
207 createDirectory(dir);
208 for (String intface : mapIntfacePTH.keySet()) {
209 // Open a new file to write into
210 FileWriter fw = new FileWriter(dir + "/" + intface + ".java");
211 pw = new PrintWriter(new BufferedWriter(fw));
212 // Pass in set of methods and get import classes
213 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
214 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
215 List<String> methods = intDecl.getMethods();
216 Set<String> importClasses = getImportClasses(methods, intDecl);
217 printImportStatements(importClasses);
218 // Write interface header
220 println("public interface " + intface + " {");
222 writeMethodJavaInterface(methods, intDecl);
225 System.out.println("IoTCompiler: Generated local interface " + intface + ".java...");
231 * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
233 public void generateJavaInterfaces() throws IOException {
235 // Create a new directory
236 String path = createDirectories(dir, subdir);
237 for (String intface : mapIntfacePTH.keySet()) {
239 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
240 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
242 // Open a new file to write into
243 String newIntface = intMeth.getKey();
244 FileWriter fw = new FileWriter(path + "/" + newIntface + ".java");
245 pw = new PrintWriter(new BufferedWriter(fw));
246 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
247 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
248 // Pass in set of methods and get import classes
249 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
250 printImportStatements(importClasses);
251 // Write interface header
253 println("public interface " + newIntface + " {");
255 writeMethodJavaInterface(intMeth.getValue(), intDecl);
258 System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
265 * HELPER: writePropertiesJavaStub() writes the properties of the stub class
267 private void writePropertiesJavaStub(String intface, String newIntface) {
269 println("private IoTRMICall rmiCall;");
270 //println("private IoTRMIObject rmiObj;");
271 println("private String address;");
272 println("private int[] ports;\n");
274 Integer objId = mapIntfaceObjId.get(intface);
275 println("private final static int objectId = " + objId + ";");
276 mapNewIntfaceObjId.put(newIntface, objId);
277 mapIntfaceObjId.put(intface, objId++);
283 * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
285 private void writeConstructorJavaStub(String intface) {
287 println("public " + intface + "(int _port, String _address, int _rev, int[] _ports) throws Exception {");
288 println("address = _address;");
289 println("ports = _ports;");
290 println("rmiCall = new IoTRMICall(_port, _address, _rev);");
296 * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class
298 private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
299 List<String> methPrmTypes, String method) {
301 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
302 String retType = intDecl.getMethodType(method);
303 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
304 // Generate array of parameter types
305 print("Class<?>[] paramCls = new Class<?>[] { ");
306 for (int i = 0; i < methParams.size(); i++) {
307 String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
308 print(getSimpleType(paramType) + ".class");
309 // Check if this is the last element (don't print a comma)
310 if (i != methParams.size() - 1) {
315 // Generate array of parameter objects
316 print("Object[] paramObj = new Object[] { ");
317 for (int i = 0; i < methParams.size(); i++) {
318 print(getSimpleIdentifier(methParams.get(i)));
319 // Check if this is the last element (don't print a comma)
320 if (i != methParams.size() - 1) {
325 // Check if this is "void"
326 if (retType.equals("void")) {
327 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
328 } else { // We do have a return value
329 // Check if the return value NONPRIMITIVES
330 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
331 String[] retGenValType = getTypeOfGeneric(retType);
332 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
333 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
334 println("return (" + retType + ")retObj;");
336 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
337 println("return (" + retType + ")retObj;");
344 * HELPER: writeMethodJavaStub() writes the method of the stub class
346 private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl) {
348 for (String method : methods) {
350 List<String> methParams = intDecl.getMethodParams(method);
351 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
352 print("public " + intDecl.getMethodType(method) + " " +
353 intDecl.getMethodId(method) + "(");
354 for (int i = 0; i < methParams.size(); i++) {
356 print(methPrmTypes.get(i) + " " + methParams.get(i));
357 // Check if this is the last element (don't print a comma)
358 if (i != methParams.size() - 1) {
363 // Now, write the body of stub!
364 writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
371 * generateJavaStubClasses() generate stubs based on the methods list in Java
373 public void generateJavaStubClasses() throws IOException {
375 // Create a new directory
376 String path = createDirectories(dir, subdir);
377 for (String intface : mapIntfacePTH.keySet()) {
379 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
380 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
382 // Open a new file to write into
383 String newIntface = intMeth.getKey();
384 String newStubClass = newIntface + "_Stub";
385 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
386 pw = new PrintWriter(new BufferedWriter(fw));
387 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
388 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
389 // Pass in set of methods and get import classes
390 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
391 List<String> stdImportClasses = getStandardJavaImportClasses();
392 List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
393 printImportStatements(allImportClasses); println("");
394 // Write class header
395 println("public class " + newStubClass + " implements " + newIntface + " {\n");
397 writePropertiesJavaStub(intface, newIntface);
399 writeConstructorJavaStub(newStubClass);
401 writeMethodJavaStub(intMeth.getValue(), intDecl);
404 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
411 * HELPER: writePropertiesJavaSkeleton() writes the properties of the skeleton class
413 private void writePropertiesJavaSkeleton(String intface) {
415 println("private " + intface + " mainObj;");
416 //println("private int ports;");
417 //println("private IoTRMICall rmiCall;");
418 println("private IoTRMIObject rmiObj;\n");
419 // Keep track of object Ids of all stubs registered to this interface
420 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
421 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
422 String newIntface = intMeth.getKey();
423 int newObjectId = mapNewIntfaceObjId.get(newIntface);
424 println("private final static int object" + newObjectId + "Id = " +
425 newObjectId + ";\t//" + newIntface);
432 * HELPER: writeConstructorJavaSkeleton() writes the constructor of the skeleton class
434 private void writeConstructorJavaSkeleton(String newSkelClass, String intface) {
436 println("public " + newSkelClass + "(" + intface + " _mainObj, int _port) throws Exception {");
437 println("mainObj = _mainObj;");
438 println("rmiObj = new IoTRMIObject(_port);");
439 //println("set0Allowed = Arrays.asList(object0Permission);");
440 println("___waitRequestInvokeMethod();");
446 * HELPER: writeStdMethodBodyJavaSkeleton() writes the standard method body in the skeleton class
448 private void writeStdMethodBodyJavaSkeleton(List<String> methParams, String methodId, String methodType) {
450 if (methodType.equals("void"))
451 print("mainObj." + methodId + "(");
453 print("return mainObj." + methodId + "(");
454 for (int i = 0; i < methParams.size(); i++) {
456 print(getSimpleIdentifier(methParams.get(i)));
457 // Check if this is the last element (don't print a comma)
458 if (i != methParams.size() - 1) {
467 * HELPER: writeMethodJavaSkeleton() writes the method of the skeleton class
469 private void writeMethodJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
471 for (String method : methods) {
473 List<String> methParams = intDecl.getMethodParams(method);
474 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
475 String methodId = intDecl.getMethodId(method);
476 print("public " + intDecl.getMethodType(method) + " " + methodId + "(");
477 for (int i = 0; i < methParams.size(); i++) {
479 print(methPrmTypes.get(i) + " " + methParams.get(i));
480 // Check if this is the last element (don't print a comma)
481 if (i != methParams.size() - 1) {
486 // Now, write the body of skeleton!
487 writeStdMethodBodyJavaSkeleton(methParams, methodId, intDecl.getMethodType(method));
494 * HELPER: writeStdMethodHelperBodyJavaSkeleton() writes the standard method body helper in the skeleton class
496 private void writeStdMethodHelperBodyJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
497 List<String> methPrmTypes, String method) {
498 // Generate array of parameter objects
499 print("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { ");
500 for (int i = 0; i < methParams.size(); i++) {
501 String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
502 print(getSimpleType(paramType) + ".class");
503 // Check if this is the last element (don't print a comma)
504 if (i != methParams.size() - 1)
508 // Generate generic class if it's a generic type.. null otherwise
509 print("new Class<?>[] { ");
510 for (int i = 0; i < methParams.size(); i++) {
511 String prmType = methPrmTypes.get(i);
512 if (getParamCategory(prmType) == ParamCategory.NONPRIMITIVES)
513 print(getTypeOfGeneric(prmType)[0] + ".class");
516 if (i != methParams.size() - 1)
520 // Check if this is "void"
521 String retType = intDecl.getMethodType(method);
522 if (retType.equals("void")) {
523 print(intDecl.getMethodId(method) + "(");
524 } else { // We do have a return value
525 print("Object retObj = " + intDecl.getMethodId(method) + "(");
527 for (int i = 0; i < methParams.size(); i++) {
528 String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
529 print("(" + paramType + ") paramObj[" + i + "]");
530 if (i != methParams.size() - 1)
534 if (!retType.equals("void"))
535 println("rmiObj.sendReturnObj(retObj);");
540 * HELPER: writeMethodHelperJavaSkeleton() writes the method helper of the skeleton class
542 private void writeMethodHelperJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
544 // Use this set to handle two same methodIds
545 Set<String> uniqueMethodIds = new HashSet<String>();
546 for (String method : methods) {
548 List<String> methParams = intDecl.getMethodParams(method);
549 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
550 String methodId = intDecl.getMethodId(method);
551 print("public void ___");
552 String helperMethod = methodId;
553 if (uniqueMethodIds.contains(methodId))
554 helperMethod = helperMethod + intDecl.getMethodNumId(method);
556 uniqueMethodIds.add(methodId);
557 // Check if this is "void"
558 String retType = intDecl.getMethodType(method);
559 if (retType.equals("void"))
560 println(helperMethod + "() {");
562 println(helperMethod + "() throws IOException {");
563 // Now, write the helper body of skeleton!
564 writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method);
571 * HELPER: writeJavaWaitRequestInvokeMethod() writes the main loop of the skeleton class
573 private void writeJavaWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl) {
575 // Use this set to handle two same methodIds
576 Set<String> uniqueMethodIds = new HashSet<String>();
577 println("private void ___waitRequestInvokeMethod() throws IOException {");
578 // Write variables here if we have callbacks or enums or structs
579 println("while (true) {");
580 println("rmiObj.getMethodBytes();");
581 println("int _objectId = rmiObj.getObjectId();");
582 println("int methodId = rmiObj.getMethodId();");
583 // TODO: code the permission check here!
584 println("switch (methodId) {");
585 // Print methods and method Ids
586 for (String method : methods) {
587 String methodId = intDecl.getMethodId(method);
588 int methodNumId = intDecl.getMethodNumId(method);
589 print("case " + methodNumId + ": ___");
590 String helperMethod = methodId;
591 if (uniqueMethodIds.contains(methodId))
592 helperMethod = helperMethod + methodNumId;
594 uniqueMethodIds.add(methodId);
595 println(helperMethod + "(); break;");
597 println("default: ");
598 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
606 * generateJavaSkeletonClass() generate skeletons based on the methods list in Java
608 public void generateJavaSkeletonClass() throws IOException {
610 // Create a new directory
611 createDirectory(dir);
612 for (String intface : mapIntfacePTH.keySet()) {
613 // Open a new file to write into
614 String newSkelClass = intface + "_Skeleton";
615 FileWriter fw = new FileWriter(dir + "/" + newSkelClass + ".java");
616 pw = new PrintWriter(new BufferedWriter(fw));
617 // Pass in set of methods and get import classes
618 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
619 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
620 List<String> methods = intDecl.getMethods();
621 Set<String> importClasses = getImportClasses(methods, intDecl);
622 List<String> stdImportClasses = getStandardJavaImportClasses();
623 List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
624 printImportStatements(allImportClasses);
625 // Write class header
627 println("public class " + newSkelClass + " implements " + intface + " {\n");
629 writePropertiesJavaSkeleton(intface);
631 writeConstructorJavaSkeleton(newSkelClass, intface);
633 writeMethodJavaSkeleton(methods, intDecl);
634 // Write method helper
635 writeMethodHelperJavaSkeleton(methods, intDecl);
636 // Write waitRequestInvokeMethod() - main loop
637 writeJavaWaitRequestInvokeMethod(methods, intDecl);
640 System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".java...");
646 * HELPER: writeMethodCplusInterface() writes the method of the interface
648 private void writeMethodCplusInterface(Collection<String> methods, InterfaceDecl intDecl) {
650 for (String method : methods) {
652 List<String> methParams = intDecl.getMethodParams(method);
653 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
654 print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
655 intDecl.getMethodId(method) + "(");
656 for (int i = 0; i < methParams.size(); i++) {
657 // Check for params with driver class types and exchange it
658 // with its remote interface
659 String paramType = checkAndGetParamClass(methPrmTypes.get(i), true);
660 paramType = checkAndGetCplusType(paramType);
661 // Check for arrays - translate into vector in C++
662 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
663 print(paramComplete);
664 // Check if this is the last element (don't print a comma)
665 if (i != methParams.size() - 1) {
675 * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking.
677 * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
678 * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
679 * The local interface has to be the input parameter for the stub and the stub
680 * interface has to be the input parameter for the local class.
682 public void generateCplusLocalInterfaces() throws IOException {
684 // Create a new directory
685 createDirectory(dir);
686 for (String intface : mapIntfacePTH.keySet()) {
687 // Open a new file to write into
688 FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
689 pw = new PrintWriter(new BufferedWriter(fw));
690 // Write file headers
691 println("#ifndef _" + intface.toUpperCase() + "_HPP__");
692 println("#define _" + intface.toUpperCase() + "_HPP__");
693 println("#include <iostream>");
694 // Pass in set of methods and get include classes
695 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
696 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
697 List<String> methods = intDecl.getMethods();
698 Set<String> includeClasses = getIncludeClasses(methods, intDecl);
699 printIncludeStatements(includeClasses); println("");
700 println("using namespace std;\n");
701 println("class " + intface); println("{");
704 writeMethodCplusInterface(methods, intDecl);
708 System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
714 * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
716 * For C++ we use virtual classe as interface
718 public void generateCPlusInterfaces() throws IOException {
720 // Create a new directory
721 String path = createDirectories(dir, subdir);
722 for (String intface : mapIntfacePTH.keySet()) {
724 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
725 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
727 // Open a new file to write into
728 String newIntface = intMeth.getKey();
729 FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp");
730 pw = new PrintWriter(new BufferedWriter(fw));
731 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
732 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
733 // Write file headers
734 println("#ifndef _" + newIntface.toUpperCase() + "_HPP__");
735 println("#define _" + newIntface.toUpperCase() + "_HPP__");
736 println("#include <iostream>");
737 // Pass in set of methods and get import classes
738 Set<String> includeClasses = getIncludeClasses(intMeth.getValue(), intDecl);
739 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
740 List<String> allIncludeClasses = getAllImportClasses(stdIncludeClasses, includeClasses);
741 printIncludeStatements(allIncludeClasses); println("");
742 println("using namespace std;\n");
743 println("class " + newIntface);
747 writeMethodCplusInterface(intMeth.getValue(), intDecl);
751 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
758 * HELPER: writeMethodCplusStub() writes the method of the stub
760 private void writeMethodCplusStub(Collection<String> methods, InterfaceDecl intDecl) {
762 for (String method : methods) {
764 List<String> methParams = intDecl.getMethodParams(method);
765 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
766 print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
767 intDecl.getMethodId(method) + "(");
768 for (int i = 0; i < methParams.size(); i++) {
769 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
770 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
771 print(methParamComplete);
772 // Check if this is the last element (don't print a comma)
773 if (i != methParams.size() - 1) {
778 writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method);
785 * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class
787 private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
788 List<String> methPrmTypes, String method) {
790 println("int numParam = " + methParams.size() + ";");
791 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
792 String retType = intDecl.getMethodType(method);
793 String retTypeC = checkAndGetCplusType(retType);
794 println("string retType = \"" + checkAndGetCplusArrayType(retTypeC) + "\";");
795 // Generate array of parameter types
796 print("string paramCls[] = { ");
797 for (int i = 0; i < methParams.size(); i++) {
798 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
799 String paramType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
800 print("\"" + paramType + "\"");
801 // Check if this is the last element (don't print a comma)
802 if (i != methParams.size() - 1) {
807 // Generate array of parameter objects
808 print("void* paramObj[] = { ");
809 for (int i = 0; i < methParams.size(); i++) {
810 print("&" + checkAndGetCplusType(getSimpleIdentifier(methParams.get(i))));
811 // Check if this is the last element (don't print a comma)
812 if (i != methParams.size() - 1) {
817 // Check if this is "void"
818 if (retType.equals("void")) {
819 println("void* retObj = NULL;");
820 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
821 } else { // We do have a return value
822 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
823 println(checkAndGetCplusType(retType) + " retVal;");
825 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
826 println("void* retObj = &retVal;");
827 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
828 println("return retVal;");
834 * HELPER: writePropertiesCplusStub() writes the properties of the stub class
836 private void writePropertiesCplusStub(String intface, String newIntface) {
838 println("IoTRMICall\t\t\t*rmiCall;");
839 //println("IoTRMIObject\t\t\t*rmiObj;");
840 println("string\t\t\t\taddress;");
841 println("vector<int>\t\t\tports;\n");
843 Integer objId = mapIntfaceObjId.get(intface);
844 println("const static int\tobjectId = " + objId + ";");
845 mapNewIntfaceObjId.put(newIntface, objId);
846 mapIntfaceObjId.put(intface, objId++);
852 * HELPER: writeConstructorCplusStub() writes the constructor of the stub class
854 private void writeConstructorCplusStub(String newStubClass) {
856 println(newStubClass +
857 "(int _port, const char* _address, int _rev, bool* _bResult, vector<int> _ports) {");
858 println("address = _address;");
859 println("ports = _ports;");
860 println("rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);");
866 * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
868 private void writeDeconstructorCplusStub(String newStubClass) {
870 println("~" + newStubClass + "() {");
871 println("if (rmiCall != NULL) {");
872 println("delete rmiCall;");
873 println("rmiCall = NULL;");
877 // Check if this is callback!!! and print "delete rmiObj and vecCBObj"
882 * generateCPlusStubClasses() generate stubs based on the methods list in C++
884 public void generateCPlusStubClasses() throws IOException {
886 // Create a new directory
887 String path = createDirectories(dir, subdir);
888 for (String intface : mapIntfacePTH.keySet()) {
890 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
891 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
892 // Open a new file to write into
893 String newIntface = intMeth.getKey();
894 String newStubClass = newIntface + "_Stub";
895 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
896 pw = new PrintWriter(new BufferedWriter(fw));
897 // Write file headers
898 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
899 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
900 println("#include <iostream>");
901 println("#include \"" + newIntface + ".hpp\""); println("");
902 println("using namespace std;"); println("");
903 println("class " + newStubClass + " : public " + newIntface); println("{");
904 println("private:\n");
905 writePropertiesCplusStub(intface, newIntface);
906 println("public:\n");
907 // Add default constructor and destructor
908 println(newStubClass + "() { }"); println("");
909 writeConstructorCplusStub(newStubClass);
910 writeDeconstructorCplusStub(newStubClass);
911 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
912 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
914 writeMethodCplusStub(intMeth.getValue(), intDecl);
915 print("}"); println(";");
918 System.out.println("IoTCompiler: Generated stub class " + newIntface + ".hpp...");
925 * HELPER: writePropertiesCplusSkeleton() writes the properties of the skeleton class
927 private void writePropertiesCplusSkeleton(String intface) {
929 println(intface + " *mainObj;");
930 //println("private int ports;");
931 //println("private IoTRMICall rmiCall;");
932 println("IoTRMIObject *rmiObj;\n");
933 // Keep track of object Ids of all stubs registered to this interface
934 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
935 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
936 String newIntface = intMeth.getKey();
937 int newObjectId = mapNewIntfaceObjId.get(newIntface);
938 // println("const static int object" + newObjectId + "Id = " +
939 // newObjectId + ";\t//" + newIntface);
942 // TODO: code the set of allowed functions here
948 * HELPER: writeConstructorCplusSkeleton() writes the constructor of the skeleton class
950 private void writeConstructorCplusSkeleton(String newSkelClass, String intface) {
952 println(newSkelClass + "(" + intface + " *_mainObj, int _port) {");
953 println("bool _bResult = false;");
954 println("mainObj = _mainObj;");
955 println("rmiObj = new IoTRMIObject(_port, &_bResult);");
956 //println("set0Allowed = Arrays.asList(object0Permission);");
957 //println("___waitRequestInvokeMethod();");
963 * HELPER: writeDeconstructorCplusSkeleton() writes the deconstructor of the skeleton class
965 private void writeDeconstructorCplusSkeleton(String newSkelClass) {
967 println("~" + newSkelClass + "() {");
968 println("if (rmiObj != NULL) {");
969 println("delete rmiObj;");
970 println("rmiObj = NULL;");
974 // Check if this is callback!!! and print "delete rmiObj and vecCBObj"
979 * HELPER: writeStdMethodBodyCplusSkeleton() writes the standard method body in the skeleton class
981 private void writeStdMethodBodyCplusSkeleton(List<String> methParams, String methodId, String methodType) {
983 if (methodType.equals("void"))
984 print("mainObj->" + methodId + "(");
986 print("return mainObj->" + methodId + "(");
987 for (int i = 0; i < methParams.size(); i++) {
989 print(getSimpleIdentifier(methParams.get(i)));
990 // Check if this is the last element (don't print a comma)
991 if (i != methParams.size() - 1) {
1000 * HELPER: writeMethodCplusSkeleton() writes the method of the skeleton class
1002 private void writeMethodCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
1004 for (String method : methods) {
1006 List<String> methParams = intDecl.getMethodParams(method);
1007 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1008 String methodId = intDecl.getMethodId(method);
1009 String methodType = checkAndGetCplusType(intDecl.getMethodType(method));
1010 print(methodType + " " + methodId + "(");
1011 for (int i = 0; i < methParams.size(); i++) {
1012 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
1013 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
1014 print(methParamComplete);
1015 // Check if this is the last element (don't print a comma)
1016 if (i != methParams.size() - 1) {
1021 // Now, write the body of skeleton!
1022 writeStdMethodBodyCplusSkeleton(methParams, methodId, intDecl.getMethodType(method));
1029 * HELPER: writeStdMethodHelperBodyCplusSkeleton() writes the standard method body helper in the skeleton class
1031 private void writeStdMethodHelperBodyCplusSkeleton(InterfaceDecl intDecl, List<String> methParams,
1032 List<String> methPrmTypes, String method, String methodId) {
1034 // Generate array of parameter types
1035 print("string paramCls[] = { ");
1036 for (int i = 0; i < methParams.size(); i++) {
1037 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
1038 String paramType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
1039 print("\"" + paramType + "\"");
1040 if (i != methParams.size() - 1) {
1045 println("int numParam = " + methParams.size() + ";");
1046 // Generate parameters
1047 for (int i = 0; i < methParams.size(); i++) {
1048 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
1049 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
1050 println(methParamComplete + ";");
1052 // Generate array of parameter objects
1053 print("void* paramObj[] = { ");
1054 for (int i = 0; i < methParams.size(); i++) {
1055 print("&" + getSimpleIdentifier(methParams.get(i)));
1056 if (i != methParams.size() - 1) {
1061 println("rmiObj->getMethodParams(paramCls, numParam, paramObj);");
1062 String retType = intDecl.getMethodType(method);
1063 // Check if this is "void"
1064 if (retType.equals("void")) {
1065 print(methodId + "(");
1066 for (int i = 0; i < methParams.size(); i++) {
1067 print(getSimpleIdentifier(methParams.get(i)));
1068 if (i != methParams.size() - 1) {
1073 } else { // We do have a return value
1074 print(checkAndGetCplusType(retType) + " retVal = " + methodId + "(");
1075 for (int i = 0; i < methParams.size(); i++) {
1076 print(getSimpleIdentifier(methParams.get(i)));
1077 if (i != methParams.size() - 1) {
1082 println("void* retObj = &retVal;");
1083 String retTypeC = checkAndGetCplusType(retType);
1084 println("rmiObj->sendReturnObj(retObj, \"" + checkAndGetCplusArrayType(retTypeC) + "\");");
1090 * HELPER: writeMethodHelperCplusSkeleton() writes the method helper of the skeleton class
1092 private void writeMethodHelperCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
1094 // Use this set to handle two same methodIds
1095 Set<String> uniqueMethodIds = new HashSet<String>();
1096 for (String method : methods) {
1098 List<String> methParams = intDecl.getMethodParams(method);
1099 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1100 String methodId = intDecl.getMethodId(method);
1102 String helperMethod = methodId;
1103 if (uniqueMethodIds.contains(methodId))
1104 helperMethod = helperMethod + intDecl.getMethodNumId(method);
1106 uniqueMethodIds.add(methodId);
1107 // Check if this is "void"
1108 String retType = intDecl.getMethodType(method);
1109 println(helperMethod + "() {");
1110 // Now, write the helper body of skeleton!
1111 writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId);
1118 * HELPER: writeCplusWaitRequestInvokeMethod() writes the main loop of the skeleton class
1120 private void writeCplusWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl) {
1122 // Use this set to handle two same methodIds
1123 Set<String> uniqueMethodIds = new HashSet<String>();
1124 println("void ___waitRequestInvokeMethod() {");
1125 // Write variables here if we have callbacks or enums or structs
1126 println("while (true) {");
1127 println("rmiObj->getMethodBytes();");
1128 println("int _objectId = rmiObj->getObjectId();");
1129 println("int methodId = rmiObj->getMethodId();");
1130 // TODO: code the permission check here!
1131 println("switch (methodId) {");
1132 // Print methods and method Ids
1133 for (String method : methods) {
1134 String methodId = intDecl.getMethodId(method);
1135 int methodNumId = intDecl.getMethodNumId(method);
1136 print("case " + methodNumId + ": ___");
1137 String helperMethod = methodId;
1138 if (uniqueMethodIds.contains(methodId))
1139 helperMethod = helperMethod + methodNumId;
1141 uniqueMethodIds.add(methodId);
1142 println(helperMethod + "(); break;");
1144 println("default: ");
1145 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
1146 println("throw exception();");
1154 * generateCplusSkeletonClass() generate skeletons based on the methods list in C++
1156 public void generateCplusSkeletonClass() throws IOException {
1158 // Create a new directory
1159 createDirectory(dir);
1160 for (String intface : mapIntfacePTH.keySet()) {
1161 // Open a new file to write into
1162 String newSkelClass = intface + "_Skeleton";
1163 FileWriter fw = new FileWriter(dir + "/" + newSkelClass + ".hpp");
1164 pw = new PrintWriter(new BufferedWriter(fw));
1165 // Write file headers
1166 println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
1167 println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
1168 println("#include <iostream>");
1169 println("#include \"" + intface + ".hpp\"\n");
1170 // Pass in set of methods and get import classes
1171 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1172 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1173 List<String> methods = intDecl.getMethods();
1174 Set<String> includeClasses = getIncludeClasses(methods, intDecl);
1175 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
1176 List<String> allIncludeClasses = getAllImportClasses(stdIncludeClasses, includeClasses);
1177 printIncludeStatements(allIncludeClasses); println("");
1178 println("using namespace std;\n");
1179 // Write class header
1180 println("class " + newSkelClass + " : public " + intface); println("{");
1181 println("private:\n");
1183 writePropertiesCplusSkeleton(intface);
1184 println("public:\n");
1185 // Write constructor
1186 writeConstructorCplusSkeleton(newSkelClass, intface);
1187 // Write deconstructor
1188 writeDeconstructorCplusSkeleton(newSkelClass);
1190 writeMethodCplusSkeleton(methods, intDecl);
1191 // Write method helper
1192 writeMethodHelperCplusSkeleton(methods, intDecl);
1193 // Write waitRequestInvokeMethod() - main loop
1194 writeCplusWaitRequestInvokeMethod(methods, intDecl);
1198 System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".hpp...");
1204 * generateInitializer() generate initializer based on type
1206 public String generateCplusInitializer(String type) {
1208 // Generate dummy returns for now
1209 if (type.equals("short")||
1210 type.equals("int") ||
1211 type.equals("long") ||
1212 type.equals("float")||
1213 type.equals("double")) {
1216 } else if ( type.equals("String") ||
1217 type.equals("string")) {
1220 } else if ( type.equals("char") ||
1221 type.equals("byte")) {
1224 } else if ( type.equals("boolean")) {
1234 * generateReturnStmt() generate return statement based on methType
1236 public String generateReturnStmt(String methType) {
1238 // Generate dummy returns for now
1239 if (methType.equals("short")||
1240 methType.equals("int") ||
1241 methType.equals("long") ||
1242 methType.equals("float")||
1243 methType.equals("double")) {
1246 } else if ( methType.equals("String")) {
1249 } else if ( methType.equals("char") ||
1250 methType.equals("byte")) {
1253 } else if ( methType.equals("boolean")) {
1263 * setDirectory() sets a new directory for stub files
1265 public void setDirectory(String _subdir) {
1272 * printUsage() prints the usage of this compiler
1274 public static void printUsage() {
1276 System.out.println();
1277 System.out.println("Sentinel interface and stub compiler version 1.0");
1278 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
1279 System.out.println("All rights reserved.");
1280 System.out.println("Usage:");
1281 System.out.println("\tjava IoTCompiler -help / --help / -h\n");
1282 System.out.println("\t\tDisplay this help texts\n\n");
1283 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>]");
1284 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>] [options]\n");
1285 System.out.println("\t\tTake one or more pairs of main-req policy files, and generate Java and/or C++ files\n");
1286 System.out.println("Options:");
1287 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
1288 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
1289 System.out.println();
1294 * parseFile() prepares Lexer and Parser objects, then parses the file
1296 public static ParseNode parseFile(String file) {
1298 ParseNode pn = null;
1300 ComplexSymbolFactory csf = new ComplexSymbolFactory();
1301 ScannerBuffer lexer =
1302 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf));
1303 Parser parse = new Parser(lexer,csf);
1304 pn = (ParseNode) parse.parse().value;
1305 } catch (Exception e) {
1306 e.printStackTrace();
1307 throw new Error("IoTCompiler: ERROR parsing policy file or wrong command line option: " + file);
1318 boolean newline=true;
1321 private void print(String str) {
1324 if (str.equals("}"))
1326 for(int i=0; i<tab; i++)
1336 * This function converts Java to C++ type for compilation
1338 private String convertType(String jType) {
1340 return mapPrimitives.get(jType);
1344 private void println(String str) {
1347 if (str.equals("}"))
1349 for(int i=0; i<tab; i++)
1358 private void updatetabbing(String str) {
1359 tablevel+=count(str,'{')-count(str,'}');
1363 private int count(String str, char key) {
1364 char[] array = str.toCharArray();
1366 for(int i=0; i<array.length; i++) {
1367 if (array[i] == key)
1374 private void createDirectory(String dirName) {
1376 File file = new File(dirName);
1377 if (!file.exists()) {
1379 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
1381 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
1384 System.out.println("IoTCompiler: Directory " + dirName + " exists...");
1389 // Create a directory and possibly a sub directory
1390 private String createDirectories(String dir, String subdir) {
1393 createDirectory(path);
1394 if (subdir != null) {
1395 path = path + "/" + subdir;
1396 createDirectory(path);
1402 // Inserting array members into a Map object
1403 // that maps arrKey to arrVal objects
1404 private void arraysToMap(Map map, Object[] arrKey, Object[] arrVal) {
1406 for(int i = 0; i < arrKey.length; i++) {
1408 map.put(arrKey[i], arrVal[i]);
1413 // Return parameter category, i.e. PRIMITIVES, NONPRIMITIVES, or USERDEFINED
1414 private ParamCategory getParamCategory(String paramType) {
1416 if (mapPrimitives.containsKey(paramType)) {
1417 return ParamCategory.PRIMITIVES;
1418 // We can either use mapNonPrimitivesJava or mapNonPrimitivesCplus here
1419 } else if (mapNonPrimitivesJava.containsKey(getSimpleType(paramType))) {
1420 return ParamCategory.NONPRIMITIVES;
1422 return ParamCategory.USERDEFINED;
1426 // Return full class name for non-primitives to generate Java import statements
1427 // e.g. java.util.Set for Set, java.util.Map for Map
1428 private String getNonPrimitiveJavaClass(String paramNonPrimitives) {
1430 return mapNonPrimitivesJava.get(paramNonPrimitives);
1434 // Return full class name for non-primitives to generate Cplus include statements
1435 // e.g. #include <set> for Set, #include <map> for Map
1436 private String getNonPrimitiveCplusClass(String paramNonPrimitives) {
1438 return mapNonPrimitivesCplus.get(paramNonPrimitives);
1442 // Get simple types, e.g. HashSet for HashSet<...>
1443 // Basically strip off the "<...>"
1444 private String getSimpleType(String paramType) {
1446 // Check if this is generics
1447 if(paramType.contains("<")) {
1448 String[] type = paramType.split("<");
1455 // Generate a set of standard classes for import statements
1456 private List<String> getStandardJavaImportClasses() {
1458 List<String> importClasses = new ArrayList<String>();
1459 // Add the standard list first
1460 importClasses.add("java.io.IOException");
1461 importClasses.add("java.util.List");
1462 importClasses.add("java.util.ArrayList");
1463 importClasses.add("iotrmi.Java.IoTRMICall");
1464 importClasses.add("iotrmi.Java.IoTRMIObject");
1466 return importClasses;
1470 // Generate a set of standard classes for import statements
1471 private List<String> getStandardCplusIncludeClasses() {
1473 List<String> importClasses = new ArrayList<String>();
1474 // Add the standard list first
1475 importClasses.add("<vector>");
1476 importClasses.add("\"IoTRMICall.hpp\"");
1477 importClasses.add("\"IoTRMIObject.hpp\"");
1479 return importClasses;
1483 // Generate a set of standard classes for import statements
1484 private List<String> getAllImportClasses(Collection<String> stdImportClasses, Collection<String> importClasses) {
1486 List<String> allImportClasses = new ArrayList<String>(stdImportClasses);
1487 // Iterate over the list of import classes
1488 for (String str : importClasses) {
1489 if (!stdImportClasses.contains(str)) {
1490 stdImportClasses.add(str);
1494 return allImportClasses;
1499 // Generate a set of classes for import statements
1500 private Set<String> getImportClasses(Collection<String> methods, InterfaceDecl intDecl) {
1502 Set<String> importClasses = new HashSet<String>();
1503 for (String method : methods) {
1504 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1505 for (String paramType : methPrmTypes) {
1507 String simpleType = getSimpleType(paramType);
1508 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
1509 importClasses.add(getNonPrimitiveJavaClass(simpleType));
1513 return importClasses;
1517 // Generate a set of classes for include statements
1518 private Set<String> getIncludeClasses(Collection<String> methods, InterfaceDecl intDecl) {
1520 Set<String> includeClasses = new HashSet<String>();
1521 for (String method : methods) {
1523 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1524 List<String> methParams = intDecl.getMethodParams(method);
1525 for (int i = 0; i < methPrmTypes.size(); i++) {
1527 String simpleType = getSimpleType(methPrmTypes.get(i));
1528 String param = methParams.get(i);
1529 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
1530 includeClasses.add("<" + getNonPrimitiveCplusClass(simpleType) + ">");
1531 } else if (getParamCategory(simpleType) == ParamCategory.USERDEFINED) {
1532 includeClasses.add("\"" + exchangeParamType(simpleType) + ".hpp\"");
1533 } else if (param.contains("[]")) {
1534 // Check if this is array for C++; translate into vector
1535 includeClasses.add("<vector>");
1539 return includeClasses;
1543 private void printImportStatements(Collection<String> importClasses) {
1545 for(String cls : importClasses) {
1546 println("import " + cls + ";");
1551 private void printIncludeStatements(Collection<String> includeClasses) {
1553 for(String cls : includeClasses) {
1554 println("#include " + cls);
1559 // Get the C++ version of a non-primitive type
1560 // e.g. set for Set and map for Map
1561 // Input nonPrimitiveType has to be generics in format
1562 private String[] getTypeOfGeneric(String nonPrimitiveType) {
1564 // Handle <, >, and , for 2-type generic/template
1565 String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(",");
1570 // This helper function strips off array declaration, e.g. D[] becomes D
1571 private String getSimpleIdentifier(String ident) {
1573 // Handle [ for array declaration
1574 String substr = ident;
1575 if (ident.contains("[]")) {
1576 substr = ident.split("\\[\\]")[0];
1582 private String checkAndGetCplusType(String paramType) {
1584 if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
1585 return convertType(paramType);
1586 } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) {
1588 // Check for generic/template format
1589 if (paramType.contains("<") && paramType.contains(">")) {
1591 String genericClass = getSimpleType(paramType);
1592 String[] genericType = getTypeOfGeneric(paramType);
1593 String cplusTemplate = null;
1594 if (genericType.length == 1) // Generic/template with one type
1595 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
1596 "<" + convertType(genericType[0]) + ">";
1597 else // Generic/template with two types
1598 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
1599 "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">";
1600 return cplusTemplate;
1602 return getNonPrimitiveCplusClass(paramType);
1604 // Just return it as is if it's not non-primitives
1609 // Detect array declaration, e.g. int A[],
1610 // then generate "int A[]" in C++ as "vector<int> A"
1611 private String checkAndGetCplusArray(String paramType, String param) {
1613 String paramComplete = null;
1614 // Check for array declaration
1615 if (param.contains("[]")) {
1616 paramComplete = "vector<" + paramType + "> " + param.replace("[]","");
1618 // Just return it as is if it's not an array
1619 paramComplete = paramType + " " + param;
1621 return paramComplete;
1625 // Detect array declaration, e.g. int A[],
1626 // then generate "int A[]" in C++ as "vector<int> A"
1627 // This method just returns the type
1628 private String checkAndGetCplusArrayType(String paramType) {
1630 String paramTypeRet = null;
1631 // Check for array declaration
1632 if (paramType.contains("[]")) {
1633 String type = paramType.split("\\[\\]")[0];
1634 paramTypeRet = checkAndGetCplusType(type) + "[]";
1635 } else if (paramType.contains("vector")) {
1636 // Just return it as is if it's not an array
1637 String type = paramType.split("<")[1].split(">")[0];
1638 paramTypeRet = checkAndGetCplusType(type) + "[]";
1640 paramTypeRet = paramType;
1642 return paramTypeRet;
1646 // Detect array declaration, e.g. int A[],
1647 // then generate "int A[]" in C++ as "vector<int> A"
1648 // This method just returns the type
1649 private String checkAndGetCplusArrayType(String paramType, String param) {
1651 String paramTypeRet = null;
1652 // Check for array declaration
1653 if (param.contains("[]")) {
1654 paramTypeRet = checkAndGetCplusType(paramType) + "[]";
1655 } else if (paramType.contains("vector")) {
1656 // Just return it as is if it's not an array
1657 String type = paramType.split("<")[1].split(">")[0];
1658 paramTypeRet = checkAndGetCplusType(type) + "[]";
1660 paramTypeRet = paramType;
1662 return paramTypeRet;
1666 // Detect array declaration, e.g. int A[],
1667 // then generate type "int[]"
1668 private String checkAndGetArray(String paramType, String param) {
1670 String paramTypeRet = null;
1671 // Check for array declaration
1672 if (param.contains("[]")) {
1673 paramTypeRet = paramType + "[]";
1675 // Just return it as is if it's not an array
1676 paramTypeRet = paramType;
1678 return paramTypeRet;
1682 // Get simple types, e.g. HashSet for HashSet<...>
1683 // Basically strip off the "<...>"
1684 private String checkAndGetParamClass(String paramType, boolean needPtr) {
1686 // Check if this is generics
1687 if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
1688 // If true then return with pointer (C++)
1690 return exchangeParamType(paramType) + "*";
1691 else // Java, so no pointer needed
1692 return exchangeParamType(paramType);
1698 // Returns the other interface for type-checking purposes for USERDEFINED
1699 // classes based on the information provided in multiple policy files
1700 // e.g. return CameraWithXXX instead of Camera
1701 private String exchangeParamType(String intface) {
1703 // Param type that's passed is the interface name we need to look for
1704 // in the map of interfaces, based on available policy files.
1705 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1706 if (decHandler != null) {
1707 // We've found the required interface policy files
1708 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(intface);
1709 Set<String> setExchInt = reqDecl.getInterfaces();
1710 if (setExchInt.size() == 1) {
1711 Iterator iter = setExchInt.iterator();
1712 return (String) iter.next();
1714 throw new Error("IoTCompiler: Ambiguous stub interfaces: " + setExchInt.toString() +
1715 ". Only one new interface can be declared if the object " + intface +
1716 " needs to be passed in as an input parameter!");
1719 // NULL value - this means policy files missing
1720 throw new Error("IoTCompiler: Parameter type lookup failed for " + intface +
1721 "... Please provide the necessary policy files for user-defined types." +
1722 " If this is an array please type the brackets after the variable name," +
1723 " e.g. \"String str[]\", not \"String[] str\"." +
1724 " If this is a Collections (Java) / STL (C++) type, this compiler only" +
1725 " supports List/ArrayList (Java) or list (C++).");
1730 public static void main(String[] args) throws Exception {
1732 // If there is no argument or just "--help" or "-h", then invoke printUsage()
1733 if ((args[0].equals("-help") ||
1734 args[0].equals("--help")||
1735 args[0].equals("-h")) ||
1736 (args.length == 0)) {
1738 IoTCompiler.printUsage();
1740 } else if (args.length > 1) {
1742 IoTCompiler comp = new IoTCompiler();
1745 // Parse main policy file
1746 ParseNode pnPol = IoTCompiler.parseFile(args[i]);
1747 // Parse "requires" policy file
1748 ParseNode pnReq = IoTCompiler.parseFile(args[i+1]);
1749 // Get interface name
1750 String intface = ParseTreeHandler.getOrigIntface(pnPol);
1751 comp.setDataStructures(intface, pnPol, pnReq);
1752 comp.getMethodsForIntface(intface);
1754 // 1) Check if this is the last option before "-java" or "-cplus"
1755 // 2) Check if this is really the last option (no "-java" or "-cplus")
1756 } while(!args[i].equals("-java") &&
1757 !args[i].equals("-cplus") &&
1760 // Generate everything if we don't see "-java" or "-cplus"
1761 if (i == args.length) {
1762 comp.generateJavaLocalInterfaces();
1763 comp.generateJavaInterfaces();
1764 comp.generateJavaStubClasses();
1765 comp.generateJavaSkeletonClass();
1766 comp.generateCplusLocalInterfaces();
1767 comp.generateCPlusInterfaces();
1768 comp.generateCPlusStubClasses();
1769 comp.generateCplusSkeletonClass();
1771 // Check other options
1772 while(i < args.length) {
1774 if (!args[i].equals("-java") &&
1775 !args[i].equals("-cplus")) {
1776 throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
1778 if (i + 1 < args.length) {
1779 comp.setDirectory(args[i+1]);
1781 throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
1783 if (args[i].equals("-java")) {
1784 comp.generateJavaLocalInterfaces();
1785 comp.generateJavaInterfaces();
1786 comp.generateJavaStubClasses();
1787 comp.generateJavaSkeletonClass();
1789 comp.generateCplusLocalInterfaces();
1790 comp.generateCPlusInterfaces();
1791 comp.generateCPlusStubClasses();
1792 comp.generateCplusSkeletonClass();
1799 // Need to at least have exactly 2 parameters, i.e. main policy file and requires file
1800 IoTCompiler.printUsage();
1801 throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");