Completed
Pull Request — master (#1105)
by Tim
42:55
created

Application::getContextNode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * \AppserverIo\Appserver\Application\Application
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Tim Wagner <[email protected]>
15
 * @copyright 2015 TechDivision GmbH <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/appserver-io/appserver
18
 * @link      http://www.appserver.io
19
 */
20
21
namespace AppserverIo\Appserver\Application;
22
23
use Rhumsaa\Uuid\Uuid;
24
use Psr\Log\LogLevel;
25
use Psr\Log\LoggerInterface;
26
use AppserverIo\Storage\GenericStackable;
27
use AppserverIo\Appserver\Core\Utilities\LoggerUtils;
28
use AppserverIo\Appserver\Core\Utilities\DirectoryKeys;
29
use AppserverIo\Appserver\Core\Traits\ThreadedContextTrait;
30
use AppserverIo\Psr\ApplicationServer\ContainerInterface;
31
use AppserverIo\Appserver\Core\Interfaces\ClassLoaderInterface;
32
use AppserverIo\Appserver\Core\Api\Node\ContextNode;
33
use AppserverIo\Appserver\Core\Api\Node\LoggerNodeInterface;
34
use AppserverIo\Appserver\Core\Api\Node\ManagerNodeInterface;
35
use AppserverIo\Appserver\Core\Api\Node\ProvisionerNodeInterface;
36
use AppserverIo\Appserver\Core\Api\Node\ClassLoaderNodeInterface;
37
use AppserverIo\Psr\Application\ManagerInterface;
38
use AppserverIo\Psr\Application\ApplicationInterface;
39
use AppserverIo\Psr\Application\ProvisionerInterface;
40
use AppserverIo\Psr\Application\DirectoryAwareInterface;
41
use AppserverIo\Psr\Application\FilesystemAwareInterface;
42
use AppserverIo\Psr\ApplicationServer\ContextInterface;
43
use AppserverIo\Appserver\Core\Environment;
44
use AppserverIo\Appserver\Core\Utilities\EnvironmentKeys;
45
use AppserverIo\Psr\Servlet\SessionUtils;
46
use AppserverIo\Appserver\Core\Api\ConfigurationService;
47
use AppserverIo\Appserver\Core\Utilities\SystemPropertyKeys;
48
use Doctrine\Common\Annotations\AnnotationRegistry;
49
50
/**
51
 * The application instance holds all information about the deployed application
52
 * and provides a reference to the servlet manager and the initial context.
53
 *
54
 * @author    Tim Wagner <[email protected]>
55
 * @copyright 2015 TechDivision GmbH <[email protected]>
56
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
57
 * @link      https://github.com/appserver-io/appserver
58
 * @link      http://www.appserver.io
59
 *
60
 * @property \AppserverIo\Appserver\Application\ApplicationStateKeys        $applicationState  The application state
61
 * @property \AppserverIo\Storage\StorageInterface                          $data              Application's data storage
62
 * @property \AppserverIo\Storage\GenericStackable                          $classLoaders      Stackable holding all class loaders this application has registered
63
 * @property \AppserverIo\Storage\GenericStackable                          $provisioners      Stackable holding all provisioners this application has registered
64
 * @property \AppserverIo\Storage\GenericStackable                          $loggers           Stackable holding all loggers this application has registered
65
 * @property \AppserverIo\Appserver\Application\Interfaces\ContextInterface $initialContext    The initial context instance
66
 * @property \AppserverIo\Storage\GenericStackable                          $managers          Stackable of managers for this application
67
 * @property string                                                         $name              Name of the application
68
 * @property string                                                         $environmentName   Name of the environment the application currently runs in (build.properties)
69
 * @property string                                                         $serial            The application's UUID
70
 * @property string                                                         $containerName     Name of the container the application is bound to
71
 * @property string                                                         $containerRunlevel Runlevel of the container the application is bound to
72
 * @property \AppserverIo\Psr\Naming\NamingDirectoryInterface               $namingDirectory   The naming directory instance
73
 * @property \AppserverIo\Appserver\Core\Api\Node\ContextNode               $contextNode       The application configuration instance
74
 */
75
class Application extends \Thread implements ApplicationInterface, DirectoryAwareInterface, FilesystemAwareInterface, \AppserverIo\Psr\Context\ContextInterface
76
{
77
78
    /**
79
     * The time we wait after each loop.
80
     *
81
     * @var integer
82
     */
83
    const TIME_TO_LIVE = 1;
84
85
    /**
86
     * Trait that provides threaded context functionality.
87
     *
88
     * @var \AppserverIo\Appserver\Core\Traits\ThreadedContextTrait
89 23
     */
90
    use ThreadedContextTrait;
91
92
    /**
93 23
     * Initialize the internal members.
94
     */
95
    public function __construct()
96 23
    {
97 23
98
        // create a UUID as prefix for dynamic object properties
99
        $this->serial = Uuid::uuid4()->toString();
100
101
        // initialize the application state
102
        $this->applicationState = ApplicationStateKeys::get(ApplicationStateKeys::WAITING_FOR_INITIALIZATION);
103
    }
104
105
    /**
106
     * Inject the environment name
107
     *
108
     * @param string $environmentName The environment name to inject
109
     *
110
     * @return void
111
     */
112
    public function injectEnvironmentName($environmentName)
113
    {
114
        $this->environmentName = $environmentName;
115
    }
116
117
    /**
118 23
     * Injects the naming directory.
119
     *
120 23
     * @param \AppserverIo\Psr\Naming\NamingDirectoryInterface $namingDirectory The naming directory instance
121 23
     *
122
     * @return void
123
     */
124
    public function injectNamingDirectory($namingDirectory)
125
    {
126
        $this->namingDirectory = $namingDirectory;
127
    }
128
129
    /**
130 23
     * Injects the storage for the managers.
131
     *
132 23
     * @param \AppserverIo\Storage\GenericStackable $managers The storage for the managers
133 23
     *
134
     * @return void
135
     */
136
    public function injectManagers(GenericStackable $managers)
137
    {
138
        $this->managers = $managers;
139
    }
140
141
    /**
142 23
     * Injects the storage for the class loaders.
143
     *
144 23
     * @param \AppserverIo\Storage\GenericStackable $classLoaders The storage for the class loaders
145 23
     *
146
     * @return void
147
     */
148
    public function injectClassLoaders(GenericStackable $classLoaders)
149
    {
150
        $this->classLoaders = $classLoaders;
151
    }
152
153
    /**
154 1
     * Injects the storage for the provisioners.
155
     *
156
     * @param \AppserverIo\Storage\GenericStackable $provisioners The storage for the provisioners
157 1
     *
158
     * @return void
159
     */
160
    public function injectProvisioners(GenericStackable $provisioners)
161
    {
162
        $this->provisioners = $provisioners;
163
    }
164
165
    /**
166
     * Injects the storage for the loggers.
167
     *
168
     * @param \AppserverIo\Storage\GenericStackable $loggers The storage for the loggers
169
     *
170
     * @return void
171
     */
172
    public function injectLoggers(GenericStackable $loggers)
173
    {
174
        $this->loggers = $loggers;
175
    }
176
177
    /**
178 4
     * The initial context instance.
179
     *
180 4
     * @param \AppserverIo\Psr\ApplicationServer\ContextInterface $initialContext The initial context instance
181 4
     *
182
     * @return void
183
     */
184
    public function injectInitialContext(ContextInterface $initialContext)
185
    {
186
        $this->initialContext = $initialContext;
0 ignored issues
show
Documentation Bug introduced by
It seems like $initialContext of type AppserverIo\Psr\ApplicationServer\ContextInterface is incompatible with the declared type AppserverIo\Appserver\Ap...rfaces\ContextInterface of property $initialContext.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
187
    }
188
189
    /**
190 23
     * Injects the application name.
191
     *
192 23
     * @param string $name The application name
193 23
     *
194
     * @return void
195
     */
196
    public function injectName($name)
197
    {
198
        $this->name = $name;
199
    }
200 11
201
    /**
202 11
     * Returns the application name (that has to be the class namespace, e.g. example)
203
     *
204
     * @return string The application name
205
     */
206
    public function getName()
207
    {
208
        return $this->name;
209
    }
210
211
    /**
212
     * Returns the applications environment name
213
     *
214
     * @return string The applications environment name
215
     */
216
    public function getEnvironmentName()
217
    {
218
        return $this->environmentName;
219
    }
220
221
    /**
222 23
     * Injects the name of the container the application is bound to.
223
     *
224 23
     * @param string $containerName The container's name
225 23
     *
226
     * @return void
227
     */
228
    public function injectContainerName($containerName)
229
    {
230
        $this->containerName = $containerName;
231
    }
232 10
233
    /**
234 10
     * Returns the name of the container the application is bound to.
235
     *
236
     * @return string The container's name
237
     */
238
    public function getContainerName()
239
    {
240
        return $this->containerName;
241
    }
242
243
    /**
244
     * Injects the runlevel of the container the application is bound to.
245
     *
246
     * @param string $containerRunlevel The container's runlevel
247
     *
248
     * @return void
249
     */
250
    public function injectContainerRunlevel($containerRunlevel)
251
    {
252
        $this->containerRunlevel = $containerRunlevel;
253
    }
254
255
    /**
256
     * Returns the runlevel of the container the application is bound to.
257
     *
258
     * @return string The container's runlevel
259
     */
260
    public function getContainerRunlevel()
261
    {
262
        return $this->containerRunlevel;
263
    }
264 15
265
    /**
266 15
     * Returns the applications naming directory.
267
     *
268
     * @return \AppserverIo\Psr\Naming\NamingDirectoryInterface The applications naming directory interface
269
     */
270
    public function getNamingDirectory()
271
    {
272
        return $this->namingDirectory;
273
    }
274
275
    /**
276 2
     * Return's the application configuration.
277
     *
278 2
     * @return \AppserverIo\Appserver\Core\Api\Node\ContextNode The application configuration
279 2
     */
280 1
    public function getContextNode()
281 1
    {
282 2
        return $this->contextNode;
283
    }
284
285
    /**
286
     * Returns the absolute path to the servers document root directory
287
     *
288
     * @param string $directoryToAppend The directory to append to the base directory
289
     *
290 1
     * @return string The base directory with appended dir if given
291
     */
292 1
    public function getBaseDirectory($directoryToAppend = null)
293
    {
294
        $baseDirectory = $this->getNamingDirectory()->search('php:env/baseDirectory');
295
        if ($directoryToAppend != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $directoryToAppend of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
296
            $baseDirectory .= $directoryToAppend;
297
        }
298
        return $baseDirectory;
299
    }
300 1
301
    /**
302 1
     * Returns the absolute path to the applications base directory.
303
     *
304
     * @return string The app base directory
305
     */
306
    public function getAppBase()
307
    {
308
        return $this->getNamingDirectory()->search(sprintf('php:env/%s/appBase', $this->getUniqueName()));
309
    }
310
311
    /**
312
     * Returns the absolute path to the web application base directory.
313
     *
314
     * @return string The path to the webapps folder
315
     */
316
    public function getWebappPath()
317
    {
318
        return $this->getNamingDirectory()->search(sprintf('php:env/%s/webappPath', $this->getUniqueName()));
319
    }
320 1
321
    /**
322 1
     * Returns the absolute path to the applications temporary directory.
323
     *
324
     * @return string The app temporary directory
325
     */
326
    public function getTmpDir()
327
    {
328
        return $this->getNamingDirectory()->search(sprintf('php:env/%s/tmpDirectory', $this->getUniqueName()));
329
    }
330 1
331
    /**
332 1
     * Returns the absolute path to the applications data directory.
333
     *
334
     * @return string The app data directory
335
     */
336
    public function getDataDir()
337
    {
338
        return $this->getNamingDirectory()->search(sprintf('php:env/%s/dataDirectory', $this->getUniqueName()));
339
    }
340 1
341
    /**
342 1
     * Returns the absolute path to the applications session directory.
343
     *
344
     * @return string The app session directory
345
     */
346
    public function getSessionDir()
347
    {
348
        return $this->getNamingDirectory()->search(sprintf('php:env/%s/sessionDirectory', $this->getUniqueName()));
349
    }
350 1
351
    /**
352 1
     * Returns the absolute path to the applications cache directory.
353
     *
354
     * @return string The app cache directory
355
     */
356
    public function getCacheDir()
357
    {
358
        return $this->getNamingDirectory()->search(sprintf('php:env/%s/cacheDirectory', $this->getUniqueName()));
359
    }
360 1
361
    /**
362 1
     * Returns the username the application should be executed with.
363
     *
364
     * @return string The username
365
     */
366
    public function getUser()
367
    {
368
        return $this->getNamingDirectory()->search('php:env/user');
369
    }
370
371
    /**
372
     * Returns the groupname the application should be executed with.
373
     *
374
     * @return string The groupname
375
     */
376
    public function getGroup()
377
    {
378
        return $this->getNamingDirectory()->search('php:env/group');
379
    }
380 1
381
    /**
382 1
     * Returns the umask the application should create files/directories with.
383
     *
384
     * @return string The umask
385
     */
386
    public function getUmask()
387
    {
388
        return $this->getNamingDirectory()->search('php:env/umask');
389
    }
390
391 10
    /**
392
     * Return's the container instance the application is bound to.
393 10
     *
394
     * @return \AppserverIo\Psr\ApplicationServer\ContainerInterface The container instance
395
     */
396
    public function getContainer()
397
    {
398
        return $this->getNamingDirectory()->search(sprintf('php:services/%s/%s', $this->getContainerRunlevel(), $this->getContainerName()));
399
    }
400
401
    /**
402
     * Return's the system properties enriched with the application specific properties like webapp.dir etc.
403
     *
404 1
     * @return \AppserverIo\Properties\PropertiesInterface The sytem properties
405
     */
406 1
    public function getSystemProperties()
407
    {
408
409
        // load the configuration service
410
        $service = $this->newService(ConfigurationService::class);
411
412
        // load the system properties
413
        $systemProperties =  $service->getSystemProperties($this->getContainer()->getContainerNode());
414 4
415
        // append the application specific properties
416 4
        $systemProperties->add(SystemPropertyKeys::WEBAPP, $webappPath = $this->getWebappPath());
417
        $systemProperties->add(SystemPropertyKeys::WEBAPP_NAME, basename($webappPath));
418
        $systemProperties->add(SystemPropertyKeys::WEBAPP_DATA, $this->getDataDir());
419
        $systemProperties->add(SystemPropertyKeys::WEBAPP_CACHE, $this->getCacheDir());
420
        $systemProperties->add(SystemPropertyKeys::WEBAPP_SESSION, $this->getSessionDir());
421
422
        // return the system properties
423
        return $systemProperties;
424
    }
425
426 1
    /**
427
     * Return's the application's UUID.
428 1
     *
429 1
     * @return string The application's UUID
430
     */
431
    public function getSerial()
432
    {
433
        return $this->serial;
434
    }
435
436
    /**
437
     * Return's the unique application name that is the container + application name
438 3
     * separated with a slash, e. g. combined-appserver/example.
439
     *
440 3
     * @return string
441
     */
442
    public function getUniqueName()
443
    {
444
        return sprintf('%s/%s', $this->getContainerName(), $this->getName());
445
    }
446
447
    /**
448 3
     * (non-PHPdoc)
449
     *
450 3
     * @param string $className The API service class name to return the instance for
451
     *
452
     * @return object The service instance
453
     * @see \AppserverIo\Psr\ApplicationServer\ContextInterface::newService()
454
     */
455
    public function newService($className)
456
    {
457
        return $this->getInitialContext()->newService($className);
458
    }
459
460 2
    /**
461
     * Returns the initial context instance.
462 2
     *
463 1
     * @return \AppserverIo\Psr\ApplicationServer\ContextInterface The initial Context
464
     */
465 1
    public function getInitialContext()
466
    {
467
        return $this->initialContext;
468
    }
469
470
    /**
471
     * Return the requested class loader instance
472
     *
473
     * @param string $identifier The unique identifier of the requested class loader
474
     *
475
     * @return \AppserverIo\Appserver\Core\Interfaces\ClassLoaderInterface The class loader instance
476
     */
477
    public function getClassLoader($identifier)
478
    {
479
        if (isset($this->classLoaders[$identifier])) {
480
            return $this->classLoaders[$identifier];
481
        }
482
    }
483
484
    /**
485
     * Return the class loaders.
486
     *
487
     * @return \AppserverIo\Storage\GenericStackable The class loader instances
488
     */
489
    public function getClassLoaders()
490
    {
491
        return $this->classLoaders;
492
    }
493
494
    /**
495
     * Returns the manager instances.
496
     *
497
     * @return \AppserverIo\Storage\GenericStackable The manager instances
498
     */
499
    public function getManagers()
500
    {
501
        return $this->managers;
502
    }
503
504
    /**
505
     * Return the requested manager instance.
506
     *
507
     * @param string $identifier The unique identifier of the requested manager
508
     *
509
     * @return \AppserverIo\Psr\Application\ManagerInterface The manager instance
510
     */
511
    public function getManager($identifier)
512
    {
513
        if (isset($this->managers[$identifier])) {
514
            return $this->managers[$identifier];
515
        }
516
    }
517
518
    /**
519
     * Returns the provisioner instances.
520
     *
521
     * @return \AppserverIo\Storage\GenericStackable The provisioner instances
522
     */
523
    public function getProvisioners()
524 3
    {
525
        return $this->provisioners;
526
    }
527
528 3
    /**
529
     * Return the requested provisioner instance.
530
     *
531 3
     * @param string $identifier The unique identifier of the requested provisioner
532 3
     *
533
     * @return \AppserverIo\Psr\Application\ProvisionerInterface The provisioner instance
534
     */
535
    public function getProvisioner($identifier)
536
    {
537
        if (isset($this->provisioners[$identifier])) {
538
            return $this->provisioners[$identifier];
539
        }
540
    }
541
542 3
    /**
543
     * Returns the logger instances.
544
     *
545
     * @return \AppserverIo\Storage\GenericStackable The logger instances
546 3
     */
547
    public function getLoggers()
548
    {
549 3
        return $this->loggers;
550 3
    }
551
552
    /**
553
     * Return the requested logger instance, by default the application's system logger.
554
     *
555
     * @param string $name The name of the requested logger
556
     *
557
     * @return \Psr\Log\LoggerInterface|null The logger instance
558
     */
559
    public function getLogger($name = LoggerUtils::SYSTEM_LOGGER)
560
    {
561
        if (isset($this->loggers[$name])) {
562
            return $this->loggers[$name];
563
        }
564
        return null;
565
    }
566
567
    /**
568
     * Injects an additional class loader.
569
     *
570
     * @param \AppserverIo\Appserver\Core\Interfaces\ClassLoaderInterface   $classLoader   A class loader to put on the class loader stack
571
     * @param \AppserverIo\Appserver\Core\Api\Node\ClassLoaderNodeInterface $configuration The class loader's configuration
572
     *
573
     * @return void
574
     */
575
    public function addClassLoader(ClassLoaderInterface $classLoader, ClassLoaderNodeInterface $configuration)
576
    {
577
578
        // bind the class loader callback to the naming directory => the application itself
579
        $this->getNamingDirectory()->bind(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), array(&$this, 'getClassLoader'), array($configuration->getName()));
0 ignored issues
show
Bug introduced by
array($this, 'getClassLoader') of type array<integer,AppserverI...ion\Application|string> is incompatible with the type object expected by parameter $value of AppserverIo\Psr\Naming\N...ectoryInterface::bind(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

579
        $this->getNamingDirectory()->bind(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), /** @scrutinizer ignore-type */ array(&$this, 'getClassLoader'), array($configuration->getName()));
Loading history...
580
581
        // add the class loader instance to the application
582
        $this->classLoaders[$configuration->getName()] = $classLoader;
583
    }
584
585
    /**
586
     * Injects manager instance and the configuration.
587
     *
588
     * @param \AppserverIo\Psr\Application\ManagerInterface             $manager       A manager instance
589
     * @param \AppserverIo\Appserver\Core\Api\Node\ManagerNodeInterface $configuration The managers configuration
590
     *
591
     * @return void
592
     */
593
    public function addManager(ManagerInterface $manager, ManagerNodeInterface $configuration)
594
    {
595
596
        // bind the manager callback to the naming directory => the application itself
597
        $this->getNamingDirectory()->bind(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), array(&$this, 'getManager'), array($configuration->getName()));
0 ignored issues
show
Bug introduced by
array($this, 'getManager') of type array<integer,AppserverI...ion\Application|string> is incompatible with the type object expected by parameter $value of AppserverIo\Psr\Naming\N...ectoryInterface::bind(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

597
        $this->getNamingDirectory()->bind(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), /** @scrutinizer ignore-type */ array(&$this, 'getManager'), array($configuration->getName()));
Loading history...
598
599
        // add the manager instance to the application
600
        $this->managers[$configuration->getName()] = $manager;
601
    }
