Passed
Pull Request — master (#1107)
by Tim
05:50
created

StandardSessionManager::injectSessionSettings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * \AppserverIo\Appserver\ServletEngine\StandardSessionManager
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\ServletEngine;
22
23
use AppserverIo\Logger\LoggerUtils;
24
use AppserverIo\Collections\HashMap;
25
use AppserverIo\Collections\CollectionInterface;
26
use AppserverIo\Appserver\ServletEngine\Http\Session;
27
use AppserverIo\Psr\Naming\NamingException;
28
use AppserverIo\Psr\Servlet\ServletContextInterface;
29
use AppserverIo\Psr\Servlet\ServletSessionInterface;
30
use AppserverIo\Psr\Application\ApplicationInterface;
31
use AppserverIo\Psr\Application\ManagerConfigurationInterface;
32
33
/**
34
 * A simple session manager implementation implementation using
35
 * session handlers to persist the sessions.
36
 *
37
 * @author    Tim Wagner <[email protected]>
38
 * @copyright 2015 TechDivision GmbH <[email protected]>
39
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
40
 * @link      https://github.com/appserver-io/appserver
41
 * @link      http://www.appserver.io
42
 */
43
class StandardSessionManager implements SessionManagerInterface
44
{
45
46
    /**
47
     * The HashMap containing the sessions.
48
     *
49
     * @var \AppserverIo\Collections\HashMap
50
     */
51
    protected $sessions;
52
53
    /**
54
     * The HashMap containing the session handlers.
55
     *
56
     * @var \AppserverIo\Collections\HashMap
57
     */
58
    protected $sessionHandlers;
59
60
    /**
61
     * The application instance.
62
     *
63
     * @var \AppserverIo\Psr\Application\ApplicationInterface
64
     */
65
    protected $application;
66
67
    /**
68
     * The settings for the session handling.
69
     *
70
     * @var \AppserverIo\Appserver\ServletEngine\SessionSettingsInterface
71
     */
72
    protected $sessionSettings;
73
74
    /**
75
     * The session marshaller instance.
76
     *
77
     * @var \AppserverIo\Appserver\ServletEngine\SessionMarshallerInterface
78
     */
79
    protected $sessionMarshaller;
80
81
    /**
82
     * The manager configuration instance.
83
     *
84
     * @var  \AppserverIo\Psr\Application\ManagerConfigurationInterface
85
     */
86
    protected $managerConfiguration;
87
88
    /**
89
     * The garbage collector instance.
90
     *
91
     * @var \AppserverIo\Appserver\ServletEngine\GarbageCollectorInterface
92
     */
93
    protected $garbageCollector;
94
95
    /**
96
     * Initialize the session manager.
97
     */
98
    public function __construct()
99
    {
100
        $this->sessions = new HashMap();
101
        $this->sessionHandlers = new HashMap();
102
    }
103
104
    /**
105
     * Inject the application instance.
106
     *
107
     * @param \AppserverIo\Psr\Application\ApplicationInterface $application The application instance
108
     *
109
     * @return void
110
     */
111
    public function injectApplication(ApplicationInterface $application)
112
    {
113
        $this->application = $application;
114
    }
115
116
    /**
117
     * Returns the application instance.
118
     *
119
     * @return \AppserverIo\Psr\Application\ApplicationInterface|\AppserverIo\Psr\Naming\NamingDirectoryInterface The application instance
120
     */
121
    public function getApplication()
122
    {
123
        return $this->application;
124
    }
125
126
    /**
127
     * Injects the session settings.
128
     *
129
     * @param \AppserverIo\Appserver\ServletEngine\SessionSettingsInterface $sessionSettings Settings for the session handling
130
     *
131
     * @return void
132
     */
133
    public function injectSessionSettings($sessionSettings)
134
    {
135
        $this->sessionSettings = $sessionSettings;
136
    }
137
138
    /**
139
     * Returns the session settings.
140
     *
141
     * @return \AppserverIo\Appserver\ServletEngine\SessionSettingsInterface The session settings
142
     */
143
    public function getSessionSettings()
144
    {
145
        return $this->sessionSettings;
146
    }
147
148
    /**
149
     * Injects the session marshaller.
150
     *
151
     * @param \AppserverIo\Appserver\ServletEngine\SessionMarshallerInterface $sessionMarshaller The session marshaller instance
152
     *
153
     * @return void
154
     */
155
    public function injectSessionMarshaller($sessionMarshaller)
156
    {
157
        $this->sessionMarshaller = $sessionMarshaller;
158
    }
159
160
    /**
161
     * Returns the session marshaller.
162
     *
163
     * @return \AppserverIo\Appserver\ServletEngine\SessionMarshallerInterface The session marshaller
164
     */
165
    public function getSessionMarshaller()
166
    {
167
        return $this->sessionMarshaller;
168
    }
169
170
    /**
171
     * Inject the configuration for this manager.
172
     *
173
     * @param \AppserverIo\Psr\Application\ManagerConfigurationInterface $managerConfiguration The managers configuration
174
     *
175
     * @return void
176
     */
177
    public function injectManagerConfiguration(ManagerConfigurationInterface $managerConfiguration)
178
    {
179
        $this->managerConfiguration = $managerConfiguration;
180
    }
181
182
    /**
183
     * Return's the manager configuration.
184
     *
185
     * @return \AppserverIo\Psr\Application\ManagerConfigurationInterface The manager configuration
186
     */
187
    public function getManagerConfiguration()
188
    {
189
        return $this->managerConfiguration;
190
    }
191
192
    /**
193
     * Inject the session handlers.
194
     *
195
     * @param \AppserverIo\Collections\CollectionInterface $sessionHandlers The session handlers
196
     *
197
     * @return void
198
     */
199
    public function injectSessionHandlers(CollectionInterface $sessionHandlers)
200
    {
201
        $this->sessionHandlers = $sessionHandlers;
0 ignored issues
show
Documentation Bug introduced by
$sessionHandlers is of type AppserverIo\Collections\CollectionInterface, but the property $sessionHandlers was declared to be of type AppserverIo\Collections\HashMap. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
202
    }
203
204
    /**
205
     * Returns all registered session handlers.
206
     *
207
     * @return \AppserverIo\Collections\ArrayList The session handlers
208
     */
209
    public function getSessionHandlers()
210
    {
211
        return $this->sessionHandlers;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->sessionHandlers returns the type AppserverIo\Collections\HashMap which is incompatible with the documented return type AppserverIo\Collections\ArrayList.
Loading history...
212
    }
213
214
    /**
215
     * Injects the garbage collector.
216
     *
217
     * @param \AppserverIo\Appserver\ServletEngine\GarbageCollectorInterface $garbageCollector The garbage collector
218
     *
219
     * @return void
220
     */
221
    public function injectGarbageCollector(GarbageCollectorInterface $garbageCollector)
222
    {
223
        $this->garbageCollector = $garbageCollector;
224
    }
225
226
    /**
227
     * Returns the garbage collector instance.
228
     *
229
     * @return \AppserverIo\Appserver\ServletEngine\GarbageCollectorInterface The garbage collector instance
230
     */
231
    public function getGarbageCollector()
232
    {
233
        return $this->garbageCollector;
234
    }
235
236
    /**
237
     * Returns all sessions actually attached to the session manager.
238
     *
239
     * @return \AppserverIo\Collections\HashMap The container with sessions
240
     */
241
    public function getSessions()
242
    {
243
        return $this->sessions;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->sessions returns the type AppserverIo\Collections\HashMap which is incompatible with the return type mandated by AppserverIo\Appserver\Se...nterface::getSessions() of AppserverIo\Appserver\Se...essionSettingsInterface.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
244
    }
245
246
    /**
247
     * Returns the attribute with the passed key from the container.
248
     *
249
     * @param string $key The key the requested value is registered with
250
     *
251
     * @return mixed|null The requested value if available
252
     */
253
    public function getAttribute($key)
254
    {
255
        // do nothing here
256
    }
257
258
    /**
259
     * Returns the session factory.
260
     *
261
     * @return \AppserverIo\Appserver\ServletEngine\Session\SessionHandlerFactory The session factory instance
262
     */
263
    public function getSessionFactory()
264
    {
265
        // do nothing here
266
    }
267
268
    /**
269
     * Returns the servlet manager instance.
270
     *
271
     * @return \AppserverIo\Psr\Servlet\ServletContextInterface The servlet manager instance
272
     */
273
    public function getServletManager()
274
    {
275
        // do nothing here
276
    }
277
278
    /**
279
     * Returns the session pool instance.
280
     *
281
     * @return \AppserverIo\Storage\StorageInterface The session pool
282
     */
283
    public function getSessionPool()
284
    {
285
        // do nothing here
286
    }
287
288
    /**
289
     * Returns the persistence manager instance.
290
     *
291
     * @return \AppserverIo\Appserver\ServletEngine\Session\SessionHandlerInterface The persistence manager instance
292
     */
293
    public function getPersistenceManager()
294
    {
295
        // do nothing here
296
    }
297
298
    /**
299
     * Lifecycle callback that'll be invoked after the application has been started.
300
     *
301
     * @param \AppserverIo\Psr\Application\ApplicationInterface $application The application instance
302
     *
303
     * @return void
304
     * @see \AppserverIo\Psr\Application\ManagerInterface::postStartup()
305
     */
306
    public function postStartup(ApplicationInterface $application)
307
    {
308
    }
309
310
    /**
311
     * Initializes the session manager.
312
     *
313
     * @param \AppserverIo\Psr\Application\ApplicationInterface $application The application instance
314
     *
315
     * @return void
316
     * @see \AppserverIo\Psr\Application\ManagerInterface::initialize()
317
     */
318
    public function initialize(ApplicationInterface $application)
319
    {
320
321
        // load the servlet manager with the session settings configured in web.xml
322
        /** @var \AppserverIo\Psr\Servlet\ServletContextInterface|\AppserverIo\Psr\Application\ManagerInterface $servletManager */
323
        $servletManager = $application->search(ServletContextInterface::IDENTIFIER);
324
325
        // load the settings, set the default session save path
326
        $sessionSettings = $this->getSessionSettings();
327
        $sessionSettings->setSessionSavePath($application->getSessionDir());
0 ignored issues
show
Bug introduced by
The method getSessionDir() does not exist on AppserverIo\Psr\Application\ApplicationInterface. It seems like you code against a sub-type of AppserverIo\Psr\Application\ApplicationInterface such as AppserverIo\Appserver\Application\Application. ( Ignorable by Annotation )

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

327
        $sessionSettings->setSessionSavePath($application->/** @scrutinizer ignore-call */ getSessionDir());
Loading history...
Bug introduced by
The method setSessionSavePath() does not exist on AppserverIo\Appserver\Se...essionSettingsInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to AppserverIo\Appserver\Se...essionSettingsInterface. ( Ignorable by Annotation )

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

327
        $sessionSettings->/** @scrutinizer ignore-call */ 
328
                          setSessionSavePath($application->getSessionDir());
Loading history...
328
329
        // if we've session parameters defined in our servlet context
330
        if ($servletManager->hasSessionParameters()) {
0 ignored issues
show
Bug introduced by
The method hasSessionParameters() does not exist on AppserverIo\Psr\Application\ManagerInterface. It seems like you code against a sub-type of AppserverIo\Psr\Application\ManagerInterface such as AppserverIo\Appserver\ServletEngine\ServletManager. ( Ignorable by Annotation )

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

330
        if ($servletManager->/** @scrutinizer ignore-call */ hasSessionParameters()) {
Loading history...
331
            // we want to merge the session settings from the servlet context
332
            $sessionSettings->mergeServletContext($servletManager);
0 ignored issues
show
Bug introduced by
It seems like $servletManager can also be of type AppserverIo\Psr\Application\ManagerInterface; however, parameter $context of AppserverIo\Appserver\Se...::mergeServletContext() does only seem to accept AppserverIo\Psr\Servlet\ServletContextInterface, maybe add an additional type check? ( Ignorable by Annotation )

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

332
            $sessionSettings->mergeServletContext(/** @scrutinizer ignore-type */ $servletManager);
Loading history...
333
        }
334
    }
335
336
    /**
337
     * Creates a new session with the passed session ID and session name if given.
338
     *
339
     * @param mixed             $id         The session ID
340
     * @param string            $name       The session name
341
     * @param integer|\DateTime $lifetime   Date and time after the session expires
342
     * @param integer|null      $maximumAge Number of seconds until the session expires
343
     * @param string|null       $domain     The host to which the user agent will send this cookie
344
     * @param string            $path       The path describing the scope of this cookie
345
     * @param boolean           $secure     If this cookie should only be sent through a "secure" channel by the user agent
346
     * @param boolean           $httpOnly   If this cookie should only be used through the HTTP protocol
347
     *
348
     * @return \AppserverIo\Psr\Servlet\ServletSessionInterface The requested session
349
     */
350
    public function create(
351
        $id,
352
        $name,
353
        $lifetime = null,
354
        $maximumAge = null,
355
        $domain = null,
356
        $path = null,
357
        $secure = null,
358
        $httpOnly = null
359
    ) {
360
361
        // copy the default session configuration for lifetime from the settings
362
        if ($lifetime == null) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $lifetime of type null|integer|DateTime against null; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
363
            $lifetime = time() + $this->getSessionSettings()->getSessionCookieLifetime();
364
        }
365
366
        // copy the default session configuration for maximum from the settings
367
        if ($maximumAge == null) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $maximumAge of type null|integer against null; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
368
            $maximumAge = $this->getSessionSettings()->getSessionMaximumAge();
369
        }
370
371
        // copy the default session configuration for cookie domain from the settings
372
        if ($domain == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $domain of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
373
            $domain = $this->getSessionSettings()->getSessionCookieDomain();
374
        }
375
376
        // copy the default session configuration for the cookie path from the settings
377
        if ($path == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $path of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
378
            $path = $this->getSessionSettings()->getSessionCookiePath();
379
        }
380
381
        // copy the default session configuration for the secure flag from the settings
382
        if ($secure == null) {
383
            $secure = $this->getSessionSettings()->getSessionCookieSecure();
384
        }
385
386
        // copy the default session configuration for the http only flag from the settings
387
        if ($httpOnly == null) {
388
            $httpOnly = $this->getSessionSettings()->getSessionCookieHttpOnly();
389
        }
390
391
        // initialize and return the session instance
392
        $session = Session::emptyInstance();
393
        $session->init($id, $name, $lifetime, $maximumAge, $domain, $path, $secure, $httpOnly);
394
395
        // attach the session to the manager
396
        $this->attach($session);
397
398
        // return the session
399
        return $session;
400
    }
401
402
    /**
403
     * Attaches the passed session to the manager and returns the instance.
404
     * If a session
405
     * with the session identifier already exists, it will be overwritten.
406
     *
407
     * @param \AppserverIo\Psr\Servlet\ServletSessionInterface $session The session to attach
408
     *
409
     * @return void
410
     */
411
    public function attach(ServletSessionInterface $session)
412
    {
413
        $this->getSessions()->add($session->getId(), $session);
414
    }
415
416
    /**
417
     * Tries to find a session for the given request. The session-ID will be
418
     * searched in the cookie header of the request, and in the request query
419
     * string. If both values are present, the value in the query string takes
420
     * precedence. If no session id is found, a new one is created and assigned
421
     * to the request.
422
     *
423
     * @param string $id The unique session ID to that has to be returned
424
     *
425
     * @return \AppserverIo\Psr\Servlet\ServletSessionInterface|null The requested session
426
     */
427
    public function find($id)
428
    {
429
430
        // return immediately if the requested session ID is empty
431
        if (empty($id)) {
432
            return;
433
        }
434
435
        // declare the session variable
436
        $session = null;
437
438
        // query whether or not the session with the passed ID exists
439
        if ($this->getSessions()->exists($id)) {
440
            $session = $this->getSessions()->get($id);
441
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
442
        } else {
443
            // iterate over the session handlers and try to un-persist the session
444
            /** @var \AppserverIo\Appserver\ServletEngine\Session\SessionHandlerInterface $sessionHandler */
445
            foreach ($this->getSessionHandlers() as $sessionHandler) {
446
                try {
447
                    if ($session = $sessionHandler->load($id)) {
448
                        $this->attach($session);
449
                        break;
450
                    }
451
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
452
                } catch (\Exception $e) {
453
                    // log the exception if a system logger is available
454
                    if ($logger = $this->getLogger(LoggerUtils::SYSTEM)) {
455
                        // log the error message
456
                        $logger->error(sprintf('Can\'t load session data for session with ID "%s" because of: "%s"', $id, $e->getMessage()));
457
                        // log the stack trace in debug log level
458
                        $logger->debug($e->__toString());
459
                    }
460
                }
461
            }
462
        }
463
464
        // if we found a session, we've to check if it can be resumed
465
        if ($session instanceof ServletSessionInterface) {
466
            if ($session->canBeResumed()) {
467
                $session->resume();
468
                return $session;
469
            }
470
        }
471
    }
472
473
    /**
474
     * Flushes the session storage and persists all sessions.
475
     *
476
     * @return void
477
     */
478
    public function flush()
479
    {
480
481
        // persist all sessions
482
        /** @var \AppserverIo\Psr\Servlet\ServletSessionInterface $session */
483
        foreach ($this->getSessions() as $session) {
484
            // iterate over the session handlers and persist the sessions
485
            /** @var \AppserverIo\Appserver\ServletEngine\Session\SessionHandlerInterface $sessionHandler */
486
            foreach ($this->getSessionHandlers() as $sessionHandler) {
487
                try {
488
                    $sessionHandler->save($session);
489
                } catch (\Exception $e) {
490
                    // log the exception if a system logger is available
491
                    if ($logger = $this->getLogger(LoggerUtils::SYSTEM)) {
492
                        $logger->error($e->__toString());
493
                    }
494
                }
495
            }
496
        }
497
    }
498
499
    /**
500
     * Initializes the manager instance.
501
     *
502
     * @return string
503
     * @see \AppserverIo\Psr\Application\ManagerInterface::initialize()
504
     */
505
    public function getIdentifier()
506
    {
507
        return SessionManagerInterface::IDENTIFIER;
508
    }
509
510
    /**
511
     * Shutdown the session manager instance.
512
     *
513
     * @return void
514
     * \AppserverIo\Psr\Application\ManagerInterface::stop()
515
     */
516
    public function stop()
517
    {
518
        $this->getGarbageCollector()->stop();
519
    }
520
521
    /**
522
     * Return's the logger with the requested name. First we look in the
523
     * application and then in the system itself.
524
     *
525
     * @param string $loggerName The name of the logger to return
526
     *
527
     * @return \Psr\Log\LoggerInterface The logger with the requested name
528
     */
529
    public function getLogger($loggerName)
530
    {
531
532
        try {
533
            // first let's see if we've an application logger registered
534
            if ($logger = $this->getApplication()->getLogger($loggerName)) {
0 ignored issues
show
Bug introduced by
The method getLogger() does not exist on AppserverIo\Psr\Application\ApplicationInterface. It seems like you code against a sub-type of AppserverIo\Psr\Application\ApplicationInterface such as AppserverIo\Appserver\Application\Application. ( Ignorable by Annotation )

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

534
            if ($logger = $this->getApplication()->/** @scrutinizer ignore-call */ getLogger($loggerName)) {
Loading history...
535
                return $logger;
536
            }
537
538
            // then try to load the global logger instance if available
539
            return $this->getApplication()->getNamingDirectory()->search(sprintf('php:global/log/%s', $loggerName));
0 ignored issues
show
Bug introduced by
The method getNamingDirectory() does not exist on AppserverIo\Psr\Application\ApplicationInterface. It seems like you code against a sub-type of AppserverIo\Psr\Application\ApplicationInterface such as AppserverIo\Appserver\Application\Application. ( Ignorable by Annotation )

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

539
            return $this->getApplication()->/** @scrutinizer ignore-call */ getNamingDirectory()->search(sprintf('php:global/log/%s', $loggerName));
Loading history...
540
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
541
        } catch (NamingException $ne) {
542
            // do nothing, we simply have no logger with the requested name
543
        }
544
    }
545
}
546