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