Completed
Push — master ( 9dc9e2...92022a )
by Tim
12s
created

Application::injectManagers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
569
570
        // add the class loader instance to the application
571
        $this->classLoaders[$configuration->getName()] = $classLoader;
572
    }
573
574
    /**
575
     * Injects manager instance and the configuration.
576
     *
577
     * @param \AppserverIo\Psr\Application\ManagerInterface             $manager       A manager instance
578
     * @param \AppserverIo\Appserver\Core\Api\Node\ManagerNodeInterface $configuration The managers configuration
579
     *
580
     * @return void
581
     */
582
    public function addManager(ManagerInterface $manager, ManagerNodeInterface $configuration)
583
    {
584
585
        // bind the manager callback to the naming directory => the application itself
586
        $this->getNamingDirectory()->bind(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), array(&$this, 'getManager'), array($configuration->getName()));
0 ignored issues
show
Documentation introduced by
array(&$this, 'getManager') is of type array<integer,this<Appse...cation>","1":"string"}>, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
587
588
        // add the manager instance to the application
589
        $this->managers[$configuration->getName()] = $manager;
590
    }
591
592
    /**
593
     * Injects the provisioner instance and the configuration.
594
     *
595
     * @param \AppserverIo\Psr\Application\ProvisionerInterface             $provisioner   A provisioner instance
596
     * @param \AppserverIo\Appserver\Core\Api\Node\ProvisionerNodeInterface $configuration The provisioner configuration
597
     *
598
     * @return void
599
     */
600
    public function addProvisioner(ProvisionerInterface $provisioner, ProvisionerNodeInterface $configuration)
601
    {
602
603
        // bind the provisioner callback to the naming directory => the application itself
604
        $this->getNamingDirectory()->bind(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), array(&$this, 'getProvisioner'), array($configuration->getName()));
0 ignored issues
show
Documentation introduced by
array(&$this, 'getProvisioner') is of type array<integer,this<Appse...cation>","1":"string"}>, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
605
606
        // add the provisioner instance to the application
607
        $this->provisioners[$configuration->getName()] = $provisioner;
608
    }
609
610
    /**
611
     * Injects the logger instance and the configuration.
612
     *
613
     * @param \Psr\Log\LoggerInterface                                 $logger        A provisioner instance
614
     * @param \AppserverIo\Appserver\Core\Api\Node\LoggerNodeInterface $configuration The provisioner configuration
615
     *
616
     * @return void
617
     */
618
    public function addLogger(LoggerInterface $logger, LoggerNodeInterface $configuration)
619
    {
620
621
        // bind the logger callback to the naming directory => the application itself
622
        $this->getNamingDirectory()->bind($name = sprintf('php:global/log/%s/%s', $this->getUniqueName(), $configuration->getName()), array(&$this, 'getLogger'), array($configuration->getName()));
0 ignored issues
show
Documentation introduced by
array(&$this, 'getLogger') is of type array<integer,this<Appse...cation>","1":"string"}>, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
623
624
        // alos bind a reference from the application to the logger scope (to make DI more comfortable)
625
        $this->getNamingDirectory()->bindReference(sprintf('php:global/%s/%s', $this->getUniqueName(), $configuration->getName()), $name);
626
627
        // add the logger instance to the application
628
        $this->loggers[$configuration->getName()] = $logger;
629
    }
630
631
    /**
632
     * Prepares the application with the specific data found in the
633
     * passed context node.
634
     *
635
     * @param \AppserverIo\Psr\ApplicationServer\ContainerInterface $container The container instance bind the application to
636
     * @param \AppserverIo\Appserver\Core\Api\Node\ContextNode      $context   The application configuration
637
     *
638
     * @return void
639
     */
640
    public function prepare(ContainerInterface $container, ContextNode $context)
