]> git.mxchange.org Git - core.git/blob - framework/main/classes/class_BaseFrameworkSystem.php
Continued:
[core.git] / framework / main / classes / class_BaseFrameworkSystem.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Object;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
7 use Org\Mxchange\CoreFramework\Criteria\Criteria;
8 use Org\Mxchange\CoreFramework\Database\Frontend\DatabaseWrapper;
9 use Org\Mxchange\CoreFramework\EntryPoint\ApplicationEntryPoint;
10 use Org\Mxchange\CoreFramework\Factory\Database\Wrapper\DatabaseWrapperFactory;
11 use Org\Mxchange\CoreFramework\Factory\ObjectFactory;
12 use Org\Mxchange\CoreFramework\Filesystem\PathWriteProtectedException;
13 use Org\Mxchange\CoreFramework\Generic\FrameworkInterface;
14 use Org\Mxchange\CoreFramework\Generic\NullPointerException;
15 use Org\Mxchange\CoreFramework\Generic\UnsupportedOperationException;
16 use Org\Mxchange\CoreFramework\Loader\ClassLoader;
17 use Org\Mxchange\CoreFramework\Manager\ManageableApplication;
18 use Org\Mxchange\CoreFramework\Middleware\Debug\DebugMiddleware;
19 use Org\Mxchange\CoreFramework\Registry\GenericRegistry;
20 use Org\Mxchange\CoreFramework\Result\Database\CachedDatabaseResult;
21 use Org\Mxchange\CoreFramework\State\Stateable;
22 use Org\Mxchange\CoreFramework\Stream\Input\InputStream;
23 use Org\Mxchange\CoreFramework\Stream\Output\OutputStreamer;
24 use Org\Mxchange\CoreFramework\Stream\Output\OutputStream;
25 use Org\Mxchange\CoreFramework\Utils\String\StringUtils;
26
27 // Import SPL stuff
28 use \stdClass;
29 use \InvalidArgumentException;
30 use \Iterator;
31 use \ReflectionClass;
32 use \SplFileInfo;
33
34 /**
35  * The simulator system class is the super class of all other classes. This
36  * class handles saving of games etc.
37  *
38  * @author              Roland Haeder <webmaster@shipsimu.org>
39  * @version             0.0.0
40  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2020 Core Developer Team
41  * @license             GNU GPL 3.0 or any newer version
42  * @link                http://www.shipsimu.org
43  *
44  * This program is free software: you can redistribute it and/or modify
45  * it under the terms of the GNU General Public License as published by
46  * the Free Software Foundation, either version 3 of the License, or
47  * (at your option) any later version.
48  *
49  * This program is distributed in the hope that it will be useful,
50  * but WITHOUT ANY WARRANTY; without even the implied warranty of
51  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
52  * GNU General Public License for more details.
53  *
54  * You should have received a copy of the GNU General Public License
55  * along with this program. If not, see <http://www.gnu.org/licenses/>.
56  */
57 abstract class BaseFrameworkSystem extends stdClass implements FrameworkInterface {
58         /**
59          * Length of output from hash()
60          */
61         private static $hashLength = NULL;
62
63         /**
64          * Self-referencing instance
65          */
66         private static $instance = NULL;
67
68         /**
69          * The real class name
70          */
71         private $realClass = __CLASS__;
72
73         /**
74          * Instance of an Iterator class
75          */
76         private $iteratorInstance = NULL;
77
78         /**
79          * An instance of a InputStream class
80          */
81         private $inputStreamInstance = NULL;
82
83         /**
84          * An instance of a OutputStream class
85          */
86         private $outputStreamInstance = NULL;
87
88         /**
89          * An instance of a database wrapper class
90          */
91         private $wrapperInstance = NULL;
92
93         /**
94          * State instance
95          */
96         private $stateInstance = NULL;
97
98         /**
99          * Call-back instance
100          */
101         private $callbackInstance = NULL;
102
103         /**
104          * Generic array
105          */
106         private $genericArray = [];
107
108         /***********************
109          * Exception codes.... *
110          ***********************/
111
112         // @todo Try to clean these constants up
113         const EXCEPTION_IS_NULL_POINTER              = 0x001;
114         const EXCEPTION_IS_NO_OBJECT                 = 0x002;
115         const EXCEPTION_IS_NO_ARRAY                  = 0x003;
116         const EXCEPTION_MISSING_METHOD               = 0x004;
117         const EXCEPTION_CLASSES_NOT_MATCHING         = 0x005;
118         const EXCEPTION_INDEX_OUT_OF_BOUNDS          = 0x006;
119         const EXCEPTION_DIMENSION_ARRAY_INVALID      = 0x007;
120         const EXCEPTION_ITEM_NOT_TRADEABLE           = 0x008;
121         const EXCEPTION_ITEM_NOT_IN_PRICE_LIST       = 0x009;
122         const EXCEPTION_GENDER_IS_WRONG              = 0x00a;
123         const EXCEPTION_BIRTH_DATE_IS_INVALID        = 0x00b;
124         const EXCEPTION_EMPTY_STRUCTURES_ARRAY       = 0x00c;
125         const EXCEPTION_HAS_ALREADY_PERSONELL_LIST   = 0x00d;
126         const EXCEPTION_NOT_ENOUGTH_UNEMPLOYEES      = 0x00e;
127         const EXCEPTION_TOTAL_PRICE_NOT_CALCULATED   = 0x00f;
128         const EXCEPTION_HARBOR_HAS_NO_SHIPYARDS      = 0x010;
129         const EXCEPTION_CONTRACT_PARTNER_INVALID     = 0x011;
130         const EXCEPTION_CONTRACT_PARTNER_MISMATCH    = 0x012;
131         const EXCEPTION_CONTRACT_ALREADY_SIGNED      = 0x013;
132         const EXCEPTION_UNEXPECTED_EMPTY_STRING      = 0x014;
133         const EXCEPTION_PATH_NOT_FOUND               = 0x015;
134         const EXCEPTION_INVALID_PATH_NAME            = 0x016;
135         const EXCEPTION_READ_PROTECED_PATH           = 0x017;
136         const EXCEPTION_WRITE_PROTECED_PATH          = 0x018;
137         const EXCEPTION_DIR_POINTER_INVALID          = 0x019;
138         const EXCEPTION_FILE_POINTER_INVALID         = 0x01a;
139         const EXCEPTION_INVALID_RESOURCE             = 0x01b;
140         const EXCEPTION_UNEXPECTED_OBJECT            = 0x01c;
141         const EXCEPTION_LIMIT_ELEMENT_IS_UNSUPPORTED = 0x01d;
142         const EXCEPTION_GETTER_IS_MISSING            = 0x01e;
143         const EXCEPTION_ARRAY_EXPECTED               = 0x01f;
144         const EXCEPTION_ARRAY_HAS_INVALID_COUNT      = 0x020;
145         const EXCEPTION_ID_IS_INVALID_FORMAT         = 0x021;
146         const EXCEPTION_MD5_CHECKSUMS_MISMATCH       = 0x022;
147         const EXCEPTION_UNEXPECTED_STRING_SIZE       = 0x023;
148         const EXCEPTION_SIMULATOR_ID_INVALID         = 0x024;
149         const EXCEPTION_MISMATCHING_COMPRESSORS      = 0x025;
150         const EXCEPTION_CONTAINER_ITEM_IS_NULL       = 0x026;
151         const EXCEPTION_ITEM_IS_NO_ARRAY             = 0x027;
152         const EXCEPTION_CONTAINER_MAYBE_DAMAGED      = 0x028;
153         const EXCEPTION_INVALID_STRING               = 0x029;
154         const EXCEPTION_VARIABLE_NOT_SET             = 0x02a;
155         const EXCEPTION_ATTRIBUTES_ARE_MISSING       = 0x02b;
156         const EXCEPTION_ARRAY_ELEMENTS_MISSING       = 0x02c;
157         const EXCEPTION_TEMPLATE_ENGINE_UNSUPPORTED  = 0x02d;
158         const EXCEPTION_UNSPPORTED_OPERATION         = 0x02e;
159         const EXCEPTION_FACTORY_REQUIRE_PARAMETER    = 0x02f;
160         const EXCEPTION_MISSING_ELEMENT              = 0x030;
161         const EXCEPTION_HEADERS_ALREADY_SENT         = 0x031;
162         const EXCEPTION_DEFAULT_CONTROLLER_GONE      = 0x032;
163         const EXCEPTION_CLASS_NOT_FOUND              = 0x033;
164         const EXCEPTION_REQUIRED_INTERFACE_MISSING   = 0x034;
165         const EXCEPTION_FATAL_ERROR                  = 0x035;
166         const EXCEPTION_FILE_NOT_FOUND               = 0x036;
167         const EXCEPTION_ASSERTION_FAILED             = 0x037;
168         const EXCEPTION_FILE_NOT_REACHABLE           = 0x038;
169         const EXCEPTION_FILE_CANNOT_BE_READ          = 0x039;
170         const EXCEPTION_FILE_CANNOT_BE_WRITTEN       = 0x03a;
171         const EXCEPTION_PATH_CANNOT_BE_WRITTEN       = 0x03b;
172         const EXCEPTION_DATABASE_UPDATED_NOT_ALLOWED = 0x03c;
173         const EXCEPTION_FILTER_CHAIN_INTERCEPTED     = 0x03d;
174         const EXCEPTION_INVALID_SOCKET               = 0x03e;
175         const EXCEPTION_SELF_INSTANCE                = 0x03f;
176
177         /**
178          * Startup time in miliseconds
179          */
180         private static $startupTime = 0;
181
182         /**
183          * Protected super constructor
184          *
185          * @param       $className      Name of the class
186          * @return      void
187          */
188         protected function __construct (string $className) {
189                 // Set real class
190                 $this->setRealClass($className);
191
192                 // Is the startup time set? (0 cannot be true anymore)
193                 if (self::$startupTime == 0) {
194                         // Then set it
195                         self::$startupTime = microtime(true);
196                 }
197         }
198
199         /**
200          * Destructor for all classes. You should not call this method on your own.
201          *
202          * @return      void
203          */
204         public function __destruct () {
205                 // Is this object already destroyed?
206                 if ($this->__toString() != 'DestructedObject') {
207                         // Destroy all informations about this class but keep some text about it alive
208                         $this->setRealClass('DestructedObject');
209                 } elseif ((defined('DEBUG_DESTRUCTOR')) && (is_object($this->getDebugInstance()))) {
210                         // Already destructed object
211                         self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('The object <span class="object_name">%s</span> is already destroyed.',
212                                 $this->__toString()
213                         ));
214                 } else {
215                         // Do not call this twice
216                         trigger_error(__METHOD__ . ': Called twice.');
217                         exit;
218                 }
219         }
220
221         /**
222          * The __call() method where all non-implemented methods end up
223          *
224          * @param       $methodName             Name of the missing method
225          * @args        $args                   Arguments passed to the method
226          * @return      void
227          */
228         public final function __call (string $methodName, array $args = NULL) {
229                 // Set self-instance
230                 self::$instance = $this;
231
232                 // Call static method
233                 self::__callStatic($methodName, $args);
234
235                 // Clear self-instance
236                 self::$instance = NULL;
237         }
238
239         /**
240          * The __callStatic() method where all non-implemented static methods end up
241          *
242          * @param       $methodName             Name of the missing method
243          * @param       $args                   Arguments passed to the method
244          * @return      void
245          * @throws      InvalidArgumentException If self::$instance is not a framework's own object
246          */
247         public static final function __callStatic (string $methodName, array $args = NULL) {
248                 // Init argument string and class name
249                 //* PRINT-DEBUG: */ printf('[%s:%d]: methodName=%s,args[]=%s - CALLED!' . PHP_EOL, __METHOD__, __LINE__, $methodName, gettype($args));
250                 $argsString = '';
251                 $className = 'unknown';
252
253                 // Is self-instance set?
254                 if (self::$instance instanceof FrameworkInterface) {
255                         // Framework's own instance
256                         $className = self::$instance->__toString();
257                 } elseif (!is_null(self::$instance)) {
258                         // Invalid argument!
259                         throw new InvalidArgumentException(sprintf('self::instance[%s] is not expected.', gettype(self::$instance)), self::EXCEPTION_SELF_INSTANCE);
260                 }
261
262                 // Is it NULL, empty or an array?
263                 if (is_null($args)) {
264                         // No arguments
265                         $argsString = 'NULL';
266                 } elseif (is_array($args)) {
267                         // Start braces
268                         $argsString = '(';
269
270                         // Some arguments are there
271                         foreach ($args as $arg) {
272                                 // Add data about the argument
273                                 $argsString .= gettype($arg) . ':';
274
275                                 if (is_null($arg)) {
276                                         // Found a NULL argument
277                                         $argsString .= 'NULL';
278                                 } elseif (is_string($arg)) {
279                                         // Add length for strings
280                                         $argsString .= strlen($arg);
281                                 } elseif ((is_int($arg)) || (is_float($arg))) {
282                                         // ... integer/float
283                                         $argsString .= $arg;
284                                 } elseif (is_array($arg)) {
285                                         // .. or size if array
286                                         $argsString .= count($arg);
287                                 } elseif (is_object($arg)) {
288                                         // Get reflection
289                                         $reflection = new ReflectionClass($arg);
290
291                                         // Is an other object, maybe no __toString() available
292                                         $argsString .= $reflection->getName();
293                                 } elseif ($arg === true) {
294                                         // ... is boolean 'true'
295                                         $argsString .= 'true';
296                                 } elseif ($arg === false) {
297                                         // ... is boolean 'false'
298                                         $argsString .= 'false';
299                                 }
300
301                                 // Comma for next one
302                                 $argsString .= ', ';
303                         }
304
305                         // Last comma found?
306                         if (substr($argsString, -2, 1) == ',') {
307                                 // Remove last comma
308                                 $argsString = substr($argsString, 0, -2);
309                         }
310
311                         // Close braces
312                         $argsString .= ')';
313                 }
314
315                 // Output stub message
316                 // @TODO __CLASS__ does always return BaseFrameworkSystem but not the extending (=child) class
317                 self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s::%s]: Stub! Args: %s',
318                         $className,
319                         $methodName,
320                         $argsString
321                 ));
322
323                 // Return nothing
324                 return NULL;
325         }
326
327         /**
328          * Getter for $realClass
329          *
330          * @return      $realClass The name of the real class (not BaseFrameworkSystem)
331          */
332         public function __toString () {
333                 return $this->realClass;
334         }
335
336         /**
337          * Magic method to catch setting of missing but set class fields/attributes
338          *
339          * @param       $name   Name of the field/attribute
340          * @param       $value  Value to store
341          * @return      void
342          */
343         public final function __set (string $name, $value) {
344                 $this->debugBackTrace(sprintf('Tried to set a missing field. name=%s, value[%s]=%s',
345                         $name,
346                         gettype($value),
347                         print_r($value, true)
348                 ));
349         }
350
351         /**
352          * Magic method to catch getting of missing fields/attributes
353          *
354          * @param       $name   Name of the field/attribute
355          * @return      void
356          */
357         public final function __get (string $name) {
358                 $this->debugBackTrace(sprintf('Tried to get a missing field. name=%s',
359                         $name
360                 ));
361         }
362
363         /**
364          * Magic method to catch unsetting of missing fields/attributes
365          *
366          * @param       $name   Name of the field/attribute
367          * @return      void
368          */
369         public final function __unset (string $name) {
370                 $this->debugBackTrace(sprintf('Tried to unset a missing field. name=%s',
371                         $name
372                 ));
373         }
374
375         /**
376          * Magic method to catch object serialization
377          *
378          * @return      $unsupported    Unsupported method
379          * @throws      UnsupportedOperationException   Objects of this framework cannot be serialized
380          */
381         public final function __sleep () {
382                 throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
383         }
384
385         /**
386          * Magic method to catch object deserialization
387          *
388          * @return      $unsupported    Unsupported method
389          * @throws      UnsupportedOperationException   Objects of this framework cannot be serialized
390          */
391         public final function __wakeup () {
392                 throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
393         }
394
395         /**
396          * Magic method to catch calls when an object instance is called
397          *
398          * @return      $unsupported    Unsupported method
399          * @throws      UnsupportedOperationException   Objects of this framework cannot be serialized
400          */
401         public final function __invoke () {
402                 throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
403         }
404
405         /**
406          * Setter for the real class name
407          *
408          * @param       $realClass      Class name (string)
409          * @return      void
410          */
411         public final function setRealClass (string $realClass) {
412                 // Set real class
413                 $this->realClass = $realClass;
414         }
415
416         /**
417          * Setter for debug instance
418          *
419          * @param       $debugInstance  The instance for debug output class
420          * @return      void
421          */
422         public final function setDebugInstance (DebugMiddleware $debugInstance) {
423                 GenericRegistry::getRegistry()->addInstance('debug', $debugInstance);
424         }
425
426         /**
427          * Getter for debug instance
428          *
429          * @return      $debugInstance  Instance to class DebugConsoleOutput or DebugWebOutput
430          */
431         public final function getDebugInstance () {
432                 // Get debug instance
433                 $debugInstance = GenericRegistry::getRegistry()->getInstance('debug');
434
435                 // Return it
436                 return $debugInstance;
437         }
438
439         /**
440          * Setter for web output instance
441          *
442          * @param       $webInstance    The instance for web output class
443          * @return      void
444          */
445         public final function setWebOutputInstance (OutputStreamer $webInstance) {
446                 GenericRegistry::getRegistry()->addInstance('web_output', $webInstance);
447         }
448
449         /**
450          * Getter for web output instance
451          *
452          * @return      $webOutputInstance - Instance to class WebOutput
453          */
454         public final function getWebOutputInstance () {
455                 $webOutputInstance = GenericRegistry::getRegistry()->getInstance('web_output');
456                 return $webOutputInstance;
457         }
458
459         /**
460          * Setter for DatabaseWrapper instance
461          *
462          * @param       $wrapperInstance        An instance of an DatabaseWrapper
463          * @return      void
464          */
465         public final function setWrapperInstance (DatabaseWrapper $wrapperInstance) {
466                 $this->wrapperInstance = $wrapperInstance;
467         }
468
469         /**
470          * Getter for DatabaseWrapper instance
471          *
472          * @return      $wrapperInstance        An instance of an DatabaseWrapper
473          */
474         public final function getWrapperInstance () {
475                 return $this->wrapperInstance;
476         }
477
478         /**
479          * Getter for a InputStream instance
480          *
481          * @param       $inputStreamInstance    The InputStream instance
482          */
483         protected final function getInputStreamInstance () {
484                 return $this->inputStreamInstance;
485         }
486
487         /**
488          * Setter for a InputStream instance
489          *
490          * @param       $inputStreamInstance    The InputStream instance
491          * @return      void
492          */
493         protected final function setInputStreamInstance (InputStream $inputStreamInstance) {
494                 $this->inputStreamInstance = $inputStreamInstance;
495         }
496
497         /**
498          * Getter for a OutputStream instance
499          *
500          * @param       $outputStreamInstance   The OutputStream instance
501          */
502         protected final function getOutputStreamInstance () {
503                 return $this->outputStreamInstance;
504         }
505
506         /**
507          * Setter for a OutputStream instance
508          *
509          * @param       $outputStreamInstance   The OutputStream instance
510          * @return      void
511          */
512         protected final function setOutputStreamInstance (OutputStream $outputStreamInstance) {
513                 $this->outputStreamInstance = $outputStreamInstance;
514         }
515
516         /**
517          * Setter for Iterator instance
518          *
519          * @param       $iteratorInstance       An instance of an Iterator
520          * @return      void
521          */
522         protected final function setIteratorInstance (Iterator $iteratorInstance) {
523                 $this->iteratorInstance = $iteratorInstance;
524         }
525
526         /**
527          * Getter for Iterator instance
528          *
529          * @return      $iteratorInstance       An instance of an Iterator
530          */
531         public final function getIteratorInstance () {
532                 return $this->iteratorInstance;
533         }
534
535         /**
536          * Setter for state instance
537          *
538          * @param       $stateInstance  A Stateable instance
539          * @return      void
540          */
541         public final function setStateInstance (Stateable $stateInstance) {
542                 $this->stateInstance = $stateInstance;
543         }
544
545         /**
546          * Getter for state instance
547          *
548          * @return      $stateInstance  A Stateable instance
549          */
550         public final function getStateInstance () {
551                 return $this->stateInstance;
552         }
553
554         /**
555          * Setter for call-back instance
556          *
557          * @param       $callbackInstance       An instance of a FrameworkInterface class
558          * @return      void
559          */
560         public final function setCallbackInstance (FrameworkInterface $callbackInstance) {
561                 $this->callbackInstance = $callbackInstance;
562         }
563
564         /**
565          * Getter for call-back instance
566          *
567          * @return      $callbackInstance       An instance of a FrameworkInterface class
568          */
569         protected final function getCallbackInstance () {
570                 return $this->callbackInstance;
571         }
572
573         /**
574          * Checks whether an object equals this object. You should overwrite this
575          * method to implement own equality checks
576          *
577          * @param       $objectInstance         An instance of a FrameworkInterface object
578          * @return      $equals                         Whether both objects equals
579          */
580         public function equals (FrameworkInterface $objectInstance) {
581                 // Now test it
582                 $equals = ((
583                         $this->__toString() == $objectInstance->__toString()
584                 ) && (
585                         $this->hashCode() == $objectInstance->hashCode()
586                 ));
587
588                 // Return the result
589                 return $equals;
590         }
591
592         /**
593          * Generates a generic hash code of this class. You should really overwrite
594          * this method with your own hash code generator code. But keep KISS in mind.
595          *
596          * @return      $hashCode       A generic hash code respresenting this whole class
597          */
598         public function hashCode () {
599                 // Simple hash code
600                 return crc32($this->__toString());
601         }
602
603         /**
604          * Appends a trailing slash to a string
605          *
606          * @param       $str    A string (maybe) without trailing slash
607          * @return      $str    A string with an auto-appended trailing slash
608          */
609         public final function addMissingTrailingSlash ($str) {
610                 // Is there a trailing slash?
611                 if (substr($str, -1, 1) != '/') {
612                         $str .= '/';
613                 }
614
615                 // Return string with trailing slash
616                 return $str;
617         }
618
619         /**
620          * Debugs this instance by putting out it's full content
621          *
622          * @param       $message        Optional message to show in debug output
623          * @return      void
624          */
625         public final function debugInstance ($message = '') {
626                 // Restore the error handler to avoid trouble with missing array elements or undeclared variables
627                 restore_error_handler();
628
629                 // Init content
630                 $content = '';
631
632                 // Is a message set?
633                 if (!empty($message)) {
634                         // Construct message
635                         $content = sprintf('<div class="debug_message">
636         Message: %s
637 </div>' . PHP_EOL, $message);
638                 }
639
640                 // Generate the output
641                 $content .= sprintf('<pre>%s</pre>',
642                         trim(
643                                 htmlentities(
644                                         print_r($this, true)
645                                 )
646                         )
647                 );
648
649                 // Output it
650                 ApplicationEntryPoint::exitApplication(sprintf('<div class="debug_header">
651         %s debug output:
652 </div>
653 <div class="debug_content">
654         %s
655 </div>
656 Loaded includes:
657 <div class="debug_include_list">
658         %s
659 </div>',
660                         $this->__toString(),
661                         $content,
662                         ClassLoader::getSelfInstance()->getPrintableIncludeList()
663                 ));
664         }
665
666         /**
667          * Replaces control characters with printable output
668          *
669          * @param       $str    String with control characters
670          * @return      $str    Replaced string
671          */
672         protected function replaceControlCharacters ($str) {
673                 // Replace them
674                 $str = str_replace(
675                         chr(13), '[r]', str_replace(
676                         chr(10), '[n]', str_replace(
677                         chr(9) , '[t]',
678                         $str
679                 )));
680
681                 // Return it
682                 return $str;
683         }
684
685         /**
686          * Output a partial stub message for the caller method
687          *
688          * @param       $message        An optional message to display
689          * @return      void
690          */
691         protected function partialStub ($message = '') {
692                 // Init variable
693                 $stubMessage = 'Partial stub!';
694
695                 // Is an extra message given?
696                 if (!empty($message)) {
697                         // Then add it as well
698                         $stubMessage .= ' Message: ' . $message;
699                 }
700
701                 // Debug instance is there?
702                 if (!is_null($this->getDebugInstance())) {
703                         // Output stub message
704                         self::createDebugInstance(__CLASS__, __LINE__)->debugOutput($stubMessage);
705                 } else {
706                         // Trigger an error
707                         trigger_error($stubMessage);
708                         exit;
709                 }
710         }
711
712         /**
713          * Outputs a debug backtrace and stops further script execution
714          *
715          * @param       $message        An optional message to output
716          * @param       $doExit         Whether exit the program (true is default)
717          * @return      void
718          */
719         public function debugBackTrace ($message = '', $doExit = true) {
720                 // Sorry, there is no other way getting this nice backtrace
721                 if (!empty($message)) {
722                         // Output message
723                         printf('Message: %s<br />' . PHP_EOL, $message);
724                 }
725
726                 print('<pre>');
727                 debug_print_backtrace();
728                 print('</pre>');
729
730                 // Exit program?
731                 if ($doExit === true) {
732                         exit();
733                 }
734         }
735
736         /**
737          * Creates an instance of a debugger instance
738          *
739          * @param       $className              Name of the class (currently unsupported)
740          * @param       $lineNumber             Line number where the call was made
741          * @return      $debugInstance  An instance of a debugger class
742          * @deprecated  Not fully, as the new Logger facilities are not finished yet.
743          */
744         public final static function createDebugInstance ($className, $lineNumber = NULL) {
745                 // Is the instance set?
746                 if (!GenericRegistry::getRegistry()->instanceExists('debug')) {
747                         // Init debug instance
748                         $debugInstance = NULL;
749
750                         // Try it
751                         try {
752                                 // Get a debugger instance
753                                 $debugInstance = DebugMiddleware::createDebugMiddleware(FrameworkBootstrap::getConfigurationInstance()->getConfigEntry('debug_' . FrameworkBootstrap::getRequestTypeFromSystem() . '_class'), $className);
754                         } catch (NullPointerException $e) {
755                                 // Didn't work, no instance there
756                                 exit(sprintf('Cannot create debugInstance! Exception=%s,message=%s,className=%s,lineNumber=%d' . PHP_EOL, $e->__toString(), $e->getMessage(), $className, $lineNumber));
757                         }
758
759                         // Empty string should be ignored and used for testing the middleware
760                         DebugMiddleware::getSelfInstance()->output('');
761
762                         // Set it in registry
763                         GenericRegistry::getRegistry()->addInstance('debug', $debugInstance);
764                 } else {
765                         // Get instance from registry
766                         $debugInstance = GenericRegistry::getRegistry()->getDebugInstance();
767                 }
768
769                 // Return it
770                 return $debugInstance;
771         }
772
773         /**
774          * Simple output of a message with line-break
775          *
776          * @param       $message        Message to output
777          * @return      void
778          */
779         public function outputLine ($message) {
780                 // Simply output it
781                 print($message . PHP_EOL);
782         }
783
784         /**
785          * Outputs a debug message whether to debug instance (should be set!) or
786          * dies with or ptints the message. Do NEVER EVER rewrite the exit() call to
787          * ApplicationEntryPoint::app_exit(), this would cause an endless loop.
788          *
789          * @param       $message        Message we shall send out...
790          * @param       $doPrint        Whether print or die here (default: print)
791          * @paran       $stripTags      Whether to strip tags (default: false)
792          * @return      void
793          */
794         public function debugOutput ($message, $doPrint = true, $stripTags = false) {
795                 // Set debug instance to NULL
796                 $debugInstance = NULL;
797
798                 // Get backtrace
799                 $backtrace = debug_backtrace(!DEBUG_BACKTRACE_PROVIDE_OBJECT);
800
801                 // Is function partialStub/__callStatic ?
802                 if (in_array($backtrace[1]['function'], array('partialStub', '__call', '__callStatic'))) {
803                         // Prepend class::function:line from 3rd element
804                         $message = sprintf('[%s::%s:%d]: %s',
805                                 $backtrace[2]['class'],
806                                 $backtrace[2]['function'],
807                                 (isset($backtrace[2]['line']) ? $backtrace[2]['line'] : '0'),
808                                 $message
809                         );
810                 } else {
811                         // Prepend class::function:line from 2nd element
812                         $message = sprintf('[%s::%s:%d]: %s',
813                                 $backtrace[1]['class'],
814                                 $backtrace[1]['function'],
815                                 (isset($backtrace[1]['line']) ? $backtrace[1]['line'] : '0'),
816                                 $message
817                         );
818                 }
819
820                 // Try it:
821                 try {
822                         // Get debug instance
823                         $debugInstance = $this->getDebugInstance();
824                 } catch (NullPointerException $e) {
825                         // The debug instance is not set (yet)
826                 }
827
828                 // Is the debug instance there?
829                 if (is_object($debugInstance)) {
830                         // Use debug output handler
831                         $debugInstance->output($message, $stripTags);
832
833                         if ($doPrint === false) {
834                                 // Die here if not printed
835                                 exit();
836                         }
837                 } else {
838                         // Are debug times enabled?
839                         if (FrameworkBootstrap::getConfigurationInstance()->getConfigEntry('debug_' . FrameworkBootstrap::getRequestTypeFromSystem() . '_output_timings') == 'Y') {
840                                 // Prepent it
841                                 $message = $this->getPrintableExecutionTime() . $message;
842                         }
843
844                         // Put directly out
845                         if ($doPrint === true) {
846                                 // Print message
847                                 $this->outputLine($message);
848                         } else {
849                                 // Die here
850                                 exit($message);
851                         }
852                 }
853         }
854
855         /**
856          * Marks up the code by adding e.g. line numbers
857          *
858          * @param       $phpCode                Unmarked PHP code
859          * @return      $markedCode             Marked PHP code
860          */
861         public function markupCode ($phpCode) {
862                 // Init marked code
863                 $markedCode = '';
864
865                 // Get last error
866                 $errorArray = error_get_last();
867
868                 // Init the code with error message
869                 if (is_array($errorArray)) {
870                         // Get error infos
871                         $markedCode = sprintf('<div id="error_header">File: <span id="error_data">%s</span>, Line: <span id="error_data">%s</span>, Message: <span id="error_data">%s</span>, Type: <span id="error_data">%s</span></div>',
872                                 basename($errorArray['file']),
873                                 $errorArray['line'],
874                                 $errorArray['message'],
875                                 $errorArray['type']
876                         );
877                 }
878
879                 // Add line number to the code
880                 foreach (explode(chr(10), $phpCode) as $lineNo => $code) {
881                         // Add line numbers
882                         $markedCode .= sprintf('<span id="code_line">%s</span>: %s' . PHP_EOL,
883                                 ($lineNo + 1),
884                                 htmlentities($code, ENT_QUOTES)
885                         );
886                 }
887
888                 // Return the code
889                 return $markedCode;
890         }
891
892         /**
893          * "Getter" for databse entry
894          *
895          * @return      $entry  An array with database entries
896          * @throws      NullPointerException    If the database result is not found
897          * @throws      InvalidDatabaseResultException  If the database result is invalid
898          * @todo        Monolithic method, should be moved to proper classes
899          */
900         protected final function getDatabaseEntry () {
901                 // Is there an instance?
902                 if (!$this->getResultInstance() instanceof SearchableResult) {
903                         // Throw an exception here
904                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
905                 }
906
907                 // Rewind it
908                 $this->getResultInstance()->rewind();
909
910                 // Do we have an entry?
911                 if ($this->getResultInstance()->valid() === false) {
912                         // @TODO Move the constant to e.g. BaseDatabaseResult when there is a non-cached database result available
913                         throw new InvalidDatabaseResultException(array($this, $this->getResultInstance()), CachedDatabaseResult::EXCEPTION_INVALID_DATABASE_RESULT);
914                 }
915
916                 // Get next entry
917                 $this->getResultInstance()->next();
918
919                 // Fetch it
920                 $entry = $this->getResultInstance()->current();
921
922                 // And return it
923                 return $entry;
924         }
925
926         /**
927          * Getter for field name
928          *
929          * @param       $fieldName              Field name which we shall get
930          * @return      $fieldValue             Field value from the user
931          * @throws      NullPointerException    If the result instance is null
932          */
933         public final function getField (string $fieldName) {
934                 // Default field value
935                 $fieldValue = NULL;
936
937                 // Get result instance
938                 $resultInstance = $this->getResultInstance();
939
940                 // Is this instance null?
941                 if (is_null($resultInstance)) {
942                         // Then the user instance is no longer valid (expired cookies?)
943                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
944                 }
945
946                 // Get current array
947                 $fieldArray = $resultInstance->current();
948                 //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput($fieldName.':<pre>'.print_r($fieldArray, true).'</pre>');
949
950                 // Convert dashes to underscore
951                 $fieldName2 = StringUtils::convertDashesToUnderscores($fieldName);
952
953                 // Does the field exist?
954                 if ($this->isFieldSet($fieldName)) {
955                         // Get it
956                         $fieldValue = $fieldArray[$fieldName2];
957                 } elseif (defined('DEVELOPER')) {
958                         // Missing field entry, may require debugging
959                         self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']:fieldArray<pre>=' . print_r($fieldArray, true) . '</pre>,fieldName=' . $fieldName . ' not found!');
960                 } else {
961                         // Missing field entry, may require debugging
962                         self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']:fieldName=' . $fieldName . ' not found!');
963                 }
964
965                 // Return it
966                 return $fieldValue;
967         }
968
969         /**
970          * Checks if given field is set
971          *
972          * @param       $fieldName      Field name to check
973          * @return      $isSet          Whether the given field name is set
974          * @throws      NullPointerException    If the result instance is null
975          */
976         public function isFieldSet (string $fieldName) {
977                 // Get result instance
978                 $resultInstance = $this->getResultInstance();
979
980                 // Is this instance null?
981                 if (is_null($resultInstance)) {
982                         // Then the user instance is no longer valid (expired cookies?)
983                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
984                 }
985
986                 // Get current array
987                 $fieldArray = $resultInstance->current();
988                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('[' . $this->__toString() . ':' . __LINE__ . '] fieldName=' . $fieldName . ',fieldArray=<pre>'.print_r($fieldArray, true).'</pre>');
989
990                 // Convert dashes to underscore
991                 $fieldName = StringUtils::convertDashesToUnderscores($fieldName);
992
993                 // Determine it
994                 $isSet = isset($fieldArray[$fieldName]);
995
996                 // Return result
997                 return $isSet;
998         }
999
1000         /**
1001          * Outputs a deprecation warning to the developer.
1002          *
1003          * @param       $message        The message we shall output to the developer
1004          * @return      void
1005          * @todo        Write a logging mechanism for productive mode
1006          */
1007         public function deprecationWarning ($message) {
1008                 // Is developer mode active?
1009                 if (defined('DEVELOPER')) {
1010                         // Debug instance is there?
1011                         if (!is_null($this->getDebugInstance())) {
1012                                 // Output stub message
1013                                 self::createDebugInstance(__CLASS__, __LINE__)->debugOutput($message);
1014                         } else {
1015                                 // Trigger an error
1016                                 trigger_error($message . "<br />\n");
1017                                 exit;
1018                         }
1019                 } else {
1020                         // @TODO Finish this part!
1021                         $this->partialStub('Developer mode inactive. Message:' . $message);
1022                 }
1023         }
1024
1025         /**
1026          * Checks whether the given PHP extension is loaded
1027          *
1028          * @param       $phpExtension   The PHP extension we shall check
1029          * @return      $isLoaded       Whether the PHP extension is loaded
1030          */
1031         public final function isPhpExtensionLoaded ($phpExtension) {
1032                 // Is it loaded?
1033                 $isLoaded = in_array($phpExtension, get_loaded_extensions());
1034
1035                 // Return result
1036                 return $isLoaded;
1037         }
1038
1039         /**
1040          * "Getter" as a time() replacement but with milliseconds. You should use this
1041          * method instead of the encapsulated getimeofday() function.
1042          *
1043          * @return      $milliTime      Timestamp with milliseconds
1044          */
1045         public function getMilliTime () {
1046                 // Get the time of day as float
1047                 $milliTime = gettimeofday(true);
1048
1049                 // Return it
1050                 return $milliTime;
1051         }
1052
1053         /**
1054          * Idles (sleeps) for given milliseconds
1055          *
1056          * @return      $hasSlept       Whether it goes fine
1057          */
1058         public function idle ($milliSeconds) {
1059                 // Sleep is fine by default
1060                 $hasSlept = true;
1061
1062                 // Idle so long with found function
1063                 if (function_exists('time_sleep_until')) {
1064                         // Get current time and add idle time
1065                         $sleepUntil = $this->getMilliTime() + abs($milliSeconds) / 1000;
1066
1067                         // New PHP 5.1.0 function found, ignore errors
1068                         $hasSlept = @time_sleep_until($sleepUntil);
1069                 } else {
1070                         /*
1071                          * My Sun station doesn't have that function even with latest PHP
1072                          * package. :(
1073                          */
1074                         usleep($milliSeconds * 1000);
1075                 }
1076
1077                 // Return result
1078                 return $hasSlept;
1079         }
1080
1081         /**
1082          * Checks whether the given encoded data was encoded with Base64
1083          *
1084          * @param       $encodedData    Encoded data we shall check
1085          * @return      $isBase64               Whether the encoded data is Base64
1086          */
1087         protected function isBase64Encoded ($encodedData) {
1088                 // Determine it
1089                 $isBase64 = (@base64_decode($encodedData, true) !== false);
1090
1091                 // Return it
1092                 return $isBase64;
1093         }
1094
1095         /**
1096          * Gets a cache key from Criteria instance
1097          *
1098          * @param       $criteriaInstance       An instance of a Criteria class
1099          * @param       $onlyKeys                       Only use these keys for a cache key
1100          * @return      $cacheKey                       A cache key suitable for lookup/storage purposes
1101          */
1102         protected function getCacheKeyByCriteria (Criteria $criteriaInstance, array $onlyKeys = []) {
1103                 // Generate it
1104                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-FRAMEWORK-SYSTEM: criteriaInstance=' . $criteriaInstance->__toString() . ',onlyKeys()=' . count($onlyKeys) . ' - CALLED!');
1105                 $cacheKey = sprintf('%s@%s',
1106                         $this->__toString(),
1107                         $criteriaInstance->getCacheKey($onlyKeys)
1108                 );
1109
1110                 // And return it
1111                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-FRAMEWORK-SYSTEM: cacheKey=' . $cacheKey . ' - EXIT!');
1112                 return $cacheKey;
1113         }
1114
1115         /**
1116          * Getter for startup time in miliseconds
1117          *
1118          * @return      $startupTime    Startup time in miliseconds
1119          */
1120         protected function getStartupTime () {
1121                 return self::$startupTime;
1122         }
1123
1124         /**
1125          * "Getter" for a printable currently execution time in nice braces
1126          *
1127          * @return      $executionTime  Current execution time in nice braces
1128          */
1129         protected function getPrintableExecutionTime () {
1130                 // Caculate the execution time
1131                 $executionTime = microtime(true) - $this->getStartupTime();
1132
1133                 // Pack it in nice braces
1134                 $executionTime = sprintf('[ %01.5f ] ', $executionTime);
1135
1136                 // And return it
1137                 return $executionTime;
1138         }
1139
1140         /**
1141          * Hashes a given string with a simple but stronger hash function (no salt)
1142          * and hex-encode it.
1143          *
1144          * @param       $str    The string to be hashed
1145          * @return      $hash   The hash from string $str
1146          */
1147         public static final function hash ($str) {
1148                 // Hash given string with (better secure) hasher
1149                 $hash = bin2hex(mhash(MHASH_SHA256, $str));
1150
1151                 // Return it
1152                 return $hash;
1153         }
1154
1155         /**
1156          * "Getter" for length of hash() output. This will be "cached" to speed up
1157          * things.
1158          *
1159          * @return      $length         Length of hash() output
1160          */
1161         public static final function getHashLength () {
1162                 // Is it cashed?
1163                 if (is_null(self::$hashLength)) {
1164                         // No, then hash a string and save its length.
1165                         self::$hashLength = strlen(self::hash('abc123'));
1166                 }
1167
1168                 // Return it
1169                 return self::$hashLength;
1170         }
1171
1172         /**
1173          * Checks whether the given number is really a number (only chars 0-9).
1174          *
1175          * @param       $num            A string consisting only chars between 0 and 9
1176          * @param       $castValue      Whether to cast the value to double. Do only use this to secure numbers from Requestable classes.
1177          * @param       $assertMismatch         Whether to assert mismatches
1178          * @return      $ret            The (hopefully) secured numbered value
1179          */
1180         public function bigintval ($num, $castValue = true, $assertMismatch = false) {
1181                 // Filter all numbers out
1182                 $ret = preg_replace('/[^0123456789]/', '', $num);
1183
1184                 // Shall we cast?
1185                 if ($castValue === true) {
1186                         // Cast to biggest numeric type
1187                         $ret = (double) $ret;
1188                 }
1189
1190                 // Assert only if requested
1191                 if ($assertMismatch === true) {
1192                         // Has the whole value changed?
1193                         assert(('' . $ret . '' != '' . $num . '') && (!is_null($num)));
1194                 }
1195
1196                 // Return result
1197                 return $ret;
1198         }
1199
1200         /**
1201          * Checks whether the given hexadecimal number is really a hex-number (only chars 0-9,a-f).
1202          *
1203          * @param       $num    A string consisting only chars between 0 and 9
1204          * @param       $assertMismatch         Whether to assert mismatches
1205          * @return      $ret    The (hopefully) secured hext-numbered value
1206          */
1207         public function hexval ($num, $assertMismatch = false) {
1208                 // Filter all numbers out
1209                 $ret = preg_replace('/[^0123456789abcdefABCDEF]/', '', $num);
1210
1211                 // Assert only if requested
1212                 if ($assertMismatch === true) {
1213                         // Has the whole value changed?
1214                         assert(('' . $ret . '' != '' . $num . '') && (!is_null($num)));
1215                 }
1216
1217                 // Return result
1218                 return $ret;
1219         }
1220
1221         /**
1222          * Determines if an element is set in the generic array
1223          *
1224          * @param       $keyGroup       Main group for the key
1225          * @param       $subGroup       Sub group for the key
1226          * @param       $key            Key to check
1227          * @param       $element        Element to check
1228          * @return      $isset          Whether the given key is set
1229          */
1230         protected final function isGenericArrayElementSet ($keyGroup, $subGroup, $key, $element) {
1231                 // Debug message
1232                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element);
1233
1234                 // Is it there?
1235                 $isset = isset($this->genericArray[$keyGroup][$subGroup][$key][$element]);
1236
1237                 // Return it
1238                 return $isset;
1239         }
1240         /**
1241          * Determines if a key is set in the generic array
1242          *
1243          * @param       $keyGroup       Main group for the key
1244          * @param       $subGroup       Sub group for the key
1245          * @param       $key            Key to check
1246          * @return      $isset          Whether the given key is set
1247          */
1248         protected final function isGenericArrayKeySet ($keyGroup, $subGroup, $key) {
1249                 // Debug message
1250                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1251
1252                 // Is it there?
1253                 $isset = isset($this->genericArray[$keyGroup][$subGroup][$key]);
1254
1255                 // Return it
1256                 return $isset;
1257         }
1258
1259
1260         /**
1261          * Determines if a group is set in the generic array
1262          *
1263          * @param       $keyGroup       Main group
1264          * @param       $subGroup       Sub group
1265          * @return      $isset          Whether the given group is set
1266          */
1267         protected final function isGenericArrayGroupSet ($keyGroup, $subGroup) {
1268                 // Debug message
1269                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup);
1270
1271                 // Is it there?
1272                 $isset = isset($this->genericArray[$keyGroup][$subGroup]);
1273
1274                 // Return it
1275                 return $isset;
1276         }
1277
1278         /**
1279          * Getter for sub key group
1280          *
1281          * @param       $keyGroup       Main key group
1282          * @param       $subGroup       Sub key group
1283          * @return      $array          An array with all array elements
1284          */
1285         protected final function getGenericSubArray ($keyGroup, $subGroup) {
1286                 // Is it there?
1287                 if (!$this->isGenericArrayGroupSet($keyGroup, $subGroup)) {
1288                         // No, then abort here
1289                         trigger_error(__METHOD__ . ': keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ' not found.');
1290                         exit;
1291                 }
1292
1293                 // Debug message
1294                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',value=' . print_r($this->genericArray[$keyGroup][$subGroup], true));
1295
1296                 // Return it
1297                 return $this->genericArray[$keyGroup][$subGroup];
1298         }
1299
1300         /**
1301          * Unsets a given key in generic array
1302          *
1303          * @param       $keyGroup       Main group for the key
1304          * @param       $subGroup       Sub group for the key
1305          * @param       $key            Key to unset
1306          * @return      void
1307          */
1308         protected final function unsetGenericArrayKey ($keyGroup, $subGroup, $key) {
1309                 // Debug message
1310                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1311
1312                 // Remove it
1313                 unset($this->genericArray[$keyGroup][$subGroup][$key]);
1314         }
1315
1316         /**
1317          * Unsets a given element in generic array
1318          *
1319          * @param       $keyGroup       Main group for the key
1320          * @param       $subGroup       Sub group for the key
1321          * @param       $key            Key to unset
1322          * @param       $element        Element to unset
1323          * @return      void
1324          */
1325         protected final function unsetGenericArrayElement ($keyGroup, $subGroup, $key, $element) {
1326                 // Debug message
1327                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element);
1328
1329                 // Remove it
1330                 unset($this->genericArray[$keyGroup][$subGroup][$key][$element]);
1331         }
1332
1333         /**
1334          * Append a string to a given generic array key
1335          *
1336          * @param       $keyGroup       Main group for the key
1337          * @param       $subGroup       Sub group for the key
1338          * @param       $key            Key to unset
1339          * @param       $value          Value to add/append
1340          * @return      void
1341          */
1342         protected final function appendStringToGenericArrayKey ($keyGroup, $subGroup, $key, $value, $appendGlue = '') {
1343                 // Debug message
1344                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',value[' . gettype($value) . ']=' . print_r($value, true) . ',appendGlue=' . $appendGlue);
1345
1346                 // Is it already there?
1347                 if ($this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) {
1348                         // Append it
1349                         $this->genericArray[$keyGroup][$subGroup][$key] .= $appendGlue . (string) $value;
1350                 } else {
1351                         // Add it
1352                         $this->genericArray[$keyGroup][$subGroup][$key] = (string) $value;
1353                 }
1354         }
1355
1356         /**
1357          * Append a string to a given generic array element
1358          *
1359          * @param       $keyGroup       Main group for the key
1360          * @param       $subGroup       Sub group for the key
1361          * @param       $key            Key to unset
1362          * @param       $element        Element to check
1363          * @param       $value          Value to add/append
1364          * @return      void
1365          */
1366         protected final function appendStringToGenericArrayElement ($keyGroup, $subGroup, $key, $element, $value, $appendGlue = '') {
1367                 // Debug message
1368                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element . ',value[' . gettype($value) . ']=' . print_r($value, true) . ',appendGlue=' . $appendGlue);
1369
1370                 // Is it already there?
1371                 if ($this->isGenericArrayElementSet($keyGroup, $subGroup, $key, $element)) {
1372                         // Append it
1373                         $this->genericArray[$keyGroup][$subGroup][$key][$element] .= $appendGlue . (string) $value;
1374                 } else {
1375                         // Add it
1376                         $this->setStringGenericArrayElement($keyGroup, $subGroup, $key, $element, $value);
1377                 }
1378         }
1379
1380         /**
1381          * Sets a string in a given generic array element
1382          *
1383          * @param       $keyGroup       Main group for the key
1384          * @param       $subGroup       Sub group for the key
1385          * @param       $key            Key to unset
1386          * @param       $element        Element to check
1387          * @param       $value          Value to add/append
1388          * @return      void
1389          */
1390         protected final function setStringGenericArrayElement ($keyGroup, $subGroup, $key, $element, $value, $appendGlue = '') {
1391                 // Debug message
1392                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element . ',value[' . gettype($value) . ']=' . print_r($value, true) . ',appendGlue=' . $appendGlue);
1393
1394                 // Set it
1395                 $this->genericArray[$keyGroup][$subGroup][$key][$element] = (string) $value;
1396         }
1397
1398         /**
1399          * Initializes given generic array group
1400          *
1401          * @param       $keyGroup       Main group for the key
1402          * @param       $subGroup       Sub group for the key
1403          * @param       $key            Key to use
1404          * @param       $forceInit      Optionally force initialization
1405          * @return      void
1406          */
1407         protected final function initGenericArrayGroup ($keyGroup, $subGroup, $forceInit = false) {
1408                 // Debug message
1409                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',forceInit=' . intval($forceInit));
1410
1411                 // Is it already set?
1412                 if (($forceInit === false) && ($this->isGenericArrayGroupSet($keyGroup, $subGroup))) {
1413                         // Already initialized
1414                         trigger_error(__METHOD__ . ':keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ' already initialized.');
1415                         exit;
1416                 }
1417
1418                 // Initialize it
1419                 $this->genericArray[$keyGroup][$subGroup] = [];
1420         }
1421
1422         /**
1423          * Initializes given generic array key
1424          *
1425          * @param       $keyGroup       Main group for the key
1426          * @param       $subGroup       Sub group for the key
1427          * @param       $key            Key to use
1428          * @param       $forceInit      Optionally force initialization
1429          * @return      void
1430          */
1431         protected final function initGenericArrayKey ($keyGroup, $subGroup, $key, $forceInit = false) {
1432                 // Debug message
1433                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',forceInit=' . intval($forceInit));
1434
1435                 // Is it already set?
1436                 if (($forceInit === false) && ($this->isGenericArrayKeySet($keyGroup, $subGroup, $key))) {
1437                         // Already initialized
1438                         trigger_error(__METHOD__ . ':keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ' already initialized.');
1439                         exit;
1440                 }
1441
1442                 // Initialize it
1443                 $this->genericArray[$keyGroup][$subGroup][$key] = [];
1444         }
1445
1446         /**
1447          * Initializes given generic array element
1448          *
1449          * @param       $keyGroup       Main group for the key
1450          * @param       $subGroup       Sub group for the key
1451          * @param       $key            Key to use
1452          * @param       $element        Element to use
1453          * @param       $forceInit      Optionally force initialization
1454          * @return      void
1455          */
1456         protected final function initGenericArrayElement ($keyGroup, $subGroup, $key, $element, $forceInit = false) {
1457                 // Debug message
1458                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element . ',forceInit=' . intval($forceInit));
1459
1460                 // Is it already set?
1461                 if (($forceInit === false) && ($this->isGenericArrayElementSet($keyGroup, $subGroup, $key, $element))) {
1462                         // Already initialized
1463                         trigger_error(__METHOD__ . ':keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element . ' already initialized.');
1464                         exit;
1465                 }
1466
1467                 // Initialize it
1468                 $this->genericArray[$keyGroup][$subGroup][$key][$element] = [];
1469         }
1470
1471         /**
1472          * Pushes an element to a generic key
1473          *
1474          * @param       $keyGroup       Main group for the key
1475          * @param       $subGroup       Sub group for the key
1476          * @param       $key            Key to use
1477          * @param       $value          Value to add/append
1478          * @return      $count          Number of array elements
1479          */
1480         protected final function pushValueToGenericArrayKey ($keyGroup, $subGroup, $key, $value) {
1481                 // Debug message
1482                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',value[' . gettype($value) . ']=' . print_r($value, true));
1483
1484                 // Is it set?
1485                 if (!$this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) {
1486                         // Initialize array
1487                         $this->initGenericArrayKey($keyGroup, $subGroup, $key);
1488                 }
1489
1490                 // Then push it
1491                 $count = array_push($this->genericArray[$keyGroup][$subGroup][$key], $value);
1492
1493                 // Return count
1494                 //* DEBUG: */ print(__METHOD__ . ': genericArray=' . print_r($this->genericArray[$keyGroup][$subGroup][$key], true));
1495                 //* DEBUG: */ print(__METHOD__ . ': count=' . $count . PHP_EOL);
1496                 return $count;
1497         }
1498
1499         /**
1500          * Pushes an element to a generic array element
1501          *
1502          * @param       $keyGroup       Main group for the key
1503          * @param       $subGroup       Sub group for the key
1504          * @param       $key            Key to use
1505          * @param       $element        Element to check
1506          * @param       $value          Value to add/append
1507          * @return      $count          Number of array elements
1508          */
1509         protected final function pushValueToGenericArrayElement ($keyGroup, $subGroup, $key, $element, $value) {
1510                 // Debug message
1511                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element . ',value[' . gettype($value) . ']=' . print_r($value, true));
1512
1513                 // Is it set?
1514                 if (!$this->isGenericArrayElementSet($keyGroup, $subGroup, $key, $element)) {
1515                         // Initialize array
1516                         $this->initGenericArrayElement($keyGroup, $subGroup, $key, $element);
1517                 }
1518
1519                 // Then push it
1520                 $count = array_push($this->genericArray[$keyGroup][$subGroup][$key][$element], $value);
1521
1522                 // Return count
1523                 //* DEBUG: */ print(__METHOD__ . ': genericArray=' . print_r($this->genericArray[$keyGroup][$subGroup][$key], true));
1524                 //* DEBUG: */ print(__METHOD__ . ': count=' . $count . PHP_EOL);
1525                 return $count;
1526         }
1527
1528         /**
1529          * Pops an element from  a generic group
1530          *
1531          * @param       $keyGroup       Main group for the key
1532          * @param       $subGroup       Sub group for the key
1533          * @param       $key            Key to unset
1534          * @return      $value          Last "popped" value
1535          */
1536         protected final function popGenericArrayElement ($keyGroup, $subGroup, $key) {
1537                 // Debug message
1538                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1539
1540                 // Is it set?
1541                 if (!$this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) {
1542                         // Not found
1543                         trigger_error(__METHOD__ . ': keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ' not found.');
1544                         exit;
1545                 }
1546
1547                 // Then "pop" it
1548                 $value = array_pop($this->genericArray[$keyGroup][$subGroup][$key]);
1549
1550                 // Return value
1551                 //* DEBUG: */ print(__METHOD__ . ': genericArray=' . print_r($this->genericArray[$keyGroup][$subGroup][$key], true));
1552                 //* DEBUG: */ print(__METHOD__ . ': value[' . gettype($value) . ']=' . print_r($value, true) . PHP_EOL);
1553                 return $value;
1554         }
1555
1556         /**
1557          * Shifts an element from  a generic group
1558          *
1559          * @param       $keyGroup       Main group for the key
1560          * @param       $subGroup       Sub group for the key
1561          * @param       $key            Key to unset
1562          * @return      $value          Last "popped" value
1563          */
1564         protected final function shiftGenericArrayElement ($keyGroup, $subGroup, $key) {
1565                 // Debug message
1566                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1567
1568                 // Is it set?
1569                 if (!$this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) {
1570                         // Not found
1571                         trigger_error(__METHOD__ . ': keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ' not found.');
1572                         exit;
1573                 }
1574
1575                 // Then "shift" it
1576                 $value = array_shift($this->genericArray[$keyGroup][$subGroup][$key]);
1577
1578                 // Return value
1579                 //* DEBUG: */ print(__METHOD__ . ': genericArray=' . print_r($this->genericArray[$keyGroup][$subGroup][$key], true));
1580                 //* DEBUG: */ print(__METHOD__ . ': value[' . gettype($value) . ']=' . print_r($value, true) . PHP_EOL);
1581                 return $value;
1582         }
1583
1584         /**
1585          * Count generic array group
1586          *
1587          * @param       $keyGroup       Main group for the key
1588          * @return      $count          Count of given group
1589          */
1590         protected final function countGenericArray ($keyGroup) {
1591                 // Debug message
1592                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup);
1593
1594                 // Is it there?
1595                 if (!isset($this->genericArray[$keyGroup])) {
1596                         // Abort here
1597                         trigger_error(__METHOD__ . ': keyGroup=' . $keyGroup . ' not found.');
1598                         exit;
1599                 }
1600
1601                 // Then count it
1602                 $count = count($this->genericArray[$keyGroup]);
1603
1604                 // Debug message
1605                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',count=' . $count);
1606
1607                 // Return it
1608                 return $count;
1609         }
1610
1611         /**
1612          * Count generic array sub group
1613          *
1614          * @param       $keyGroup       Main group for the key
1615          * @param       $subGroup       Sub group for the key
1616          * @return      $count          Count of given group
1617          */
1618         protected final function countGenericArrayGroup ($keyGroup, $subGroup) {
1619                 // Debug message
1620                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup);
1621
1622                 // Is it there?
1623                 if (!$this->isGenericArrayGroupSet($keyGroup, $subGroup)) {
1624                         // Abort here
1625                         trigger_error(__METHOD__ . ': keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ' not found.');
1626                         exit;
1627                 }
1628
1629                 // Then count it
1630                 $count = count($this->genericArray[$keyGroup][$subGroup]);
1631
1632                 // Debug message
1633                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',count=' . $count);
1634
1635                 // Return it
1636                 return $count;
1637         }
1638
1639         /**
1640          * Count generic array elements
1641          *
1642          * @param       $keyGroup       Main group for the key
1643          * @param       $subGroup       Sub group for the key
1644          * @para        $key            Key to count
1645          * @return      $count          Count of given key
1646          */
1647         protected final function countGenericArrayElements ($keyGroup, $subGroup, $key) {
1648                 // Debug message
1649                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1650
1651                 // Is it there?
1652                 if (!$this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) {
1653                         // Abort here
1654                         trigger_error(__METHOD__ . ': keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ' not found.');
1655                         exit;
1656                 } elseif (!$this->isValidGenericArrayGroup($keyGroup, $subGroup)) {
1657                         // Not valid
1658                         trigger_error(__METHOD__ . ': keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ' is not an array.');
1659                         exit;
1660                 }
1661
1662                 // Then count it
1663                 $count = count($this->genericArray[$keyGroup][$subGroup][$key]);
1664
1665                 // Debug message
1666                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',count=' . $count);
1667
1668                 // Return it
1669                 return $count;
1670         }
1671
1672         /**
1673          * Getter for whole generic group array
1674          *
1675          * @param       $keyGroup       Key group to get
1676          * @return      $array          Whole generic array group
1677          */
1678         protected final function getGenericArray ($keyGroup) {
1679                 // Debug message
1680                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup);
1681
1682                 // Is it there?
1683                 if (!isset($this->genericArray[$keyGroup])) {
1684                         // Then abort here
1685                         trigger_error(__METHOD__ . ': keyGroup=' . $keyGroup . ' does not exist.');
1686                         exit;
1687                 }
1688
1689                 // Return it
1690                 return $this->genericArray[$keyGroup];
1691         }
1692
1693         /**
1694          * Setter for generic array key
1695          *
1696          * @param       $keyGroup       Key group to get
1697          * @param       $subGroup       Sub group for the key
1698          * @param       $key            Key to unset
1699          * @param       $value          Mixed value from generic array element
1700          * @return      void
1701          */
1702         protected final function setGenericArrayKey ($keyGroup, $subGroup, $key, $value) {
1703                 // Debug message
1704                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',value[' . gettype($value) . ']=' . print_r($value, true));
1705
1706                 // Set value here
1707                 $this->genericArray[$keyGroup][$subGroup][$key] = $value;
1708         }
1709
1710         /**
1711          * Getter for generic array key
1712          *
1713          * @param       $keyGroup       Key group to get
1714          * @param       $subGroup       Sub group for the key
1715          * @param       $key            Key to unset
1716          * @return      $value          Mixed value from generic array element
1717          */
1718         protected final function getGenericArrayKey ($keyGroup, $subGroup, $key) {
1719                 // Debug message
1720                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1721
1722                 // Is it there?
1723                 if (!$this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) {
1724                         // Then abort here
1725                         trigger_error(__METHOD__ . ': keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ' does not exist.');
1726                         exit;
1727                 }
1728
1729                 // Return it
1730                 return $this->genericArray[$keyGroup][$subGroup][$key];
1731         }
1732
1733         /**
1734          * Sets a value in given generic array key/element
1735          *
1736          * @param       $keyGroup       Main group for the key
1737          * @param       $subGroup       Sub group for the key
1738          * @param       $key            Key to set
1739          * @param       $element        Element to set
1740          * @param       $value          Value to set
1741          * @return      void
1742          */
1743         protected final function setGenericArrayElement ($keyGroup, $subGroup, $key, $element, $value) {
1744                 // Debug message
1745                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element . ',value[' . gettype($value) . ']=' . print_r($value, true));
1746
1747                 // Then set it
1748                 $this->genericArray[$keyGroup][$subGroup][$key][$element] = $value;
1749         }
1750
1751         /**
1752          * Getter for generic array element
1753          *
1754          * @param       $keyGroup       Key group to get
1755          * @param       $subGroup       Sub group for the key
1756          * @param       $key            Key to look for
1757          * @param       $element        Element to look for
1758          * @return      $value          Mixed value from generic array element
1759          */
1760         protected final function getGenericArrayElement ($keyGroup, $subGroup, $key, $element) {
1761                 // Debug message
1762                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element);
1763
1764                 // Is it there?
1765                 if (!$this->isGenericArrayElementSet($keyGroup, $subGroup, $key, $element)) {
1766                         // Then abort here
1767                         trigger_error(__METHOD__ . ': keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element . ' does not exist.');
1768                         exit;
1769                 }
1770
1771                 // Return it
1772                 return $this->genericArray[$keyGroup][$subGroup][$key][$element];
1773         }
1774
1775         /**
1776          * Checks if a given sub group is valid (array)
1777          *
1778          * @param       $keyGroup       Key group to get
1779          * @param       $subGroup       Sub group for the key
1780          * @return      $isValid        Whether given sub group is valid
1781          */
1782         protected final function isValidGenericArrayGroup ($keyGroup, $subGroup) {
1783                 // Debug message
1784                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup);
1785
1786                 // Determine it
1787                 $isValid = (($this->isGenericArrayGroupSet($keyGroup, $subGroup)) && (is_array($this->getGenericSubArray($keyGroup, $subGroup))));
1788
1789                 // Return it
1790                 return $isValid;
1791         }
1792
1793         /**
1794          * Checks if a given key is valid (array)
1795          *
1796          * @param       $keyGroup       Key group to get
1797          * @param       $subGroup       Sub group for the key
1798          * @param       $key            Key to check
1799          * @return      $isValid        Whether given sub group is valid
1800          */
1801         protected final function isValidGenericArrayKey ($keyGroup, $subGroup, $key) {
1802                 // Debug message
1803                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1804
1805                 // Determine it
1806                 $isValid = (($this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) && (is_array($this->getGenericArrayKey($keyGroup, $subGroup, $key))));
1807
1808                 // Return it
1809                 return $isValid;
1810         }
1811
1812         /**
1813          * Initializes the web output instance
1814          *
1815          * @return      void
1816          */
1817         protected function initWebOutputInstance () {
1818                 // Get application instance
1819                 $applicationInstance = GenericRegistry::getRegistry()->getInstance('application');
1820
1821                 // Init web output instance
1822                 $outputInstance = ObjectFactory::createObjectByConfiguredName('output_class', array($applicationInstance));
1823
1824                 // Set it locally
1825                 $this->setWebOutputInstance($outputInstance);
1826         }
1827
1828         /**
1829          * Translates boolean true to 'Y' and false to 'N'
1830          *
1831          * @param       $boolean                Boolean value
1832          * @return      $translated             Translated boolean value
1833          */
1834         public static final function translateBooleanToYesNo (bool $boolean) {
1835                 // Make sure it is really boolean
1836                 assert(is_bool($boolean));
1837
1838                 // "Translate" it
1839                 $translated = ($boolean === true) ? 'Y' : 'N';
1840
1841                 // ... and return it
1842                 return $translated;
1843         }
1844
1845         /**
1846          * Creates a full-qualified file name (FQFN) for given file name by adding
1847          * a configured temporary file path to it.
1848          *
1849          * @param       $infoInstance   An instance of a SplFileInfo class
1850          * @return      $tempInstance   An instance of a SplFileInfo class (temporary file)
1851          * @throw       PathWriteProtectedException If the path in 'temp_file_path' is write-protected
1852          * @throws      FileIoException If the file cannot be written
1853          */
1854          protected static function createTempPathForFile (SplFileInfo $infoInstance) {
1855                 // Get config entry
1856                 $basePath = FrameworkBootstrap::getConfigurationInstance()->getConfigEntry('temp_file_path');
1857
1858                 // Is the path writeable?
1859                 if (!is_writable($basePath)) {
1860                         // Path is write-protected
1861                         throw new PathWriteProtectedException($infoInstance, self::EXCEPTION_PATH_CANNOT_BE_WRITTEN);
1862                 }
1863
1864                 // Add it
1865                 $tempInstance = new SplFileInfo($basePath . DIRECTORY_SEPARATOR . $infoInstance->getBasename());
1866
1867                 // Is it reachable?
1868                 if (!FrameworkBootstrap::isReachableFilePath($tempInstance)) {
1869                         // Not reachable
1870                         throw new FileIoException($tempInstance, self::EXCEPTION_FILE_NOT_REACHABLE);
1871                 }
1872
1873                 // Return it
1874                 return $tempInstance;
1875          }
1876
1877         /**
1878          * "Getter" for a printable state name
1879          *
1880          * @return      $stateName      Name of the node's state in a printable format
1881          */
1882         public final function getPrintableState () {
1883                 // Default is 'null'
1884                 $stateName = 'null';
1885
1886                 // Get the state instance
1887                 $stateInstance = $this->getStateInstance();
1888
1889                 // Is it an instance of Stateable?
1890                 if ($stateInstance instanceof Stateable) {
1891                         // Then use that state name
1892                         $stateName = $stateInstance->getStateName();
1893                 }
1894
1895                 // Return result
1896                 return $stateName;
1897         }
1898
1899 }