Completed
Push — master ( 2b6b4e...ce5cb5 )
by Tim
13s queued 10s
created

Application::getContextNode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 1
cts 1
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\ClassLoaderNodeInterface;
36
use AppserverIo\Psr\Application\ManagerInterface;
37
use AppserverIo\Psr\Application\ApplicationInterface;
38
use AppserverIo\Psr\Application\ProvisionerInterface;
39
use AppserverIo\Psr\Application\DirectoryAwareInterface;
40
use AppserverIo\Psr\Application\FilesystemAwareInterface;
41
use AppserverIo\Psr\ApplicationServer\ContextInterface;
42
use AppserverIo\Appserver\Core\Environment;
43
use AppserverIo\Appserver\Core\Utilities\EnvironmentKeys;
44
use AppserverIo\Psr\Servlet\SessionUtils;
45
use AppserverIo\Appserver\Core\Api\ConfigurationService;
46
use AppserverIo\Appserver\Core\Utilities\SystemPropertyKeys;
47
use Doctrine\Common\Annotations\AnnotationRegistry;
48
use AppserverIo\Appserver\Core\Utilities\AppEnvironmentHelper;
49
use AppserverIo\Provisioning\Configuration\ProvisionerConfigurationInterface;
50
use AppserverIo\Properties\PropertiesUtil;
51
52
/**
53
 * The application instance holds all information about the deployed application
54
 * and provides a reference to the servlet manager and the initial context.
55
 *
56
 * @author    Tim Wagner <[email protected]>
57
 * @copyright 2015 TechDivision GmbH <[email protected]>
58
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
59
 * @link      https://github.com/appserver-io/appserver
60
 * @link      http://www.appserver.io
61
 *
62
 * @property \AppserverIo\Appserver\Application\ApplicationStateKeys        $applicationState  The application state
63
 * @property \AppserverIo\Storage\StorageInterface                          $data              Application's data storage
64
 * @property \AppserverIo\Storage\GenericStackable                          $classLoaders      Stackable holding all class loaders this application has registered
65
 * @property \AppserverIo\Storage\GenericStackable                          $provisioners      Stackable holding all provisioners this application has registered
66
 * @property \AppserverIo\Storage\GenericStackable                          $loggers           Stackable holding all loggers this application has registered
67
 * @property \AppserverIo\Appserver\Application\Interfaces\ContextInterface $initialContext    The initial context instance
68
 * @property \AppserverIo\Storage\GenericStackable                          $managers          Stackable of managers for this application
69
 * @property string                                                         $name              Name of the application
70
 * @property string                                                         $environmentName   Name of the environment the application currently runs in (build.properties)
71
 * @property string                                                         $serial            The application's UUID
72
 * @property string                                                         $containerName     Name of the container the application is bound to
73
 * @property string                                                         $containerRunlevel Runlevel of the container the application is bound to
74
 * @property \AppserverIo\Psr\Naming\NamingDirectoryInterface               $namingDirectory   The naming directory instance
75
 * @property \AppserverIo\Appserver\Core\Api\Node\ContextNode               $contextNode       The application configuration instance
76
 */