641
    {
642
643
644
        $this->context = $context;
0 ignored issues
show
Bug introduced by
The property context does not seem to exist. Did you mean initialContext?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
645
646
        // load the unique application name + the naming directory
647
        $uniqueName = $this->getUniqueName();
648
        $namingDirectory = $this->getNamingDirectory();
649
650
        // create subdirectories for the application and the logger
651
        $namingDirectory->createSubdirectory(sprintf('php:global/%s', $uniqueName));
652
        $namingDirectory->createSubdirectory(sprintf('php:global/log/%s', $uniqueName));
653
654
        // create the applications 'env' + 'env/persistence' directory the beans + persistence units will be bound to
655
        $namingDirectory->createSubdirectory(sprintf('php:env/%s', $uniqueName));
656
        $namingDirectory->createSubdirectory(sprintf('php:global/%s/env', $uniqueName));
657
        $namingDirectory->createSubdirectory(sprintf('php:global/%s/env/persistence', $uniqueName));
658
659
        // bind the directory containing the applications
660
        $namingDirectory->bind(sprintf('php:env/%s/appBase', $uniqueName), $container->getAppBase());
0 ignored issues
show
Documentation introduced by
$container->getAppBase() is of type string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
661
662
        // prepare the application specific directories
663
        $webappPath = sprintf('%s/%s', $this->getAppBase(), $this->getName());
664
        $tmpDirectory = sprintf('%s/%s', $container->getTmpDir(), $this->getName());
665
        $dataDirectory = sprintf('%s/%s', $tmpDirectory, ltrim($context->getParam(DirectoryKeys::DATA), '/'));
666
        $cacheDirectory = sprintf('%s/%s', $tmpDirectory, ltrim($context->getParam(DirectoryKeys::CACHE), '/'));
667
        $sessionDirectory = sprintf('%s/%s', $tmpDirectory, ltrim($context->getParam(DirectoryKeys::SESSION), '/'));
668
669
        // prepare the application specific environment variables
670
        $namingDirectory->bind(sprintf('php:env/%s/webappPath', $uniqueName), $webappPath);
0 ignored issues
show
Documentation introduced by
$webappPath is of type string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
671
        $namingDirectory->bind(sprintf('php:env/%s/tmpDirectory', $uniqueName), $tmpDirectory);
0 ignored issues
show
Documentation introduced by
$tmpDirectory is of type string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
672
        $namingDirectory->bind(sprintf('php:env/%s/dataDirectory', $uniqueName), $dataDirectory);
0 ignored issues
show
Documentation introduced by
$dataDirectory is of type string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
673
        $namingDirectory->bind(sprintf('php:env/%s/cacheDirectory', $uniqueName), $cacheDirectory);
0 ignored issues
show
Documentation introduced by
$cacheDirectory is of type string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
674
        $namingDirectory->bind(sprintf('php:env/%s/sessionDirectory', $uniqueName), $sessionDirectory);
0 ignored issues
show
Documentation introduced by
$sessionDirectory is of type string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
675
676
        // bind the interface as reference to the application
677
        $namingDirectory->bind($uri = sprintf('php:global/%s/%s', $uniqueName, ApplicationInterface::IDENTIFIER), $this);
678
679
        // also bind an alias to the application
680
        /** @deprecated Also bind an alias to the application to ensure backwards compatibility */
681
        $namingDirectory->bindReference(sprintf('php:global/%s/Application', $uniqueName), $uri);
682
    }
683
684
    /**
685
     * Cleanup the naming directory from the application entries.
686
     *
687
     * @return void
688
     */
689
    public function unload()
690
    {
691
692
        // load the unique application name + the naming directory
693
        $uniqueName = $this->getUniqueName();
694
        $namingDirectory = $this->getNamingDirectory();
695
696
        // unbind the environment references of the application
697
        $namingDirectory->unbind(sprintf('php:env/%s/webappPath', $uniqueName));
698
        $namingDirectory->unbind(sprintf('php:env/%s/tmpDirectory', $uniqueName));
699
        $namingDirectory->unbind(sprintf('php:env/%s/dataDirectory', $uniqueName));
700
        $namingDirectory->unbind(sprintf('php:env/%s/cacheDirectory', $uniqueName));
701
        $namingDirectory->unbind(sprintf('php:env/%s/sessionDirectory', $uniqueName));
702
        $namingDirectory->unbind(sprintf('php:env/%s', $uniqueName));
703
704
        // unbind the global references of the application
705
        $namingDirectory->unbind(sprintf('php:global/%s/env/ApplicationInterface', $uniqueName));
706
        $namingDirectory->unbind(sprintf('php:global/%s/env/persistence', $uniqueName));
707
        $namingDirectory->unbind(sprintf('php:global/%s/env', $uniqueName));
708
        $namingDirectory->unbind(sprintf('php:global/%s', $uniqueName));
709
    }