602
603
    /**
604
     * Injects the provisioner instance and the configuration.
605
     *
606
     * @param \AppserverIo\Psr\Application\ProvisionerInterface             $provisioner   A provisioner instance
607
     * @param \AppserverIo\Appserver\Core\Api\Node\ProvisionerNodeInterface $configuration The provisioner configuration
608
     *
609
     * @return void
610
     */
611
    public function addProvisioner(ProvisionerInterface $provisioner, ProvisionerNodeInterface $configuration)
612
    {
613
614
        // bind the provisioner callback to the naming directory => the application itself
615
        $this->getNamingDirectory()->bind(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), array(&$this, 'getProvisioner'), array($configuration->getName()));
0 ignored issues
show
Bug introduced by
array($this, 'getProvisioner') of type array<integer,AppserverI...ion\Application|string> is incompatible with the type object expected by parameter $value of AppserverIo\Psr\Naming\N...ectoryInterface::bind(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

615
        $this->getNamingDirectory()->bind(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), /** @scrutinizer ignore-type */ array(&$this, 'getProvisioner'), array($configuration->getName()));
Loading history...
616
617
        // add the provisioner instance to the application
618
        $this->provisioners[$configuration->getName()] = $provisioner;
619
    }
620
621
    /**
622
     * Injects the logger instance and the configuration.
623
     *
624
     * @param \Psr\Log\LoggerInterface                                 $logger        A provisioner instance
625
     * @param \AppserverIo\Appserver\Core\Api\Node\LoggerNodeInterface $configuration The provisioner configuration
626
     *
627
     * @return void
628
     */