77
class Application extends \Thread implements ApplicationInterface, DirectoryAwareInterface, FilesystemAwareInterface, \AppserverIo\Psr\Context\ContextInterface
78
{
79
80
    /**
81
     * The time we wait after each loop.
82
     *
83
     * @var integer
84
     */
85
    const TIME_TO_LIVE = 1;
86
87
    /**
88
     * Trait that provides threaded context functionality.
89 23
     *
90
     * @var \AppserverIo\Appserver\Core\Traits\ThreadedContextTrait
91
     */
92
    use ThreadedContextTrait;
93 23
94
    /**
95
     * Initialize the internal members.
96 23
     */
97 23
    public function __construct()
98
    {
99
100
        // create a UUID as prefix for dynamic object properties
101
        $this->serial = Uuid::uuid4()->toString();
102
103
        // initialize the application state
104
        $this->applicationState = ApplicationStateKeys::get(ApplicationStateKeys::WAITING_FOR_INITIALIZATION);
105
    }
106
107
    /**
108
     * Inject the environment name
109
     *
110
     * @param string $environmentName The environment name to inject
111
     *
112
     * @return void
113
     */
114
    public function injectEnvironmentName($environmentName)
115
    {
116
        $this->environmentName = $environmentName;
117
    }
118 23
119
    /**
120 23
     * Injects the naming directory.
121 23
     *
122
     * @param \AppserverIo\Psr\Naming\NamingDirectoryInterface $namingDirectory The naming directory instance
123
     *
124
     * @return void
125
     */
126
    public function injectNamingDirectory($namingDirectory)
127
    {
128
        $this->namingDirectory = $namingDirectory;
129
    }
130 23
131
    /**
132 23
     * Injects the storage for the managers.
133 23
     *
134
     * @param \AppserverIo\Storage\GenericStackable $managers The storage for the managers
135
     *
136
     * @return void
137
     */
138
    public function injectManagers(GenericStackable $managers)
139
    {
140
        $this->managers = $managers;
141
    }
142 23
143
    /**
144 23
     * Injects the storage for the class loaders.
145 23
     *
146
     * @param \AppserverIo\Storage\GenericStackable $classLoaders The storage for the class loaders
147
     *
148
     * @return void
149
     */
150
    public function injectClassLoaders(GenericStackable $classLoaders)
151
    {
152
        $this->classLoaders = $classLoaders;
153
    }
154 1
155
    /**
156
     * Injects the storage for the provisioners.
157 1
     *
158
     * @param \AppserverIo\Storage\GenericStackable $provisioners The storage for the provisioners
159
     *
160
     * @return void
161
     */
162
    public function injectProvisioners(GenericStackable $provisioners)
163
    {
164
        $this->provisioners = $provisioners;
165
    }
166
167
    /**
168
     * Injects the storage for the loggers.
169
     *
170
     * @param \AppserverIo\Storage\GenericStackable $loggers The storage for the loggers
171
     *
172
     * @return void
173
     */
174
    public function injectLoggers(GenericStackable $loggers)
175
    {
176
        $this->loggers = $loggers;
177
    }
178 4
179
    /**
180 4
     * The initial context instance.
181 4
     *
182
     * @param \AppserverIo\Psr\ApplicationServer\ContextInterface $initialContext The initial context instance
183
     *
184
     * @return void
185
     */
186
    public function injectInitialContext(ContextInterface $initialContext)
187
    {
188
        $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...
189
    }
190 23
191
    /**
192 23
     * Injects the application name.
193 23
     *
194
     * @param string $name The application name
195
     *
196
     * @return void
197
     */
198
    public function injectName($name)
199
    {
200 11
        $this->name = $name;
201
    }
202 11
203
    /**
204
     * Returns the application name (that has to be the class namespace, e.g. example)
205
     *
206
     * @return string The application name
207
     */
208
    public function getName()
209
    {
210
        return $this->name;
211
    }
212
213
    /**
214
     * Returns the applications environment name
215
     *
216
     * @return string The applications environment name
217
     */
218
    public function getEnvironmentName()
219
    {
220
        return $this->environmentName;
221
    }
222 23
223
    /**
224 23
     * Injects the name of the container the application is bound to.
225 23
     *
226
     * @param string $containerName The container's name
227
     *
228
     * @return void
229
     */
230
    public function injectContainerName($containerName)
231
    {
232 10
        $this->containerName = $containerName;
233
    }
234 10
235
    /**
236
     * Returns the name of the container the application is bound to.
237
     *
238
     * @return string The container's name
239
     */
240
    public function getContainerName()
241
    {
242
        return $this->containerName;
243
    }
244
245
    /**
246
     * Injects the runlevel of the container the application is bound to.
247
     *
248
     * @param string $containerRunlevel The container's runlevel
249
     *
250
     * @return void
251
     */
252
    public function injectContainerRunlevel($containerRunlevel)
253
    {
254
        $this->containerRunlevel = $containerRunlevel;
255
    }
256
257
    /**
258
     * Returns the runlevel of the container the application is bound to.
259
     *
260
     * @return string The container's runlevel
261
     */
262
    public function getContainerRunlevel()
263
    {
264 15
        return $this->containerRunlevel;
265
    }
266 15
267
    /**
268
     * Returns the applications naming directory.
269
     *
270
     * @return \AppserverIo\Psr\Naming\NamingDirectoryInterface The applications naming directory interface
271
     */
272
    public function getNamingDirectory()
273
    {
274
        return $this->namingDirectory;
275
    }
276 2
277
    /**
278 2
     * Return's the application configuration.
279 2
     *
280 1
     * @return \AppserverIo\Appserver\Core\Api\Node\ContextNode The application configuration
281 1
     */
282 2
    public function getContextNode()
283
    {
284
        return $this->contextNode;
285
    }
286
287
    /**
288
     * Returns the absolute path to the servers document root directory
289
     *
290 1
     * @param string $directoryToAppend The directory to append to the base directory
291
     *
292 1
     * @return string The base directory with appended dir if given
293
     */
294
    public function getBaseDirectory($directoryToAppend = null)
295
    {
296
        $baseDirectory = $this->getNamingDirectory()->search('php:env/baseDirectory');
297
        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...
298
            $baseDirectory .= $directoryToAppend;
299
        }
300 1
        return $baseDirectory;
301
    }