710
711
    /**
712
     * Has been automatically invoked by the container after the application
713
     * instance has been created.
714
     *
715 1
     * @return void
716
     * @see \Thread::run()
717
     * @codeCoverageIgnore
718
     */
719
    public function connect()
720 1
    {
721
        $this->start();
722 1
    }
723 1
724 1
    /**
725
     * TRUE if the application has been connected, else FALSE.
726
     *
727 1
     * @return boolean Returns TRUE if the application has been connected, else FALSE
728
     */
729
    public function isConnected()
730 1
    {
731 1
        return $this->synchronized(function ($self) {
732 1
            return $self->applicationState->equals(ApplicationStateKeys::get(ApplicationStateKeys::INITIALIZATION_SUCCESSFUL));
733 1
        }, $this);
734 1
    }
735
736
    /**
737
     * Registers all class loaders injected to the applications in the opposite
738
     * order as they have been injected.
739
     *
740
     * @return void
741 1
     */
742
    public function registerClassLoaders()
743
    {
744
745
        // initialize the registered managers
746 1
        /** @var \AppserverIo\Appserver\Core\Interfaces\ClassLoaderInterface $classLoader */
747
        foreach ($this->getClassLoaders() as $classLoader) {
748 1
            // log the class loader we want to initialize
749 1
            $this->getInitialContext()->getSystemLogger()->debug(
750 1
                sprintf('Now register classloader %s for application %s', get_class($classLoader), $this->getName())
751
            );
752
753 1
            // register the class loader instance
754
            $classLoader->register(true, true);
755
756 1
            // log the class loader we've successfully registered
757 1
            $this->getInitialContext()->getSystemLogger()->debug(
758 1
                sprintf('Successfully registered classloader %s for application %s', get_class($classLoader), $this->getName())
759 1
            );
760 1
        }
761
    }
762
763
    /**
764
     * Register's additional annotation registries defined in the configuration.
765
     *
766
     * @return void
767
     */
768
    public function registerAnnotationRegistries()
769
    {
770
771
        // reset the annotation registry
772
        AnnotationRegistry::reset();
773
774
        // register additional annotation libraries
775
        foreach ($this->context->getAnnotationRegistries() as $annotationRegistry) {
0 ignored issues
show
Bug introduced by
The property context does not seem to exist. Did you mean initialContext?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
776
            // register the annotations specified by the annotation registery
777
            $annotationRegistryType = $annotationRegistry->getType();
778
            $registry = new $annotationRegistryType();
779
            $registry->register($annotationRegistry);
780
        }
781
    }
782
783
    /**
784
     * Provisions the initialized application.
785
     *
786
     * @return void
787
     */
788
    public function provision()
789
    {
790
791
        // invoke the provisioners and provision the application
792
        /** @var \AppserverIo\Psr\Application\ProvisionerInterface $provisioner */
793
        foreach ($this->getProvisioners() as $provisioner) {
794
            // log the manager we want to initialize
795
            \debug(sprintf('Now invoking provisioner %s for application %s', get_class($provisioner), $this->getName()));
796
797
            // execute the provisioning steps
798
            $provisioner->provision($this);
799
800
            // log the manager we've successfully registered
801
            \debug(sprintf('Successfully invoked provisioner %s for application %s', get_class($provisioner), $this->getName()));
802
        }
803
    }
804
805
    /**
806
     * Registers all managers in the application.
807
     *
808
     * @return void
809
     */
810 View Code Duplication
    public function initializeManagers()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