629
    public function addLogger(LoggerInterface $logger, LoggerNodeInterface $configuration)
630
    {
631
632
        // bind the logger callback to the naming directory => the application itself
633
        $this->getNamingDirectory()->bind($name = sprintf('php:global/log/%s/%s', $this->getUniqueName(), $configuration->getName()), array(&$this, 'getLogger'), array($configuration->getName()));
0 ignored issues
show
Bug introduced by
array($this, 'getLogger') of type array<integer,AppserverI...ion\Application|string> is incompatible with the type object expected by parameter $value of AppserverIo\Psr\Naming\N...ectoryInterface::bind(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

633
        $this->getNamingDirectory()->bind($name = sprintf('php:global/log/%s/%s', $this->getUniqueName(), $configuration->getName()), /** @scrutinizer ignore-type */ array(&$this, 'getLogger'), array($configuration->getName()));
Loading history...
634
635
        // alos bind a reference from the application to the logger scope (to make DI more comfortable)
636
        $this->getNamingDirectory()->bindReference(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), $name);
637
638
        // add the logger instance to the application
639
        $this->loggers[$configuration->getName()] = $logger;
640
    }
641
642
    /**
643
     * Prepares the application with the specific data found in the
644
     * passed context node.
645
     *
646
     * @param \AppserverIo\Psr\ApplicationServer\ContainerInterface $container   The container instance bind the application to
647
     * @param \AppserverIo\Appserver\Core\Api\Node\ContextNode      $contextNode The application configuration
648
     *
649
     * @return void
650
     */
