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