811
    {
812
813
        // initialize the registered managers
814
        /** @var \AppserverIo\Psr\Application\ManagerInterface $manager */
815
        foreach ($this->getManagers() as $manager) {
816
            // log the manager we want to initialize
817
            \debug(sprintf('Now register manager %s for application %s', get_class($manager), $this->getName()));
818
819
            // initialize the manager instance
820
            $manager->initialize($this);
821
822
            // log the manager we've successfully registered
823
            \debug(sprintf('Now registered manager %s for application %s', get_class($manager), $this->getName()));
824
        }
825
    }
826
827
    /**
828
     * Invokes the postStartup() method lifecycle callback of the registered managers.
829
     *
830
     * @return void
831
     */
832 View Code Duplication
    public function postStartupManagers()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
833
    {
834
835
        // initialize the registered managers
836
        /** @var \AppserverIo\Psr\Application\ManagerInterface $manager */
837
        foreach ($this->getManagers() as $manager) {
838
            // log the manager we want to invoke the postStartup() lifecycle callback
839
            \debug(sprintf('Now invoke the postStartup() lifecycle callback of manager %s for application %s', get_class($manager), $this->getName()));
840
841
            // invoke the manager's postStartup() lifecycle callback
842
            $manager->postStartup($this);
843
844
            // log the manager we've successfully invoked the postStartup() lifecycle callback
845
            \debug(sprintf('Successfully invoked the postStartup() lifecycle callback of manager %s for application %s', get_class($manager), $this->getName()));
846
        }
847
    }
848
849
    /**
850
     * Stops the application instance.
851
     *
852
     * @return void
853
     */
854
    public function stop()
855
    {
856
857
        // start application shutdown
858
        $this->synchronized(function ($self) {
859
            $self->applicationState = ApplicationStateKeys::get(ApplicationStateKeys::HALT);
860
        }, $this);
861
862
        do {
863
            // log a message that we'll wait till application has been shutdown
864
            \info(sprintf('Wait for application %s to be shutdown', $this->getName()));
865
866
            // query whether application state key is SHUTDOWN or not
867
            $waitForShutdown = $this->synchronized(function ($self) {
868
                return $self->applicationState->notEquals(ApplicationStateKeys::get(ApplicationStateKeys::SHUTDOWN));
869
            }, $this);
870
871
            // wait one second more
872
            sleep(1);
873
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
874
        } while ($waitForShutdown);
875
    }
876
877
    /**
878
     * Queries the naming directory for the requested name and returns the value
879
     * or invokes the bound callback.
880
     *
881
     * @param string $name The name of the requested value
882
     * @param array  $args The arguments to pass to the callback
883
     *
884
     * @return mixed The requested value
885
     * @see \AppserverIo\Appserver\Naming\NamingDirectory::search()
886
     */
887
    public function search($name, array $args = array())
888
    {
889
        return $this->getNamingDirectory()->search(sprintf('php:global/%s/%s', $this->getUniqueName(), $name), $args);
890
    }
891
892
    /**
893
     * This is the threads main() method that initializes the application with the autoloader and
894
     * instantiates all the necessary manager instances.
895
     *
896
     * @return void
897
     * @codeCoverageIgnore
898
     */
899
    public function run()
