]> git.mxchange.org Git - hub.git/blob - application/hub/main/nodes/class_BaseHubNode.php
Added all node types, moved iterator class:
[hub.git] / application / hub / main / nodes / class_BaseHubNode.php
1 <?php
2 /**
3  * A general hub node class
4  *
5  * @author              Roland Haeder <webmaster@ship-simu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2011 Hub Developer Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.ship-simu.org
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24 class BaseHubNode extends BaseHubSystem implements Updateable {
25         /**
26          * Node types
27          */
28         const NODE_TYPE_BOOT    = 'boot';
29         const NODE_TYPE_MASTER  = 'master';
30         const NODE_TYPE_LIST    = 'list';
31         const NODE_TYPE_REGULAR = 'regular';
32
33         // Exception constants
34         const EXCEPTION_HUB_ALREADY_ANNOUNCED = 0xe00;
35
36         /**
37          * IP/port number of bootstrapping node
38          */
39         private $bootIpPort = '';
40
41         /**
42          * Query connector instance
43          */
44         private $queryConnectorInstance = null;
45
46         /**
47          * Queue connector instance
48          */
49         private $queueConnectorInstance = null;
50
51         /**
52          * Listener pool instance
53          */
54         private $listenerPoolInstance = null;
55
56         /**
57          * Wether this node is anncounced (KEEP ON false!)
58          * @deprecated
59          */
60         private $hubIsAnnounced = false;
61
62         /**
63          * State instance
64          */
65         private $stateInstance = null;
66
67         /**
68          * Wether this hub is active
69          */
70         private $isActive = false;
71
72         /**
73          * Protected constructor
74          *
75          * @param       $className      Name of the class
76          * @return      void
77          */
78         protected function __construct ($className) {
79                 // Call parent constructor
80                 parent::__construct($className);
81
82                 // Init state which sets the state to 'init'
83                 $this->initState();
84         }
85
86         /**
87          * Initializes the node's state which sets it to 'init'
88          *
89          * @return      void
90          */
91         private function initState() {
92                 // Get the state factory and create the initial state, we don't need
93                 // the state instance here
94                 StateFactory::createStateInstanceByName('init', $this);
95         }
96
97         /**
98          * Setter for node id
99          *
100          * @param       $nodeId         Our new node id
101          * @return      void
102          */
103         private final function setNodeId ($nodeId) {
104                 // Set it config now
105                 $this->getConfigInstance()->setConfigEntry('node_id', (string) $nodeId);
106         }
107
108         /**
109          * Getter for node id
110          *
111          * @return      $nodeId         Current node id
112          */
113         private final function getNodeId () {
114                 // Get it from config
115                 return $this->getConfigInstance()->getConfigEntry('node_id');
116         }
117
118         /**
119          * Setter for listener pool instance
120          *
121          * @param       $listenerPoolInstance   Our new listener pool instance
122          * @return      void
123          */
124         private final function setListenerPoolInstance (PoolableListener $listenerPoolInstance) {
125                 $this->listenerPoolInstance = $listenerPoolInstance;
126         }
127
128         /**
129          * Getter for listener pool instance
130          *
131          * @return      $listenerPoolInstance   Our current listener pool instance
132          */
133         public final function getListenerPoolInstance () {
134                 return $this->listenerPoolInstance;
135         }
136
137         /**
138          * Setter for state instance
139          *
140          * @param       $stateInstance  Node's current state instance
141          * @return      void
142          */
143         public final function setStateInstance (Stateable $stateInstance) {
144                 $this->stateInstance = $stateInstance;
145         }
146
147         /**
148          * Getter for state instance
149          *
150          * @return      $stateInstance  Node's current state instance
151          */
152         public final function getStateInstance () {
153                 return $this->stateInstance;
154         }
155
156         /**
157          * Setter for session id
158          *
159          * @param       $sessionId              Our new session id
160          * @return      void
161          */
162         private final function setSessionId ($sessionId) {
163                 $this->getConfigInstance()->setConfigEntry('session_id', (string) $sessionId);
164         }
165
166         /**
167          * Getter for session id
168          *
169          * @return      $sessionId              Current session id
170          */
171         public final function getSessionId () {
172                 return $this->getConfigInstance()->getConfigEntry('session_id');
173         }
174
175         /**
176          * Setter for query instance
177          *
178          * @param       $connectorInstance              Our new query instance
179          * @return      void
180          */
181         private final function setQueryConnectorInstance (Connectable $connectorInstance) {
182                 $this->queryConnectorInstance = $connectorInstance;
183         }
184
185         /**
186          * Getter for query instance
187          *
188          * @return      $connectorInstance              Our new query instance
189          */
190         public final function getQueryConnectorInstance () {
191                 return $this->queryConnectorInstance;
192         }
193
194         /**
195          * Setter for queue instance
196          *
197          * @param       $connectorInstance              Our new queue instance
198          * @return      void
199          */
200         private final function setQueueConnectorInstance (Connectable $connectorInstance) {
201                 $this->queueConnectorInstance = $connectorInstance;
202         }
203
204         /**
205          * Getter for queue instance
206          *
207          * @return      $connectorInstance              Our new queue instance
208          */
209         public final function getQueueConnectorInstance () {
210                 return $this->queueConnectorInstance;
211         }
212
213         /**
214          * Getter for boot IP/port combination
215          *
216          * @return      $bootIpPort             The IP/port combination of the boot node
217          */
218         protected final function getBootIpPort () {
219                 return $this->bootIpPort;
220         }
221
222         /**
223          * "Getter" for a printable state name
224          *
225          * @return      $stateName      Name of the node's state in a printable format
226          */
227         public final function getPrintableState () {
228                 // Default is 'null'
229                 $stateName = 'null';
230
231                 // Get the state instance
232                 $stateInstance = $this->getStateInstance();
233
234                 // Is it an instance of Stateable?
235                 if ($stateInstance instanceof Stateable) {
236                         // Then use that state name
237                         $stateName = $stateInstance->getStateName();
238                 } // END - if
239
240                 // Return result
241                 return $stateName;
242         }
243
244         /**
245          * Checks wether the given IP address matches one of the bootstrapping nodes
246          *
247          * @param       $remoteAddr             IP address to checkout against our bootstrapping list
248          * @return      $isFound                Wether the IP is found
249          */
250         protected function ifAddressMatchesBootstrappingNodes ($remoteAddr) {
251                 // By default nothing is found
252                 $isFound = false;
253
254                 // Run through all configured IPs
255                 foreach (explode(',', $this->getConfigInstance()->getConfigEntry('hub_bootstrap_nodes')) as $ipPort) {
256                         // Split it up in IP/port
257                         $ipPortArray = explode(':', $ipPort);
258
259                         // Does it match?
260                         if ($ipPortArray[0] == $remoteAddr) {
261                                 // Found it!
262                                 $isFound = true;
263
264                                 // Remember the port number
265                                 $this->bootIpPort = $ipPort;
266
267                                 // Output message
268                                 $this->debugOutput('BOOTSTRAP: ' . __FUNCTION__ . '[' . __LINE__ . ']: IP matches remote address ' . $ipPort . '.');
269
270                                 // Stop further searching
271                                 break;
272                         } elseif ($ipPortArray[0] == $this->getConfigInstance()->getConfigEntry('node_listen_addr')) {
273                                 // IP matches listen address. At this point we really don't care
274                                 // if we can really listen on that address
275                                 $isFound = true;
276
277                                 // Remember the port number
278                                 $this->bootIpPort = $ipPort;
279
280                                 // Output message
281                                 $this->debugOutput('BOOTSTRAP: ' . __FUNCTION__ . '[' . __LINE__ . ']: IP matches listen address ' . $ipPort . '.');
282
283                                 // Stop further searching
284                                 break;
285                         }
286                 } // END - foreach
287
288                 // Return the result
289                 return $isFound;
290         }
291
292         /**
293          * Outputs the console teaser. This should only be executed on startup or
294          * full restarts. This method generates some space around the teaser.
295          *
296          * @return      void
297          */
298         public function outputConsoleTeaser () {
299                 // Get the app instance (for shortening our code)
300                 $app = $this->getApplicationInstance();
301
302                 // Output all lines
303                 $this->debugOutput(' ');
304                 $this->debugOutput($app->getAppName() . ' v' . $app->getAppVersion() . ' - ' . $this->getRequestInstance()->getRequestElement('mode') . ' mode active');
305                 $this->debugOutput('Copyright (c) 2007 - 2008 Roland Haeder, 2009 - 2011 Hub Developer Team');
306                 $this->debugOutput(' ');
307                 $this->debugOutput('This program comes with ABSOLUTELY NO WARRANTY; for details see docs/COPYING.');
308                 $this->debugOutput('This is free software, and you are welcome to redistribute it under certain');
309                 $this->debugOutput('conditions; see docs/COPYING for details.');
310                 $this->debugOutput(' ');
311         }
312
313         /**
314          * Generic method to acquire a hub-id. On first run this generates a new one
315          * based on many pseudo-random data. On any later run, unless the id
316          * got not removed from database, it will be restored from the database.
317          *
318          * @param       $requestInstance        A Requestable class
319          * @param       $responseInstance       A Responseable class
320          * @return      void
321          */
322         public function bootstrapAcquireNodeId (Requestable $requestInstance, Responseable $responseInstance) {
323                 // Get a wrapper instance
324                 $wrapperInstance = ObjectFactory::createObjectByConfiguredName('node_info_db_wrapper_class');
325
326                 // Now get a search criteria instance
327                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
328
329                 // Search for the node number zero which is hard-coded the default
330                 $searchInstance->addCriteria(NodeInformationDatabaseWrapper::DB_COLUMN_NODE_NR, 1);
331                 $searchInstance->addCriteria(NodeInformationDatabaseWrapper::DB_COLUMN_NODE_TYPE, $this->getRequestInstance()->getRequestElement('mode'));
332                 $searchInstance->setLimit(1);
333
334                 // Get a result back
335                 $resultInstance = $wrapperInstance->doSelectByCriteria($searchInstance);
336
337                 // Is it valid?
338                 if ($resultInstance->next()) {
339                         // Save the result instance in this class
340                         $this->setResultInstance($resultInstance);
341
342                         // Get the node id from result and set it
343                         $this->setNodeId($this->getField(NodeInformationDatabaseWrapper::DB_COLUMN_NODE_ID));
344
345                         // Output message
346                         $this->debugOutput('BOOTSTRAP: Re-using found node-id: ' . $this->getNodeId() . '');
347                 } else {
348                         // Get an RNG instance (Random Number Generator)
349                         $rngInstance = ObjectFactory::createObjectByConfiguredName('rng_class');
350
351                         // Generate a pseudo-random string
352                         $randomString = $rngInstance->randomString(255) . ':' . $this->getBootIpPort()  . ':' . $this->getRequestInstance()->getRequestElement('mode');
353
354                         // Get a crypto instance
355                         $cryptoInstance = ObjectFactory::createObjectByConfiguredName('crypto_class');
356
357                         // Hash and encrypt the string so we become a node id (also documented as "hub id")
358                         $this->setNodeId($cryptoInstance->hashString($cryptoInstance->encryptString($randomString)));
359
360                         // Register the node id with our wrapper
361                         $wrapperInstance->registerNodeId($this, $this->getRequestInstance());
362
363                         // Output message
364                         $this->debugOutput('BOOTSTRAP: Created new node-id: ' . $this->getNodeId() . '');
365                 }
366         }
367
368         /**
369          * Generates a session id which will be sent to the other hubs and peers
370          *
371          * @return      void
372          */
373         public function bootstrapGenerateSessionId () {
374                 // Get an RNG instance
375                 $rngInstance = ObjectFactory::createObjectByConfiguredName('rng_class');
376
377                 // Generate a pseudo-random string
378                 $randomString = $rngInstance->randomString(255) . ':' . $this->getBootIpPort() . ':' . $this->getRequestInstance()->getRequestElement('mode');
379
380                 // Get a crypto instance
381                 $cryptoInstance = ObjectFactory::createObjectByConfiguredName('crypto_class');
382
383                 // Hash and encrypt the string so we become a "node id" aka Hub-Id
384                 $this->setSessionId($cryptoInstance->hashString($cryptoInstance->encryptString($randomString)));
385
386                 // Get a wrapper instance
387                 $wrapperInstance = ObjectFactory::createObjectByConfiguredName('node_info_db_wrapper_class');
388
389                 // Register the node id with our wrapper
390                 $wrapperInstance->registerSessionId($this, $this->getRequestInstance());
391
392                 // Output message
393                 $this->debugOutput('BOOTSTRAP: Created new session-id: ' . $this->getSessionId() . '');
394
395                 // Change the state because the node has auired a hub id
396                 $this->getStateInstance()->nodeGeneratedSessionId();
397         }
398
399         /**
400          * Initializes queues which every node needs
401          *
402          * @return      void
403          */
404         protected function initGenericQueues () {
405                 // Debug message
406                 $this->debugOutput('BOOTSTRAP: Initialize queues: START');
407
408                 // Set the query connector instance
409                 $this->setQueryConnectorInstance(ObjectFactory::createObjectByConfiguredName('query_connector_class', array($this)));
410
411                 // Run a test query
412                 $this->getQueryConnectorInstance()->doTestQuery();
413
414                 // Set the queue connector instance
415                 $this->setQueueConnectorInstance(ObjectFactory::createObjectByConfiguredName('queue_connector_class', array($this)));
416
417                 // Run a test queue
418                 $this->getQueueConnectorInstance()->doTestQueue();
419
420                 // Debug message
421                 $this->debugOutput('BOOTSTRAP: Initialize queues: FINISHED');
422         }
423
424         /**
425          * Adds hub data elements to a given dataset instance
426          *
427          * @param       $criteriaInstance       An instance of a storeable criteria
428          * @param       $requestInstance        An instance of a Requestable class
429          * @return      void
430          */
431         public function addElementsToDataSet (StoreableCriteria $criteriaInstance, Requestable $requestInstance) {
432                 // Add node number and type
433                 $criteriaInstance->addCriteria(NodeInformationDatabaseWrapper::DB_COLUMN_NODE_NR, 1);
434                 $criteriaInstance->addCriteria(NodeInformationDatabaseWrapper::DB_COLUMN_NODE_TYPE, $requestInstance->getRequestElement('mode'));
435
436                 // Add the node id
437                 $criteriaInstance->addCriteria(NodeInformationDatabaseWrapper::DB_COLUMN_NODE_ID, $this->getNodeId());
438
439                 // Add the session id if acquired
440                 if ($this->getSessionId() != '') {
441                         $criteriaInstance->addCriteria(NodeInformationDatabaseWrapper::DB_COLUMN_SESSION_ID, $this->getSessionId());
442                 } // END - if
443         }
444
445         /**
446          * Updates a given field with new value
447          *
448          * @param       $fieldName              Field to update
449          * @param       $fieldValue             New value to store
450          * @return      void
451          * @throws      DatabaseUpdateSupportException  If this class does not support database updates
452          * @todo        Try to make this method more generic so we can move it in BaseFrameworkSystem
453          */
454         public function updateDatabaseField ($fieldName, $fieldValue) {
455                 // Unfinished
456                 $this->partialStub('Unfinished!');
457                 return;
458
459                 // Get a critieria instance
460                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
461
462                 // Add search criteria
463                 $searchInstance->addCriteria(UserDatabaseWrapper::DB_COLUMN_USERNAME, $this->getUserName());
464                 $searchInstance->setLimit(1);
465
466                 // Now get another criteria
467                 $updateInstance = ObjectFactory::createObjectByConfiguredName('update_criteria_class');
468
469                 // Add criteria entry which we shall update
470                 $updateInstance->addCriteria($fieldName, $fieldValue);
471
472                 // Add the search criteria for searching for the right entry
473                 $updateInstance->setSearchInstance($searchInstance);
474
475                 // Set wrapper class name
476                 $updateInstance->setWrapperConfigEntry('user_db_wrapper_class');
477
478                 // Remember the update in database result
479                 $this->getResultInstance()->add2UpdateQueue($updateInstance);
480         }
481
482         /**
483          * Announces this hub to the upper (bootstrap or list) hubs. After this is
484          * successfully done the given task is unregistered from the handler. This
485          * might look a bit overloaded here but the announcement phase isn't a
486          * simple "Hello there" message, it may later on also contain more
487          * informations like the object list.
488          *
489          * @param       $taskInstance   The task instance running this announcement
490          * @return      void
491          * @throws      HubAlreadyAnnouncedException    If this hub is already announced
492          * @todo        Change the first if() block to check for a specific state
493          */
494         public function announceSelfToUpperNodes (Taskable $taskInstance) {
495                 // Is this hub node announced?
496                 if ($this->hubIsAnnounced === true) {
497                         // Already announced!
498                         throw new HubAlreadyAnnouncedException($this, self::EXCEPTION_HUB_ALREADY_ANNOUNCED);
499                 } // END - if
500
501                 // Debug output
502                 $this->debugOutput('HUB: Announcement: START (taskInstance=' . $taskInstance->__toString(). ')');
503
504                 // Get a helper instance
505                 $helperInstance = ObjectFactory::createObjectByConfiguredName('hub_announcement_helper_class', array($this));
506
507                 // Load the announcement descriptor
508                 $helperInstance->loadDescriptorXml();
509
510                 // Set some dummy configuration entries, e.g. node_status
511                 $this->getConfigInstance()->setConfigEntry('node_status', $this->getStateInstance()->getStateName());
512
513                 // Compile all variables
514                 $helperInstance->getTemplateInstance()->compileConfigInVariables();
515
516                 // "Publish" the descriptor by sending it to the bootstrap/list nodes
517                 $helperInstance->sendPackage();
518
519                 // Change the state, this should be the last line except debug output
520                 $this->getStateInstance()->nodeAnnouncedToUpperHubs();
521
522                 // Debug output
523                 $this->debugOutput('HUB: Announcement: FINISHED');
524         }
525
526         /**
527          * Does a self-connect attempt on the public IP address. This should make
528          * it sure, we are reachable from outside world. For this kind of package we
529          * don't need that overload we have in the announcement phase.
530          *
531          * @param       $taskInstance   The task instance running this announcement
532          * @return      void
533          */
534         public function doSelfConnection (Taskable $taskInstance) {
535                 // Debug output
536                 $this->debugOutput('HUB: Self Connection: START (taskInstance=' . $taskInstance->__toString(). ')');
537
538                 // Get a helper instance
539                 $helperInstance = ObjectFactory::createObjectByConfiguredName('hub_self_connect_helper_class', array($this));
540
541                 // Load the descriptor (XML) file
542                 $helperInstance->loadDescriptorXml();
543
544                 // And send the package away
545                 $helperInstance->sendPackage();
546
547                 // Debug output
548                 $this->debugOutput('HUB: Self Connection: FINISHED');
549         }
550
551         /**
552          * Activates the hub by doing some final preparation and setting
553          * $hubIsActive to true
554          *
555          * @param       $requestInstance        A Requestable class
556          * @param       $responseInstance       A Responseable class
557          * @return      void
558          */
559         public function activateNode (Requestable $requestInstance, Responseable $responseInstance) {
560                 // Checks wether a listener is still active and shuts it down if one
561                 // is still listening.
562                 if (($this->determineIfListenerIsActive()) && ($this->getIsActive())) {
563                         // Shutdown them down before they can hurt anything
564                         $this->shutdownListenerPool();
565                 } // END - if
566
567                 // Get the controller here
568                 $controllerInstance = Registry::getRegistry()->getInstance('controller');
569
570                 // Run all filters for the hub activation
571                 $controllerInstance->executeActivationFilters($requestInstance, $responseInstance);
572
573                 // ----------------------- Last step from here ------------------------
574                 // Activate the hub. This is ALWAYS the last step in this method
575                 $this->getStateInstance()->nodeIsActivated();
576                 // ---------------------- Last step until here ------------------------
577         }
578
579         /**
580          * Initializes the listener pool (class)
581          *
582          * @return      void
583          */
584         public function initializeListenerPool () {
585                 // Debug output
586                 $this->debugOutput('HUB: Initialize listener: START');
587
588                 // Get a new pool instance
589                 $this->setListenerPoolInstance(ObjectFactory::createObjectByConfiguredName('listener_pool_class', array($this)));
590
591                 // Get an instance of the low-level listener
592                 $listenerInstance = ObjectFactory::createObjectByConfiguredName('tcp_listener_class', array($this));
593
594                 // Setup address and port
595                 $listenerInstance->setListenAddressByConfiguration('node_listen_addr');
596                 if ($this instanceof HubBootNode) {
597                         // Bootstrap have different listening port
598                         $listenerInstance->setListenPortByConfiguration('boot_node_tcp_listen_port');
599                 } else {
600                         // All other nodes use the default port
601                         $listenerInstance->setListenPortByConfiguration('node_tcp_listen_port');
602                 }
603
604                 // Initialize the listener
605                 $listenerInstance->initListener();
606
607                 // Get a decorator class
608                 $decoratorInstance = ObjectFactory::createObjectByConfiguredName('hub_tcp_listener_class', array($listenerInstance));
609
610                 // Add this listener to the pool
611                 $this->getListenerPoolInstance()->addListener($decoratorInstance);
612
613                 // Get a decorator class
614                 $decoratorInstance = ObjectFactory::createObjectByConfiguredName('peer_tcp_listener_class', array($listenerInstance));
615
616                 // Add this listener to the pool
617                 $this->getListenerPoolInstance()->addListener($decoratorInstance);
618
619                 // Get an instance of the low-level listener
620                 $listenerInstance = ObjectFactory::createObjectByConfiguredName('udp_listener_class', array($this));
621
622                 // Setup address and port
623                 $listenerInstance->setListenAddressByConfiguration('node_listen_addr');
624                 if ($this instanceof HubBootNode) {
625                         // Bootstrap have different listening port
626                         $listenerInstance->setListenPortByConfiguration('boot_node_udp_listen_port');
627                 } else {
628                         // All other nodes use the default port
629                         $listenerInstance->setListenPortByConfiguration('node_udp_listen_port');
630                 }
631
632                 // Initialize the listener
633                 $listenerInstance->initListener();
634
635                 // Get a decorator class
636                 $decoratorInstance = ObjectFactory::createObjectByConfiguredName('hub_udp_listener_class', array($listenerInstance));
637
638                 // Add this listener to the pool
639                 $this->getListenerPoolInstance()->addListener($decoratorInstance);
640
641                 // Get a decorator class
642                 $decoratorInstance = ObjectFactory::createObjectByConfiguredName('peer_udp_listener_class', array($listenerInstance));
643
644                 // Add this listener to the pool
645                 $this->getListenerPoolInstance()->addListener($decoratorInstance);
646
647                 // Debug output
648                 $this->debugOutput('HUB: Initialize listener: FINISHED.');
649         }
650
651         /**
652          * Restores a previously stored node list from database
653          *
654          * @return      void
655          */
656         public function bootstrapRestoreNodeList () {
657                 // Debug output
658                 $this->debugOutput('HUB: Restore node list: START');
659
660                 // Get a wrapper instance
661                 $wrapperInstance = ObjectFactory::createObjectByConfiguredName('node_list_db_wrapper_class');
662
663                 // Now get a search criteria instance
664                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
665
666                 // Search for the node number zero which is hard-coded the default
667                 // @TODO Add some criteria, e.g. if the node is active or so
668                 //$searchInstance->addCriteria(NodeListDatabaseWrapper::DB_COLUMN_NODE_NR, 1);
669                 //$searchInstance->addCriteria(NodeListDatabaseWrapper::DB_COLUMN_NODE_TYPE, $this->getRequestInstance()->getRequestElement('mode'));
670                 //$searchInstance->setLimit(1);
671
672                 // Get a result back
673                 $resultInstance = $wrapperInstance->doSelectByCriteria($searchInstance);
674
675                 // Is it valid?
676                 if ($resultInstance->next()) {
677                         $this->partialStub('Do something for restoring the list.');
678                         // Output message
679                         //$this->debugOutput('HUB: ');
680                 } else {
681                         // No previously saved node list found!
682                         $this->debugOutput('HUB: No previously saved node list found. This is fine.');
683                 }
684
685                 // Debug output
686                 $this->debugOutput('HUB: Restore node list: FINISHED.');
687         }
688
689         /**
690          * Getter for isActive attribute
691          *
692          * @return      $isActive       Wether the hub is active
693          */
694         public final function getIsActive () {
695                 return $this->isActive;
696         }
697
698         /**
699          * Enables (default) or disables isActive flag
700          *
701          * @param       $isActive       Wether the hub is active
702          * @return      void
703          */
704         public final function enableIsActive ($isActive = true) {
705                 $this->isActive = (bool) $isActive;
706         }
707
708         /**
709          * "Getter for address:port combination
710          *
711          * @param       $handlerInstance        A valid Networkable instance
712          * @return      $addressPort            A address:port combination for this node
713          */
714         public final function getAddressPort (Networkable $handlerInstance) {
715                 // Construct config entry
716                 $configEntry = 'node_' . $handlerInstance->getHandlerName() . '_listen_port';
717
718                 // Get IP and port
719                 $addressPort = $this->getConfigInstance()->detectServerAddress() . ':' . $this->getConfigInstance()->getConfigEntry($configEntry);
720
721                 // Return it
722                 return $addressPort;
723         }
724 }
725
726 // [EOF]
727 ?>