Adding early version of IoT RMI system; for now: 1) Connects Java to Java; 2) Transla...
authorrtrimana <rtrimana@uci.edu>
Mon, 10 Oct 2016 17:35:13 +0000 (10:35 -0700)
committerrtrimana <rtrimana@uci.edu>
Mon, 10 Oct 2016 17:35:13 +0000 (10:35 -0700)
iotjava/Makefile
iotjava/iotpolicy/IoTCompiler.java
iotjava/iotrmi/IoTRMITypes.java [new file with mode: 0644]
iotjava/iotrmi/Java/IoTRMICall.java [new file with mode: 0644]
iotjava/iotrmi/Java/IoTRMIObject.java [new file with mode: 0644]
iotjava/iotrmi/Java/IoTRMIUtil.java [new file with mode: 0644]
iotjava/iotrmi/Java/IoTSocketClient.java [new file with mode: 0644]
iotjava/iotrmi/Java/IoTSocketServer.java [new file with mode: 0644]

index 9854cc8..d40d939 100644 (file)
@@ -17,10 +17,15 @@ compiler:
        $(JAVAC) -cp .:$(PARSERJARS) -d $(BIN_DIR) iotpolicy/*.java
        cp ../config/iotpolicy/*.pol $(BIN_DIR)/iotpolicy/
 
-PHONY += run
-run:
+PHONY += run-compiler
+run-compiler:
        cd $(BIN_DIR)/iotpolicy; $(JAVA) -cp .:..:../$(PARSERJARS):../$(BIN_DIR) iotpolicy.IoTCompiler camerapolicy.pol camerarequires.pol lightbulbpolicy.pol lightbulbrequires.pol -cplus Cplus -java Java
 
+PHONY += rmi
+rmi:
+       $(JAVAC) -cp . -d $(BIN_DIR) iotrmi/*.java
+       $(JAVAC) -cp .:../$(BIN_DIR) -d $(BIN_DIR) iotrmi/Java/*.java
+
 PHONY += doc
 doc: iotruntime iotinstaller
        $(JAVADOC) -d $(DOCS_DIR) iotpolicy/*.java
index 79202c4..f4248f2 100644 (file)
@@ -664,9 +664,9 @@ public class IoTCompiler {
        }
 
 
-       /**================================================
-        * Helper functions to write stub codes into files
-        **================================================
+       /**================
+        * Helper functions
+        **================
         */
        boolean newline=true;
        int tablevel=0;