651
    public function prepare(ContainerInterface $container, ContextNode $contextNode)
652
    {
653
654
        // set the application configuration
655
        $this->contextNode = $contextNode;
656
657
        // load the unique application name + the naming directory
658
        $uniqueName = $this->getUniqueName();
659
        $namingDirectory = $this->getNamingDirectory();
660
661
        // create subdirectories for the application and the logger
662
        $namingDirectory->createSubdirectory(sprintf('php:global/%s', $uniqueName));
663
        $namingDirectory->createSubdirectory(sprintf('php:global/log/%s', $uniqueName));
664
665
        // create the applications 'env' + 'env/persistence' directory the beans + persistence units will be bound to
666
        $namingDirectory->createSubdirectory(sprintf('php:env/%s', $uniqueName));
667
        $namingDirectory->createSubdirectory(sprintf('php:global/%s/env', $uniqueName));
668
        $namingDirectory->createSubdirectory(sprintf('php:global/%s/env/persistence', $uniqueName));
669
670
        // bind the directory containing the applications
671
        $namingDirectory->bind(sprintf('php:env/%s/appBase', $uniqueName), $container->getAppBase());
0 ignored issues
show
Bug introduced by
$container->getAppBase() of type string is incompatible with the type object expected by parameter $value of AppserverIo\Psr\Naming\N...ectoryInterface::bind(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

671
        $namingDirectory->bind(sprintf('php:env/%s/appBase', $uniqueName), /** @scrutinizer ignore-type */ $container->getAppBase());
Loading history...
672
673
        // prepare the application specific directories
674
        $webappPath = sprintf('%s/%s', $this->getAppBase(), $this->getName());
675
        $tmpDirectory = sprintf('%s/%s', $container->getTmpDir(), $this->getName());
676
        $dataDirectory = sprintf('%s/%s', $tmpDirectory, ltrim($contextNode->getParam(DirectoryKeys::DATA), '/'));
677
        $cacheDirectory = sprintf('%s/%s', $tmpDirectory, ltrim($contextNode->getParam(DirectoryKeys::CACHE), '/'));
678
        $sessionDirectory = sprintf('%s/%s', $tmpDirectory, ltrim($contextNode->getParam(DirectoryKeys::SESSION), '/'));
679
680
        // prepare the application specific environment variables
681
        $namingDirectory->bind(sprintf('php:env/%s/webappPath', $uniqueName), $webappPath);
682
        $namingDirectory->bind(sprintf('php:env/%s/tmpDirectory', $uniqueName), $tmpDirectory);
683
        $namingDirectory->bind(sprintf('php:env/%s/dataDirectory', $uniqueName), $dataDirectory);
684
        $namingDirectory->bind(sprintf('php:env/%s/cacheDirectory', $uniqueName), $cacheDirectory);
685
        $namingDirectory->bind(sprintf('php:env/%s/sessionDirectory', $uniqueName), $sessionDirectory);
686
687
        // bind the interface as reference to the application
688
        $namingDirectory->bind($uri = sprintf('php:global/%s/%s', $uniqueName, ApplicationInterface::IDENTIFIER), $this);
689
690
        // also bind an alias to the application
691
        /** @deprecated Also bind an alias to the application to ensure backwards compatibility */
692
        $namingDirectory->bindReference(sprintf('php:global/%s/Application', $uniqueName), $uri);
693
    }
694
695
    /**
696
     * Cleanup the naming directory from the application entries.
697
     *
698
     * @return void
699
     */
700
    public function unload()
701
    {
702
703
        // load the unique application name + the naming directory
704
        $uniqueName = $this->getUniqueName();
705
        $namingDirectory = $this->getNamingDirectory();
706
707
        // unbind the environment references of the application
708
        $namingDirectory->unbind(sprintf('php:env/%s/webappPath', $uniqueName));
709
        $namingDirectory->unbind(sprintf('php:env/%s/tmpDirectory', $uniqueName));
710
        $namingDirectory->unbind(sprintf('php:env/%s/dataDirectory', $uniqueName));
711
        $namingDirectory->unbind(sprintf('php:env/%s/cacheDirectory', $uniqueName));
712
        $namingDirectory->unbind(sprintf('php:env/%s/sessionDirectory', $uniqueName));
713
        $namingDirectory->unbind(sprintf('php:env/%s', $uniqueName));
714
715 1
        // unbind the global references of the application
716
        $namingDirectory->unbind(sprintf('php:global/%s/env/ApplicationInterface', $uniqueName));
717
        $namingDirectory->unbind(sprintf('php:global/%s/env/persistence', $uniqueName));
718
        $namingDirectory->unbind(sprintf('php:global/%s/env', $uniqueName));
719
        $namingDirectory->unbind(sprintf('php:global/%s', $uniqueName));
720 1
    }
721
722 1
    /**
723 1
     * Has been automatically invoked by the container after the application
724 1
     * instance has been created.
725
     *
726
     * @return void
727 1
     * @see \Thread::run()
728
     * @codeCoverageIgnore
729
     */
730 1
    public function connect()
731 1
    {
732 1
        $this->start();
733 1
    }
734 1
735
    /**
736
     * TRUE if the application has been connected, else FALSE.
737
     *
738
     * @return boolean Returns TRUE if the application has been connected, else FALSE
739
     */
740
    public function isConnected()
741 1
    {
742
        return $this->synchronized(function ($self) {
743
            return $self->applicationState->equals(ApplicationStateKeys::get(ApplicationStateKeys::INITIALIZATION_SUCCESSFUL));
744
        }, $this);
745
    }
746 1
747
    /**
748 1
     * Registers all class loaders injected to the applications in the opposite
749 1
     * order as they have been injected.
750 1
     *
751
     * @return void
752
     */
753 1
    public function registerClassLoaders()
754
    {
755
756 1
        // initialize the registered managers
757 1
        /** @var \AppserverIo\Appserver\Core\Interfaces\ClassLoaderInterface $classLoader */
758 1
        foreach ($this->getClassLoaders() as $classLoader) {
759 1
            // log the class loader we want to initialize
760 1
            $this->getInitialContext()->getSystemLogger()->debug(
761
                sprintf('Now register classloader %s for application %s', get_class($classLoader), $this->getName())
762
            );
763
764
            // register the class loader instance
765
            $classLoader->register(true, true);
766
767
            // log the class loader we've successfully registered
768
            $this->getInitialContext()->getSystemLogger()->debug(
769
                sprintf('Successfully registered classloader %s for application %s', get_class($classLoader), $this->getName())
770
            );
771
        }
772
    }
773
774
    /**
775
     * Register's additional annotation registries defined in the configuration.
776
     *
777
     * @return void
778
     */
779
    public function registerAnnotationRegistries()
780
    {
781
782
        // reset the annotation registry
783
        AnnotationRegistry::reset();
784
785
        // register additional annotation libraries
786
        foreach ($this->getContextNode()->getAnnotationRegistries() as $annotationRegistry) {
787
            // register the annotations specified by the annotation registery
788
            $annotationRegistryType = $annotationRegistry->getType();
789
            $registry = new $annotationRegistryType();
790
            $registry->register($annotationRegistry);
791
        }
792
    }
793
794
    /**
795
     * Provisions the initialized application.
796
     *
797
     * @return void
798
     */
799
    public function provision()
800
    {
801
802
        // invoke the provisioners and provision the application
803
        /** @var \AppserverIo\Psr\Application\ProvisionerInterface $provisioner */
804
        foreach ($this->getProvisioners() as $provisioner) {
805
            // log the manager we want to initialize
806
            \debug(sprintf('Now invoking provisioner %s for application %s', get_class($provisioner), $this->getName()));
807
808
            // execute the provisioning steps
809
            $provisioner->provision($this);
810
811
            // log the manager we've successfully registered
812
            \debug(sprintf('Successfully invoked provisioner %s for application %s', get_class($provisioner), $this->getName()));
813
        }
814
    }
815
816
    /**
817
     * Registers all managers in the application.
818
     *
819
     * @return void
820
     */
821
    public function initializeManagers()
822
    {
823
824
        // initialize the registered managers
825
        /** @var \AppserverIo\Psr\Application\ManagerInterface $manager */
826
        foreach ($this->getManagers() as $manager) {
827
            // log the manager we want to initialize
828
            \debug(sprintf('Now register manager %s for application %s', get_class($manager), $this->getName()));
829
830
            // initialize the manager instance
831
            $manager->initialize($this);
832
833
            // log the manager we've successfully registered
834
            \debug(sprintf('Now registered manager %s for application %s', get_class($manager), $this->getName()));
835
        }
836
    }
837
838
    /**
839
     * Invokes the postStartup() method lifecycle callback of the registered managers.
840
     *
841
     * @return void
842
     */
843
    public function postStartupManagers()
844
    {
845
846
        // initialize the registered managers
847
        /** @var \AppserverIo\Psr\Application\ManagerInterface $manager */
848
        foreach ($this->getManagers() as $manager) {
849
            // log the manager we want to invoke the postStartup() lifecycle callback
850
            \debug(sprintf('Now invoke the postStartup() lifecycle callback of manager %s for application %s', get_class($manager), $this->getName()));
851
852
            // invoke the manager's postStartup() lifecycle callback
853
            $manager->postStartup($this);
854
855
            // log the manager we've successfully invoked the postStartup() lifecycle callback
856
            \debug(sprintf('Successfully invoked the postStartup() lifecycle callback of manager %s for application %s', get_class($manager), $this->getName()));
857
        }
858
    }
859
860
    /**
861
     * Stops the application instance.
862
     *
863
     * @return void
864
     */
865
    public function stop()
866
    {
867
868
        // start application shutdown
869
        $this->synchronized(function ($self) {
870
            $self->applicationState = ApplicationStateKeys::get(ApplicationStateKeys::HALT);
871
        }, $this);
872
873
        do {
874
            // log a message that we'll wait till application has been shutdown
875
            \info(sprintf('Wait for application %s to be shutdown', $this->getName()));
876
877
            // query whether application state key is SHUTDOWN or not
878
            $waitForShutdown = $this->synchronized(function ($self) {
879
                return $self->applicationState->notEquals(ApplicationStateKeys::get(ApplicationStateKeys::SHUTDOWN));
880
            }, $this);
881
882
            // wait one second more
883
            sleep(1);
884
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
885
        } while ($waitForShutdown);
886
    }
887
888
    /**
889
     * Queries the naming directory for the requested name and returns the value
890
     * or invokes the bound callback.
891
     *
892
     * @param string $name The name of the requested value
893
     * @param array  $args The arguments to pass to the callback
894
     *
895
     * @return mixed The requested value
896
     * @see \AppserverIo\Appserver\Naming\NamingDirectory::search()
897
     */
898
    public function search($name, array $args = array())
899
    {
900
        return $this->getNamingDirectory()->search(sprintf('php:global/%s/%s', $this->getUniqueName(), $name), $args);
901
    }
902
903
    /**
904
     * This is the threads main() method that initializes the application with the autoloader and
905
     * instantiates all the necessary manager instances.
906
     *
907
     * @return void
908
     * @codeCoverageIgnore
909
     */
910
    public function run()
911
    {
912
913
        try {
914
            // register the default autoloader
915
            require SERVER_AUTOLOADER;
916
917
            // register shutdown handler
918
            register_shutdown_function(array(&$this, "shutdown"));
919
920
            // add the application instance to the environment
921
            Environment::singleton()->setAttribute(EnvironmentKeys::APPLICATION, $this);
922
923
            // create s simulated request/session ID whereas session equals request ID
924
            Environment::singleton()->setAttribute(EnvironmentKeys::SESSION_ID, $sessionId = SessionUtils::generateRandomString());
925
            Environment::singleton()->setAttribute(EnvironmentKeys::REQUEST_ID, $sessionId);
926
927
            // log a message that we now start to connect the application
928
            $this->getInitialContext()->getSystemLogger()->debug(sprintf('%s wait to be connected', $this->getName()));
929
930
            // register the class loaders
931
            $this->registerClassLoaders();
932
933
            // register the annotation registries
934
            $this->registerAnnotationRegistries();
935
936
            // initialize the managers
937
            $this->initializeManagers();
938
939
            // provision the application
940
            if ($this->getContainer()->hasProvisioningEnabled()) {
941
                $this->provision();
942
            }
943
944
            // initialize the profile logger and the thread context
945
            $profileLogger = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $profileLogger is dead and can be removed.
Loading history...
946
            /** @var \AppserverIo\Logger\ThreadSafeLoggerInterface $profileLogger */
947
            if ($profileLogger = $this->getInitialContext()->getLogger(LoggerUtils::PROFILE)) {
948
                $profileLogger->appendThreadContext('application');
949
            }
950
951
            // the application has successfully been initialized
952
            $this->synchronized(function ($self) {
953
                $self->applicationState = ApplicationStateKeys::get(ApplicationStateKeys::INITIALIZATION_SUCCESSFUL);
954
            }, $this);
955
956
            // log a message that we has successfully been connected now
957
            \info(sprintf('%s has successfully been connected', $this->getName()));
958
959
            // invoke the application's managers postStartup() lifecycle callbacks
960
            $this->postStartupManagers();
961
962
            // initialize the flag to keep the application running
963
            $keepRunning = true;
964
965
            // wait till application will be shutdown
966
            while ($keepRunning) {
967
                // query whether we've a profile logger, log resource usage
968
                if ($profileLogger) {
969
                    $profileLogger->debug(sprintf('Application %s is running', $this->getName()));
970
                }
971
972
                // wait a second to lower system load
973
                $keepRunning = $this->synchronized(function ($self) {
974
                    $self->wait(100000 * Application::TIME_TO_LIVE);
975
                    return $self->applicationState->equals(ApplicationStateKeys::get(ApplicationStateKeys::INITIALIZATION_SUCCESSFUL));
976
                }, $this);
977
            }
978
979
            // log a message that we has successfully been shutdown now
980
            \info(sprintf('%s start to shutdown managers', $this->getName()));
981
982
            // array for the manager shutdown threads
983
            $shutdownThreads = array();
984
985
            // we need to stop all managers, because they've probably running threads
986
            /** @var \AppserverIo\Psr\Application\ManagerInterface $manager */
987
            foreach ($this->getManagers() as $manager) {
988
                $shutdownThreads[] = new ManagerShutdownThread($manager);
989
            }
990
991
            // wait till all managers have been shutdown
992
            /** @var \AppserverIo\Appserver\Application\ManagerShutdownThread $shutdownThread */
993
            foreach ($shutdownThreads as $shutdownThread) {
994
                $shutdownThread->join();
995
            }
996
997
            // the application has been shutdown successfully
998
            $this->synchronized(function ($self) {
999
                $self->applicationState = ApplicationStateKeys::get(ApplicationStateKeys::SHUTDOWN);
1000
            }, $this);
1001
1002
            // cleanup the naming directory with the application entries
1003
            $this->unload();
1004
1005
            // log a message that we has successfully been shutdown now
1006
            \info(sprintf('%s has successfully been shutdown', $this->getName()));
1007
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
1008
        } catch (\Exception $e) {
1009
            LoggerUtils::log(LogLevel::ERROR, $e);
1010
        }
1011
    }
1012
1013
    /**
1014
     * Shutdown function to log unexpected errors.
1015
     *
1016
     * @return void
1017
     * @see http://php.net/register_shutdown_function
1018
     */
1019
    public function shutdown()
1020
    {
1021
1022
        // check if there was a fatal error caused shutdown
1023
        if ($lastError = error_get_last()) {
1024
            // initialize error type and message
1025
            $type = 0;
1026
            $message = '';
1027
            // extract the last error values
1028
            extract($lastError);
1029
            // query whether we've a fatal/user error
1030
            if ($type === E_ERROR || $type === E_USER_ERROR) {
1031
                LoggerUtils::log(LogLevel::CRITICAL, $message);
1032
            }
1033
        }
1034
    }
1035
}
1036