302 1
303
    /**
304
     * Returns the absolute path to the applications base directory.
305
     *
306
     * @return string The app base directory
307
     */
308
    public function getAppBase()
309
    {
310
        return $this->getNamingDirectory()->search(sprintf('php:env/%s/appBase', $this->getUniqueName()));
311
    }
312
313
    /**
314
     * Returns the absolute path to the web application base directory.
315
     *
316
     * @return string The path to the webapps folder
317
     */
318
    public function getWebappPath()
319
    {
320 1
        return $this->getNamingDirectory()->search(sprintf('php:env/%s/webappPath', $this->getUniqueName()));
321
    }
322 1
323
    /**
324
     * Returns the absolute path to the applications temporary directory.
325
     *
326
     * @return string The app temporary directory
327
     */
328
    public function getTmpDir()
329
    {
330 1
        return $this->getNamingDirectory()->search(sprintf('php:env/%s/tmpDirectory', $this->getUniqueName()));
331
    }
332 1
333
    /**
334
     * Returns the absolute path to the applications data directory.
335
     *
336
     * @return string The app data directory
337
     */
338
    public function getDataDir()
339
    {
340 1
        return $this->getNamingDirectory()->search(sprintf('php:env/%s/dataDirectory', $this->getUniqueName()));
341
    }
342 1
343
    /**
344
     * Returns the absolute path to the applications session directory.
345
     *
346
     * @return string The app session directory
347
     */
348
    public function getSessionDir()
349
    {
350 1
        return $this->getNamingDirectory()->search(sprintf('php:env/%s/sessionDirectory', $this->getUniqueName()));
351
    }
352 1
353
    /**
354
     * Returns the absolute path to the applications cache directory.
355
     *
356
     * @return string The app cache directory
357
     */
358
    public function getCacheDir()
359
    {
360 1
        return $this->getNamingDirectory()->search(sprintf('php:env/%s/cacheDirectory', $this->getUniqueName()));
361
    }
362 1
363
    /**
364
     * Returns the username the application should be executed with.
365
     *
366
     * @return string The username
367
     */
368
    public function getUser()
369
    {
370
        return $this->getNamingDirectory()->search('php:env/user');
371
    }
372
373
    /**
374
     * Returns the groupname the application should be executed with.
375
     *
376
     * @return string The groupname
377
     */
378
    public function getGroup()
379
    {
380 1
        return $this->getNamingDirectory()->search('php:env/group');
381
    }
382 1
383
    /**
384
     * Returns the umask the application should create files/directories with.
385
     *
386
     * @return string The umask
387
     */
388
    public function getUmask()
389
    {
390
        return $this->getNamingDirectory()->search('php:env/umask');
391 10
    }
392
393 10
    /**
394
     * Return's the container instance the application is bound to.
395
     *
396
     * @return \AppserverIo\Psr\ApplicationServer\ContainerInterface The container instance
397
     */
398
    public function getContainer()
399
    {
400
        return $this->getNamingDirectory()->search(sprintf('php:services/%s/%s', $this->getContainerRunlevel(), $this->getContainerName()));
401
    }
402
403
    /**
404 1
     * Return's the system properties enriched with the application specific properties like webapp.dir etc.
405
     *
406 1
     * @return \AppserverIo\Properties\PropertiesInterface The sytem properties
407
     */
408
    public function getSystemProperties()
409
    {
410
411
        // load the configuration service
412
        $service = $this->newService(ConfigurationService::class);
413
414 4
        // load the system properties
415
        $systemProperties =  $service->getSystemProperties($this->getContainer()->getContainerNode());
416 4
417
        // append the application specific properties
418
        $systemProperties->add(SystemPropertyKeys::WEBAPP, $webappPath = $this->getWebappPath());
419
        $systemProperties->add(SystemPropertyKeys::WEBAPP_NAME, basename($webappPath));
420
        $systemProperties->add(SystemPropertyKeys::WEBAPP_DATA, $this->getDataDir());
421
        $systemProperties->add(SystemPropertyKeys::WEBAPP_CACHE, $this->getCacheDir());
422
        $systemProperties->add(SystemPropertyKeys::WEBAPP_SESSION, $this->getSessionDir());
423
424
        // return the system properties
425
        return $systemProperties;
426 1
    }
