]> git.mxchange.org Git - hub.git/blob - application/hub/main/class_BaseHubSystem.php
b0abb8c4ae30f9da24d95b953069e97e1b8366e5
[hub.git] / application / hub / main / class_BaseHubSystem.php
1 <?php
2 /**
3  * A general hub system 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 BaseHubSystem extends BaseFrameworkSystem {
25         // Exception codes
26         const EXCEPTION_UNSUPPORTED_ERROR_HANDLER = 0x900;
27
28         /**
29          * Separator for all bootstrap node entries
30          */
31         const BOOTSTRAP_NODES_SEPARATOR = ';';
32
33         /**
34          * An instance of a node
35          */
36         private $nodeInstance = NULL;
37
38         /**
39          * An instance of a cruncher
40          */
41         private $cruncherInstance = NULL;
42
43         /**
44          * Listener instance
45          */
46         private $listenerInstance = NULL;
47
48         /**
49          * A network package handler instance
50          */
51         private $packageInstance = NULL;
52
53         /**
54          * A Receivable instance
55          */
56         private $receiverInstance = NULL;
57
58         /**
59          * State instance
60          */
61         private $stateInstance = NULL;
62
63         /**
64          * Listener pool instance
65          */
66         private $listenerPoolInstance = NULL;
67
68         /**
69          * Protected constructor
70          *
71          * @param       $className      Name of the class
72          * @return      void
73          */
74         protected function __construct ($className) {
75                 // Call parent constructor
76                 parent::__construct($className);
77         }
78
79         /**
80          * Getter for node instance
81          *
82          * @return      $nodeInstance   An instance of a node node
83          */
84         public final function getNodeInstance () {
85                 return $this->nodeInstance;
86         }
87
88         /**
89          * Setter for node instance
90          *
91          * @param       $nodeInstance   An instance of a node node
92          * @return      void
93          */
94         protected final function setNodeInstance (NodeHelper $nodeInstance) {
95                 $this->nodeInstance = $nodeInstance;
96         }
97
98         /**
99          * Getter for cruncher instance
100          *
101          * @return      $cruncherInstance       An instance of a cruncher cruncher
102          */
103         public final function getCruncherInstance () {
104                 return $this->cruncherInstance;
105         }
106
107         /**
108          * Setter for cruncher instance
109          *
110          * @param       $cruncherInstance       An instance of a cruncher cruncher
111          * @return      void
112          */
113         protected final function setCruncherInstance (CruncherHelper $cruncherInstance) {
114                 $this->cruncherInstance = $cruncherInstance;
115         }
116
117         /**
118          * Setter for listener instance
119          *
120          * @param       $listenerInstance       A Listenable instance
121          * @return      void
122          */
123         protected final function setListenerInstance (Listenable $listenerInstance) {
124                 $this->listenerInstance = $listenerInstance;
125         }
126
127         /**
128          * Getter for listener instance
129          *
130          * @return      $listenerInstance       A Listenable instance
131          */
132         protected final function getListenerInstance () {
133                 return $this->listenerInstance;
134         }
135
136         /**
137          * Setter for network package handler instance
138          *
139          * @param       $packageInstance        The network package handler instance we shall set
140          * @return      void
141          */
142         protected final function setPackageInstance (Networkable $packageInstance) {
143                 $this->packageInstance = $packageInstance;
144         }
145
146         /**
147          * Getter for network package handler instance
148          *
149          * @return      $packageInstance        The network package handler instance we shall set
150          */
151         protected final function getPackageInstance () {
152                 return $this->packageInstance;
153         }
154
155         /**
156          * Setter for receiver instance
157          *
158          * @param       $receiverInstance       A Receivable instance we shall set
159          * @return      void
160          */
161         protected final function setReceiverInstance (Receivable $receiverInstance) {
162                 $this->receiverInstance = $receiverInstance;
163         }
164
165         /**
166          * Getter for receiver instance
167          *
168          * @return      $receiverInstance       A Receivable instance we shall get
169          */
170         protected final function getReceiverInstance () {
171                 return $this->receiverInstance;
172         }
173
174         /**
175          * Setter for state instance
176          *
177          * @param       $stateInstance  A Stateable instance
178          * @return      void
179          */
180         public final function setStateInstance (Stateable $stateInstance) {
181                 $this->stateInstance = $stateInstance;
182         }
183
184         /**
185          * Getter for state instance
186          *
187          * @return      $stateInstance  A Stateable instance
188          */
189         public final function getStateInstance () {
190                 return $this->stateInstance;
191         }
192
193         /**
194          * Setter for listener pool instance
195          *
196          * @param       $listenerPoolInstance   Our new listener pool instance
197          * @return      void
198          */
199         protected final function setListenerPoolInstance (PoolableListener $listenerPoolInstance) {
200                 $this->listenerPoolInstance = $listenerPoolInstance;
201         }
202
203         /**
204          * Getter for listener pool instance
205          *
206          * @return      $listenerPoolInstance   Our current listener pool instance
207          */
208         public final function getListenerPoolInstance () {
209                 return $this->listenerPoolInstance;
210         }
211
212         /**
213          * Constructs a callable method name from given socket error code. If the
214          * method is not found, a generic one is used.
215          *
216          * @param       $errorCode              Error code from socket_last_error()
217          * @return      $methodName             Call-back method name for the error handler
218          * @throws      UnsupportedSocketErrorHandlerException If the error handler is not implemented
219          */
220         protected function getSocketErrorHandlerFromCode ($errorCode) {
221                 // Set NULL, so everyone is forced to implement socket error handlers
222                 $handlerName = NULL;
223
224                 // Temporary create a possible name from translated error code
225                 $handlerName = 'socketError' . $this->convertToClassName($this->translateSocketErrorCodeToName($errorCode)) . 'Handler';
226
227                 // Is the call-back method there?
228                 if (!method_exists($this, $handlerName)) {
229                         // Please implement this
230                         throw new UnsupportedSocketErrorHandlerException(array($this, $handlerName, $errorCode), self::EXCEPTION_UNSUPPORTED_ERROR_HANDLER);
231                 } // END - if
232
233                 // Return it
234                 return $handlerName;
235         }
236
237         /**
238          * Handles socket error for given socket resource and peer data. This method
239          * validates $socketResource if it is a valid resource (see is_resource())
240          * but assumes valid data in array $recipientData, except that
241          * count($recipientData) is always 2.
242          *
243          * @param       $socketResource         A valid socket resource
244          * @param       $recipientData          An array with two elements: 0=IP number, 1=port number
245          * @return      void
246          * @throws      InvalidSocketException  If $socketResource is no socket resource
247          * @throws      NoSocketErrorDetectedException  If socket_last_error() gives zero back
248          */
249         protected final function handleSocketError ($socketResource, array $recipientData) {
250                 // This method handles only socket resources
251                 if (!is_resource($socketResource)) {
252                         // No resource, abort here
253                         throw new InvalidSocketException(array($this, $socketResource), BaseListener::EXCEPTION_INVALID_SOCKET);
254                 } // END - if
255
256                 // Check count of array, should be two
257                 assert(count($recipientData) == 2);
258
259                 // Get error code for first validation (0 is not an error)
260                 $errorCode = socket_last_error($socketResource);
261
262                 // If the error code is zero, someone called this method without an error
263                 if ($errorCode == 0) {
264                         // No error detected (or previously cleared outside this method)
265                         throw new NoSocketErrorDetectedException(array($this, $socketResource), BaseListener::EXCEPTION_NO_SOCKET_ERROR);
266                 } // END - if
267
268                 // Get handler (method) name
269                 $handlerName = $this->getSocketErrorHandlerFromCode($errorCode);
270
271                 // Call-back the error handler method
272                 call_user_func(array($this, $handlerName), $socketResource);
273
274                 // Finally clear the error because it has been handled
275                 socket_clear_error($socketResource);
276         }
277
278         /**
279          * Translates socket error codes into our own internal names which can be
280          * used for call-backs.
281          *
282          * @param       $errorCode      The error code from socket_last_error() to be translated
283          * @return      $errorName      The translated name (all lower-case, with underlines)
284          */
285         public function translateSocketErrorCodeToName ($errorCode) {
286                 // Nothing bad happened by default
287                 $errorName = BaseRawDataHandler::SOCKET_CONNECTED;
288
289                 // Is the code a number, then we have to change it
290                 switch ($errorCode) {
291                         case 0: // Silently ignored, the socket is connected
292                                 break;
293
294                         case 11:  // "Resource temporary unavailable"
295                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_RESOURCE_UNAVAILABLE;
296                                 break;
297
298                         case 107: // "Transport end-point not connected"
299                         case 134: // On some (?) systems for 'transport end-point not connected'
300                                 // @TODO On some systems it is 134, on some 107?
301                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_TRANSPORT_ENDPOINT;
302                                 break;
303
304                         case 110: // "Connection timed out"
305                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_CONNECTION_TIMED_OUT;
306                                 break;
307
308                         case 111: // "Connection refused"
309                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_CONNECTION_REFUSED;
310                                 break;
311
312                         case 113: // "No route to host"
313                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_NO_ROUTE_TO_HOST;
314                                 break;
315
316                         case 114: // "Operation already in progress"
317                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_OPERATION_ALREADY_PROGRESS;
318                                 break;
319
320                         case 115: // "Operation now in progress"
321                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_OPERATION_IN_PROGRESS;
322                                 break;
323
324                         default: // Everything else <> 0
325                                 // Unhandled error code detected, so first debug it because we may want to handle it like the others
326                                 $this->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] UNKNOWN ERROR CODE = ' . $errorCode . ', MESSAGE = ' . socket_strerror($errorCode));
327
328                                 // Change it only in this class
329                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_UNKNOWN;
330                                 break;
331                 }
332
333                 // Return translated name
334                 return $errorName;
335         }
336
337         /**
338          * Shuts down a given socket resource. This method does only ease calling
339          * the right visitor.
340          *
341          * @param       $socketResource         A valid socket resource
342          * @return      void
343          */
344         public function shutdownSocket ($socketResource) {
345                 // Debug message
346                 $this->debugOutput('HUB-SYSTEM: Shutting down socket resource ' . $socketResource . ' with state ' . $this->getPrintableState() . ' ...');
347
348                 // Set socket resource
349                 $this->setSocketResource($socketResource);
350
351                 // Get a visitor instance
352                 $visitorInstance = ObjectFactory::createObjectByConfiguredName('shutdown_socket_visitor_class');
353
354                 // Call the visitor
355                 $this->accept($visitorInstance);
356         }
357
358         /**
359          * Half-shuts down a given socket resource. This method does only ease calling
360          * an other visitor than shutdownSocket() does.
361          *
362          * @param       $socketResource         A valid socket resource
363          * @return      void
364          */
365         public function halfShutdownSocket ($socketResource) {
366                 // Debug message
367                 $this->debugOutput('HUB-SYSTEM: Half-shutting down socket resource ' . $socketResource . ' with state ' . $this->getPrintableState() . ' ...');
368
369                 // Set socket resource
370                 $this->setSocketResource($socketResource);
371
372                 // Get a visitor instance
373                 $visitorInstance = ObjectFactory::createObjectByConfiguredName('half_shutdown_socket_visitor_class');
374
375                 // Call the visitor
376                 $this->accept($visitorInstance);
377         }
378
379         /**
380          * "Getter" for a printable state name
381          *
382          * @return      $stateName      Name of the node's state in a printable format
383          */
384         public final function getPrintableState () {
385                 // Default is 'null'
386                 $stateName = 'null';
387
388                 // Get the state instance
389                 $stateInstance = $this->getStateInstance();
390
391                 // Is it an instance of Stateable?
392                 if ($stateInstance instanceof Stateable) {
393                         // Then use that state name
394                         $stateName = $stateInstance->getStateName();
395                 } // END - if
396
397                 // Return result
398                 return $stateName;
399         }
400 }
401
402 // [EOF]
403 ?>