Porting and compiling SmartLightsController
[iot2.git] / iotjava / iotruntime / slave / IoTSlave.java
1 package iotruntime.slave;
2
3 import iotruntime.*;
4 import iotruntime.zigbee.*;
5 import iotruntime.messages.*;
6 import iotruntime.master.RuntimeOutput;
7
8 // Java packages
9 import java.io.File;
10 import java.io.FileInputStream;
11 import java.io.FileOutputStream;
12 import java.io.ObjectInputStream;
13 import java.io.ObjectOutputStream;
14 import java.io.InputStream;
15 import java.io.OutputStream;
16 import java.io.IOException;
17 import java.io.FileNotFoundException;
18 import java.lang.ClassNotFoundException;
19 import java.lang.Class;
20 import java.lang.reflect.*;
21 import java.lang.ClassLoader;
22 import java.net.InetAddress;
23 import java.net.Socket;
24 import java.net.UnknownHostException;
25 import java.net.URL;
26 import java.net.URLClassLoader;
27 import java.rmi.registry.LocateRegistry;
28 import java.rmi.registry.Registry;
29 import java.rmi.Remote;
30 import java.rmi.RemoteException;
31 import java.rmi.AlreadyBoundException;
32 import java.rmi.NotBoundException;
33 import java.rmi.server.UnicastRemoteObject;
34 import java.util.Properties;
35 import java.util.HashMap;
36 import java.util.Map;
37
38 // Zip/Unzip utility
39 import net.lingala.zip4j.exception.ZipException;
40 import net.lingala.zip4j.core.ZipFile;
41
42 /** Class IoTSlave is run by IoTMaster on a different JVM's.
43  *  It needs to respond to IoTMaster's commands
44  *
45  * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
46  * @version     1.0
47  * @since       2016-06-16
48  */
49 public class IoTSlave {
50
51         /**
52          * IoTSlave class properties
53          */
54         private Message sIoTMasterMsg;
55         private String sIoTMasterHostAdd;
56         private String sMainObjectName;
57         private int iComPort;
58         private int iRMIRegPort;
59         private int iRMIStubPort;
60         private String strFieldName;
61         private Class<?> clsMain;
62         private Object objMainCls;
63         private Object iRelFirstObject;
64         private Object iRelSecondObject;
65         private Socket socket;
66         private ObjectOutputStream outStream;
67         private ObjectInputStream inStream;
68
69         /**
70          * IoTSet object, e.g. IoTSet<ProximitySensor> proximity_sensors;
71          * IoTRelation object, e.g. IoTRelation<ProximitySensor, LightBulb> ps_lb_relation;
72          */
73         private ISet<Object> isetObject;
74         private IoTSet<Object> iotsetObject;
75         private IRelation<Object,Object> irelObject;
76         private IoTRelation<Object,Object> iotrelObject;
77
78         // Constants that are to be extracted from config file
79         private static String STR_JAR_FILE_PATH;
80         private static String STR_OBJ_CLS_PFX;
81         private static String STR_INTERFACE_PFX;
82         private static String SKEL_CLASS_SUFFIX;
83         private static String STUB_CLASS_SUFFIX;
84         private static boolean BOOL_VERBOSE;
85         private static boolean CAPAB_BASED_RMI;
86
87         /**
88          * IoTSlave class constants - not to be changed by users
89          */
90         private static final String STR_IOT_SLAVE_NAME = "IoTSlave";
91         private static final String STR_CFG_FILE_EXT = ".config";
92         private static final String STR_CLS_FILE_EXT = ".class";
93         private static final String STR_JAR_FILE_EXT = ".jar";
94         private static final String STR_ZIP_FILE_EXT = ".zip";
95         private static final String STR_UNZIP_DIR = "./";
96         private static final Class<?>[] STR_URL_PARAM = new Class[] {URL.class };
97         private static final String STR_YES = "Yes";
98         private static final String STR_NO = "No";
99
100         /**
101          * Class constructor
102          *
103          */
104         public IoTSlave(String[] argInp) {
105
106                 sIoTMasterMsg = null;
107                 sIoTMasterHostAdd = argInp[0];
108                 iComPort = Integer.parseInt(argInp[1]);
109                 iRMIRegPort = Integer.parseInt(argInp[2]);
110                 iRMIStubPort = Integer.parseInt(argInp[3]);
111                 sMainObjectName = null;
112                 strFieldName = null;
113                 clsMain = null;
114                 objMainCls = null;
115                 isetObject = null;
116                 iotsetObject = null;
117                 irelObject = null;
118                 iotrelObject = null;
119                 iRelFirstObject = null;
120                 iRelSecondObject = null;
121                 socket = null;
122                 outStream = null;
123                 inStream = null;
124
125                 STR_JAR_FILE_PATH = null;
126                 STR_OBJ_CLS_PFX = null;
127                 STR_INTERFACE_PFX = null;
128                 SKEL_CLASS_SUFFIX = null;
129                 STUB_CLASS_SUFFIX = null;
130                 BOOL_VERBOSE = false;
131                 CAPAB_BASED_RMI = false;
132         }
133
134         /**
135          * A method to initialize constants from config file
136          *
137          * @return void
138          */
139         private void parseIoTSlaveConfigFile() {
140                 // Parse configuration file
141                 Properties prop = new Properties();
142                 String strCfgFileName = STR_IOT_SLAVE_NAME + STR_CFG_FILE_EXT;
143                 File file = new File(strCfgFileName);
144                 try {
145                         FileInputStream fis = new FileInputStream(file);
146                         prop.load(fis);
147                 } catch (IOException ex) {
148                         System.out.println("IoTMaster: Error reading config file: " + strCfgFileName);
149                         ex.printStackTrace();
150                 }
151                 System.out.println("IoTMaster: Extracting information from config file: " + strCfgFileName);
152                 // Initialize constants from config file
153                 STR_JAR_FILE_PATH = prop.getProperty("JAR_FILE_PATH");
154                 STR_OBJ_CLS_PFX = prop.getProperty("OBJECT_CLASS_PREFIX");
155                 STR_INTERFACE_PFX = prop.getProperty("INTERFACE_PREFIX");
156                 SKEL_CLASS_SUFFIX = prop.getProperty("SKEL_CLASS_SUFFIX");
157                 STUB_CLASS_SUFFIX = prop.getProperty("STUB_CLASS_SUFFIX");
158                 if (prop.getProperty("VERBOSE").equals(STR_YES)) {
159                         BOOL_VERBOSE = true;
160                 }
161                 if (prop.getProperty("CAPAB_BASED_RMI").equals(STR_YES)) {
162                         CAPAB_BASED_RMI = true;
163                 }
164
165                 System.out.println("JAR_FILE_PATH=" + STR_JAR_FILE_PATH);
166                 System.out.println("OBJECT_CLASS_PREFIX=" + STR_OBJ_CLS_PFX);
167                 System.out.println("INTERFACE_PREFIX=" + STR_INTERFACE_PFX);
168                 System.out.println("SKEL_CLASS_SUFFIX=" + SKEL_CLASS_SUFFIX);
169                 System.out.println("STUB_CLASS_SUFFIX=" + STUB_CLASS_SUFFIX);
170                 System.out.println("CAPAB_BASED_RMI=" + CAPAB_BASED_RMI);
171                 System.out.println("IoTMaster: Information extracted successfully!");
172         }
173
174         /**
175          * Adds the content pointed by the URL to the classpath dynamically at runtime (hack!!!)
176          *
177          * @param  url         the URL pointing to the content to be added
178          * @throws IOException
179          * @see    <a href="http://stackoverflow.com/questions/60764/how-should-i-load-jars-dynamically-at-runtime</a>
180          */
181         private static void addURL(URL url) throws IOException {
182
183                 URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
184                 Class<?> sysclass = URLClassLoader.class;
185
186                 try {
187
188                         Method method = sysclass.getDeclaredMethod("addURL", STR_URL_PARAM);
189                         method.setAccessible(true);
190                         method.invoke(sysloader,new Object[] { url });
191
192                 } catch (Throwable t) {
193
194                         t.printStackTrace();
195                         throw new IOException("IoTSlave: Could not add URL to system classloader!");
196                 }
197         }
198
199         /**
200          * A private method to create object
201          *
202          * @return  void
203          */
204         private void createCapabBasedRMIJava(MessageCreateObject sMessage) throws 
205                 ClassNotFoundException, NoSuchMethodException {
206
207                 // Instantiate the skeleton and put in the object
208                 String strObjSkelName = STR_OBJ_CLS_PFX + "." + sMessage.getObjectClass() +
209                                                                         "." + sMessage.getObjectInterfaceName() + SKEL_CLASS_SUFFIX;
210                 RuntimeOutput.print("IoTSlave: Skeleton object: " + strObjSkelName, BOOL_VERBOSE);
211                 Class<?> clsSkel = Class.forName(strObjSkelName);
212                 Class<?> clsInt = Class.forName(STR_OBJ_CLS_PFX + "." + STR_INTERFACE_PFX + 
213                         "." + sMessage.getObjectInterfaceName());
214                 Class[] clsSkelParams = { clsInt, String.class, int.class };    // Port number is integer
215                 Constructor<?> objSkelCons = clsSkel.getDeclaredConstructor(clsSkelParams);
216                 String callbackAddress = InetAddress.getLocalHost().getHostAddress();   // Callback address is this machine's address
217                 Object objSkelParams[] = { objMainCls, callbackAddress, iRMIStubPort };
218                 // Create a new thread for each skeleton
219                 Thread objectThread = new Thread(new Runnable() {
220                         public void run() {
221                                 try {
222                                         Object objSkel = objSkelCons.newInstance(objSkelParams);
223                                 } catch (InstantiationException |
224                                                  IllegalAccessException |
225                                                  InvocationTargetException ex) {
226                                         ex.printStackTrace();
227                                 }
228                         }
229                 });
230                 objectThread.start();
231                 RuntimeOutput.print("IoTSlave: Done generating object!", BOOL_VERBOSE);
232         }
233
234         /**
235          * A private method to create object
236          *
237          * @return  void
238          */
239         private void createObject() throws IOException,
240                 ClassNotFoundException, NoSuchMethodException, InstantiationException,
241                         RemoteException, AlreadyBoundException, IllegalAccessException,
242                                 InvocationTargetException {
243
244                 // Translating into the actual Message class
245                 MessageCreateObject sMessage = (MessageCreateObject) sIoTMasterMsg;
246                 // Instantiate object using reflection
247                 String strObjClassName = STR_OBJ_CLS_PFX + "." + sMessage.getObjectClass() +
248                                                                                                                  "." + sMessage.getObjectClass();
249                 File file = new File(STR_JAR_FILE_PATH + sMessage.getObjectClass() + STR_JAR_FILE_EXT);
250                 RuntimeOutput.print("IoTSlave: DEBUG print path: " + STR_JAR_FILE_PATH +
251                                                                                          sMessage.getObjectClass() + STR_JAR_FILE_EXT, BOOL_VERBOSE);
252                 addURL(file.toURI().toURL());
253                 clsMain = Class.forName(strObjClassName);
254                 Class[] clsParams = sMessage.getObjectFldCls();
255                 Constructor<?> ct = clsMain.getDeclaredConstructor(clsParams);
256                 Object objParams[] = sMessage.getObjectFields();
257                 objMainCls = ct.newInstance(objParams);
258                 RuntimeOutput.print("IoTSlave: Creating RMI skeleton: " +
259                         sMessage.getHostAddress() + ":" + sMessage.getRMIRegPort() +
260                         " with RMI stub port: " + iRMIStubPort, BOOL_VERBOSE);
261                 if (CAPAB_BASED_RMI) {
262                 // Use the new capability-based RMI in Java
263                         createCapabBasedRMIJava(sMessage);
264                 } else {
265                         // Register object to RMI - there are 2 ports: RMI registry port and RMI stub port
266                         Object objStub = (Object)
267                                 UnicastRemoteObject.exportObject((Remote) objMainCls, iRMIStubPort);
268                         Registry registry = LocateRegistry.createRegistry(iRMIRegPort);
269                         registry.bind(sMessage.getObjectName(), (Remote) objStub);
270                 }
271                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
272                 RuntimeOutput.print("IoTSlave: Registering object via RMI!", BOOL_VERBOSE);
273
274         }
275
276         
277         /**
278          * A private method to transfer file
279          *
280          * @return  void
281          */
282         private void transferFile() throws IOException,
283                 UnknownHostException, FileNotFoundException {
284
285                 // Translating into the actual Message class
286                 MessageSendFile sMessage = (MessageSendFile) sIoTMasterMsg;
287
288                 // Send back the received message as acknowledgement
289                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
290
291                 // Write file to the current location
292                 Socket filesocket = new Socket(sIoTMasterHostAdd, iComPort);
293                 InputStream inFileStream = filesocket.getInputStream();
294                 OutputStream outFileStream = new FileOutputStream(sMessage.getFileName());
295                 byte[] bytFile = new byte[Math.toIntExact(sMessage.getFileSize())];
296
297                 int iCount = 0;
298                 while ((iCount = inFileStream.read(bytFile)) > 0) {
299                         outFileStream.write(bytFile, 0, iCount);
300                 }
301                 // Unzip if this is a zipped file
302                 if (sMessage.getFileName().contains(STR_ZIP_FILE_EXT)) {
303                         RuntimeOutput.print("IoTSlave: Unzipping file: " + sMessage.getFileName(), BOOL_VERBOSE);
304                         try {
305                                 ZipFile zipFile = new ZipFile(sMessage.getFileName());
306                                 zipFile.extractAll(STR_UNZIP_DIR);
307                         } catch (ZipException ex) {
308                                 System.out.println("IoTSlave: Error in unzipping file!");
309                                 ex.printStackTrace();
310                         }
311                 }
312                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
313                 RuntimeOutput.print("IoTSlave: Receiving file transfer!", BOOL_VERBOSE);
314         }
315
316         /**
317          * A private method to create a main object
318          *
319          * @return  void
320          */
321         private void createMainObject() throws IOException,
322                 ClassNotFoundException, InstantiationException, IllegalAccessException,
323                         InvocationTargetException {
324
325                 // Translating into the actual Message class
326                 MessageCreateMainObject sMessage = (MessageCreateMainObject) sIoTMasterMsg;
327
328                 // Getting controller class
329                 File file = new File(STR_JAR_FILE_PATH + sMessage.getObjectName() + STR_JAR_FILE_EXT);
330                 RuntimeOutput.print("IoTSlave: DEBUG print path: " + STR_JAR_FILE_PATH +
331                                                                                          sMessage.getObjectName() + STR_JAR_FILE_EXT, BOOL_VERBOSE);
332                 addURL(file.toURI().toURL());
333                 // We will always have a package name <object name>.<object name>
334                 // e.g. SmartLightsController.SmartLightsController
335                 sMainObjectName = sMessage.getObjectName();
336                 clsMain = Class.forName(sMainObjectName + "." + sMainObjectName);
337                 objMainCls = clsMain.newInstance();
338
339                 // Send back the received message as acknowledgement
340                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
341                 RuntimeOutput.print("IoTSlave: Instantiating main controller/device class "
342                                                                                          + sMessage.getObjectName(), BOOL_VERBOSE);
343
344         }
345
346         /**
347          * A private method to create a new IoTSet
348          *
349          * @return  void
350          */
351         private void createNewIoTSet() throws IOException {
352
353                 // Translating into the actual Message class
354                 MessageCreateSetRelation sMessage = (MessageCreateSetRelation) sIoTMasterMsg;
355
356                 // Initialize field name
357                 strFieldName = sMessage.getObjectFieldName();
358                 RuntimeOutput.print("IoTSlave: Setting up field " + strFieldName, BOOL_VERBOSE);
359
360                 // Creating a new IoTSet object
361                 isetObject = new ISet<Object>();
362
363                 // Send back the received message as acknowledgement
364                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
365                 RuntimeOutput.print("IoTSlave: Creating a new IoTSet object!", BOOL_VERBOSE);
366
367         }
368
369         /**
370          * A private method to create a new IoTRelation
371          *
372          * @return  void
373          */
374         private void createNewIoTRelation() throws IOException {
375
376                 // Translating into the actual Message class
377                 MessageCreateSetRelation sMessage = (MessageCreateSetRelation) sIoTMasterMsg;
378
379                 // Initialize field name
380                 strFieldName = sMessage.getObjectFieldName();
381                 RuntimeOutput.print("IoTSlave: Setting up field " + strFieldName, BOOL_VERBOSE);
382
383                 // Creating a new IoTRelation object
384                 irelObject = new IRelation<Object,Object>();
385
386                 // Send back the received message as acknowledgement
387                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
388                 RuntimeOutput.print("IoTSlave: Creating a new IoTRelation object!", BOOL_VERBOSE);
389
390         }
391
392         /**
393          * A private method to get an object from the registry
394          *
395          * @return  Object
396          */
397         private Object getObjectFromRegistry() throws RemoteException,
398                         ClassNotFoundException, NotBoundException {
399
400                 // Translating into the actual Message class
401                 MessageGetObject sMessage = (MessageGetObject) sIoTMasterMsg;
402
403                 // Locate RMI registry and add object into IoTSet
404                 Registry registry =
405                         LocateRegistry.getRegistry(sMessage.getHostAddress(), sMessage.getRMIRegPort());
406                 RuntimeOutput.print("IoTSlave: Looking for RMI registry: " +
407                         sMessage.getHostAddress() + ":" + sMessage.getRMIRegPort() +
408                         " with RMI stub port: " + sMessage.getRMIStubPort(), BOOL_VERBOSE);
409                 Object stubObj = registry.lookup(sMessage.getObjectName());
410                 RuntimeOutput.print("IoTSlave: Looking for object name: " + sMessage.getObjectName(), BOOL_VERBOSE);
411
412                 // Class conversion to interface class of this class,
413                 // e.g. ProximitySensorImpl has ProximitySensor interface
414                 String strObjClassInterfaceName = STR_OBJ_CLS_PFX + "." + STR_INTERFACE_PFX + "." +
415                         sMessage.getObjectInterfaceName();
416                 Class<?> clsInf = Class.forName(strObjClassInterfaceName);
417                 Object stubObjConv = clsInf.cast(stubObj);
418
419                 return stubObjConv;
420         }
421
422         /**
423          * A private method to get an object and create a stub
424          * <p>
425          * This is using the capability-based RMI skeleton and stub scheme
426          *
427          * @return  Object
428          */
429         private Object getObjectFromStub() throws RemoteException,
430                         ClassNotFoundException, NoSuchMethodException, InstantiationException, 
431                         IllegalAccessException, NotBoundException, InvocationTargetException, UnknownHostException {
432
433                 // Translating into the actual Message class
434                 MessageGetObject sMessage = (MessageGetObject) sIoTMasterMsg;
435                 // Instantiate the stub and put in the object
436                 String strObjStubName = sMainObjectName + "." + sMessage.getObjectStubInterfaceName() + STUB_CLASS_SUFFIX;
437                 RuntimeOutput.print("IoTSlave: Stub object: " + strObjStubName, BOOL_VERBOSE);
438                 Class<?> clsStub = Class.forName(strObjStubName);       // Port number is integer
439                 Class[] clsStubParams = { int.class, String.class, String.class, int.class, int[].class };
440                 Constructor<?> objStubCons = clsStub.getDeclaredConstructor(clsStubParams);
441                 int[] ports = { sMessage.getRMIRegPort() };             // TODO: Change this temporary use of reg port for callbacks
442                 int rev = 0;
443                 String callbackAddress = InetAddress.getLocalHost().getHostAddress();   // Callback address is this machine's address
444                 Object objStubParams[] = { sMessage.getRMIStubPort(), sMessage.getHostAddress(), callbackAddress,
445                                                                         rev, ports };
446                 RuntimeOutput.print("IoTSlave: Creating RMI stub: " +
447                         sMessage.getHostAddress() + ":" + sMessage.getRMIRegPort() +
448                         " with callback address: " + callbackAddress + " and RMI stub port: " + sMessage.getRMIStubPort(), BOOL_VERBOSE);
449                 Object stubObj = objStubCons.newInstance(objStubParams);
450                 RuntimeOutput.print("IoTSlave: Object name: " + sMessage.getObjectName(), BOOL_VERBOSE);
451                 RuntimeOutput.print("IoTSlave: Stub address: " + callbackAddress, BOOL_VERBOSE);
452                 // Class conversion to interface class of this class,
453                 // e.g. ProximitySensorImpl has ProximitySensor interface
454                 String strObjClassInterfaceName = STR_OBJ_CLS_PFX + "." + STR_INTERFACE_PFX + "." +
455                         sMessage.getObjectStubInterfaceName();
456                 Class<?> clsInf = Class.forName(strObjClassInterfaceName);
457                 Object stubObjConv = clsInf.cast(stubObj);
458
459                 return stubObjConv;
460         }
461
462         /**
463          * A private method to get an IoTSet object
464          *
465          * @return  void
466          */
467         private void getIoTSetObject() throws IOException,
468                 ClassNotFoundException, RemoteException, NotBoundException, NoSuchMethodException,
469                 InstantiationException, IllegalAccessException, InvocationTargetException {
470
471                 Object objRegistry = null;
472                 if (CAPAB_BASED_RMI)
473                         objRegistry = getObjectFromStub();
474                 else
475                         objRegistry = getObjectFromRegistry();
476                 isetObject.add(objRegistry);
477                 RuntimeOutput.print("IoTSlave: This IoTSet now has: " + isetObject.size() + " entry(s)", BOOL_VERBOSE);
478
479                 // Send back the received message as acknowledgement
480                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
481                 RuntimeOutput.print("IoTSlave: Getting an object for IoTSet!", BOOL_VERBOSE);
482         }
483
484         /**
485          * A private method to get an IoTRelation first object
486          *
487          * @return  void
488          */
489         private void getIoTRelationFirstObject() throws IOException,
490                 ClassNotFoundException, RemoteException, NotBoundException, NoSuchMethodException,
491                 InstantiationException, IllegalAccessException, InvocationTargetException {
492
493                 Object objRegistry = null;
494                 if (CAPAB_BASED_RMI)
495                         objRegistry = getObjectFromStub();
496                 else
497                         objRegistry = getObjectFromRegistry();
498                 iRelFirstObject = objRegistry;
499
500                 // Send back the received message as acknowledgement
501                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
502                 RuntimeOutput.print("IoTSlave: Getting a first object for IoTRelation!", BOOL_VERBOSE);
503
504         }
505
506         /**
507          * A private method to get an IoTRelation second object
508          *
509          * @return  void
510          */
511         private void getIoTRelationSecondObject() throws IOException,
512                 ClassNotFoundException, RemoteException, NotBoundException, NoSuchMethodException,
513                 InstantiationException, IllegalAccessException, InvocationTargetException {
514
515                 Object objRegistry = null;
516                 if (CAPAB_BASED_RMI)
517                         objRegistry = getObjectFromStub();
518                 else
519                         objRegistry = getObjectFromRegistry();
520                 iRelSecondObject = objRegistry;
521
522                 // Now add the first and the second object into IoTRelation
523                 irelObject.put(iRelFirstObject, iRelSecondObject);
524                 RuntimeOutput.print("IoTSlave: This IoTRelation now has: " + irelObject.size() + " entry(s)", BOOL_VERBOSE);
525
526                 // Send back the received message as acknowledgement
527                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
528                 RuntimeOutput.print("IoTSlave: Getting a second object for IoTRelation!", BOOL_VERBOSE);
529
530         }
531
532         /**
533          * A private method to reinitialize IoTSet field
534          *
535          * @return  void
536          */
537         private void reinitializeIoTSetField() throws IOException,
538                 IllegalAccessException, NoSuchFieldException {
539
540                 // Reinitialize IoTSet field after getting all the objects
541                 iotsetObject = new IoTSet<Object>(isetObject.values());
542
543                 // Private fields need getDeclaredField(), while public fields use getField()
544                 Field fld = clsMain.getDeclaredField(strFieldName);
545                 boolean bAccess = fld.isAccessible();
546                 fld.setAccessible(true);
547                 fld.set(objMainCls, iotsetObject);
548                 fld.setAccessible(bAccess);
549                 RuntimeOutput.print("IoTSlave: Reinitializing field " + strFieldName, BOOL_VERBOSE);
550
551                 // Send back the received message as acknowledgement
552                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
553                 RuntimeOutput.print("IoTSlave: Reinitializing IoTSet field!", BOOL_VERBOSE);
554
555         }
556
557         /**
558          * A private method to reinitialize IoTRelation field
559          *
560          * @return  void
561          */
562         private void reinitializeIoTRelationField() throws IOException,
563                 IllegalAccessException, NoSuchFieldException {
564
565                 // Reinitialize IoTSet field after getting all the objects
566                 iotrelObject = new IoTRelation<Object,Object>(irelObject.relationMap(), irelObject.size());
567
568                 // Private fields need getDeclaredField(), while public fields use getField()
569                 Field fld = clsMain.getDeclaredField(strFieldName);
570                 boolean bAccess = fld.isAccessible();
571                 fld.setAccessible(true);
572                 fld.set(objMainCls, iotrelObject);
573                 fld.setAccessible(bAccess);
574                 RuntimeOutput.print("IoTSlave: Reinitializing field " + strFieldName, BOOL_VERBOSE);
575
576                 // Send back the received message as acknowledgement
577                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
578                 RuntimeOutput.print("IoTSlave: Reinitializing IoTRelation field!", BOOL_VERBOSE);
579
580         }
581
582         /**
583          * A private method to get the device driver object's IoTSet
584          * <p>
585          * This is to handle device driver's IoTSet that contains IP addresses
586          *
587          * @return  void
588          */
589         private void getDeviceIoTSetObject() throws IOException {
590
591                 // Translating into the actual Message class
592                 MessageGetDeviceObject sMessage = (MessageGetDeviceObject) sIoTMasterMsg;
593
594                 // Get IoTSet objects for IP address set on device driver/controller
595                 IoTDeviceAddress objDeviceAddress = new IoTDeviceAddress(sMessage.getHostAddress(),
596                         sMessage.getSourceDeviceDriverPort(),
597                         sMessage.getDestinationDeviceDriverPort(),
598                         sMessage.isSourcePortWildCard(),
599                         sMessage.isDestinationPortWildCard());
600                 RuntimeOutput.print("IoTSlave: Device address transferred: " + sMessage.getHostAddress(), BOOL_VERBOSE);
601                 isetObject.add(objDeviceAddress);
602                 RuntimeOutput.print("IoTSlave: This IoTSet now has: " + isetObject.size() + " entry(s)", BOOL_VERBOSE);
603
604                 // Send back the received message as acknowledgement
605                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
606                 RuntimeOutput.print("IoTSlave: Getting an object for IoTSet!", BOOL_VERBOSE);
607
608         }
609
610         /**
611          * A private method to get the device driver object's IoTSet for IoTZigbeeAddress
612          * <p>
613          * This is to handle device driver's IoTSet that contains Zigbee addresses
614          *
615          * @return  void
616          */
617         private void getZBDevIoTSetObject() throws IOException {
618
619                 // Translating into the actual Message class
620                 MessageGetSimpleDeviceObject sMessage = (MessageGetSimpleDeviceObject) sIoTMasterMsg;
621
622                 // Get IoTSet objects for IP address set on device driver/controller
623                 IoTZigbeeAddress objZBDevAddress = new IoTZigbeeAddress(sMessage.getHostAddress());
624                 RuntimeOutput.print("IoTSlave: Device address transferred: " + sMessage.getHostAddress(), BOOL_VERBOSE);
625                 isetObject.add(objZBDevAddress);
626                 RuntimeOutput.print("IoTSlave: This IoTSet now has: " + isetObject.size() + " entry(s)", BOOL_VERBOSE);
627
628                 // Send back the received message as acknowledgement
629                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
630                 RuntimeOutput.print("IoTSlave: Getting an object for IoTSet!", BOOL_VERBOSE);
631
632         }
633
634         
635         /**
636          * A private method to get IoTAddress objects for IoTSet
637          *
638          * @return  void
639          */
640         private void getAddIoTSetObject() throws IOException {
641
642                 // Translating into the actual Message class
643                 MessageGetSimpleDeviceObject sMessage = (MessageGetSimpleDeviceObject) sIoTMasterMsg;
644
645                 // Get IoTSet objects for IP address set on device driver/controller
646                 IoTAddress objAddress = new IoTAddress(sMessage.getHostAddress());
647                 RuntimeOutput.print("IoTSlave: Address transferred: " + sMessage.getHostAddress(), BOOL_VERBOSE);
648                 isetObject.add(objAddress);
649                 RuntimeOutput.print("IoTSlave: This IoTSet now has: " + isetObject.size() + " entry(s)", BOOL_VERBOSE);
650                 // Send back the received message as acknowledgement
651                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
652                 RuntimeOutput.print("IoTSlave: Getting an object for IoTSet!", BOOL_VERBOSE);
653
654         }
655         
656         /**
657          * A private method to invoke init() method in the controller object
658          *
659          * @return  void
660          */
661         private void invokeInitMethod() throws IOException {
662
663                 new Thread() {
664                         public void run() {
665                                 try {
666                                         Class<?> noparams[] = {};
667                                         Method method = clsMain.getDeclaredMethod("init", noparams);
668                                         method.invoke(objMainCls);
669                                 } catch (NoSuchMethodException  |
670                                                  IllegalAccessException |
671                                                  InvocationTargetException ex) {
672                                         System.out.println("IoTSlave: Exception: "
673                                                  + ex.getMessage());
674                                         ex.printStackTrace();
675                                 }
676                         }
677                 }.start();
678
679                 // Start a new thread to invoke the init function
680                 RuntimeOutput.print("IoTSlave: Invoke init method! Job done!", BOOL_VERBOSE);
681
682                 // Send back the received message as acknowledgement
683                 outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
684
685         }
686
687         /**
688          * A public method to do communication with IoTMaster
689          *
690          * @params  iIndex  Integer index
691          * @return  void
692          */
693         public void commIoTMaster() {
694
695                 try {
696
697                         // Loop, receive and process commands from IoTMaster
698                         socket = new Socket(sIoTMasterHostAdd, iComPort);
699                         outStream = new ObjectOutputStream(socket.getOutputStream());
700                         inStream = new ObjectInputStream(socket.getInputStream());
701
702                         LOOP:
703                         while(true) {
704                                 // Get the first payload
705                                 RuntimeOutput.print("IoTSlave: Slave waiting...", BOOL_VERBOSE);
706                                 sIoTMasterMsg = (Message) inStream.readObject();
707
708                                 // Check payload message from IoTMaster and make a decision
709                                 switch (sIoTMasterMsg.getMessage()) {
710
711                                 case CREATE_OBJECT:
712                                         createObject();
713                                         break;
714
715                                 case TRANSFER_FILE:
716                                         transferFile();
717                                         break;
718
719                                 case CREATE_MAIN_OBJECT:
720                                         createMainObject();
721                                         break;
722
723                                 case CREATE_NEW_IOTSET:
724                                         createNewIoTSet();
725                                         break;
726
727                                 case CREATE_NEW_IOTRELATION:
728                                         createNewIoTRelation();
729                                         break;
730
731                                 case GET_IOTSET_OBJECT:
732                                         getIoTSetObject();
733                                         break;
734
735                                 case GET_IOTRELATION_FIRST_OBJECT:
736                                         getIoTRelationFirstObject();
737                                         break;
738
739                                 case GET_IOTRELATION_SECOND_OBJECT:
740                                         getIoTRelationSecondObject();
741                                         break;
742
743                                 case REINITIALIZE_IOTSET_FIELD:
744                                         reinitializeIoTSetField();
745                                         break;
746
747                                 case REINITIALIZE_IOTRELATION_FIELD:
748                                         reinitializeIoTRelationField();
749                                         break;
750
751                                 case GET_DEVICE_IOTSET_OBJECT:
752                                         getDeviceIoTSetObject();
753                                         break;
754
755                                 case GET_ZB_DEV_IOTSET_OBJECT:
756                                         getZBDevIoTSetObject();
757                                         break;
758
759                                 case GET_ADD_IOTSET_OBJECT:
760                                         getAddIoTSetObject();
761                                         break;
762
763                                 case INVOKE_INIT_METHOD:
764                                         invokeInitMethod();
765                                         break;
766
767                                 case END_SESSION:
768                                         // END of session
769                                         break LOOP;
770
771                                 default:
772                                         break;
773                                 }
774                         }
775                         RuntimeOutput.print("IoTSlave: Session ends!", BOOL_VERBOSE);
776
777                         // Closing streams and end session
778                         outStream.close();
779                         inStream.close();
780                         socket.close();
781                         RuntimeOutput.print("IoTSlave: Closing!", BOOL_VERBOSE);
782                         // We have to continuously loop because we are preserving our stubs and skeletons
783                         //while(true) { }
784
785                 } catch (IOException               |
786                                  ClassNotFoundException    |
787                                  NoSuchMethodException     |
788                                  InstantiationException    |
789                                  AlreadyBoundException     |
790                                  IllegalAccessException    |
791                                  InvocationTargetException |
792                                  NotBoundException         |
793                                  NoSuchFieldException ex) {
794                         System.out.println("IoTSlave: Exception: "
795                                  + ex.getMessage());
796                         ex.printStackTrace();
797                 }
798         }
799
800         public static void main(String args[]) {
801                 IoTSlave iotSlave = new IoTSlave(args);
802                 iotSlave.parseIoTSlaveConfigFile();
803                 iotSlave.commIoTMaster();
804         }
805 }