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