900
    {
901
902
        try {
903
            // register the default autoloader
904
            require SERVER_AUTOLOADER;
905
906
            // register shutdown handler
907
            register_shutdown_function(array(&$this, "shutdown"));
908
909
            // add the application instance to the environment
910
            Environment::singleton()->setAttribute(EnvironmentKeys::APPLICATION, $this);
911
912
            // create s simulated request/session ID whereas session equals request ID
913
            Environment::singleton()->setAttribute(EnvironmentKeys::SESSION_ID, $sessionId = SessionUtils::generateRandomString());
914
            Environment::singleton()->setAttribute(EnvironmentKeys::REQUEST_ID, $sessionId);
915
916
            // log a message that we now start to connect the application
917
            $this->getInitialContext()->getSystemLogger()->debug(sprintf('%s wait to be connected', $this->getName()));
918
919
            // register the class loaders
920
            $this->registerClassLoaders();
921
922
            // register the annotation registries
923
            $this->registerAnnotationRegistries();
924
925
            // initialize the managers
926
            $this->initializeManagers();
927
928
            // provision the application
929
            if ($this->getContainer()->hasProvisioningEnabled()) {
930
                $this->provision();
931
            }
932
933
            // initialize the profile logger and the thread context
934
            $profileLogger = null;
935
            /** @var \AppserverIo\Logger\ThreadSafeLoggerInterface $profileLogger */
936
            if ($profileLogger = $this->getInitialContext()->getLogger(LoggerUtils::PROFILE)) {
937
                $profileLogger->appendThreadContext('application');
938
            }
939
940
            // the application has successfully been initialized
941
            $this->synchronized(function ($self) {
942
                $self->applicationState = ApplicationStateKeys::get(ApplicationStateKeys::INITIALIZATION_SUCCESSFUL);
943
            }, $this);
944
945
            // log a message that we has successfully been connected now
946
            \info(sprintf('%s has successfully been connected', $this->getName()));
947
948
            // invoke the application's managers postStartup() lifecycle callbacks
949
            $this->postStartupManagers();
950
951
            // initialize the flag to keep the application running
952
            $keepRunning = true;
953
954
            // wait till application will be shutdown
955 View Code Duplication
            while ($keepRunning) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
956
                // query whether we've a profile logger, log resource usage
957
                if ($profileLogger) {
958
                    $profileLogger->debug(sprintf('Application %s is running', $this->getName()));
959
                }
960
961
                // wait a second to lower system load
962
                $keepRunning = $this->synchronized(function ($self) {
963
                    $self->wait(100000 * Application::TIME_TO_LIVE);
964
                    return $self->applicationState->equals(ApplicationStateKeys::get(ApplicationStateKeys::INITIALIZATION_SUCCESSFUL));
965
                }, $this);
966
            }
967
968
            // log a message that we has successfully been shutdown now
969
            \info(sprintf('%s start to shutdown managers', $this->getName()));
970
971
            // array for the manager shutdown threads
972
            $shutdownThreads = array();
973
974
            // we need to stop all managers, because they've probably running threads
975
            /** @var \AppserverIo\Psr\Application\ManagerInterface $manager */
976
            foreach ($this->getManagers() as $manager) {
977
                $shutdownThreads[] = new ManagerShutdownThread($manager);
978
            }
979
980
            // wait till all managers have been shutdown
981
            /** @var \AppserverIo\Appserver\Application\ManagerShutdownThread $shutdownThread */
982
            foreach ($shutdownThreads as $shutdownThread) {
983
                $shutdownThread->join();
984
            }
985
986
            // the application has been shutdown successfully
987
            $this->synchronized(function ($self) {
988
                $self->applicationState = ApplicationStateKeys::get(ApplicationStateKeys::SHUTDOWN);
989
            }, $this);
990
991
            // cleanup the naming directory with the application entries
992
            $this->unload();
993
994
            // log a message that we has successfully been shutdown now
995
            \info(sprintf('%s has successfully been shutdown', $this->getName()));
996
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
997
        } catch (\Exception $e) {
998
            LoggerUtils::log(LogLevel::ERROR, $e);
999
        }
1000
    }
1001
1002
    /**
1003
     * Shutdown function to log unexpected errors.
1004
     *
1005
     * @return void
1006
     * @see http://php.net/register_shutdown_function
1007
     */
1008
    public function shutdown()
1009
    {
1010
1011
        // check if there was a fatal error caused shutdown
1012
        if ($lastError = error_get_last()) {
1013
            // initialize error type and message
1014
            $type = 0;
1015
            $message = '';
1016
            // extract the last error values
1017
            extract($lastError);
1018
            // query whether we've a fatal/user error
1019
            if ($type === E_ERROR || $type === E_USER_ERROR) {
1020
                LoggerUtils::log(LogLevel::CRITICAL, $message);
1021
            }
1022
        }
1023
    }
1024
}
1025