$(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
}
- /**================================================
- * Helper functions to write stub codes into files
- **================================================
+ /**================
+ * Helper functions
+ **================
*/
boolean newline=true;
int tablevel=0;
--- /dev/null
+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]);
+ }
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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();
+ }
+}
+