427
428 1
    /**
429 1
     * Replaces the variablies in the passed file.
430
     *
431
     * @param string $pathname The filename with the variables that has to be replaced
432
     *
433
     * @return string The content of the file with the replaced variables
434
     */
435
    public function replaceSystemProperties($pathname)
436
    {
437
       return PropertiesUtil::singleton()->replacePropertiesInString($this->getSystemProperties(), file_get_contents($pathname));
438 3
    }
439
440 3
    /**
441
     * Return's the application's UUID.
442
     *
443
     * @return string The application's UUID
444
     */
445
    public function getSerial()
446
    {
447
        return $this->serial;
448 3
    }
449
450 3
    /**
451
     * Return's the unique application name that is the container + application name
452
     * separated with a slash, e. g. combined-appserver/example.
453
     *
454
     * @return string
455
     */
456
    public function getUniqueName()
457
    {
458
        return sprintf('%s/%s', $this->getContainerName(), $this->getName());
459
    }
460 2
461
    /**
462 2
     * (non-PHPdoc)
463 1
     *
464
     * @param string $className The API service class name to return the instance for
465 1
     *
466
     * @return object The service instance
467
     * @see \AppserverIo\Psr\ApplicationServer\ContextInterface::newService()
468
     */
469
    public function newService($className)
470
    {
471
        return $this->getInitialContext()->newService($className);
472
    }
473
474
    /**
475
     * Returns the initial context instance.
476
     *
477
     * @return \AppserverIo\Psr\ApplicationServer\ContextInterface The initial Context
478
     */
479
    public function getInitialContext()
480
    {
481
        return $this->initialContext;
482
    }
483
484
    /**
485
     * Return the requested class loader instance
486
     *
487
     * @param string $identifier The unique identifier of the requested class loader
488
     *
489
     * @return \AppserverIo\Appserver\Core\Interfaces\ClassLoaderInterface The class loader instance
490
     */
491
    public function getClassLoader($identifier)
492
    {
493
        if (isset($this->classLoaders[$identifier])) {
494
            return $this->classLoaders[$identifier];
495
        }
496
    }
497
498
    /**
499
     * Return the class loaders.
500
     *
501
     * @return \AppserverIo\Storage\GenericStackable The class loader instances
502
     */
503
    public function getClassLoaders()
504
    {
505
        return $this->classLoaders;
506
    }
507
508
    /**
509
     * Returns the manager instances.
510
     *
511
     * @return \AppserverIo\Storage\GenericStackable The manager instances
512
     */
513
    public function getManagers()
514
    {
515
        return $this->managers;
516
    }
517
518
    /**
519
     * Return the requested manager instance.
520
     *
521
     * @param string $identifier The unique identifier of the requested manager
522
     *
523
     * @return \AppserverIo\Psr\Application\ManagerInterface The manager instance
524 3
     */
525
    public function getManager($identifier)
526
    {
527
        if (isset($this->managers[$identifier])) {
528 3
            return $this->managers[$identifier];
529
        }
530
    }
531 3
532 3
    /**
533
     * Returns the provisioner instances.
534
     *
535
     * @return \AppserverIo\Storage\GenericStackable The provisioner instances
536
     */
537
    public function getProvisioners()
538
    {
539
        return $this->provisioners;
540
    }
541
542 3
    /**
543
     * Return the requested provisioner instance.
544
     *
545
     * @param string $identifier The unique identifier of the requested provisioner
546 3
     *
547
     * @return \AppserverIo\Psr\Application\ProvisionerInterface The provisioner instance
548
     */
549 3
    public function getProvisioner($identifier)
550 3
    {
551
        if (isset($this->provisioners[$identifier])) {
552
            return $this->provisioners[$identifier];
553
        }
554
    }
555
556
    /**
557
     * Returns the logger instances.
558
     *
559
     * @return \AppserverIo\Storage\GenericStackable The logger instances
560
     */
561
    public function getLoggers()
562
    {
563
        return $this->loggers;
564
    }
565
566
    /**
567
     * Return the requested logger instance, by default the application's system logger.
568
     *
569
     * @param string $name The name of the requested logger
570
     *
571
     * @return \Psr\Log\LoggerInterface|null The logger instance
572
     */
573
    public function getLogger($name = LoggerUtils::SYSTEM_LOGGER)
574
    {
575
        if (isset($this->loggers[$name])) {
576
            return $this->loggers[$name];
577
        }
578
        return null;
579
    }
580
581
    /**
582
     * Injects an additional class loader.
583
     *
584
     * @param \AppserverIo\Appserver\Core\Interfaces\ClassLoaderInterface   $classLoader   A class loader to put on the class loader stack
585
     * @param \AppserverIo\Appserver\Core\Api\Node\ClassLoaderNodeInterface $configuration The class loader's configuration
586
     *
587
     * @return void
588
     */
