Adding Java callback support in compiler
authorrtrimana <rtrimana@uci.edu>
Wed, 16 Nov 2016 17:02:27 +0000 (09:02 -0800)
committerrtrimana <rtrimana@uci.edu>
Wed, 16 Nov 2016 17:02:27 +0000 (09:02 -0800)
config/iotpolicy/camerapolicy.pol
iotjava/Makefile
iotjava/iotpolicy/IoTCompiler.java
iotjava/iotpolicy/tree/InterfaceDecl.java

index 0afb5a0..809f12d 100644 (file)
@@ -6,6 +6,7 @@ public interface Camera {
     public String MethodC(String E, List<Integer> F);
     public float MethodD(List<String> G, float H);
     public boolean MethodE(String I, boolean J);
+       public void MethodF(LightBulb K);
 
        capability ImageCapture {
                description = "The quick brown fox jumps over the smart dog";
@@ -13,6 +14,7 @@ public interface Camera {
                method = "MethodA(int A, int B)";
                method = "MethodB(int C, String D[])";
                method = "MethodC(String E, List<Integer> F)";
+               method = "MethodF(LightBulb K)";
        }
 
        capability VideoRecording {
index 50792f4..e748017 100644 (file)
@@ -32,8 +32,8 @@ PHONY += compile
 compile:
        cd $(BIN_DIR)/iotpolicy/output_files; cp *.java ./Java
        cd $(BIN_DIR)/iotpolicy/output_files; cp *.hpp ./Cplus
-       #cd $(BIN_DIR)/iotpolicy/output_files/Java; $(JAVAC) -cp .:..:../../../$(BIN_DIR) *.java
-       cd $(BIN_DIR)/iotpolicy/output_files/Cplus; $(G++) ./*.hpp --std=c++11 -pthread -pg -I../../../../iotjava/iotrmi/C++/
+       cd $(BIN_DIR)/iotpolicy/output_files/Java; $(JAVAC) -cp .:..:../../../$(BIN_DIR) *.java
+#      cd $(BIN_DIR)/iotpolicy/output_files/Cplus; $(G++) ./*.hpp --std=c++11 -pthread -pg -I../../../../iotjava/iotrmi/C++/
 
 PHONY += clean
 clean:
index f3a1ce1..9c6a16a 100644 (file)
@@ -180,6 +180,32 @@ public class IoTCompiler {
        }
 
 
+       /**
+        * HELPER: writeMethodJavaLocalInterface() writes the method of the interface
+        */
+       private void writeMethodJavaLocalInterface(Collection<String> methods, InterfaceDecl intDecl) {
+
+               for (String method : methods) {
+
+                       List<String> methParams = intDecl.getMethodParams(method);
+                       List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
+                       print("public " + intDecl.getMethodType(method) + " " +
+                               intDecl.getMethodId(method) + "(");
+                       for (int i = 0; i < methParams.size(); i++) {
+                               // Check for params with driver class types and exchange it 
+                               //              with its remote interface
+                               String paramType = checkAndGetParamClass(methPrmTypes.get(i), false);
+                               print(paramType + " " + methParams.get(i));
+                               // Check if this is the last element (don't print a comma)
+                               if (i != methParams.size() - 1) {
+                                       print(", ");
+                               }
+                       }
+                       println(");");
+               }
+       }
+
+
        /**
         * HELPER: writeMethodJavaInterface() writes the method of the interface
         */
@@ -194,7 +220,7 @@ public class IoTCompiler {
                        for (int i = 0; i < methParams.size(); i++) {
                                // Check for params with driver class types and exchange it 
                                //              with its remote interface
-                               String paramType = checkAndGetParamClass(methPrmTypes.get(i), false);
+                               String paramType = methPrmTypes.get(i);
                                print(paramType + " " + methParams.get(i));
                                // Check if this is the last element (don't print a comma)
                                if (i != methParams.size() - 1) {
@@ -287,7 +313,7 @@ public class IoTCompiler {
                        StructDecl structDecl = (StructDecl) decHandler.getStructDecl(intface);
                        writeStructJava(structDecl);
                        // Write methods
-                       writeMethodJavaInterface(methods, intDecl);
+                       writeMethodJavaLocalInterface(methods, intDecl);
                        println("}");
                        pw.close();
                        System.out.println("IoTCompiler: Generated local interface " + intface + ".java...");
@@ -332,10 +358,9 @@ public class IoTCompiler {
        /**
         * HELPER: writePropertiesJavaStub() writes the properties of the stub class
         */
-       private void writePropertiesJavaStub(String intface, String newIntface) {
+       private void writePropertiesJavaStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
 
                println("private IoTRMICall rmiCall;");
-               //println("private IoTRMIObject rmiObj;");
                println("private String address;");
                println("private int[] ports;\n");
                // Get the object Id
@@ -343,6 +368,15 @@ public class IoTCompiler {
                println("private final static int objectId = " + objId + ";");
                mapNewIntfaceObjId.put(newIntface, objId);
                mapIntfaceObjId.put(intface, objId++);
+               if (callbackExist) {
+               // We assume that each class only has one callback interface for now
+                       Iterator it = callbackClasses.iterator();
+                       String callbackType = (String) it.next();
+                       println("// Callback properties");
+                       println("private IoTRMIObject rmiObj;");
+                       println("List<" + callbackType + "> listCallbackObj;");
+                       println("private static int objIdCnt = 0;");
+               }
                println("\n");
        }
 
@@ -350,12 +384,57 @@ public class IoTCompiler {
        /**
         * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
         */
-       private void writeConstructorJavaStub(String intface) {
+       private void writeConstructorJavaStub(String intface, boolean callbackExist, Set<String> callbackClasses) {
 
                println("public " + intface + "(int _port, String _address, int _rev, int[] _ports) throws Exception {");
                println("address = _address;");
                println("ports = _ports;");
                println("rmiCall = new IoTRMICall(_port, _address, _rev);");
+               if (callbackExist) {
+                       Iterator it = callbackClasses.iterator();
+                       String callbackType = (String) it.next();
+                       println("listCallbackObj = new ArrayList<" + callbackType + ">();");
+                       println("___initCallBack();");
+               }
+               println("}\n");
+       }
+
+
+       /**
+        * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
+        */
+       private void writeInitCallbackJavaStub(String intface, InterfaceDecl intDecl) {
+
+               println("public void ___initCallBack() {");
+               // Generate main thread for callbacks
+               println("Thread thread = new Thread() {");
+               println("public void run() {");
+               println("try {");
+               println("rmiObj = new IoTRMIObject(ports[0]);");
+               println("while (true) {");
+               println("byte[] method = rmiObj.getMethodBytes();");
+               println("int objId = IoTRMIObject.getObjectId(method);");
+               println(intface + "_CallbackSkeleton skel = (" + intface + "_CallbackSkeleton) listCallbackObj.get(objId);");
+               println("if (skel != null) {");
+               println("skel.invokeMethod(rmiObj);");
+               println("} else {");
+               println("throw new Error(\"" + intface + ": Object with Id \" + objId + \" not found!\");");
+               println("}");
+               println("}");
+               println("} catch (Exception ex) {");
+               println("ex.printStackTrace();");
+               println("throw new Error(\"Error instantiating class " + intface + "_CallbackSkeleton!\");");
+               println("}");
+               println("}");
+               println("};");
+               println("thread.start();\n");
+               // Generate info sending part
+               String method = "___initCallBack()";
+               println("int methodId = " + intDecl.getHelperMethodNumId(method) + ";");
+               println("Class<?> retType = void.class;");
+               println("Class<?>[] paramCls = new Class<?>[] { int.class, String.class, int.class };");
+               println("Object[] paramObj = new Object[] { ports[0], address, 0 };");
+               println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
                println("}\n");
        }
 
@@ -408,10 +487,101 @@ public class IoTCompiler {
        }
 
 
+       /**
+        * HELPER: checkCallbackType() checks the callback type
+        */
+       private boolean checkCallbackType(String paramType, String callbackType) {
+
+               if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES)
+                       paramType = getTypeOfGeneric(paramType)[0];
+               return callbackType.equals(paramType);
+       }
+
+
+       /**
+        * HELPER: writeCallbackMethodBodyJavaStub() writes the callback method of the stub class
+        */
+       private void writeCallbackMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
+                       List<String> methPrmTypes, String method, String callbackType) {
+
+               println("try {");
+               // Check if this is single object, array, or list of objects
+               for (int i = 0; i < methParams.size(); i++) {
+
+                       String paramType = methPrmTypes.get(i);
+                       if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
+                               String param = methParams.get(i);
+                               if (isArrayOrList(paramType, param)) {  // Generate loop
+                                       println("for (" + paramType + " cb : " + getSimpleIdentifier(param) + ") {");
+                                       println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(cb, objIdCnt++);");
+                               } else
+                                       println(callbackType + "_CallbackSkeleton skel = new " + callbackType + "_CallbackSkeleton(" +
+                                               getSimpleIdentifier(param) + ", objIdCnt++);");
+                               println("listCallbackObj.add(skel);");
+                               if (isArrayOrList(paramType, param))
+                                       println("}");
+                       }
+               }
+               println("} catch (Exception ex) {");
+               println("ex.printStackTrace();");
+               println("throw new Error(\"Exception when generating skeleton objects!\");");
+               println("}\n");
+               println("int methodId = " + intDecl.getMethodNumId(method) + ";");
+               String retType = intDecl.getMethodType(method);
+               println("Class<?> retType = " + getSimpleType(retType) + ".class;");
+               // Generate array of parameter types
+               print("Class<?>[] paramCls = new Class<?>[] { ");
+               for (int i = 0; i < methParams.size(); i++) {
+                       String paramType = methPrmTypes.get(i);
+                       if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
+                               print("int.class");
+                       } else { // Generate normal classes if it's not a callback object
+                               String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
+                               print(getSimpleType(prmType) + ".class");
+                       }
+                       if (i != methParams.size() - 1) // Check if this is the last element
+                               print(", ");
+               }
+               println(" };");
+               // Generate array of parameter objects
+               print("Object[] paramObj = new Object[] { ");
+               for (int i = 0; i < methParams.size(); i++) {
+                       String paramType = methPrmTypes.get(i);
+                       if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
+                               if (isArray(methPrmTypes.get(i), methParams.get(i)))
+                                       print(getSimpleIdentifier(methParams.get(i)) + ".length");
+                               else if (isList(methPrmTypes.get(i), methParams.get(i)))
+                                       print(getSimpleIdentifier(methParams.get(i)) + ".size()");
+                               else
+                                       print("new Integer(1)");
+                       } else
+                               print(getSimpleIdentifier(methParams.get(i)));
+                       if (i != methParams.size() - 1)
+                               print(", ");
+               }
+               println(" };");
+               // Check if this is "void"
+               if (retType.equals("void")) {
+                       println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
+               } else { // We do have a return value
+               // Check if the return value NONPRIMITIVES
+                       if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
+                               String[] retGenValType = getTypeOfGeneric(retType);
+                               println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
+                               println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
+                               println("return (" + retType + ")retObj;");
+                       } else {
+                               println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
+                               println("return (" + retType + ")retObj;");
+                       }
+               }
+       }
+
+
        /**
         * HELPER: writeMethodJavaStub() writes the method of the stub class
         */
-       private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl) {
+       private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
 
                for (String method : methods) {
 
@@ -419,8 +589,21 @@ public class IoTCompiler {
                        List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
                        print("public " + intDecl.getMethodType(method) + " " +
                                intDecl.getMethodId(method) + "(");
+                       boolean isCallbackMethod = false;
+                       String callbackType = null;
                        for (int i = 0; i < methParams.size(); i++) {
 
+                               String paramType = methPrmTypes.get(i);
+                               if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES)
+                                       paramType = getTypeOfGeneric(paramType)[0];
+                               // Check if this has callback object
+                               if (callbackClasses != null) {
+                                       if (callbackClasses.contains(paramType)) {
+                                               isCallbackMethod = true;
+                                               callbackType = paramType;       
+                                               // Even if there're 2 callback arguments, we expect them to be of the same interface
+                                       }
+                               }
                                print(methPrmTypes.get(i) + " " + methParams.get(i));
                                // Check if this is the last element (don't print a comma)
                                if (i != methParams.size() - 1) {
@@ -429,8 +612,14 @@ public class IoTCompiler {
                        }
                        println(") {");
                        // Now, write the body of stub!
-                       writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
+                       if (isCallbackMethod)
+                               writeCallbackMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method, callbackType);
+                       else
+                               writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
                        println("}\n");
+                       // Write the init callback helper method
+                       if (isCallbackMethod)
+                               writeInitCallbackJavaStub(callbackType, intDecl);
                }
        }
 
@@ -455,18 +644,22 @@ public class IoTCompiler {
                                DeclarationHandler decHandler = mapIntDeclHand.get(intface);
                                InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
                                // Pass in set of methods and get import classes
-                               Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
+                               Set<String> methods = intMeth.getValue();
+                               Set<String> importClasses = getImportClasses(methods, intDecl);
                                List<String> stdImportClasses = getStandardJavaImportClasses();
                                List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
                                printImportStatements(allImportClasses); println("");
+                               // Find out if there are callback objects
+                               Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
+                               boolean callbackExist = !callbackClasses.isEmpty();
                                // Write class header
                                println("public class " + newStubClass + " implements " + newIntface + " {\n");
                                // Write properties
-                               writePropertiesJavaStub(intface, newIntface);
+                               writePropertiesJavaStub(intface, newIntface, callbackExist, callbackClasses);
                                // Write constructor
-                               writeConstructorJavaStub(newStubClass);
+                               writeConstructorJavaStub(newStubClass, callbackExist, callbackClasses);
                                // Write methods
-                               writeMethodJavaStub(intMeth.getValue(), intDecl);
+                               writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses);
                                println("}");
                                pw.close();
                                System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
@@ -475,15 +668,107 @@ public class IoTCompiler {
        }
 
 
+       /**
+        * HELPER: writePropertiesJavaCallbackStub() writes the properties of the callback stub class
+        */
+       private void writePropertiesJavaCallbackStub(String intface, String newIntface, boolean callbackExist, Set<String> callbackClasses) {
+
+               println("private IoTRMICall rmiCall;");
+               // Get the object Id
+               println("private static int objectId = 0;");
+               if (callbackExist) {
+               // We assume that each class only has one callback interface for now
+                       Iterator it = callbackClasses.iterator();
+                       String callbackType = (String) it.next();
+                       println("// Callback properties");
+                       println("private IoTRMIObject rmiObj;");
+                       println("List<" + callbackType + "> listCallbackObj;");
+                       println("private static int objIdCnt = 0;");
+               }
+               println("\n");
+       }
+
+
+       /**
+        * HELPER: writeConstructorJavaCallbackStub() writes the constructor of the callback stub class
+        */
+       private void writeConstructorJavaCallbackStub(String intface, boolean callbackExist, Set<String> callbackClasses) {
+
+               println("public " + intface + "(IoTRMICall _rmiCall, int _objectId) throws Exception {");
+               println("objectId = _objectId;");
+               println("rmiCall = _rmiCall;");
+               if (callbackExist) {
+                       Iterator it = callbackClasses.iterator();
+                       String callbackType = (String) it.next();
+                       println("listCallbackObj = new ArrayList<" + callbackType + ">();");
+                       println("___initCallBack();");
+               }
+               println("}\n");
+       }
+
+
+       /**
+        * generateJavaCallbackStubClasses() generate callback stubs based on the methods list in Java
+        * <p>
+        * Callback stubs gets the IoTRMICall objects from outside of the class as contructor input
+        * because all these stubs are populated by the class that takes in this object as a callback
+        * object. In such a class, we only use one socket, hence one IoTRMICall, for all callback objects.
+        */
+       public void generateJavaCallbackStubClasses() throws IOException {
+
+               // Create a new directory
+               String path = createDirectories(dir, subdir);
+               for (String intface : mapIntfacePTH.keySet()) {
+
+                       Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
+                       for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
+
+                               // Open a new file to write into
+                               String newIntface = intMeth.getKey();
+                               String newStubClass = newIntface + "_CallbackStub";
+                               FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
+                               pw = new PrintWriter(new BufferedWriter(fw));
+                               DeclarationHandler decHandler = mapIntDeclHand.get(intface);
+                               InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
+                               // Pass in set of methods and get import classes
+                               Set<String> methods = intMeth.getValue();
+                               Set<String> importClasses = getImportClasses(methods, intDecl);
+                               List<String> stdImportClasses = getStandardJavaImportClasses();
+                               List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
+                               printImportStatements(allImportClasses); println("");
+                               // Find out if there are callback objects
+                               Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
+                               boolean callbackExist = !callbackClasses.isEmpty();
+                               // Write class header
+                               println("public class " + newStubClass + " implements " + newIntface + " {\n");
+                               // Write properties
+                               writePropertiesJavaCallbackStub(intface, newIntface, callbackExist, callbackClasses);
+                               // Write constructor
+                               writeConstructorJavaCallbackStub(newStubClass, callbackExist, callbackClasses);
+                               // Write methods
+                               // TODO: perhaps need to generate callback for callback
+                               writeMethodJavaStub(intMeth.getValue(), intDecl, callbackClasses);
+                               println("}");
+                               pw.close();
+                               System.out.println("IoTCompiler: Generated callback stub class " + newStubClass + ".java...");
+                       }
+               }
+       }
+
+
        /**
         * HELPER: writePropertiesJavaSkeleton() writes the properties of the skeleton class
         */
-       private void writePropertiesJavaSkeleton(String intface) {
+       private void writePropertiesJavaSkeleton(String intface, boolean callbackExist) {
 
                println("private " + intface + " mainObj;");
                //println("private int ports;");
-               //println("private IoTRMICall rmiCall;");
                println("private IoTRMIObject rmiObj;\n");
+               // Callback
+               if (callbackExist) {
+                       println("private static int objIdCnt = 0;");
+                       println("private IoTRMICall rmiCall;");
+               }
                // Keep track of object Ids of all stubs registered to this interface
                Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
                for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
@@ -531,10 +816,23 @@ public class IoTCompiler {
        }
 
 
+       /**
+        * HELPER: writeInitCallbackJavaSkeleton() writes the init callback method for skeleton class
+        */
+       private void writeInitCallbackJavaSkeleton() {
+
+               println("public void ___regCB() throws IOException {");
+               println("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class, String.class, int.class },");
+               println("\tnew Class<?>[] { null, null, null });");
+               println("rmiCall = new IoTRMICall((int) paramObj[0], (String) paramObj[1], (int) paramObj[2]);");
+               println("}\n");
+       }
+
+
        /**
         * HELPER: writeMethodJavaSkeleton() writes the method of the skeleton class
         */
-       private void writeMethodJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
+       private void writeMethodJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
 
                for (String method : methods) {
 
@@ -542,9 +840,19 @@ public class IoTCompiler {
                        List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
                        String methodId = intDecl.getMethodId(method);
                        print("public " + intDecl.getMethodType(method) + " " + methodId + "(");
+                       boolean isCallbackMethod = false;
+                       String callbackType = null;
                        for (int i = 0; i < methParams.size(); i++) {
 
-                               print(methPrmTypes.get(i) + " " + methParams.get(i));
+                               String origParamType = methPrmTypes.get(i);
+                               String paramType = checkAndGetParamClass(origParamType, false);
+                               if (callbackClasses != null) {  // Check if this has callback object
+                                       if (callbackClasses.contains(origParamType)) {
+                                               isCallbackMethod = true;
+                                               callbackType = origParamType;   
+                                       }
+                               }
+                               print(paramType + " " + methParams.get(i));
                                // Check if this is the last element (don't print a comma)
                                if (i != methParams.size() - 1) {
                                        print(", ");
@@ -554,7 +862,56 @@ public class IoTCompiler {
                        // Now, write the body of skeleton!
                        writeStdMethodBodyJavaSkeleton(methParams, methodId, intDecl.getMethodType(method));
                        println("}\n");
+                       if (isCallbackMethod)
+                               writeInitCallbackJavaSkeleton();
+               }
+       }
+
+
+       /**
+        * HELPER: writeCallbackStubGeneration() writes the callback stub generation part
+        */
+       private Map<Integer,String> writeCallbackStubGeneration(List<String> methParams, List<String> methPrmTypes, String callbackType) {
+
+               Map<Integer,String> mapStubParam = new HashMap<Integer,String>();
+               // Iterate over callback objects
+               for (int i = 0; i < methParams.size(); i++) {
+                       String paramType = methPrmTypes.get(i);
+                       String param = methParams.get(i);
+                       //if (callbackType.equals(paramType)) {
+                       if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
+                               println("try {");
+                               String exchParamType = checkAndGetParamClass(paramType, false);
+                               // Print array if this is array or list if this is a list of callback objects
+                               if (isArray(paramType, param)) {
+                                       println("int numStubs" + i + " = (int) paramObj[" + i + "];");
+                                       println(exchParamType + "[] stub" + i + " = new " + exchParamType + "[numStubs" + i + "];");
+                               } else if (isList(paramType, param)) {
+                                       println("int numStubs" + i + " = (int) paramObj[" + i + "];");
+                                       println("List<" + exchParamType + "> stub" + i + " = new ArrayList<" + exchParamType + ">();");
+                               } else {
+                                       println(exchParamType + " stub" + i + " = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
+                                       println("objIdCnt++;");
+                               }
+                       }
+                       // Generate a loop if needed
+                       if (checkCallbackType(paramType, callbackType)) { // Check if this has callback object
+                               String exchParamType = checkAndGetParamClass(paramType, false);
+                               if (isArray(paramType, param)) {
+                                       println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
+                                       println("stub" + i + "[objId] = new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt);");
+                                       println("objIdCnt++;");
+                                       println("}");
+                               } else if (isList(paramType, param)) {
+                                       println("for (int objId = 0; objId < numStubs" + i + "; objId++) {");
+                                       println("stub" + i + ".add(new " + exchParamType + "_CallbackStub(rmiCall, objIdCnt));");
+                                       println("objIdCnt++;");
+                                       println("}");
+                               }
+                       }
+                       mapStubParam.put(i, "stub" + i);        // List of all stub parameters
                }
+               return mapStubParam;
        }
 
 
@@ -562,13 +919,28 @@ public class IoTCompiler {
         * HELPER: writeStdMethodHelperBodyJavaSkeleton() writes the standard method body helper in the skeleton class
         */
        private void writeStdMethodHelperBodyJavaSkeleton(InterfaceDecl intDecl, List<String> methParams,
-                       List<String> methPrmTypes, String method) {
+                       List<String> methPrmTypes, String method, Set<String> callbackClasses) {
                // Generate array of parameter objects
+               boolean isCallbackMethod = false;
+               String callbackType = null;
                print("Object[] paramObj = rmiObj.getMethodParams(new Class<?>[] { ");
                for (int i = 0; i < methParams.size(); i++) {
-                       String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
-                       print(getSimpleType(paramType) + ".class");
-                       // Check if this is the last element (don't print a comma)
+                       String paramType = methPrmTypes.get(i);
+                       if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES)
+                               paramType = getTypeOfGeneric(paramType)[0];
+                       if (callbackClasses != null) {
+                               if (callbackClasses.contains(paramType)) {
+                                       isCallbackMethod = true;
+                                       callbackType = paramType;
+                                       print("int.class");
+                               } else {
+                                       String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
+                                       print(getSimpleType(prmType) + ".class");
+                               }
+                       } else { // Generate normal classes if it's not a callback object
+                               String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
+                               print(getSimpleType(prmType) + ".class");
+                       }
                        if (i != methParams.size() - 1)
                                print(", ");
                }
@@ -585,6 +957,9 @@ public class IoTCompiler {
                                print(", ");
                }
                println(" });");
+               Map<Integer,String> mapStubParam = null;
+               if (isCallbackMethod)
+                       mapStubParam = writeCallbackStubGeneration(methParams, methPrmTypes, callbackType);
                // Check if this is "void"
                String retType = intDecl.getMethodType(method);
                if (retType.equals("void")) {
@@ -593,21 +968,32 @@ public class IoTCompiler {
                        print("Object retObj = " + intDecl.getMethodId(method) + "(");
                }
                for (int i = 0; i < methParams.size(); i++) {
-                       String paramType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
-                       print("(" + paramType + ") paramObj[" + i + "]");
+
+                       if (isCallbackMethod) {
+                               print(mapStubParam.get(i));     // Get the callback parameter
+                       } else {
+                               String prmType = checkAndGetArray(methPrmTypes.get(i), methParams.get(i));
+                               print("(" + prmType + ") paramObj[" + i + "]");
+                       }
                        if (i != methParams.size() - 1)
                                print(", ");
                }
                println(");");
                if (!retType.equals("void"))
                        println("rmiObj.sendReturnObj(retObj);");
+               if (isCallbackMethod) { // Catch exception if this is callback
+                       println("} catch(Exception ex) {");
+                       println("ex.printStackTrace();");
+                       println("throw new Error(\"Exception from callback object instantiation!\");");
+                       println("}");
+               }
        }
 
 
        /**
         * HELPER: writeMethodHelperJavaSkeleton() writes the method helper of the skeleton class
         */
-       private void writeMethodHelperJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
+       private void writeMethodHelperJavaSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
 
                // Use this set to handle two same methodIds
                Set<String> uniqueMethodIds = new HashSet<String>();
@@ -629,7 +1015,7 @@ public class IoTCompiler {
                        else
                                println(helperMethod + "() throws IOException {");
                        // Now, write the helper body of skeleton!
-                       writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method);
+                       writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
                        println("}\n");
                }
        }
@@ -638,7 +1024,7 @@ public class IoTCompiler {
        /**
         * HELPER: writeJavaWaitRequestInvokeMethod() writes the main loop of the skeleton class
         */
-       private void writeJavaWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl) {
+       private void writeJavaWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist) {
 
                // Use this set to handle two same methodIds
                Set<String> uniqueMethodIds = new HashSet<String>();
@@ -662,6 +1048,12 @@ public class IoTCompiler {
                                uniqueMethodIds.add(methodId);
                        println(helperMethod + "(); break;");
                }
+               String method = "___initCallBack()";
+               // Print case -9999 (callback handler) if callback exists
+               if (callbackExist) {
+                       int methodId = intDecl.getHelperMethodNumId(method);
+                       println("case " + methodId + ": ___regCB(); break;");
+               }
                println("default: ");
                println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
                println("}");
@@ -676,11 +1068,11 @@ public class IoTCompiler {
        public void generateJavaSkeletonClass() throws IOException {
 
                // Create a new directory
-               createDirectory(dir);
+               String path = createDirectories(dir, subdir);
                for (String intface : mapIntfacePTH.keySet()) {
                        // Open a new file to write into
                        String newSkelClass = intface + "_Skeleton";
-                       FileWriter fw = new FileWriter(dir + "/" + newSkelClass + ".java");
+                       FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
                        pw = new PrintWriter(new BufferedWriter(fw));
                        // Pass in set of methods and get import classes
                        DeclarationHandler decHandler = mapIntDeclHand.get(intface);
@@ -690,19 +1082,22 @@ public class IoTCompiler {
                        List<String> stdImportClasses = getStandardJavaImportClasses();
                        List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
                        printImportStatements(allImportClasses);
+                       // Find out if there are callback objects
+                       Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
+                       boolean callbackExist = !callbackClasses.isEmpty();
                        // Write class header
                        println("");
                        println("public class " + newSkelClass  + " implements " + intface + " {\n");
                        // Write properties
-                       writePropertiesJavaSkeleton(intface);
+                       writePropertiesJavaSkeleton(intface, callbackExist);
                        // Write constructor
                        writeConstructorJavaSkeleton(newSkelClass, intface);
                        // Write methods
-                       writeMethodJavaSkeleton(methods, intDecl);
+                       writeMethodJavaSkeleton(methods, intDecl, callbackClasses);
                        // Write method helper
-                       writeMethodHelperJavaSkeleton(methods, intDecl);
+                       writeMethodHelperJavaSkeleton(methods, intDecl, callbackClasses);
                        // Write waitRequestInvokeMethod() - main loop
-                       writeJavaWaitRequestInvokeMethod(methods, intDecl);
+                       writeJavaWaitRequestInvokeMethod(methods, intDecl, callbackExist);
                        println("}");
                        pw.close();
                        System.out.println("IoTCompiler: Generated skeleton class " + newSkelClass + ".java...");
@@ -710,6 +1105,146 @@ public class IoTCompiler {
        }
 
 
+       /**
+        * HELPER: writePropertiesJavaCallbackSkeleton() writes the properties of the callback skeleton class
+        */
+       private void writePropertiesJavaCallbackSkeleton(String intface, boolean callbackExist) {
+
+               println("private " + intface + " mainObj;");
+               // For callback skeletons, this is its own object Id
+               println("private static int objectId = 0;");
+               // Callback
+               if (callbackExist) {
+                       println("private static int objIdCnt = 0;");
+                       println("private IoTRMICall rmiCall;");
+               }
+               println("\n");
+       }
+
+
+       /**
+        * HELPER: writeConstructorJavaCallbackSkeleton() writes the constructor of the skeleton class
+        */
+       private void writeConstructorJavaCallbackSkeleton(String newSkelClass, String intface) {
+
+               println("public " + newSkelClass + "(" + intface + " _mainObj, int _objectId) throws Exception {");
+               println("mainObj = _mainObj;");
+               println("objectId = _objectId;");
+               println("}\n");
+       }
+
+
+       /**
+        * HELPER: writeMethodHelperJavaCallbackSkeleton() writes the method helper of the callback skeleton class
+        */
+       private void writeMethodHelperJavaCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl, Set<String> callbackClasses) {
+
+               // Use this set to handle two same methodIds
+               Set<String> uniqueMethodIds = new HashSet<String>();
+               for (String method : methods) {
+
+                       List<String> methParams = intDecl.getMethodParams(method);
+                       List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
+                       String methodId = intDecl.getMethodId(method);
+                       print("public void ___");
+                       String helperMethod = methodId;
+                       if (uniqueMethodIds.contains(methodId))
+                               helperMethod = helperMethod + intDecl.getMethodNumId(method);
+                       else
+                               uniqueMethodIds.add(methodId);
+                       // Check if this is "void"
+                       String retType = intDecl.getMethodType(method);
+                       if (retType.equals("void"))
+                               println(helperMethod + "(IoTRMIObject rmiObj) {");
+                       else
+                               println(helperMethod + "(IoTRMIObject rmiObj) throws IOException {");
+                       // Now, write the helper body of skeleton!
+                       writeStdMethodHelperBodyJavaSkeleton(intDecl, methParams, methPrmTypes, method, callbackClasses);
+                       println("}\n");
+               }
+       }
+
+
+       /**
+        * HELPER: writeJavaCallbackWaitRequestInvokeMethod() writes the main loop of the skeleton class
+        */
+       private void writeJavaCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl, boolean callbackExist) {
+
+               // Use this set to handle two same methodIds
+               Set<String> uniqueMethodIds = new HashSet<String>();
+               println("public void invokeMethod(IoTRMIObject rmiObj) throws IOException {");
+               // Write variables here if we have callbacks or enums or structs
+               println("int methodId = rmiObj.getMethodId();");
+               // TODO: code the permission check here!
+               println("switch (methodId) {");
+               // Print methods and method Ids
+               for (String method : methods) {
+                       String methodId = intDecl.getMethodId(method);
+                       int methodNumId = intDecl.getMethodNumId(method);
+                       print("case " + methodNumId + ": ___");
+                       String helperMethod = methodId;
+                       if (uniqueMethodIds.contains(methodId))
+                               helperMethod = helperMethod + methodNumId;
+                       else
+                               uniqueMethodIds.add(methodId);
+                       println(helperMethod + "(rmiObj); break;");
+               }
+               String method = "___initCallBack()";
+               // Print case -9999 (callback handler) if callback exists
+               if (callbackExist) {
+                       int methodId = intDecl.getHelperMethodNumId(method);
+                       println("case " + methodId + ": ___regCB(); break;");
+               }
+               println("default: ");
+               println("throw new Error(\"Method Id \" + methodId + \" not recognized!\");");
+               println("}");
+               println("}\n");
+       }
+
+
+       /**
+        * generateJavaCallbackSkeletonClass() generate callback skeletons based on the methods list in Java
+        */
+       public void generateJavaCallbackSkeletonClass() throws IOException {
+
+               // Create a new directory
+               String path = createDirectories(dir, subdir);
+               for (String intface : mapIntfacePTH.keySet()) {
+                       // Open a new file to write into
+                       String newSkelClass = intface + "_CallbackSkeleton";
+                       FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".java");
+                       pw = new PrintWriter(new BufferedWriter(fw));
+                       // Pass in set of methods and get import classes
+                       DeclarationHandler decHandler = mapIntDeclHand.get(intface);
+                       InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
+                       List<String> methods = intDecl.getMethods();
+                       Set<String> importClasses = getImportClasses(methods, intDecl);
+                       List<String> stdImportClasses = getStandardJavaImportClasses();
+                       List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
+                       printImportStatements(allImportClasses);
+                       // Find out if there are callback objects
+                       Set<String> callbackClasses = getCallbackClasses(methods, intDecl);
+                       boolean callbackExist = !callbackClasses.isEmpty();
+                       // Write class header
+                       println("");
+                       println("public class " + newSkelClass  + " implements " + intface + " {\n");
+                       // Write properties
+                       writePropertiesJavaCallbackSkeleton(intface, callbackExist);
+                       // Write constructor
+                       writeConstructorJavaCallbackSkeleton(newSkelClass, intface);
+                       // Write methods
+                       writeMethodJavaSkeleton(methods, intDecl, callbackClasses);
+                       // Write method helper
+                       writeMethodHelperJavaCallbackSkeleton(methods, intDecl, callbackClasses);
+                       // Write waitRequestInvokeMethod() - main loop
+                       writeJavaCallbackWaitRequestInvokeMethod(methods, intDecl, callbackExist);
+                       println("}");
+                       pw.close();
+                       System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".java...");
+               }
+       }
+
+
        /**
         * HELPER: writeMethodCplusInterface() writes the method of the interface
         */
@@ -724,7 +1259,8 @@ public class IoTCompiler {
                        for (int i = 0; i < methParams.size(); i++) {
                                // Check for params with driver class types and exchange it 
                                //              with its remote interface
-                               String paramType = checkAndGetParamClass(methPrmTypes.get(i), true);
+                               //String paramType = checkAndGetParamClass(methPrmTypes.get(i), true);
+                               String paramType = methPrmTypes.get(i);
                                paramType = checkAndGetCplusType(paramType);
                                // Check for arrays - translate into vector in C++
                                String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
@@ -891,7 +1427,10 @@ public class IoTCompiler {
                        print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
                                intDecl.getMethodId(method) + "(");
                        for (int i = 0; i < methParams.size(); i++) {
-                               String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
+
+                               //String paramType = checkAndGetParamClass(methPrmTypes.get(i), true);
+                               String paramType = methPrmTypes.get(i);
+                               String methPrmType = checkAndGetCplusType(paramType);
                                String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
                                print(methParamComplete);
                                // Check if this is the last element (don't print a comma)
@@ -960,13 +1499,13 @@ public class IoTCompiler {
         */
        private void writePropertiesCplusStub(String intface, String newIntface) {
 
-               println("IoTRMICall\t\t\t*rmiCall;");
+               println("IoTRMICall *rmiCall;");
                //println("IoTRMIObject\t\t\t*rmiObj;");
-               println("string\t\t\t\taddress;");
-               println("vector<int>\t\t\tports;\n");
+               println("string address;");
+               println("vector<int> ports;\n");
                // Get the object Id
                Integer objId = mapIntfaceObjId.get(intface);
-               println("const static int\tobjectId = " + objId + ";");
+               println("const static int objectId = " + objId + ";");
                mapNewIntfaceObjId.put(newIntface, objId);
                mapIntfaceObjId.put(intface, objId++);
                println("\n");
@@ -1046,6 +1585,73 @@ public class IoTCompiler {
        }
 
 
+       /**
+        * HELPER: writePropertiesCplusCallbackStub() writes the properties of the stub class
+        */
+       private void writePropertiesCplusCallbackStub(String intface, String newIntface) {
+
+               println("IoTRMICall *rmiCall;");
+               // Get the object Id
+               println("static int objectId;");
+               println("\n");
+       }
+
+
+       /**
+        * HELPER: writeConstructorCplusCallbackStub() writes the constructor of the stub class
+        */
+       private void writeConstructorCplusCallbackStub(String newStubClass) {
+
+               println(newStubClass + "(IoTRMICall* _rmiCall, int _objectId) {");
+               println("objectId = _objectId;");
+               println("rmiCall = _rmiCall;");
+               println("}\n");
+       }
+
+
+       /**
+        * generateCPlusCallbackStubClasses() generate callback stubs based on the methods list in C++
+        */
+       public void generateCPlusCallbackStubClasses() throws IOException {
+
+               // Create a new directory
+               String path = createDirectories(dir, subdir);
+               for (String intface : mapIntfacePTH.keySet()) {
+
+                       Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
+                       for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
+                               // Open a new file to write into
+                               String newIntface = intMeth.getKey();
+                               String newStubClass = newIntface + "_CallbackStub";
+                               FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
+                               pw = new PrintWriter(new BufferedWriter(fw));
+                               // Write file headers
+                               println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
+                               println("#define _" + newStubClass.toUpperCase() + "_HPP__");
+                               println("#include <iostream>");
+                               println("#include \"" + newIntface + ".hpp\""); println("");            
+                               println("using namespace std;"); println("");
+                               println("class " + newStubClass + " : public " + newIntface); println("{");
+                               println("private:\n");
+                               writePropertiesCplusCallbackStub(intface, newIntface);
+                               println("public:\n");
+                               // Add default constructor and destructor
+                               println(newStubClass + "() { }"); println("");
+                               writeConstructorCplusCallbackStub(newStubClass);
+                               writeDeconstructorCplusStub(newStubClass);
+                               DeclarationHandler decHandler = mapIntDeclHand.get(intface);
+                               InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
+                               // Write methods
+                               writeMethodCplusStub(intMeth.getValue(), intDecl);
+                               print("}"); println(";");
+                               println("#endif");
+                               pw.close();
+                               System.out.println("IoTCompiler: Generated callback stub class " + newIntface + ".hpp...");
+                       }
+               }
+       }
+
+
        /**
         * HELPER: writePropertiesCplusSkeleton() writes the properties of the skeleton class
         */
@@ -1134,7 +1740,9 @@ public class IoTCompiler {
                        String methodType = checkAndGetCplusType(intDecl.getMethodType(method));
                        print(methodType + " " + methodId + "(");
                        for (int i = 0; i < methParams.size(); i++) {
-                               String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
+
+                               String paramType = checkAndGetParamClass(methPrmTypes.get(i), true);
+                               String methPrmType = checkAndGetCplusType(paramType);
                                String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
                                print(methParamComplete);
                                // Check if this is the last element (don't print a comma)
@@ -1281,11 +1889,11 @@ public class IoTCompiler {
        public void generateCplusSkeletonClass() throws IOException {
 
                // Create a new directory
-               createDirectory(dir);
+               String path = createDirectories(dir, subdir);
                for (String intface : mapIntfacePTH.keySet()) {
                        // Open a new file to write into
                        String newSkelClass = intface + "_Skeleton";
-                       FileWriter fw = new FileWriter(dir + "/" + newSkelClass + ".hpp");
+                       FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp");
                        pw = new PrintWriter(new BufferedWriter(fw));
                        // Write file headers
                        println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
@@ -1325,6 +1933,142 @@ public class IoTCompiler {
        }
 
 
+       /**
+        * HELPER: writePropertiesCplusCallbackSkeleton() writes the properties of the callback skeleton class
+        */
+       private void writePropertiesCplusCallbackSkeleton(String intface) {
+
+               println(intface + " *mainObj;");
+               //println("IoTRMIObject *rmiObj;\n");
+               // Keep track of object Ids of all stubs registered to this interface
+               println("static int objectId;");
+               println("\n");
+       }
+
+
+       /**
+        * HELPER: writeConstructorCplusCallbackSkeleton() writes the constructor of the skeleton class
+        */
+       private void writeConstructorCplusCallbackSkeleton(String newSkelClass, String intface) {
+
+               println(newSkelClass + "(" + intface + " *_mainObj, int _objectId) {");
+               println("mainObj = _mainObj;");
+               println("objectId = _objectId;");
+               println("}\n");
+       }
+
+
+       /**
+        * HELPER: writeMethodHelperCplusCallbackSkeleton() writes the method helper of the callback skeleton class
+        */
+       private void writeMethodHelperCplusCallbackSkeleton(Collection<String> methods, InterfaceDecl intDecl) {
+
+               // Use this set to handle two same methodIds
+               Set<String> uniqueMethodIds = new HashSet<String>();
+               for (String method : methods) {
+
+                       List<String> methParams = intDecl.getMethodParams(method);
+                       List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
+                       String methodId = intDecl.getMethodId(method);
+                       print("void ___");
+                       String helperMethod = methodId;
+                       if (uniqueMethodIds.contains(methodId))
+                               helperMethod = helperMethod + intDecl.getMethodNumId(method);
+                       else
+                               uniqueMethodIds.add(methodId);
+                       // Check if this is "void"
+                       String retType = intDecl.getMethodType(method);
+                       println(helperMethod + "(IoTRMIObject* rmiObj) {");
+                       // Now, write the helper body of skeleton!
+                       writeStdMethodHelperBodyCplusSkeleton(intDecl, methParams, methPrmTypes, method, methodId);
+                       println("}\n");
+               }
+       }
+
+
+       /**
+        * HELPER: writeCplusCallbackWaitRequestInvokeMethod() writes the main loop of the skeleton class
+        */
+       private void writeCplusCallbackWaitRequestInvokeMethod(Collection<String> methods, InterfaceDecl intDecl) {
+
+               // Use this set to handle two same methodIds
+               Set<String> uniqueMethodIds = new HashSet<String>();
+               println("void invokeMethod(IoTRMIObject* rmiObj) {");
+               // Write variables here if we have callbacks or enums or structs
+               println("int methodId = rmiObj->getMethodId();");
+               // TODO: code the permission check here!
+               println("switch (methodId) {");
+               // Print methods and method Ids
+               for (String method : methods) {
+                       String methodId = intDecl.getMethodId(method);
+                       int methodNumId = intDecl.getMethodNumId(method);
+                       print("case " + methodNumId + ": ___");
+                       String helperMethod = methodId;
+                       if (uniqueMethodIds.contains(methodId))
+                               helperMethod = helperMethod + methodNumId;
+                       else
+                               uniqueMethodIds.add(methodId);
+                       println(helperMethod + "(rmiObj); break;");
+               }
+               println("default: ");
+               println("cerr << \"Method Id \" << methodId << \" not recognized!\" << endl;");
+               println("throw exception();");
+               println("}");
+               println("}\n");
+       }
+
+
+
+       /**
+        * generateCplusCallbackSkeletonClass() generate callback skeletons based on the methods list in C++
+        */
+       public void generateCplusCallbackSkeletonClass() throws IOException {
+
+               // Create a new directory
+               String path = createDirectories(dir, subdir);
+               for (String intface : mapIntfacePTH.keySet()) {
+                       // Open a new file to write into
+                       String newSkelClass = intface + "_CallbackSkeleton";
+                       FileWriter fw = new FileWriter(path + "/" + newSkelClass + ".hpp");
+                       pw = new PrintWriter(new BufferedWriter(fw));
+                       // Write file headers
+                       println("#ifndef _" + newSkelClass.toUpperCase() + "_HPP__");
+                       println("#define _" + newSkelClass.toUpperCase() + "_HPP__");
+                       println("#include <iostream>");
+                       println("#include \"" + intface + ".hpp\"\n");
+                       // Pass in set of methods and get import classes
+                       DeclarationHandler decHandler = mapIntDeclHand.get(intface);
+                       InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
+                       List<String> methods = intDecl.getMethods();
+                       Set<String> includeClasses = getIncludeClasses(methods, intDecl);
+                       List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
+                       List<String> allIncludeClasses = getAllImportClasses(stdIncludeClasses, includeClasses);
+                       printIncludeStatements(allIncludeClasses); println("");                 
+                       println("using namespace std;\n");
+                       // Write class header
+                       println("class " + newSkelClass + " : public " + intface); println("{");
+                       println("private:\n");
+                       // Write properties
+                       writePropertiesCplusCallbackSkeleton(intface);
+                       println("public:\n");
+                       // Write constructor
+                       writeConstructorCplusCallbackSkeleton(newSkelClass, intface);
+                       // Write deconstructor
+                       //writeDeconstructorCplusSkeleton(newSkelClass);
+                       // Write methods
+                       writeMethodCplusSkeleton(methods, intDecl);
+                       // Write method helper
+                       writeMethodHelperCplusCallbackSkeleton(methods, intDecl);
+                       // Write waitRequestInvokeMethod() - main loop
+                       writeCplusCallbackWaitRequestInvokeMethod(methods, intDecl);
+                       println("};");
+                       println("#endif");
+                       pw.close();
+                       System.out.println("IoTCompiler: Generated callback skeleton class " + newSkelClass + ".hpp...");
+               }
+       }
+
+
        /**
         * generateInitializer() generate initializer based on type
         */
@@ -1665,6 +2409,32 @@ public class IoTCompiler {
        }
 
 
+       // Generate a set of callback classes
+       private Set<String> getCallbackClasses(Collection<String> methods, InterfaceDecl intDecl) {
+
+               Set<String> callbackClasses = new HashSet<String>();
+               for (String method : methods) {
+
+                       List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
+                       List<String> methParams = intDecl.getMethodParams(method);
+                       for (int i = 0; i < methPrmTypes.size(); i++) {
+
+                               String type = methPrmTypes.get(i);
+                               if (getParamCategory(type) == ParamCategory.USERDEFINED) {
+                                       callbackClasses.add(type);
+                               } else if (getParamCategory(type) == ParamCategory.NONPRIMITIVES) {
+                               // Can be a List<...> of callback objects ...
+                                       String genericType = getTypeOfGeneric(type)[0];
+                                       if (getParamCategory(type) == ParamCategory.USERDEFINED) {
+                                               callbackClasses.add(type);
+                                       }
+                               }
+                       }
+               }
+               return callbackClasses;
+       }
+
+
        private void printImportStatements(Collection<String> importClasses) {
 
                for(String cls : importClasses) {
@@ -1804,8 +2574,42 @@ public class IoTCompiler {
        }
 
 
-       // Get simple types, e.g. HashSet for HashSet<...>
-       // Basically strip off the "<...>"
+       // Is array or list?
+       private boolean isArrayOrList(String paramType, String param) {
+
+               // Check for array declaration
+               if (isArray(paramType, param))
+                       return true;
+               else if (isList(paramType, param))
+                       return true;
+               else
+                       return false;
+       }
+
+
+       // Is array or list?
+       private boolean isArray(String paramType, String param) {
+
+               // Check for array declaration
+               if (param.contains("[]"))
+                       return true;
+               else
+                       return false;
+       }
+
+
+       // Is array or list?
+       private boolean isList(String paramType, String param) {
+
+               // Check for array declaration
+               if (paramType.contains("List"))
+                       return true;
+               else
+                       return false;
+       }
+
+
+       // Get the right type for a callback object
        private String checkAndGetParamClass(String paramType, boolean needPtr) {
 
                // Check if this is generics
@@ -1887,11 +2691,15 @@ public class IoTCompiler {
                                comp.generateJavaLocalInterfaces();
                                comp.generateJavaInterfaces();
                                comp.generateJavaStubClasses();
+                               comp.generateJavaCallbackStubClasses();
                                comp.generateJavaSkeletonClass();
+                               comp.generateJavaCallbackSkeletonClass();
                                comp.generateCplusLocalInterfaces();
                                comp.generateCPlusInterfaces();
                                comp.generateCPlusStubClasses();
+                               comp.generateCPlusCallbackStubClasses();
                                comp.generateCplusSkeletonClass();
+                               comp.generateCplusCallbackSkeletonClass();
                        } else {
                        // Check other options
                                while(i < args.length) {
@@ -1909,12 +2717,16 @@ public class IoTCompiler {
                                                        comp.generateJavaLocalInterfaces();
                                                        comp.generateJavaInterfaces();
                                                        comp.generateJavaStubClasses();
+                                                       comp.generateJavaCallbackStubClasses();
                                                        comp.generateJavaSkeletonClass();
+                                                       comp.generateJavaCallbackSkeletonClass();
                                                } else {
                                                        comp.generateCplusLocalInterfaces();
                                                        comp.generateCPlusInterfaces();
                                                        comp.generateCPlusStubClasses();
+                                                       comp.generateCPlusCallbackStubClasses();
                                                        comp.generateCplusSkeletonClass();
+                                                       comp.generateCplusCallbackSkeletonClass();
                                                }
                                        }
                                        i = i + 2;
index 69ad796..30dd3ce 100644 (file)
@@ -38,6 +38,9 @@ public class InterfaceDecl extends Declaration {
        private List<String> listMethodTypes;                           // Method types, e.g. void
        private List<List<String>> listMethodParams;            // Method parameter names, e.g. A, B
        private List<List<String>> listMethodParamTypes;        // Method parameter types, e.g. int, int
+       private Map<String,Integer> mapHelperNumMethodId;       // Helper method Id, e.g. for callbacks, structs.
+
+       private static int helperMethodIdNum = -9999;
 
        /**
         * Class constructors
@@ -50,6 +53,7 @@ public class InterfaceDecl extends Declaration {
                listMethodTypes = new ArrayList<String>();
                listMethodParams = new ArrayList<List<String>>();
                listMethodParamTypes = new ArrayList<List<String>>();
+               mapHelperNumMethodId = new HashMap<String,Integer>();
        }
 
 
@@ -61,6 +65,7 @@ public class InterfaceDecl extends Declaration {
                listMethodTypes = new ArrayList<String>();
                listMethodParams = new ArrayList<List<String>>();
                listMethodParamTypes = new ArrayList<List<String>>();
+               mapHelperNumMethodId = new HashMap<String,Integer>();
        }
 
 
@@ -108,6 +113,20 @@ public class InterfaceDecl extends Declaration {
        }
 
 
+       /**
+        * getHelperMethodNumId() gets Id number for a method
+        */
+       public int getHelperMethodNumId(String method) {
+
+               if (!mapHelperNumMethodId.containsKey(method)) {
+                       mapHelperNumMethodId.put(method, helperMethodIdNum++);
+                       return mapHelperNumMethodId.get(method);
+               } else {
+                       return mapHelperNumMethodId.get(method);
+               }
+       }
+
+
        /**
         * getMethodIds() gets method identifiers
         */