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;
27 import iotpolicy.tree.EnumDecl;
28 import iotpolicy.tree.StructDecl;
30 import iotrmi.Java.IoTRMITypes;
33 /** Class IoTCompiler is the main interface/stub compiler for
34 * files generation. This class calls helper classes
35 * such as Parser, Lexer, InterfaceDecl, CapabilityDecl,
36 * RequiresDecl, ParseTreeHandler, etc.
38 * @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
42 public class IoTCompiler {
47 // Maps multiple interfaces to multiple objects of ParseTreeHandler
48 private Map<String,ParseTreeHandler> mapIntfacePTH;
49 private Map<String,DeclarationHandler> mapIntDeclHand;
50 private Map<String,Map<String,Set<String>>> mapInt2NewInts;
51 // Data structure to store our types (primitives and non-primitives) for compilation
52 private Map<String,String> mapPrimitives;
53 private Map<String,String> mapNonPrimitivesJava;
54 private Map<String,String> mapNonPrimitivesCplus;
55 // Other data structures
56 private Map<String,Integer> mapIntfaceObjId; // Maps interface name to object Id
57 private Map<String,Integer> mapNewIntfaceObjId; // Maps new interface name to its object Id (keep track of stubs)
58 private PrintWriter pw;
60 private String subdir;
65 private final static String OUTPUT_DIRECTORY = "output_files";
67 private enum ParamCategory {
69 PRIMITIVES, // All the primitive types, e.g. byte, short, int, long, etc.
70 NONPRIMITIVES, // Non-primitive types, e.g. Set, Map, List, etc.
71 USERDEFINED // Non-supported type by default; assumed as driver classes
77 public IoTCompiler() {
79 mapIntfacePTH = new HashMap<String,ParseTreeHandler>();
80 mapIntDeclHand = new HashMap<String,DeclarationHandler>();
81 mapInt2NewInts = new HashMap<String,Map<String,Set<String>>>();
82 mapIntfaceObjId = new HashMap<String,Integer>();
83 mapNewIntfaceObjId = new HashMap<String,Integer>();
84 mapPrimitives = new HashMap<String,String>();
85 arraysToMap(mapPrimitives, IoTRMITypes.primitivesJava, IoTRMITypes.primitivesCplus);
86 mapNonPrimitivesJava = new HashMap<String,String>();
87 arraysToMap(mapNonPrimitivesJava, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitiveJavaLibs);
88 mapNonPrimitivesCplus = new HashMap<String,String>();
89 arraysToMap(mapNonPrimitivesCplus, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitivesCplus);
91 dir = OUTPUT_DIRECTORY;
97 * setDataStructures() sets parse tree and other data structures based on policy files.
99 * It also generates parse tree (ParseTreeHandler) and
100 * copies useful information from parse tree into
101 * InterfaceDecl, CapabilityDecl, and RequiresDecl
103 * Additionally, the data structure handles are
104 * returned from tree-parsing for further process.
107 public void setDataStructures(String origInt, ParseNode pnPol, ParseNode pnReq) {
109 ParseTreeHandler ptHandler = new ParseTreeHandler(origInt, pnPol, pnReq);
110 DeclarationHandler decHandler = new DeclarationHandler();
111 // Process ParseNode and generate Declaration objects
113 ptHandler.processInterfaceDecl();
114 InterfaceDecl intDecl = ptHandler.getInterfaceDecl();
115 decHandler.addInterfaceDecl(origInt, intDecl);
117 ptHandler.processCapabilityDecl();
118 CapabilityDecl capDecl = ptHandler.getCapabilityDecl();
119 decHandler.addCapabilityDecl(origInt, capDecl);
121 ptHandler.processRequiresDecl();
122 RequiresDecl reqDecl = ptHandler.getRequiresDecl();
123 decHandler.addRequiresDecl(origInt, reqDecl);
125 ptHandler.processEnumDecl();
126 EnumDecl enumDecl = ptHandler.getEnumDecl();
127 decHandler.addEnumDecl(origInt, enumDecl);
129 ptHandler.processStructDecl();
130 StructDecl structDecl = ptHandler.getStructDecl();
131 decHandler.addStructDecl(origInt, structDecl);
133 mapIntfacePTH.put(origInt, ptHandler);
134 mapIntDeclHand.put(origInt, decHandler);
135 // Set object Id counter to 0 for each interface
136 mapIntfaceObjId.put(origInt, new Integer(0));
141 * getMethodsForIntface() reads for methods in the data structure
143 * It is going to give list of methods for a certain interface
144 * based on the declaration of capabilities.
146 public void getMethodsForIntface(String origInt) {
148 ParseTreeHandler ptHandler = mapIntfacePTH.get(origInt);
149 Map<String,Set<String>> mapNewIntMethods = new HashMap<String,Set<String>>();
150 // Get set of new interfaces, e.g. CameraWithCaptureAndData
151 // Generate this new interface with all the methods it needs
152 // from different capabilities it declares
153 DeclarationHandler decHandler = mapIntDeclHand.get(origInt);
154 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(origInt);
155 Set<String> setIntfaces = reqDecl.getInterfaces();
156 for (String strInt : setIntfaces) {
158 // Initialize a set of methods
159 Set<String> setMethods = new HashSet<String>();
160 // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc.
161 List<String> listCapab = reqDecl.getCapabList(strInt);
162 for (String strCap : listCapab) {
164 // Get list of methods for each capability
165 CapabilityDecl capDecl = (CapabilityDecl) decHandler.getCapabilityDecl(origInt);
166 List<String> listCapabMeth = capDecl.getMethods(strCap);
167 for (String strMeth : listCapabMeth) {
169 // Add methods into setMethods
170 // This is to also handle redundancies (say two capabilities
171 // share the same methods)
172 setMethods.add(strMeth);
175 // Add interface and methods information into map
176 mapNewIntMethods.put(strInt, setMethods);
178 // Map the map of interface-methods to the original interface
179 mapInt2NewInts.put(origInt, mapNewIntMethods);
184 * HELPER: writeMethodJavaInterface() writes the method of the interface
186 private void writeMethodJavaInterface(Collection<String> methods, InterfaceDecl intDecl) {
188 for (String method : methods) {
190 List<String> methParams = intDecl.getMethodParams(method);
191 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
192 print("public " + intDecl.getMethodType(method) + " " +
193 intDecl.getMethodId(method) + "(");
194 for (int i = 0; i < methParams.size(); i++) {
195 // Check for params with driver class types and exchange it
196 // with its remote interface
197 String paramType = checkAndGetParamClass(methPrmTypes.get(i), false);
198 print(paramType + " " + methParams.get(i));
199 // Check if this is the last element (don't print a comma)
200 if (i != methParams.size() - 1) {
210 * HELPER: writeEnumJava() writes the enumeration declaration
212 private void writeEnumJava(EnumDecl enumDecl) {
214 Set<String> enumTypes = enumDecl.getEnumDeclarations();
215 // Iterate over enum declarations
216 for (String enType : enumTypes) {
218 println("public enum " + enType + " {");
219 List<String> enumMembers = enumDecl.getMembers(enType);
220 for (int i = 0; i < enumMembers.size(); i++) {
222 String member = enumMembers.get(i);
224 // Check if this is the last element (don't print a comma)
225 if (i != enumMembers.size() - 1)
236 * HELPER: writeStructJava() writes the struct declaration
238 private void writeStructJava(StructDecl structDecl) {
240 List<String> structTypes = structDecl.getStructTypes();
241 // Iterate over enum declarations
242 for (String stType : structTypes) {
244 println("public class " + stType + " {");
245 List<String> structMemberTypes = structDecl.getMemberTypes(stType);
246 List<String> structMembers = structDecl.getMembers(stType);
247 for (int i = 0; i < structMembers.size(); i++) {
249 String memberType = structMemberTypes.get(i);
250 String member = structMembers.get(i);
251 println("public static " + memberType + " " + member + ";");
259 * generateJavaLocalInterface() writes the local interface and provides type-checking.
261 * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
262 * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
263 * The local interface has to be the input parameter for the stub and the stub
264 * interface has to be the input parameter for the local class.
266 public void generateJavaLocalInterfaces() throws IOException {
268 // Create a new directory
269 createDirectory(dir);
270 for (String intface : mapIntfacePTH.keySet()) {
271 // Open a new file to write into
272 FileWriter fw = new FileWriter(dir + "/" + intface + ".java");
273 pw = new PrintWriter(new BufferedWriter(fw));
274 // Pass in set of methods and get import classes
275 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
276 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
277 List<String> methods = intDecl.getMethods();
278 Set<String> importClasses = getImportClasses(methods, intDecl);
279 printImportStatements(importClasses);
280 // Write interface header
282 println("public interface " + intface + " {");
283 // Write enum if any...
284 EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface);
285 writeEnumJava(enumDecl);
286 // Write struct if any...
287 StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
288 writeStructJava(structDecl);
290 writeMethodJavaInterface(methods, intDecl);
293 System.out.println("IoTCompiler: Generated local interface " + intface + ".java...");
299 * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
301 public void generateJavaInterfaces() throws IOException {
303 // Create a new directory
304 String path = createDirectories(dir, subdir);
305 for (String intface : mapIntfacePTH.keySet()) {
307 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
308 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
310 // Open a new file to write into
311 String newIntface = intMeth.getKey();
312 FileWriter fw = new FileWriter(path + "/" + newIntface + ".java");
313 pw = new PrintWriter(new BufferedWriter(fw));
314 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
315 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
316 // Pass in set of methods and get import classes
317 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
318 printImportStatements(importClasses);
319 // Write interface header
321 println("public interface " + newIntface + " {\n");
323 writeMethodJavaInterface(intMeth.getValue(), intDecl);
326 System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
333 * HELPER: writePropertiesJavaStub() writes the properties of the stub class
335 private void writePropertiesJavaStub(String intface, String newIntface) {
337 println("private IoTRMICall rmiCall;");
338 //println("private IoTRMIObject rmiObj;");
339 println("private String address;");
340 println("private int[] ports;\n");
342 Integer objId = mapIntfaceObjId.get(intface);
343 println("private final static int objectId = " + objId + ";");
344 mapNewIntfaceObjId.put(newIntface, objId);
345 mapIntfaceObjId.put(intface, objId++);
351 * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
353 private void writeConstructorJavaStub(String intface) {
355 println("public " + intface + "(int _port, String _address, int _rev, int[] _ports) throws Exception {");
356 println("address = _address;");
357 println("ports = _ports;");
358 println("rmiCall = new IoTRMICall(_port, _address, _rev);");
364 * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class
366 private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
367 List<String> methPrmTypes, String method) {
369 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
370 String retType = intDecl.getMethodType(method);
371 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
372 // Generate array of parameter types
373 print("Class<?>[] paramCls = new Class<?>[] { ");
374 for (int i = 0; i < methParams.size(); i++) {
375 String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
376 print(getSimpleType(paramType) + ".class");
377 // Check if this is the last element (don't print a comma)
378 if (i != methParams.size() - 1) {
383 // Generate array of parameter objects
384 print("Object[] paramObj = new Object[] { ");
385 for (int i = 0; i < methParams.size(); i++) {
386 print(getSimpleIdentifier(methParams.get(i)));
387 // Check if this is the last element (don't print a comma)
388 if (i != methParams.size() - 1) {
393 // Check if this is "void"
394 if (retType.equals("void")) {
395 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
396 } else { // We do have a return value
397 // Check if the return value NONPRIMITIVES
398 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
399 String[] retGenValType = getTypeOfGeneric(retType);
400 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
401 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
402 println("return (" + retType + ")retObj;");
404 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
405 println("return (" + retType + ")retObj;");
412 * HELPER: writeMethodJavaStub() writes the method of the stub class
414 private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl) {
416 for (String method : methods) {
418 List<String> methParams = intDecl.getMethodParams(method);
419 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
420 print("public " + intDecl.getMethodType(method) + " " +
421 intDecl.getMethodId(method) + "(");
422 for (int i = 0; i < methParams.size(); i++) {
424 print(methPrmTypes.get(i) + " " + methParams.get(i));
425 // Check if this is the last element (don't print a comma)
426 if (i != methParams.size() - 1) {
431 // Now, write the body of stub!
432 writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
439 * generateJavaStubClasses() generate stubs based on the methods list in Java
441 public void generateJavaStubClasses() throws IOException {
443 // Create a new directory
444 String path = createDirectories(dir, subdir);
445 for (String intface : mapIntfacePTH.keySet()) {
447 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
448 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
450 // Open a new file to write into
451 String newIntface = intMeth.getKey();
452 String newStubClass = newIntface + "_Stub";
453 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
454 pw = new PrintWriter(new BufferedWriter(fw));
455 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
456 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
457 // Pass in set of methods and get import classes
458 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
459 List<String> stdImportClasses = getStandardJavaImportClasses();
460 List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
461 printImportStatements(allImportClasses); println("");
462 // Write class header
463 println("public class " + newStubClass + " implements " + newIntface + " {\n");
465 writePropertiesJavaStub(intface, newIntface);
467 writeConstructorJavaStub(newStubClass);
469 writeMethodJavaStub(intMeth.getValue(), intDecl);
472 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
479 * HELPER: writePropertiesJavaSkeleton() writes the properties of the skeleton class
481 private void writePropertiesJavaSkeleton(String intface) {
483 println("private " + intface + " mainObj;");
484 //println("private int ports;");
485 //println("private IoTRMICall rmiCall;");
486 println("private IoTRMIObject rmiObj;\n");
487 // Keep track of object Ids of all stubs registered to this interface
488 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
489 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
490 String newIntface = intMeth.getKey();
491 int newObjectId = mapNewIntfaceObjId.get(newIntface);
492 println("private final static int object" + newObjectId + "Id = " +
493 newObjectId + ";\t//" + newIntface);
500 * HELPER: writeConstructorJavaSkeleton() writes the constructor of the skeleton class
502 private void writeConstructorJavaSkeleton(String newSkelClass, String intface) {
504 println("public " + newSkelClass + "(" + intface + " _mainObj, int _port) throws Exception {");
505 println("mainObj = _mainObj;");
506 println("rmiObj = new IoTRMIObject(_port);");
507 //println("set0Allowed = Arrays.asList(object0Permission);");
508 println("___waitRequestInvokeMethod();");
514 * HELPER: writeStdMethodBodyJavaSkeleton() writes the standard method body in the skeleton class
516 private void writeStdMethodBodyJavaSkeleton(List<String> methParams, String methodId, String methodType) {
518 if (methodType.equals("void"))
519 print("mainObj." + methodId + "(");
521 print("return mainObj." + methodId + "(");
522 for (int i = 0; i < methParams.size(); i++) {
524 print(getSimpleIdentifier(methParams.get(i)));
525 // Check if this is the last element (don't print a comma)
526 if (i != methParams.size() - 1) {
535 * HELPER: writeMethodJavaSkeleton() writes the method of the skeleton class
537 private void writeMethodJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
539 for (String method : methods) {
541 List<String> methParams = intDecl.getMethodParams(method);
542 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
543 String methodId = intDecl.getMethodId(method);
544 print("public " + intDecl.getMethodType(method) + " " + methodId + "(");
545 for (int i = 0; i < methParams.size(); i++) {
547 print(methPrmTypes.get(i) + " " + methParams.get(i));
548 // Check if this is the last element (don't print a comma)
549 if (i != methParams.size() - 1) {
554 // Now, write the body of skeleton!
555 writeStdMethodBodyJavaSkeleton(methParams, methodId, intDecl.getMethodType(method));
562 * HELPER: writeStdMethodHelperBodyJavaSkeleton() writes the standard method body helper in the skeleton class
564 private void writeStdMethodHelperBodyJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
565 List<String> methPrmTypes, String method) {
566 // Generate array of parameter objects
567 print("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { ");
568 for (int i = 0; i < methParams.size(); i++) {
569 String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
570 print(getSimpleType(paramType) + ".class");
571 // Check if this is the last element (don't print a comma)
572 if (i != methParams.size() - 1)
576 // Generate generic class if it's a generic type.. null otherwise
577 print("new Class<?>[] { ");
578 for (int i = 0; i < methParams.size(); i++) {
579 String prmType = methPrmTypes.get(i);
580 if (getParamCategory(prmType) == ParamCategory.NONPRIMITIVES)
581 print(getTypeOfGeneric(prmType)[0] + ".class");
584 if (i != methParams.size() - 1)
588 // Check if this is "void"
589 String retType = intDecl.getMethodType(method);
590 if (retType.equals("void")) {
591 print(intDecl.getMethodId(method) + "(");
592 } else { // We do have a return value
593 print("Object retObj = " + intDecl.getMethodId(method) + "(");
595 for (int i = 0; i < methParams.size(); i++) {
596 String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
597 print("(" + paramType + ") paramObj[" + i + "]");
598 if (i != methParams.size() - 1)
602 if (!retType.equals("void"))
603 println("rmiObj.sendReturnObj(retObj);");
608 * HELPER: writeMethodHelperJavaSkeleton() writes the method helper of the skeleton class
610 private void writeMethodHelperJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
612 // Use this set to handle two same methodIds
613 Set<String> uniqueMethodIds = new HashSet<String>();
614 for (String method : methods) {
616 List<String> methParams = intDecl.getMethodParams(method);
617 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
618 String methodId = intDecl.getMethodId(method);
619 print("public void ___");
620 String helperMethod = methodId;
621 if (uniqueMethodIds.contains(methodId))
622 helperMethod = helperMethod + intDecl.getMethodNumId(method);
624 uniqueMethodIds.add(methodId);
625 // Check if this is "void"
626 String retType = intDecl.getMethodType(method);
627 if (retType.equals("void"))
628 println(helperMethod + "() {");
630 println(helperMethod + "() throws IOException {");
631 // Now, write the helper body of skeleton!
632 writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method);
639 * HELPER: writeJavaWaitRequestInvokeMethod() writes the main loop of the skeleton class
641 private void writeJavaWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl) {
643 // Use this set to handle two same methodIds
644 Set<String> uniqueMethodIds = new HashSet<String>();
645 println("private void ___waitRequestInvokeMethod() throws IOException {");
646 // Write variables here if we have callbacks or enums or structs
647 println("while (true) {");
648 println("rmiObj.getMethodBytes();");
649 println("int _objectId = rmiObj.getObjectId();");
650 println("int methodId = rmiObj.getMethodId();");
651 // TODO: code the permission check here!
652 println("switch (methodId) {");
653 // Print methods and method Ids
654 for (String method : methods) {
655 String methodId = intDecl.getMethodId(method);
656 int methodNumId = intDecl.getMethodNumId(method);
657 print("case " + methodNumId + ": ___");
658 String helperMethod = methodId;
659 if (uniqueMethodIds.contains(methodId))
660 helperMethod = helperMethod + methodNumId;
662 uniqueMethodIds.add(methodId);
663 println(helperMethod + "(); break;");
665 println("default: ");
666 println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
674 * generateJavaSkeletonClass() generate skeletons based on the methods list in Java
676 public void generateJavaSkeletonClass() throws IOException {
678 // Create a new directory
679 createDirectory(dir);
680 for (String intface : mapIntfacePTH.keySet()) {
681 // Open a new file to write into
682 String newSkelClass = intface + "_Skeleton";
683 FileWriter fw = new FileWriter(dir + "/" + newSkelClass + ".java");
684 pw = new PrintWriter(new BufferedWriter(fw));
685 // Pass in set of methods and get import classes
686 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
687 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
688 List<String> methods = intDecl.getMethods();
689 Set<String> importClasses = getImportClasses(methods, intDecl);
690 List<String> stdImportClasses = getStandardJavaImportClasses();
691 List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
692 printImportStatements(allImportClasses);
693 // Write class header
695 println("public class " + newSkelClass + " implements " + intface + " {\n");
697 writePropertiesJavaSkeleton(intface);
699 writeConstructorJavaSkeleton(newSkelClass, intface);
701 writeMethodJavaSkeleton(methods, intDecl);
702 // Write method helper
703 writeMethodHelperJavaSkeleton(methods, intDecl);
704 // Write waitRequestInvokeMethod() - main loop
705 writeJavaWaitRequestInvokeMethod(methods, intDecl);
708 System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".java...");
714 * HELPER: writeMethodCplusInterface() writes the method of the interface
716 private void writeMethodCplusInterface(Collection<String> methods, InterfaceDecl intDecl) {
718 for (String method : methods) {
720 List<String> methParams = intDecl.getMethodParams(method);
721 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
722 print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
723 intDecl.getMethodId(method) + "(");
724 for (int i = 0; i < methParams.size(); i++) {
725 // Check for params with driver class types and exchange it
726 // with its remote interface
727 String paramType = checkAndGetParamClass(methPrmTypes.get(i), true);
728 paramType = checkAndGetCplusType(paramType);
729 // Check for arrays - translate into vector in C++
730 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
731 print(paramComplete);
732 // Check if this is the last element (don't print a comma)
733 if (i != methParams.size() - 1) {
743 * HELPER: writeEnumCplus() writes the enumeration declaration
745 private void writeEnumCplus(EnumDecl enumDecl) {
747 Set<String> enumTypes = enumDecl.getEnumDeclarations();
748 // Iterate over enum declarations
749 for (String enType : enumTypes) {
751 println("enum " + enType + " {");
752 List<String> enumMembers = enumDecl.getMembers(enType);
753 for (int i = 0; i < enumMembers.size(); i++) {
755 String member = enumMembers.get(i);
757 // Check if this is the last element (don't print a comma)
758 if (i != enumMembers.size() - 1)
769 * HELPER: writeStructCplus() writes the struct declaration
771 private void writeStructCplus(StructDecl structDecl) {
773 List<String> structTypes = structDecl.getStructTypes();
774 // Iterate over enum declarations
775 for (String stType : structTypes) {
777 println("struct " + stType + " {");
778 List<String> structMemberTypes = structDecl.getMemberTypes(stType);
779 List<String> structMembers = structDecl.getMembers(stType);
780 for (int i = 0; i < structMembers.size(); i++) {
782 String memberType = structMemberTypes.get(i);
783 String member = structMembers.get(i);
784 String structTypeC = checkAndGetCplusType(memberType);
785 String structComplete = checkAndGetCplusArray(structTypeC, member);
786 println(structComplete + ";");
794 * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking.
796 * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
797 * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
798 * The local interface has to be the input parameter for the stub and the stub
799 * interface has to be the input parameter for the local class.
801 public void generateCplusLocalInterfaces() throws IOException {
803 // Create a new directory
804 createDirectory(dir);
805 for (String intface : mapIntfacePTH.keySet()) {
806 // Open a new file to write into
807 FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
808 pw = new PrintWriter(new BufferedWriter(fw));
809 // Write file headers
810 println("#ifndef _" + intface.toUpperCase() + "_HPP__");
811 println("#define _" + intface.toUpperCase() + "_HPP__");
812 println("#include <iostream>");
813 // Pass in set of methods and get include classes
814 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
815 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
816 List<String> methods = intDecl.getMethods();
817 Set<String> includeClasses = getIncludeClasses(methods, intDecl);
818 printIncludeStatements(includeClasses); println("");
819 println("using namespace std;\n");
820 // Write enum if any...
821 EnumDecl enumDecl = (EnumDecl) decHandler.getEnumDecl(intface);
822 writeEnumCplus(enumDecl);
823 // Write struct if any...
824 StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
825 writeStructCplus(structDecl);
826 println("class " + intface); println("{");
829 writeMethodCplusInterface(methods, intDecl);
833 System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
839 * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
841 * For C++ we use virtual classe as interface
843 public void generateCPlusInterfaces() throws IOException {
845 // Create a new directory
846 String path = createDirectories(dir, subdir);
847 for (String intface : mapIntfacePTH.keySet()) {
849 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
850 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
852 // Open a new file to write into
853 String newIntface = intMeth.getKey();
854 FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp");
855 pw = new PrintWriter(new BufferedWriter(fw));
856 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
857 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
858 // Write file headers
859 println("#ifndef _" + newIntface.toUpperCase() + "_HPP__");
860 println("#define _" + newIntface.toUpperCase() + "_HPP__");
861 println("#include <iostream>");
862 // Pass in set of methods and get import classes
863 Set<String> includeClasses = getIncludeClasses(intMeth.getValue(), intDecl);
864 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
865 List<String> allIncludeClasses = getAllImportClasses(stdIncludeClasses, includeClasses);
866 printIncludeStatements(allIncludeClasses); println("");
867 println("using namespace std;\n");
868 println("class " + newIntface);
872 writeMethodCplusInterface(intMeth.getValue(), intDecl);
876 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
883 * HELPER: writeMethodCplusStub() writes the method of the stub
885 private void writeMethodCplusStub(Collection<String> methods, InterfaceDecl intDecl) {
887 for (String method : methods) {
889 List<String> methParams = intDecl.getMethodParams(method);
890 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
891 print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
892 intDecl.getMethodId(method) + "(");
893 for (int i = 0; i < methParams.size(); i++) {
894 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
895 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
896 print(methParamComplete);
897 // Check if this is the last element (don't print a comma)
898 if (i != methParams.size() - 1) {
903 writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method);
910 * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class
912 private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
913 List<String> methPrmTypes, String method) {
915 println("int numParam = " + methParams.size() + ";");
916 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
917 String retType = intDecl.getMethodType(method);
918 String retTypeC = checkAndGetCplusType(retType);
919 println("string retType = \"" + checkAndGetCplusArrayType(retTypeC) + "\";");
920 // Generate array of parameter types
921 print("string paramCls[] = { ");
922 for (int i = 0; i < methParams.size(); i++) {
923 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
924 String paramType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
925 print("\"" + paramType + "\"");
926 // Check if this is the last element (don't print a comma)
927 if (i != methParams.size() - 1) {
932 // Generate array of parameter objects
933 print("void* paramObj[] = { ");
934 for (int i = 0; i < methParams.size(); i++) {
935 print("&" + checkAndGetCplusType(getSimpleIdentifier(methParams.get(i))));
936 // Check if this is the last element (don't print a comma)
937 if (i != methParams.size() - 1) {
942 // Check if this is "void"
943 if (retType.equals("void")) {
944 println("void* retObj = NULL;");
945 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
946 } else { // We do have a return value
947 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
948 println(checkAndGetCplusType(retType) + " retVal;");
950 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
951 println("void* retObj = &retVal;");
952 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
953 println("return retVal;");
959 * HELPER: writePropertiesCplusStub() writes the properties of the stub class
961 private void writePropertiesCplusStub(String intface, String newIntface) {
963 println("IoTRMICall\t\t\t*rmiCall;");
964 //println("IoTRMIObject\t\t\t*rmiObj;");
965 println("string\t\t\t\taddress;");
966 println("vector<int>\t\t\tports;\n");
968 Integer objId = mapIntfaceObjId.get(intface);
969 println("const static int\tobjectId = " + objId + ";");
970 mapNewIntfaceObjId.put(newIntface, objId);
971 mapIntfaceObjId.put(intface, objId++);
977 * HELPER: writeConstructorCplusStub() writes the constructor of the stub class
979 private void writeConstructorCplusStub(String newStubClass) {
981 println(newStubClass +
982 "(int _port, const char* _address, int _rev, bool* _bResult, vector<int> _ports) {");
983 println("address = _address;");
984 println("ports = _ports;");
985 println("rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);");
991 * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
993 private void writeDeconstructorCplusStub(String newStubClass) {
995 println("~" + newStubClass + "() {");
996 println("if (rmiCall != NULL) {");
997 println("delete rmiCall;");
998 println("rmiCall = NULL;");
1002 // Check if this is callback!!! and print "delete rmiObj and vecCBObj"
1007 * generateCPlusStubClasses() generate stubs based on the methods list in C++
1009 public void generateCPlusStubClasses() throws IOException {
1011 // Create a new directory
1012 String path = createDirectories(dir, subdir);
1013 for (String intface : mapIntfacePTH.keySet()) {
1015 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1016 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1017 // Open a new file to write into
1018 String newIntface = intMeth.getKey();
1019 String newStubClass = newIntface + "_Stub";
1020 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
1021 pw = new PrintWriter(new BufferedWriter(fw));
1022 // Write file headers
1023 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
1024 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
1025 println("#include <iostream>");
1026 println("#include \"" + newIntface + ".hpp\""); println("");
1027 println("using namespace std;"); println("");
1028 println("class " + newStubClass + " : public " + newIntface); println("{");
1029 println("private:\n");
1030 writePropertiesCplusStub(intface, newIntface);
1031 println("public:\n");
1032 // Add default constructor and destructor
1033 println(newStubClass + "() { }"); println("");
1034 writeConstructorCplusStub(newStubClass);
1035 writeDeconstructorCplusStub(newStubClass);
1036 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1037 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1039 writeMethodCplusStub(intMeth.getValue(), intDecl);
1040 print("}"); println(";");
1043 System.out.println("IoTCompiler: Generated stub class " + newIntface + ".hpp...");
1050 * HELPER: writePropertiesCplusSkeleton() writes the properties of the skeleton class
1052 private void writePropertiesCplusSkeleton(String intface) {
1054 println(intface + " *mainObj;");
1055 //println("private int ports;");
1056 //println("private IoTRMICall rmiCall;");
1057 println("IoTRMIObject *rmiObj;\n");
1058 // Keep track of object Ids of all stubs registered to this interface
1059 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
1060 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
1061 String newIntface = intMeth.getKey();
1062 int newObjectId = mapNewIntfaceObjId.get(newIntface);
1063 // println("const static int object" + newObjectId + "Id = " +
1064 // newObjectId + ";\t//" + newIntface);
1067 // TODO: code the set of allowed functions here
1073 * HELPER: writeConstructorCplusSkeleton() writes the constructor of the skeleton class
1075 private void writeConstructorCplusSkeleton(String newSkelClass, String intface) {
1077 println(newSkelClass + "(" + intface + " *_mainObj, int _port) {");
1078 println("bool _bResult = false;");
1079 println("mainObj = _mainObj;");
1080 println("rmiObj = new IoTRMIObject(_port, &_bResult);");
1081 //println("set0Allowed = Arrays.asList(object0Permission);");
1082 //println("___waitRequestInvokeMethod();");
1088 * HELPER: writeDeconstructorCplusSkeleton() writes the deconstructor of the skeleton class
1090 private void writeDeconstructorCplusSkeleton(String newSkelClass) {
1092 println("~" + newSkelClass + "() {");
1093 println("if (rmiObj != NULL) {");
1094 println("delete rmiObj;");
1095 println("rmiObj = NULL;");
1099 // Check if this is callback!!! and print "delete rmiObj and vecCBObj"
1104 * HELPER: writeStdMethodBodyCplusSkeleton() writes the standard method body in the skeleton class
1106 private void writeStdMethodBodyCplusSkeleton(List<String> methParams, String methodId, String methodType) {
1108 if (methodType.equals("void"))
1109 print("mainObj->" + methodId + "(");
1111 print("return mainObj->" + methodId + "(");
1112 for (int i = 0; i < methParams.size(); i++) {
1114 print(getSimpleIdentifier(methParams.get(i)));
1115 // Check if this is the last element (don't print a comma)
1116 if (i != methParams.size() - 1) {
1125 * HELPER: writeMethodCplusSkeleton() writes the method of the skeleton class
1127 private void writeMethodCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
1129 for (String method : methods) {
1131 List<String> methParams = intDecl.getMethodParams(method);
1132 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1133 String methodId = intDecl.getMethodId(method);
1134 String methodType = checkAndGetCplusType(intDecl.getMethodType(method));
1135 print(methodType + " " + methodId + "(");
1136 for (int i = 0; i < methParams.size(); i++) {
1137 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
1138 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
1139 print(methParamComplete);
1140 // Check if this is the last element (don't print a comma)
1141 if (i != methParams.size() - 1) {
1146 // Now, write the body of skeleton!
1147 writeStdMethodBodyCplusSkeleton(methParams, methodId, intDecl.getMethodType(method));
1154 * HELPER: writeStdMethodHelperBodyCplusSkeleton() writes the standard method body helper in the skeleton class
1156 private void writeStdMethodHelperBodyCplusSkeleton(InterfaceDecl intDecl, List<String> methParams,
1157 List<String> methPrmTypes, String method, String methodId) {
1159 // Generate array of parameter types
1160 print("string paramCls[] = { ");
1161 for (int i = 0; i < methParams.size(); i++) {
1162 String paramTypeC = checkAndGetCplusType(methPrmTypes.get(i));
1163 String paramType = checkAndGetCplusArrayType(paramTypeC, methParams.get(i));
1164 print("\"" + paramType + "\"");
1165 if (i != methParams.size() - 1) {
1170 println("int numParam = " + methParams.size() + ";");
1171 // Generate parameters
1172 for (int i = 0; i < methParams.size(); i++) {
1173 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
1174 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
1175 println(methParamComplete + ";");
1177 // Generate array of parameter objects
1178 print("void* paramObj[] = { ");
1179 for (int i = 0; i < methParams.size(); i++) {
1180 print("&" + getSimpleIdentifier(methParams.get(i)));
1181 if (i != methParams.size() - 1) {
1186 println("rmiObj->getMethodParams(paramCls, numParam, paramObj);");
1187 String retType = intDecl.getMethodType(method);
1188 // Check if this is "void"
1189 if (retType.equals("void")) {
1190 print(methodId + "(");
1191 for (int i = 0; i < methParams.size(); i++) {
1192 print(getSimpleIdentifier(methParams.get(i)));
1193 if (i != methParams.size() - 1) {
1198 } else { // We do have a return value
1199 print(checkAndGetCplusType(retType) + " retVal = " + methodId + "(");
1200 for (int i = 0; i < methParams.size(); i++) {
1201 print(getSimpleIdentifier(methParams.get(i)));
1202 if (i != methParams.size() - 1) {
1207 println("void* retObj = &retVal;");
1208 String retTypeC = checkAndGetCplusType(retType);
1209 println("rmiObj->sendReturnObj(retObj, \"" + checkAndGetCplusArrayType(retTypeC) + "\");");
1215 * HELPER: writeMethodHelperCplusSkeleton() writes the method helper of the skeleton class
1217 private void writeMethodHelperCplusSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
1219 // Use this set to handle two same methodIds
1220 Set<String> uniqueMethodIds = new HashSet<String>();
1221 for (String method : methods) {
1223 List<String> methParams = intDecl.getMethodParams(method);
1224 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1225 String methodId = intDecl.getMethodId(method);
1227 String helperMethod = methodId;
1228 if (uniqueMethodIds.contains(methodId))
1229 helperMethod = helperMethod + intDecl.getMethodNumId(method);
1231 uniqueMethodIds.add(methodId);
1232 // Check if this is "void"
1233 String retType = intDecl.getMethodType(method);
1234 println(helperMethod + "() {");
1235 // Now, write the helper body of skeleton!
1236 writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId);
1243 * HELPER: writeCplusWaitRequestInvokeMethod() writes the main loop of the skeleton class
1245 private void writeCplusWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl) {
1247 // Use this set to handle two same methodIds
1248 Set<String> uniqueMethodIds = new HashSet<String>();
1249 println("void ___waitRequestInvokeMethod() {");
1250 // Write variables here if we have callbacks or enums or structs
1251 println("while (true) {");
1252 println("rmiObj->getMethodBytes();");
1253 println("int _objectId = rmiObj->getObjectId();");
1254 println("int methodId = rmiObj->getMethodId();");
1255 // TODO: code the permission check here!
1256 println("switch (methodId) {");
1257 // Print methods and method Ids
1258 for (String method : methods) {
1259 String methodId = intDecl.getMethodId(method);
1260 int methodNumId = intDecl.getMethodNumId(method);
1261 print("case " + methodNumId + ": ___");
1262 String helperMethod = methodId;
1263 if (uniqueMethodIds.contains(methodId))
1264 helperMethod = helperMethod + methodNumId;
1266 uniqueMethodIds.add(methodId);
1267 println(helperMethod + "(); break;");
1269 println("default: ");
1270 println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
1271 println("throw exception();");
1279 * generateCplusSkeletonClass() generate skeletons based on the methods list in C++
1281 public void generateCplusSkeletonClass() throws IOException {
1283 // Create a new directory
1284 createDirectory(dir);
1285 for (String intface : mapIntfacePTH.keySet()) {
1286 // Open a new file to write into
1287 String newSkelClass = intface + "_Skeleton";
1288 FileWriter fw = new FileWriter(dir + "/" + newSkelClass + ".hpp");
1289 pw = new PrintWriter(new BufferedWriter(fw));
1290 // Write file headers
1291 println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
1292 println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
1293 println("#include <iostream>");
1294 println("#include \"" + intface + ".hpp\"\n");
1295 // Pass in set of methods and get import classes
1296 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1297 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
1298 List<String> methods = intDecl.getMethods();
1299 Set<String> includeClasses = getIncludeClasses(methods, intDecl);
1300 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
1301 List<String> allIncludeClasses = getAllImportClasses(stdIncludeClasses, includeClasses);
1302 printIncludeStatements(allIncludeClasses); println("");
1303 println("using namespace std;\n");
1304 // Write class header
1305 println("class " + newSkelClass + " : public " + intface); println("{");
1306 println("private:\n");
1308 writePropertiesCplusSkeleton(intface);
1309 println("public:\n");
1310 // Write constructor
1311 writeConstructorCplusSkeleton(newSkelClass, intface);
1312 // Write deconstructor
1313 writeDeconstructorCplusSkeleton(newSkelClass);
1315 writeMethodCplusSkeleton(methods, intDecl);
1316 // Write method helper
1317 writeMethodHelperCplusSkeleton(methods, intDecl);
1318 // Write waitRequestInvokeMethod() - main loop
1319 writeCplusWaitRequestInvokeMethod(methods, intDecl);
1323 System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".hpp...");
1329 * generateInitializer() generate initializer based on type
1331 public String generateCplusInitializer(String type) {
1333 // Generate dummy returns for now
1334 if (type.equals("short")||
1335 type.equals("int") ||
1336 type.equals("long") ||
1337 type.equals("float")||
1338 type.equals("double")) {
1341 } else if ( type.equals("String") ||
1342 type.equals("string")) {
1345 } else if ( type.equals("char") ||
1346 type.equals("byte")) {
1349 } else if ( type.equals("boolean")) {
1359 * generateReturnStmt() generate return statement based on methType
1361 public String generateReturnStmt(String methType) {
1363 // Generate dummy returns for now
1364 if (methType.equals("short")||
1365 methType.equals("int") ||
1366 methType.equals("long") ||
1367 methType.equals("float")||
1368 methType.equals("double")) {
1371 } else if ( methType.equals("String")) {
1374 } else if ( methType.equals("char") ||
1375 methType.equals("byte")) {
1378 } else if ( methType.equals("boolean")) {
1388 * setDirectory() sets a new directory for stub files
1390 public void setDirectory(String _subdir) {
1397 * printUsage() prints the usage of this compiler
1399 public static void printUsage() {
1401 System.out.println();
1402 System.out.println("Sentinel interface and stub compiler version 1.0");
1403 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
1404 System.out.println("All rights reserved.");
1405 System.out.println("Usage:");
1406 System.out.println("\tjava IoTCompiler -help / --help / -h\n");
1407 System.out.println("\t\tDisplay this help texts\n\n");
1408 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>]");
1409 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>] [options]\n");
1410 System.out.println("\t\tTake one or more pairs of main-req policy files, and generate Java and/or C++ files\n");
1411 System.out.println("Options:");
1412 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
1413 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
1414 System.out.println();
1419 * parseFile() prepares Lexer and Parser objects, then parses the file
1421 public static ParseNode parseFile(String file) {
1423 ParseNode pn = null;
1425 ComplexSymbolFactory csf = new ComplexSymbolFactory();
1426 ScannerBuffer lexer =
1427 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf));
1428 Parser parse = new Parser(lexer,csf);
1429 pn = (ParseNode) parse.parse().value;
1430 } catch (Exception e) {
1431 e.printStackTrace();
1432 throw new Error("IoTCompiler: ERROR parsing policy file or wrong command line option: " + file);
1443 boolean newline=true;
1446 private void print(String str) {
1449 if (str.equals("}"))
1451 for(int i=0; i<tab; i++)
1461 * This function converts Java to C++ type for compilation
1463 private String convertType(String jType) {
1465 return mapPrimitives.get(jType);
1469 private void println(String str) {
1472 if (str.equals("}"))
1474 for(int i=0; i<tab; i++)
1483 private void updatetabbing(String str) {
1484 tablevel+=count(str,'{')-count(str,'}');
1488 private int count(String str, char key) {
1489 char[] array = str.toCharArray();
1491 for(int i=0; i<array.length; i++) {
1492 if (array[i] == key)
1499 private void createDirectory(String dirName) {
1501 File file = new File(dirName);
1502 if (!file.exists()) {
1504 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
1506 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
1509 System.out.println("IoTCompiler: Directory " + dirName + " exists...");
1514 // Create a directory and possibly a sub directory
1515 private String createDirectories(String dir, String subdir) {
1518 createDirectory(path);
1519 if (subdir != null) {
1520 path = path + "/" + subdir;
1521 createDirectory(path);
1527 // Inserting array members into a Map object
1528 // that maps arrKey to arrVal objects
1529 private void arraysToMap(Map map, Object[] arrKey, Object[] arrVal) {
1531 for(int i = 0; i < arrKey.length; i++) {
1533 map.put(arrKey[i], arrVal[i]);
1538 // Return parameter category, i.e. PRIMITIVES, NONPRIMITIVES, or USERDEFINED
1539 private ParamCategory getParamCategory(String paramType) {
1541 if (mapPrimitives.containsKey(paramType)) {
1542 return ParamCategory.PRIMITIVES;
1543 // We can either use mapNonPrimitivesJava or mapNonPrimitivesCplus here
1544 } else if (mapNonPrimitivesJava.containsKey(getSimpleType(paramType))) {
1545 return ParamCategory.NONPRIMITIVES;
1547 return ParamCategory.USERDEFINED;
1551 // Return full class name for non-primitives to generate Java import statements
1552 // e.g. java.util.Set for Set, java.util.Map for Map
1553 private String getNonPrimitiveJavaClass(String paramNonPrimitives) {
1555 return mapNonPrimitivesJava.get(paramNonPrimitives);
1559 // Return full class name for non-primitives to generate Cplus include statements
1560 // e.g. #include <set> for Set, #include <map> for Map
1561 private String getNonPrimitiveCplusClass(String paramNonPrimitives) {
1563 return mapNonPrimitivesCplus.get(paramNonPrimitives);
1567 // Get simple types, e.g. HashSet for HashSet<...>
1568 // Basically strip off the "<...>"
1569 private String getSimpleType(String paramType) {
1571 // Check if this is generics
1572 if(paramType.contains("<")) {
1573 String[] type = paramType.split("<");
1580 // Generate a set of standard classes for import statements
1581 private List<String> getStandardJavaImportClasses() {
1583 List<String> importClasses = new ArrayList<String>();
1584 // Add the standard list first
1585 importClasses.add("java.io.IOException");
1586 importClasses.add("java.util.List");
1587 importClasses.add("java.util.ArrayList");
1588 importClasses.add("iotrmi.Java.IoTRMICall");
1589 importClasses.add("iotrmi.Java.IoTRMIObject");
1591 return importClasses;
1595 // Generate a set of standard classes for import statements
1596 private List<String> getStandardCplusIncludeClasses() {
1598 List<String> importClasses = new ArrayList<String>();
1599 // Add the standard list first
1600 importClasses.add("<vector>");
1601 importClasses.add("\"IoTRMICall.hpp\"");
1602 importClasses.add("\"IoTRMIObject.hpp\"");
1604 return importClasses;
1608 // Generate a set of standard classes for import statements
1609 private List<String> getAllImportClasses(Collection<String> stdImportClasses, Collection<String> importClasses) {
1611 List<String> allImportClasses = new ArrayList<String>(stdImportClasses);
1612 // Iterate over the list of import classes
1613 for (String str : importClasses) {
1614 if (!stdImportClasses.contains(str)) {
1615 stdImportClasses.add(str);
1619 return allImportClasses;
1624 // Generate a set of classes for import statements
1625 private Set<String> getImportClasses(Collection<String> methods, InterfaceDecl intDecl) {
1627 Set<String> importClasses = new HashSet<String>();
1628 for (String method : methods) {
1629 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1630 for (String paramType : methPrmTypes) {
1632 String simpleType = getSimpleType(paramType);
1633 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
1634 importClasses.add(getNonPrimitiveJavaClass(simpleType));
1638 return importClasses;
1642 // Generate a set of classes for include statements
1643 private Set<String> getIncludeClasses(Collection<String> methods, InterfaceDecl intDecl) {
1645 Set<String> includeClasses = new HashSet<String>();
1646 for (String method : methods) {
1648 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1649 List<String> methParams = intDecl.getMethodParams(method);
1650 for (int i = 0; i < methPrmTypes.size(); i++) {
1652 String simpleType = getSimpleType(methPrmTypes.get(i));
1653 String param = methParams.get(i);
1654 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
1655 includeClasses.add("<" + getNonPrimitiveCplusClass(simpleType) + ">");
1656 } else if (getParamCategory(simpleType) == ParamCategory.USERDEFINED) {
1657 includeClasses.add("\"" + exchangeParamType(simpleType) + ".hpp\"");
1658 } else if (param.contains("[]")) {
1659 // Check if this is array for C++; translate into vector
1660 includeClasses.add("<vector>");
1664 return includeClasses;
1668 private void printImportStatements(Collection<String> importClasses) {
1670 for(String cls : importClasses) {
1671 println("import " + cls + ";");
1676 private void printIncludeStatements(Collection<String> includeClasses) {
1678 for(String cls : includeClasses) {
1679 println("#include " + cls);
1684 // Get the C++ version of a non-primitive type
1685 // e.g. set for Set and map for Map
1686 // Input nonPrimitiveType has to be generics in format
1687 private String[] getTypeOfGeneric(String nonPrimitiveType) {
1689 // Handle <, >, and , for 2-type generic/template
1690 String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(",");
1695 // This helper function strips off array declaration, e.g. D[] becomes D
1696 private String getSimpleIdentifier(String ident) {
1698 // Handle [ for array declaration
1699 String substr = ident;
1700 if (ident.contains("[]")) {
1701 substr = ident.split("\\[\\]")[0];
1707 private String checkAndGetCplusType(String paramType) {
1709 if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
1710 return convertType(paramType);
1711 } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) {
1713 // Check for generic/template format
1714 if (paramType.contains("<") && paramType.contains(">")) {
1716 String genericClass = getSimpleType(paramType);
1717 String[] genericType = getTypeOfGeneric(paramType);
1718 String cplusTemplate = null;
1719 if (genericType.length == 1) // Generic/template with one type
1720 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
1721 "<" + convertType(genericType[0]) + ">";
1722 else // Generic/template with two types
1723 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
1724 "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">";
1725 return cplusTemplate;
1727 return getNonPrimitiveCplusClass(paramType);
1729 // Just return it as is if it's not non-primitives
1734 // Detect array declaration, e.g. int A[],
1735 // then generate "int A[]" in C++ as "vector<int> A"
1736 private String checkAndGetCplusArray(String paramType, String param) {
1738 String paramComplete = null;
1739 // Check for array declaration
1740 if (param.contains("[]")) {
1741 paramComplete = "vector<" + paramType + "> " + param.replace("[]","");
1743 // Just return it as is if it's not an array
1744 paramComplete = paramType + " " + param;
1746 return paramComplete;
1750 // Detect array declaration, e.g. int A[],
1751 // then generate "int A[]" in C++ as "vector<int> A"
1752 // This method just returns the type
1753 private String checkAndGetCplusArrayType(String paramType) {
1755 String paramTypeRet = null;
1756 // Check for array declaration
1757 if (paramType.contains("[]")) {
1758 String type = paramType.split("\\[\\]")[0];
1759 paramTypeRet = checkAndGetCplusType(type) + "[]";
1760 } else if (paramType.contains("vector")) {
1761 // Just return it as is if it's not an array
1762 String type = paramType.split("<")[1].split(">")[0];
1763 paramTypeRet = checkAndGetCplusType(type) + "[]";
1765 paramTypeRet = paramType;
1767 return paramTypeRet;
1771 // Detect array declaration, e.g. int A[],
1772 // then generate "int A[]" in C++ as "vector<int> A"
1773 // This method just returns the type
1774 private String checkAndGetCplusArrayType(String paramType, String param) {
1776 String paramTypeRet = null;
1777 // Check for array declaration
1778 if (param.contains("[]")) {
1779 paramTypeRet = checkAndGetCplusType(paramType) + "[]";
1780 } else if (paramType.contains("vector")) {
1781 // Just return it as is if it's not an array
1782 String type = paramType.split("<")[1].split(">")[0];
1783 paramTypeRet = checkAndGetCplusType(type) + "[]";
1785 paramTypeRet = paramType;
1787 return paramTypeRet;
1791 // Detect array declaration, e.g. int A[],
1792 // then generate type "int[]"
1793 private String checkAndGetArray(String paramType, String param) {
1795 String paramTypeRet = null;
1796 // Check for array declaration
1797 if (param.contains("[]")) {
1798 paramTypeRet = paramType + "[]";
1800 // Just return it as is if it's not an array
1801 paramTypeRet = paramType;
1803 return paramTypeRet;
1807 // Get simple types, e.g. HashSet for HashSet<...>
1808 // Basically strip off the "<...>"
1809 private String checkAndGetParamClass(String paramType, boolean needPtr) {
1811 // Check if this is generics
1812 if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
1813 // If true then return with pointer (C++)
1815 return exchangeParamType(paramType) + "*";
1816 else // Java, so no pointer needed
1817 return exchangeParamType(paramType);
1823 // Returns the other interface for type-checking purposes for USERDEFINED
1824 // classes based on the information provided in multiple policy files
1825 // e.g. return CameraWithXXX instead of Camera
1826 private String exchangeParamType(String intface) {
1828 // Param type that's passed is the interface name we need to look for
1829 // in the map of interfaces, based on available policy files.
1830 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1831 if (decHandler != null) {
1832 // We've found the required interface policy files
1833 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(intface);
1834 Set<String> setExchInt = reqDecl.getInterfaces();
1835 if (setExchInt.size() == 1) {
1836 Iterator iter = setExchInt.iterator();
1837 return (String) iter.next();
1839 throw new Error("IoTCompiler: Ambiguous stub interfaces: " + setExchInt.toString() +
1840 ". Only one new interface can be declared if the object " + intface +
1841 " needs to be passed in as an input parameter!");
1844 // NULL value - this means policy files missing
1845 throw new Error("IoTCompiler: Parameter type lookup failed for " + intface +
1846 "... Please provide the necessary policy files for user-defined types." +
1847 " If this is an array please type the brackets after the variable name," +
1848 " e.g. \"String str[]\", not \"String[] str\"." +
1849 " If this is a Collections (Java) / STL (C++) type, this compiler only" +
1850 " supports List/ArrayList (Java) or list (C++).");
1855 public static void main(String[] args) throws Exception {
1857 // If there is no argument or just "--help" or "-h", then invoke printUsage()
1858 if ((args[0].equals("-help") ||
1859 args[0].equals("--help")||
1860 args[0].equals("-h")) ||
1861 (args.length == 0)) {
1863 IoTCompiler.printUsage();
1865 } else if (args.length > 1) {
1867 IoTCompiler comp = new IoTCompiler();
1870 // Parse main policy file
1871 ParseNode pnPol = IoTCompiler.parseFile(args[i]);
1872 // Parse "requires" policy file
1873 ParseNode pnReq = IoTCompiler.parseFile(args[i+1]);
1874 // Get interface name
1875 String intface = ParseTreeHandler.getOrigIntface(pnPol);
1876 comp.setDataStructures(intface, pnPol, pnReq);
1877 comp.getMethodsForIntface(intface);
1879 // 1) Check if this is the last option before "-java" or "-cplus"
1880 // 2) Check if this is really the last option (no "-java" or "-cplus")
1881 } while(!args[i].equals("-java") &&
1882 !args[i].equals("-cplus") &&
1885 // Generate everything if we don't see "-java" or "-cplus"
1886 if (i == args.length) {
1887 comp.generateJavaLocalInterfaces();
1888 comp.generateJavaInterfaces();
1889 comp.generateJavaStubClasses();
1890 comp.generateJavaSkeletonClass();
1891 comp.generateCplusLocalInterfaces();
1892 comp.generateCPlusInterfaces();
1893 comp.generateCPlusStubClasses();
1894 comp.generateCplusSkeletonClass();
1896 // Check other options
1897 while(i < args.length) {
1899 if (!args[i].equals("-java") &&
1900 !args[i].equals("-cplus")) {
1901 throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
1903 if (i + 1 < args.length) {
1904 comp.setDirectory(args[i+1]);
1906 throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
1908 if (args[i].equals("-java")) {
1909 comp.generateJavaLocalInterfaces();
1910 comp.generateJavaInterfaces();
1911 comp.generateJavaStubClasses();
1912 comp.generateJavaSkeletonClass();
1914 comp.generateCplusLocalInterfaces();
1915 comp.generateCPlusInterfaces();
1916 comp.generateCPlusStubClasses();
1917 comp.generateCplusSkeletonClass();
1924 // Need to at least have exactly 2 parameters, i.e. main policy file and requires file
1925 IoTCompiler.printUsage();
1926 throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");