589
    public function addClassLoader(ClassLoaderInterface $classLoader, ClassLoaderNodeInterface $configuration)
590
    {
591
592
        // bind the class loader callback to the naming directory => the application itself
593
        $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

593
        $this->getNamingDirectory()->bind(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), /** @scrutinizer ignore-type */ array(&$this, 'getClassLoader'), array($configuration->getName()));
Loading history...
594
595
        // add the class loader instance to the application
596
        $this->classLoaders[$configuration->getName()] = $classLoader;
597
    }
598
599
    /**
600
     * Injects manager instance and the configuration.
601
     *
602
     * @param \AppserverIo\Psr\Application\ManagerInterface             $manager       A manager instance
603
     * @param \AppserverIo\Appserver\Core\Api\Node\ManagerNodeInterface $configuration The managers configuration
604
     *
605
     * @return void
606
     */
607
    public function addManager(ManagerInterface $manager, ManagerNodeInterface $configuration)
608
    {
609
610
        // bind the manager callback to the naming directory => the application itself
611
        $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

611
        $this->getNamingDirectory()->bind(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), /** @scrutinizer ignore-type */ array(&$this, 'getManager'), array($configuration->getName()));
Loading history...
612
613
        // add the manager instance to the application
614
        $this->managers[$configuration->getName()] = $manager;
615
    }
616
617
    /**
618
     * Injects the provisioner instance and the configuration.
619
     *
620
     * @param \AppserverIo\Psr\Application\ProvisionerInterface                         $provisioner   A provisioner instance
621
     * @param \AppserverIo\Provisioning\Configuration\ProvisionerConfigurationInterface $configuration The provisioner configuration
622
     *
623
     * @return void
624
     */
625
    public function addProvisioner(ProvisionerInterface $provisioner, ProvisionerConfigurationInterface $configuration)
626
    {
627
628
        // bind the provisioner callback to the naming directory => the application itself
629
        $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

629
        $this->getNamingDirectory()->bind(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), /** @scrutinizer ignore-type */ array(&$this, 'getProvisioner'), array($configuration->getName()));
Loading history...
630
631
        // add the provisioner instance to the application
632
        $this->provisioners[$configuration->getName()] = $provisioner;
633
    }
634
635
    /**
636
     * Injects the logger instance and the configuration.
637
     *
638
     * @param \Psr\Log\LoggerInterface                                 $logger        A provisioner instance
639
     * @param \AppserverIo\Appserver\Core\Api\Node\LoggerNodeInterface $configuration The provisioner configuration
640
     *
641
     * @return void
642
     */
643
    public function addLogger(LoggerInterface $logger, LoggerNodeInterface $configuration)
644
    {
645
646
        // bind the logger callback to the naming directory => the application itself
647
        $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

647
        $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...
648
649
        // alos bind a reference from the application to the logger scope (to make DI more comfortable)
650
        $this->getNamingDirectory()->bindReference(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), $name);
651
652
        // add the logger instance to the application
653
        $this->loggers[$configuration->getName()] = $logger;
654
    }
655
656
    /**
657
     * Prepares the application with the specific data found in the
658
     * passed context node.
659
     *
660
     * @param \AppserverIo\Psr\ApplicationServer\ContainerInterface $container   The container instance bind the application to
661
     * @param \AppserverIo\Appserver\Core\Api\Node\ContextNode      $contextNode The application configuration
662
     *
663
     * @return void
664
     */
665
    public function prepare(ContainerInterface $container, ContextNode $contextNode)
666
    {
667
668
        // set the application configuration
669
        $this->contextNode = $contextNode;
670
671
        // load the unique application name + the naming directory
672
        $uniqueName = $this->getUniqueName();
673
        $namingDirectory = $this->getNamingDirectory();
674
675
        // create subdirectories for the application and the logger
676
        $namingDirectory->createSubdirectory(sprintf('php:global/%s', $uniqueName));
677
        $namingDirectory->createSubdirectory(sprintf('php:global/log/%s', $uniqueName));
678
679
        // create the applications 'env' + 'env/persistence' directory the beans + persistence units will be bound to
680
        $namingDirectory->createSubdirectory(sprintf('php:env/%s', $uniqueName));
681
        $namingDirectory->createSubdirectory(sprintf('php:global/%s/env', $uniqueName));
682
        $namingDirectory->createSubdirectory(sprintf('php:global/%s/env/persistence', $uniqueName));
683
684
        // bind the directory containing the applications
685
        $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

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