diff --git a/iotjava/iotrmi/IoTRMITypes.java b/iotjava/iotrmi/IoTRMITypes.java
new file mode 100644 (file)
index 0000000..a0c682f
--- /dev/null
@@ -0,0 +1,140 @@
+package iotrmi;
+
+/** Class IoTRMITypes is a class that provides type translations.
+ *  <p>
+ *  It stores C++ and Java types.
+ *
+ * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
+ * @version     1.0
+ * @since       2016-10-03
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class IoTRMITypes {
+
+       /**
+        * Primitive data types in Java
+        */
+       public final static String[] primitivesJava = new String[] {
+
+               "byte",                 // 1 byte
+               "Byte",                 // 1 byte
+               "short",                // 2 bytes
+               "Short",                // 2 bytes
+               "int",                  // 4 bytes
+               "Integer",              // 4 bytes
+               "long",                 // 8 bytes
+               "Long",                 // 8 bytes
+               "float",                // 4 bytes
+               "Float",                // 4 bytes
+               "double",               // 8 bytes
+               "Double",               // 8 bytes
+               "boolean",              // 1 bytes
+               "Boolean",              // 1 bytes
+               "char",                 // 2 bytes
+               "Character",    // 2 bytes
+               "string",               // indefinite
+               "String",               // indefinite
+               "void"                  // 0 byte
+       };
+
+       
+       /**
+        * Primitive data types in C++ to map the primitives list
+        */
+       public final static String[] primitivesCplus = new String[] {
+
+               "char",                 // 1 byte
+               "char",                 // 1 byte
+               "short",                // 2 bytes
+               "short",                // 2 bytes
+               "int",                  // 4 bytes
+               "int",                  // 4 bytes
+               "long",                 // 4 bytes
+               "long",                 // 4 bytes
+               "float",                // 4 bytes
+               "float",                // 4 bytes
+               "double",               // 8 bytes
+               "double",               // 8 bytes
+               "bool",                 // 1 byte
+               "bool",                 // 1 byte
+               "char",                 // 1 byte
+               "char",                 // 1 byte
+               "string",               // indefinite
+               "string",               // indefinite
+               "void"                  // 0 byte
+       };
+
+
+       /**
+        * Primitive sizes in Java - Long is 8 bytes and char is 2 bytes
+        */
+       public final static Integer[] primitivesJavaSizes = new Integer[] {
+
+               1, 1, 2, 2, 4, 4, 8, 8, 4, 4, 8, 8, 1, 1, 2, 2, -1, -1, 0
+       };
+
+
+       /**
+        * Primitive sizes in Cplus - Long is 4 bytes and char is 1 byte
+        */
+       public final static Integer[] primitivesCplusSizes = new Integer[] {
+
+               1, 1, 2, 2, 4, 4, 4, 4, 4, 4, 8, 8, 1, 1, 1, 1, -1, -1, 0
+       };
+
+
+       /**
+        * Non-primitive Java data types
+        */
+       public final static String[] nonPrimitivesJava = new String[] {
+
+               "Set",
+               "HashSet",
+               "Map",
+               "HashMap",
+               "List",
+               "ArrayList"
+       };
+
+
+       /**
+        * Non-primitive C++ data types
+        */
+       public final static String[] nonPrimitivesCplus = new String[] {
+
+               "set",
+               "unordered_set",
+               "map",
+               "unordered_map",
+               "list",
+               "list"
+       };
+
+
+       /**================
+        * Helper functions
+        **================
+        */
+       // Inserting array members into a Map object
+       // that maps arrKey to arrVal objects
+       public static void arraysToMap(Map<String,String> map, String[] arrKey, String[] arrVal) {
+
+               for(int i = 0; i < arrKey.length; i++) {
+
+                       map.put(arrKey[i], arrVal[i]);
+               }
+       }
+
+       // Inserting array members into a Map object
+       // that maps arrKey to arrVal objects
+       public static void arraysToMap(Map<String,Integer> map, String[] arrKey, Integer[] arrVal) {
+
+               for(int i = 0; i < arrKey.length; i++) {
+
+                       map.put(arrKey[i], arrVal[i]);
+               }
+       }
+}
diff --git a/iotjava/iotrmi/Java/IoTRMICall.java b/iotjava/iotrmi/Java/IoTRMICall.java
new file mode 100644 (file)
index 0000000..9410662
--- /dev/null
@@ -0,0 +1,120 @@
+package iotrmi.Java;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.lang.reflect.Method;
+
+
+/** Class IoTRMICall is a class that serves method calls on stub.
+ *  <p>
+ *  A stub will use an object of this class to send the method
+ *  information, e.g. object identifier, method identifier, and
+ *  parameters.
+ *
+ * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
+ * @version     1.0
+ * @since       2016-10-04
+ */
+public class IoTRMICall {
+
+       /**
+        * Class Properties
+        */
+       private IoTRMIUtil rmiUtil;
+       private IoTSocketClient rmiClient;
+
+
+       /**
+        * Constructors
+        */
+       public IoTRMICall(int _port, String _address, int _rev) throws IOException {
+
+               rmiUtil = new IoTRMIUtil();
+               rmiClient = new IoTSocketClient(_port, _address, _rev);
+       }
+
+
+       /**
+        * remoteCall() calls a method remotely by passing in parameters and getting a return Object
+        */
+       public Object remoteCall(String methodSign, String retType, Class<?>[] paramCls, Object[] paramObj) throws IOException {
+
+               // Send method info
+               byte[] methodBytes = methodToBytes(methodSign, paramCls, paramObj);
+               rmiClient.sendBytes(methodBytes);
+               // Receive return value and return it to caller
+               byte[] retObjBytes = null;
+               retObjBytes = rmiClient.receiveBytes(retObjBytes);
+               Object retObj = IoTRMIUtil.getParamObject(retType, retObjBytes);
+               return retObj;
+       }
+
+
+       /**
+        * methodToBytes() returns byte representation of a method
+        */
+       public byte[] methodToBytes(String methodSign, Class<?>[] paramCls, Object[] paramObj) {
+
+               // Get method ID in bytes
+               byte[] methodId = IoTRMIUtil.getHashCodeBytes(methodSign);
+
+               // Get byte arrays and calculate method bytes length
+               int numbParam = paramObj.length;
+               int methodLen = IoTRMIUtil.METHOD_ID_LEN;       // Initialized to the length of method ID
+               byte[][] objBytesArr = new byte[numbParam][];
+               for (int i=0; i < numbParam; i++) {
+                       // Get byte arrays for the objects
+                       objBytesArr[i] = IoTRMIUtil.getObjectBytes(paramObj[i]);
+                       String clsName = paramCls[i].getSimpleName();
+                       int paramLen = rmiUtil.getTypeSize(clsName);
+                       if (paramLen == -1) {           // indefinite length
+                               methodLen = methodLen + IoTRMIUtil.PARAM_LEN;
+                       }
+                       methodLen = methodLen + objBytesArr[i].length;
+               }
+
+               // Construct method in byte array
+               byte[] method = new byte[methodLen];
+               int pos = 0;
+               System.arraycopy(methodId, 0, method, 0, methodId.length);
+               pos = pos + IoTRMIUtil.METHOD_ID_LEN;
+               // Second iteration for copying bytes
+               for (int i=0; i < numbParam; i++) {
+
+                       String clsName = paramCls[i].getSimpleName();
+                       int paramLen = rmiUtil.getTypeSize(clsName);
+                       if (paramLen == -1) {           // indefinite length
+                               paramLen = objBytesArr[i].length;
+                               byte[] paramLenBytes = IoTRMIUtil.intToByteArray(paramLen);
+                               System.arraycopy(paramLenBytes, 0, method, pos, IoTRMIUtil.PARAM_LEN);
+                               pos = pos + IoTRMIUtil.PARAM_LEN;
+                       }               
+                       System.arraycopy(objBytesArr[i], 0, method, pos, paramLen);
+                       pos = pos + paramLen;
+               }
+
+               return method;
+       }
+
+       
+       public static void main(String[] args) throws Exception {
+
+               int port = 5010;
+               String address = "localhost";
+               int rev = 0;
+               IoTRMICall rmiCall = new IoTRMICall(port, address, rev);
+               String sign = "intsetACAndGetA(string,int)";
+               String retType = "int";
+               System.out.println("Calling function: " + sign);
+               Object retObj = rmiCall.remoteCall(sign, retType, new Class<?>[] { String.class, int.class }, 
+                       new Object[] { "Test param", 1234567 });
+               System.out.println("Returned object: " + retObj);
+
+               System.out.println();
+       }
+}
diff --git a/iotjava/iotrmi/Java/IoTRMIObject.java b/iotjava/iotrmi/Java/IoTRMIObject.java
new file mode 100644 (file)
index 0000000..9f40b82
--- /dev/null
@@ -0,0 +1,231 @@
+package iotrmi.Java;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.lang.reflect.*;
+
+
+/** Class IoTRMIObject is a class that stores info of an object.
+ *  <p>
+ *  It stores object ID, methods, method ID, method's signature 
+ *  and parameters.
+ *  This class also receive calls from different objects as they
+ *  ask to execute certain methods remotely. This will have the 
+ *  execution result (return value) sent back to 
+ *
+ * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
+ * @version     1.0
+ * @since       2016-10-03
+ */
+public class IoTRMIObject {
+
+       /**
+        * Class Properties
+        */
+       private Map<String,Method> mapSign2Method;      // Map from signature to method
+       private Map<Integer,String> mapHash2Sign;       // Map from hashcode(method ID) to signature
+       private IoTRMIUtil rmiUtil;
+       private IoTSocketServer rmiServer;
+       private Object obj;
+       private Class<?> cls;
+       private Method[] methods;
+
+
+       /**
+        * Constructors
+        */
+       public IoTRMIObject(String _clsName, int _port) throws 
+                       ClassNotFoundException, InstantiationException, 
+                               IllegalAccessException, IOException {
+
+               rmiUtil = new IoTRMIUtil();
+               cls = Class.forName(_clsName);
+               obj = cls.newInstance();
+               methods = cls.getDeclaredMethods();
+               mapSign2Method = new HashMap<String,Method>();
+               mapHash2Sign = new HashMap<Integer,String>();
+               getMethodSignatures();  // Initialize the signature map
+               getMethodIds();                 // Initialize the method ID map
+               rmiServer = new IoTSocketServer(_port);
+               rmiServer.connect();
+       }
+
+
+       /**
+        * getName() gets class name
+        */
+       public String getName() {
+
+               return cls.getName();
+       }
+
+
+       /**
+        * getSignatures() gets method signatures
+        */
+       public Set<String> getSignatures() {
+
+               return mapSign2Method.keySet();
+       }
+
+       
+       /**
+        * getMethodParamTypes() gets method parameter types
+        */
+       public Class<?>[] getMethodParamTypes(String signature) {
+
+               Method method = mapSign2Method.get(signature);
+               return method.getParameterTypes();
+       }
+
+
+       /**
+        * getMethodRetType() gets method return type
+        */
+       public Class<?> getMethodRetType(String signature) {
+
+               Method method = mapSign2Method.get(signature);
+               return method.getReturnType();
+       }
+       
+
+       /**
+        * invokeMethod() invokes a method based on signature and params
+        */
+       public Object invokeMethod(String signature, Object[] params) {
+
+               Method method = mapSign2Method.get(signature);
+               Object retVal = null;
+               try {
+                       retVal = method.invoke(obj, params);
+               } catch (IllegalAccessException |
+                                InvocationTargetException ex) {
+                       ex.printStackTrace();
+                       throw new Error("IoTRMICall: Error invoking method: " + signature);
+               }
+
+               return retVal;
+       }
+
+
+       /**
+        * recvAndInvoke() waits for method transmission and invoke the method
+        */
+       private void recvAndInvoke() throws IOException {
+
+               // Receive method info and invoke
+               byte[] method = null;
+               method = rmiServer.receiveBytes(method);
+               Object retObj = invokeMethod(method);
+               // Send back return value
+               byte[] retObjBytes = IoTRMIUtil.getObjectBytes(retObj);
+               rmiServer.sendBytes(retObjBytes);
+       }
+       
+
+       /**
+        * invokeMethod() invokes a method based on byte array received
+        * <p>
+        * Basically this is the format of a method in bytes:
+        * 1) 32-bit value of method ID (hash code)
+        * 2) m parameters with n-bit value each (m x n-bit)
+        * For the parameters that don't have definite length,
+        * we need to extract the length from a preceding 32-bit
+        * field in front of it.
+        *
+        * For primitive objects:
+        * | 32-bit method ID | m-bit actual data (fixed length)  |
+        * 
+        * For string, arrays, and non-primitive objects:
+        * | 32-bit method ID | 32-bit length | n-bit actual data | ...
+        * 
+        */
+       public Object invokeMethod(byte[] methodBytes) {
+
+               // Byte scanning position
+               int pos = 0;
+               // Get method ID
+               byte[] methodIdBytes = new byte[IoTRMIUtil.METHOD_ID_LEN];
+               System.arraycopy(methodBytes, pos, methodIdBytes, 0, IoTRMIUtil.METHOD_ID_LEN);
+               pos = pos + IoTRMIUtil.METHOD_ID_LEN;
+               // Get Method object to handle method
+               int methodId = IoTRMIUtil.byteArrayToInt(methodIdBytes);
+               String signature = mapHash2Sign.get(methodId);
+               Method method = mapSign2Method.get(signature);
+               // Get class name and then param length
+               Class<?>[] arrCls = method.getParameterTypes();
+               Object[] paramObj = new Object[arrCls.length];
+               for (int i=0; i < arrCls.length; i++) {
+
+                       String paramType = arrCls[i].getSimpleName();
+                       int paramSize = rmiUtil.getTypeSize(paramType);
+                       // Get the 32-bit field in the byte array to get the actual
+                       //              length (this is a param with indefinite length)
+                       if (paramSize == -1) {
+                               byte[] bytPrmLen = new byte[IoTRMIUtil.PARAM_LEN];
+                               System.arraycopy(methodBytes, pos, bytPrmLen, 0, IoTRMIUtil.PARAM_LEN);
+                               pos = pos + IoTRMIUtil.PARAM_LEN;
+                               paramSize = IoTRMIUtil.byteArrayToInt(bytPrmLen);
+                       }
+                       byte[] paramBytes = new byte[paramSize];
+                       System.arraycopy(methodBytes, pos, paramBytes, 0, paramSize);
+                       pos = pos + paramSize;
+                       paramObj[i] = IoTRMIUtil.getParamObject(paramType, paramBytes);
+               }
+               Object retObj = null;
+               try {
+                       retObj = method.invoke(obj, paramObj);
+               } catch (IllegalAccessException |
+                                InvocationTargetException ex) {
+                       ex.printStackTrace();
+                       throw new Error("IoTRMICall: Error invoking method: " + signature);
+               }
+
+               return retObj;
+       }
+
+
+       /**================
+        * Helper methods
+        **================
+        */
+       /**
+        * getMethodSignatures() gets methods signatures and store them in the Map
+        */
+       private void getMethodSignatures() {
+
+               for (Method m : methods) {
+                       String sign = rmiUtil.getSignature(m);
+                       //System.out.println("Signature: " + sign);
+                       mapSign2Method.put(sign, m);
+               }
+       }
+       
+       
+       /**
+        * getMethodIds() gets methods identifiers (hash code) and store them in the Map
+        */
+       private void getMethodIds() {
+
+               Set<String> setSignatures = getSignatures();
+               for (String sign : setSignatures) {
+                       byte[] hashCode = IoTRMIUtil.getHashCodeBytes(sign);
+                       int methodId = IoTRMIUtil.byteArrayToInt(hashCode);
+                       mapHash2Sign.put(methodId, sign);
+               }
+       }
+
+
+       public static void main(String[] args) throws Exception {
+
+               int port = 5010;
+               IoTRMIObject rmiObj = new IoTRMIObject("TestClass", port);
+               rmiObj.recvAndInvoke();
+       }
+}
diff --git a/iotjava/iotrmi/Java/IoTRMIUtil.java b/iotjava/iotrmi/Java/IoTRMIUtil.java
new file mode 100644 (file)
index 0000000..df76959
--- /dev/null
@@ -0,0 +1,465 @@
+package iotrmi.Java;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.lang.reflect.Method;
+
+import iotrmi.IoTRMITypes;
+
+/** Class IoTRMI provides utility services.
+ *  <p>
+ *  It provides miscellaneous (data type/value) translations.
+ *
+ * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
+ * @version     1.0
+ * @since       2016-10-04
+ */
+public class IoTRMIUtil {
+
+       /**
+        * Class Properties
+        */
+       private Map<String,String> mapPrimitives;
+       private Map<String,Integer> mapPrimitiveSizesJava;
+       private Map<String,Integer> mapPrimitiveSizesCplus;
+       private Map<String,String> mapNonPrimitives;
+
+       /**
+        * Class Constants
+        */
+       public final static int METHOD_ID_LEN = 4;      // 4 bytes = 32 bits
+       public final static int PARAM_LEN = 4;          // 4 bytes = 32 bits (4-byte field that stores the length of the param)
+
+       /**
+        * Constructors
+        */
+       public IoTRMIUtil() {
+
+               mapPrimitives = new HashMap<String,String>();
+                       IoTRMITypes.arraysToMap(mapPrimitives, 
+                               IoTRMITypes.primitivesJava, IoTRMITypes.primitivesCplus);
+               mapPrimitiveSizesJava = new HashMap<String,Integer>();
+                       IoTRMITypes.arraysToMap(mapPrimitiveSizesJava, 
+                               IoTRMITypes.primitivesJava, IoTRMITypes.primitivesJavaSizes);
+               mapPrimitiveSizesCplus = new HashMap<String,Integer>();
+                       IoTRMITypes.arraysToMap(mapPrimitiveSizesCplus, 
+                               IoTRMITypes.primitivesCplus, IoTRMITypes.primitivesCplusSizes);
+               mapNonPrimitives = new HashMap<String,String>();
+                       IoTRMITypes.arraysToMap(mapNonPrimitives, 
+                               IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitivesCplus);
+       }
+
+
+       /**
+        * getSignature() gets method signature, i.e. type, identifier, parameters
+        */
+       public String getSignature(Method m) {
+
+               String retType = translateType(m.getReturnType().getSimpleName());
+               String signature = retType + 
+                       m.getName() + "(";
+               Class<?>[] clsParam = m.getParameterTypes();
+               for (int i = 0; i < clsParam.length; i++) {
+                       String paramType = translateType(clsParam[i].getSimpleName());
+                       signature = signature + paramType;
+                       if (i < clsParam.length - 1) {
+                               signature = signature + ",";
+                       }
+               }
+               signature = signature + ")";
+               return signature;
+       }
+
+
+       /**
+        * getHashCodeBytes() gets hash value (in bytes) from method name
+        */
+       public static byte[] getHashCodeBytes(String string) {
+
+               int hash = string.hashCode();
+               byte[] hashBytes = ByteBuffer.allocate(4).putInt(hash).array();
+               return hashBytes;
+       }
+
+
+       /**================
+        * Helper methods
+        **================
+        */
+       /**
+        * translateType() try to translate a type
+        * <p>
+        * It returns the original type when fails.
+        */
+       public String translateType(String type) {
+
+               if (mapPrimitives.containsKey(type))
+                       return mapPrimitives.get(type);
+               else if (mapNonPrimitives.containsKey(type))
+                       return mapNonPrimitives.get(type);
+               else
+                       return type;
+       }
+
+
+       /**
+        * getTypeSize() gets the size of a type
+        *
+        */
+       public int getTypeSize(String type) {
+
+               if (mapPrimitiveSizesJava.containsKey(type))
+                       return mapPrimitiveSizesJava.get(type);
+               else if (mapPrimitiveSizesCplus.containsKey(type))
+                       return mapPrimitiveSizesCplus.get(type);
+               else
+                       return -1; // Size is unknown
+       }
+       
+       
+       /**
+        * getParamObject() converts byte array of certain object type into Object
+        */
+       public static Object getParamObject(String type, byte[] paramBytes) {
+               
+               Object retObj = null;
+               if (type.equals("byte") ||
+                       type.equals("Byte")) {
+                       retObj = (Object) paramBytes[0];
+               } else if (     type.equals("short") ||
+                                       type.equals("Short")) {
+                       retObj = (Object) byteArrayToShort(paramBytes);
+               } else if (     type.equals("int") ||
+                                       type.equals("Integer")) {
+                       retObj = (Object) byteArrayToInt(paramBytes);
+               } else if (     type.equals("long") ||
+                                       type.equals("Long")) {
+                       retObj = (Object) byteArrayToLong(paramBytes);
+               } else if (     type.equals("float") ||
+                                       type.equals("Float")) {
+                       retObj = (Object) byteArrayToFloat(paramBytes);
+               } else if (     type.equals("double") ||
+                                       type.equals("Double")) {
+                       retObj = (Object) byteArrayToDouble(paramBytes);
+               } else if (     type.equals("boolean") ||
+                                       type.equals("Boolean")) {
+                       retObj = (Object) byteArrayToBoolean(paramBytes);
+               } else if (     type.equals("char") ||
+                                       type.equals("Character")) {
+                       retObj = (Object) byteArrayToChar(paramBytes);
+               } else if (type.equals("String")) {
+                       retObj = (Object) toString(paramBytes);
+               } else
+                       throw new Error("IoTRMIUtil: Unrecognizable type: " + type);
+               
+               return retObj;
+       }
+
+
+       /**
+        * getObjectBytes() converts an object into byte array
+        */
+       public static byte[] getObjectBytes(Object obj) {
+               
+               byte[] retObjBytes = null;
+               if (obj instanceof Byte) {
+                       retObjBytes = (byte[]) obj;
+               } else if (obj instanceof Short) {
+                       retObjBytes = shortToByteArray((short) obj);
+               } else if (obj instanceof Integer) {
+                       retObjBytes = intToByteArray((int) obj);
+               } else if (obj instanceof Long) {
+                       retObjBytes = longToByteArray((long) obj);
+               } else if (obj instanceof Float) {
+                       retObjBytes = floatToByteArray((float) obj);
+               } else if (obj instanceof Double) {
+                       retObjBytes = doubleToByteArray((double) obj);
+               } else if (obj instanceof Character) {
+                       retObjBytes = charToByteArray((char) obj);
+               } else if (obj instanceof Boolean) {
+                       retObjBytes = booleanToByteArray((boolean) obj);
+               } else if (obj instanceof String) {
+                       retObjBytes = ((String) obj).getBytes();
+               } else
+                       throw new Error("IoTRMIUtil: Unrecognizable object: " + obj);
+
+               return retObjBytes;
+       }
+       
+
+       /**
+        * Converters to byte array
+        */
+       // Single variables
+       public static byte[] shortToByteArray(short s) {
+
+               ByteBuffer bb = ByteBuffer.allocate(2);
+               bb.putShort(s);
+
+               return bb.array();
+       }
+
+
+       public static byte[] intToByteArray(int i) {
+
+               ByteBuffer bb = ByteBuffer.allocate(4);
+               bb.putInt(i);
+
+               return bb.array();
+       }
+
+
+       public static byte[] longToByteArray(long l) {
+
+               ByteBuffer bb = ByteBuffer.allocate(8);
+               bb.putLong(l);
+
+               return bb.array();
+       }
+
+
+       public static byte[] floatToByteArray(float f) {
+
+               ByteBuffer bb = ByteBuffer.allocate(4);
+               bb.putFloat(f);
+
+               return bb.array();
+       }
+
+
+       public static byte[] doubleToByteArray(double d) {
+
+               ByteBuffer bb = ByteBuffer.allocate(8);
+               bb.putDouble(d);
+
+               return bb.array();
+       }
+
+
+       public static byte[] charToByteArray(char c) {
+
+               ByteBuffer bb = ByteBuffer.allocate(2);
+               bb.putChar(c);
+
+               return bb.array();
+       }
+
+
+       public static byte[] booleanToByteArray(boolean b) {
+
+               ByteBuffer bb = ByteBuffer.allocate(1);
+               if (b)
+                       bb.put((byte)1);
+               else
+                       bb.put((byte)0);
+
+               return bb.array();
+       }
+
+
+       // Arrays
+       public static byte[] arrShortToByteArray(short[] arrShort) {
+
+               ByteBuffer bb = ByteBuffer.allocate(2 * arrShort.length);
+               for(short s : arrShort) {
+                       bb.putShort(s);
+               }
+
+               return bb.array();
+       }
+
+
+       public static byte[] arrIntToByteArray(int[] arrInt) {
+
+               ByteBuffer bb = ByteBuffer.allocate(4 * arrInt.length);
+               for(int i : arrInt) {
+                       bb.putInt(i);
+               }
+
+               return bb.array();
+       }
+
+
+       public static byte[] arrLongToByteArray(long[] arrLong) {
+
+               ByteBuffer bb = ByteBuffer.allocate(8 * arrLong.length);
+               for(long l : arrLong) {
+                       bb.putLong(l);
+               }
+
+               return bb.array();
+       }
+
+
+       public static byte[] arrFloatToByteArray(float[] arrFloat) {
+
+               ByteBuffer bb = ByteBuffer.allocate(4 * arrFloat.length);
+               for(float f : arrFloat) {
+                       bb.putFloat(f);
+               }
+
+               return bb.array();
+       }
+
+
+       public static byte[] arrDoubleToByteArray(double[] arrDouble) {
+
+               ByteBuffer bb = ByteBuffer.allocate(8 * arrDouble.length);
+               for(double d : arrDouble) {
+                       bb.putDouble(d);
+               }
+
+               return bb.array();
+       }
+
+
+       public static byte[] arrCharToByteArray(char[] arrChar) {
+
+               ByteBuffer bb = ByteBuffer.allocate(2 * arrChar.length);
+               for(char c : arrChar) {
+                       bb.putChar(c);
+               }
+
+               return bb.array();
+       }
+
+
+       public static byte[] arrBooleanToByteArray(boolean[] arrBool) {
+
+               ByteBuffer bb = ByteBuffer.allocate(1 * arrBool.length);
+               for(boolean b : arrBool) {
+                       if (b)
+                               bb.put((byte)1);
+                       else
+                               bb.put((byte)0);
+               }
+
+               return bb.array();
+       }
+
+
+       /**
+        * Converters from byte array
+        */
+       // Single variables
+       public static short byteArrayToShort(byte[] bytes) {
+
+               return ByteBuffer.wrap(bytes).getShort();
+       }
+
+
+       public static int byteArrayToInt(byte[] bytes) {
+
+               return ByteBuffer.wrap(bytes).getInt();
+       }
+
+
+       public static long byteArrayToLong(byte[] bytes) {
+
+               return ByteBuffer.wrap(bytes).getLong();
+       }
+
+
+       public static float byteArrayToFloat(byte[] bytes) {
+
+               return ByteBuffer.wrap(bytes).getFloat();
+       }
+
+
+       public static double byteArrayToDouble(byte[] bytes) {
+
+               return ByteBuffer.wrap(bytes).getDouble();
+       }
+
+
+       public static char byteArrayToChar(byte[] bytes) {
+
+               return ByteBuffer.wrap(bytes).getChar();
+       }
+
+
+       public static boolean byteArrayToBoolean(byte[] bytes) {
+
+               Byte boolValByte = ByteBuffer.wrap(bytes).get();
+               short boolVal = boolValByte.shortValue();
+               if (boolVal == 1)
+                       return true;
+               else
+                       return false;
+       }
+
+
+    public static String toString(byte[] bytes) {
+        return new String(bytes);
+    }
+
+
+       /**
+        * toByteArray() gets Object and return its byte array
+        * <p>
+        * Adapted from http://www.java2s.com/
+        *              @see <a href="http://www.java2s.com/Code/Java/File-Input-
+        *              Output/Convertobjecttobytearrayandconvertbytearraytoobject.htm"</a>
+        */
+    // toByteArray and toObject are taken from: http://tinyurl.com/69h8l7x
+    public static byte[] toByteArray(Object obj) throws IOException {
+
+        byte[] bytes = null;
+        ByteArrayOutputStream bos = null;
+        ObjectOutputStream oos = null;
+        try {
+
+            bos = new ByteArrayOutputStream();
+            oos = new ObjectOutputStream(bos);
+            oos.writeObject(obj);
+            oos.flush();
+            bytes = bos.toByteArray();
+        } finally {
+
+            if (oos != null) {
+                oos.close();
+            }
+            if (bos != null) {
+                bos.close();
+            }
+        }
+        return bytes;
+    }
+
+
+       /**
+        * toObject() gets byte array and return its Object
+        * <p>
+        * Adapted from http://www.java2s.com/
+        *              @see <a href="http://www.java2s.com/Code/Java/File-Input-
+        *              Output/Convertobjecttobytearrayandconvertbytearraytoobject.htm"</a>
+        */
+    public static Object toObject(byte[] bytes) throws IOException, ClassNotFoundException {
+
+        Object obj = null;
+        ByteArrayInputStream bis = null;
+        ObjectInputStream ois = null;
+        try {
+
+            bis = new ByteArrayInputStream(bytes);
+            ois = new ObjectInputStream(bis);
+            obj = ois.readObject();
+        } finally {
+
+            if (bis != null) {
+                bis.close();
+            }
+            if (ois != null) {
+                ois.close();
+            }
+        }
+        return obj;
+    }
+}
diff --git a/iotjava/iotrmi/Java/IoTSocketClient.java b/iotjava/iotrmi/Java/IoTSocketClient.java
new file mode 100644 (file)
index 0000000..3d3e8b7
--- /dev/null
@@ -0,0 +1,133 @@
+package iotrmi.Java;
+
+// Java libraries
+import java.io.*;
+import java.net.*;
+import java.awt.*;
+import java.util.*;
+
+
+/** Class IoTSocketClient is a communication class
+ *  that provides interfaces to connect to either
+ *  Java or C++ socket endpoint
+ *  <p>
+ *  Adapted from Java/C++ socket implementation
+ *  by Keith Vertanen
+ *  @see        <a href="https://www.keithv.com/software/socket/</a>
+ *
+ * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
+ * @version     1.0
+ * @since       2016-08-17
+ */
+public class IoTSocketClient {
+
+       /**
+        * Class Properties
+        */
+       byte data[];
+       int port;
+       Socket sock;
+       BufferedInputStream input;
+       BufferedOutputStream output;
+
+       /**
+        * Class Constant
+        */
+       static int BUFFSIZE = 128000;   // how many bytes our incoming buffer can hold 
+
+       /**
+        * Default constructor
+        */
+       public IoTSocketClient(int _port, String _address, int rev) throws IOException
+       {
+               port = _port;
+               try {
+                       sock = new Socket( InetAddress.getByName(_address), port );
+                       input = new BufferedInputStream(sock.getInputStream(), BUFFSIZE);
+                       output = new BufferedOutputStream(sock.getOutputStream(),BUFFSIZE);
+               }
+               catch ( IOException e ) {
+                       e.printStackTrace();
+               }
+               data = new byte[BUFFSIZE];
+               // now we want to tell the server if we want reversed bytes or not
+               output.write(rev);
+               output.flush();
+       }
+
+
+       /**
+        * sendBytes() sends an array of bytes
+        */
+       public void sendBytes(byte vals[]) throws IOException
+       {
+               int len = vals.length;
+               output.write(len);
+               output.flush();
+               output.write(vals, 0, len);
+               output.flush();
+               receiveAck();
+               sendAck();
+       }
+
+
+       /**
+        * receiveBytes() receives an array of bytes
+        */
+       public byte[] receiveBytes(byte val[]) throws IOException
+       {
+               int i;
+               int totalbytes = 0;
+               int numbytes;
+               // Read the maxlen first
+               int maxlen = (int)input.read();
+               if (maxlen>BUFFSIZE)
+                       System.out.println("IoTSocketClient/Server: Sending more bytes then will fit in buffer!");
+               val = new byte[maxlen];
+               while (totalbytes < maxlen)
+               {
+                       numbytes = input.read(data);
+                       // copy the bytes into the result buffer
+                       for (i=totalbytes; i<totalbytes+numbytes; i++)
+                               val[i] = data[i-totalbytes];
+                       totalbytes += numbytes;
+               }
+               // we now send an acknowledgement to the server to let them
+               // know we've got it
+               sendAck();
+               receiveAck();
+
+               return val;
+       }
+
+
+       /**
+        * Close socket connection
+        */
+       public void close() throws IOException
+       {
+               sock.close();
+       }
+
+
+       /**
+        * Send ACK
+        */
+       private void sendAck() throws IOException
+       {
+               int ack;
+               ack = 0;
+               output.write(ack);
+               output.flush();
+       }
+
+
+       /**
+        * Receive ACK
+        */
+       private void receiveAck() throws IOException
+       {
+               int ack;
+               ack = (int) input.read();
+       }
+}
diff --git a/iotjava/iotrmi/Java/IoTSocketServer.java b/iotjava/iotrmi/Java/IoTSocketServer.java
new file mode 100644 (file)
index 0000000..480b2e6
--- /dev/null
@@ -0,0 +1,146 @@
+package iotrmi.Java;
+
+// Java libraries
+import java.io.*;
+import java.net.*;
+import java.awt.*;
+import java.util.*;
+
+
+/** Class IoTSocketServer is a communication class
+ *  that provides interfaces to connect to either
+ *  Java or C++ socket endpoint
+ *  <p>
+ *  Adapted from Java/C++ socket implementation
+ *  by Keith Vertanen
+ *  @see        <a href="https://www.keithv.com/software/socket/</a>
+ *
+ * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
+ * @version     1.0
+ * @since       2016-08-17
+ */
+public class IoTSocketServer {
+
+       /**
+        * Class Properties
+        */
+       byte data[];
+       int port;
+       ServerSocket server;
+       Socket sock;
+       BufferedInputStream input;
+       BufferedOutputStream output;
+
+       /**
+        * Class Constant
+        */
+       static int BUFFSIZE = 128000;   // how many bytes our incoming buffer can hold  
+
+       /**
+        * Constructors
+        */
+       public IoTSocketServer(int _port) throws IOException
+       {
+               port = _port;
+               try {
+                       server = new ServerSocket(port, 100);
+               }
+               catch ( IOException e ) {
+                       e.printStackTrace();
+               }
+               data = new byte[BUFFSIZE];
+    }
+
+
+       /**
+        * Establish connection
+        */
+       public void connect() throws IOException
+       {
+               byte rev[] = new byte[1];
+               rev[0] = 0;
+               sock = server.accept();
+               input = new BufferedInputStream(sock.getInputStream(), BUFFSIZE);
+               output = new BufferedOutputStream(sock.getOutputStream(),BUFFSIZE);
+               // now find out if we want reversed bytes
+               input.read(rev);
+       }
+
+
+       /**
+        * sendBytes() sends an array of bytes
+        */
+       public void sendBytes(byte vals[]) throws IOException
+       {
+               int len = vals.length;
+               output.write(len);
+               output.flush();
+               output.write(vals, 0, len);
+               output.flush();
+               receiveAck();
+               sendAck();
+       }
+
+
+       /**
+        * receiveBytes() receives an array of bytes
+        */
+       public byte[] receiveBytes(byte val[]) throws IOException
+       {
+               int i;
+               int totalbytes = 0;
+               int numbytes;
+
+               // Read the maxlen first
+               int maxlen = (int)input.read();
+               if (maxlen>BUFFSIZE)
+                       System.out.println("IoTSocketClient/Server: Sending more bytes then will fit in buffer!");
+               val = new byte[maxlen];
+               while (totalbytes < maxlen)
+               {
+                       numbytes = input.read(data);
+                       // copy the bytes into the result buffer
+                       for (i=totalbytes; i<totalbytes+numbytes; i++)
+                               val[i] = data[i-totalbytes];
+                       totalbytes += numbytes;
+               }
+               // we now send an acknowledgement to the server to let them
+               // know we've got it
+               sendAck();
+               receiveAck();
+
+               return val;
+       }
+
+
+       /**
+        * Close socket connection
+        */
+       public void close() throws IOException
+       {
+               sock.close();
+       }
+
+
+       /**
+        * Send ACK
+        */
+       private void sendAck() throws IOException
+       {
+               int ack;
+               ack = 0;
+               output.write(ack);
+               output.flush();
+       }
+
+
+       /**
+        * Receive ACK
+        */
+       private void receiveAck() throws IOException
+       {
+               int ack;
+               ack = (int) input.read();
+       }
+}
+