StatefulSessionBeanMap   F
last analyzed

Complexity

Total Complexity 67

Size/Duplication

Total Lines 324
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 111
c 1
b 0
f 0
dl 0
loc 324
ccs 0
cts 174
cp 0
rs 3.04
wmc 67

13 Methods

Rating   Name   Duplication   Size   Complexity  
A size() 0 3 1
A isEmpty() 0 3 1
A clear() 0 3 1
A exists() 0 3 1
C add() 0 46 15
A getLifetime() 0 3 1
A toArray() 0 7 2
A isTimedOut() 0 8 3
D get() 0 48 20
A toIndexedArray() 0 7 2
A addAll() 0 3 1
A __construct() 0 4 1
D remove() 0 56 18

How to fix   Complexity   

Complex Class

Complex classes like StatefulSessionBeanMap often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use StatefulSessionBeanMap, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * \AppserverIo\Appserver\PersistenceContainer\StatefulSessionBeanMap
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\PersistenceContainer;
22
23
use AppserverIo\Storage\GenericStackable;
24
use AppserverIo\Lang\String;
25
use AppserverIo\Lang\Float;
26
use AppserverIo\Lang\Integer;
27
use AppserverIo\Lang\Boolean;
28
use AppserverIo\Lang\NullPointerException;
29
use AppserverIo\Collections\MapInterface;
30
use AppserverIo\Collections\InvalidKeyException;
31
use AppserverIo\Collections\IndexOutOfBoundsException;
32
33
/**
34
 * A hash map implementation designed to handle stateful session beans.
35
 *
36
 * @author    Tim Wagner <[email protected]>
37
 * @copyright 2015 TechDivision GmbH <[email protected]>
38
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
39
 * @link      https://github.com/appserver-io/appserver
40
 * @link      http://www.appserver.io
41
 *
42
 * @property \AppserverIo\Storage\GenericStackable $lifetime Contains the lifetime of the items
43
 * @property \AppserverIo\Storage\GenericStackable $items    The items the map contains
44
 */
45
class StatefulSessionBeanMap extends GenericStackable implements MapInterface
46
{
47
48
    /**
49
     * Initializes the map.
50
     */
51
    public function __construct()
52
    {
53
        $this->items = new GenericStackable();
54
        $this->lifetime = new GenericStackable();
55
    }
56
57
    /**
58
     * This method adds the passed object with the passed key
59
     * to the instance.
60
     *
61
     * @param mixed   $key      The key to add the passed value under
62
     * @param mixed   $object   The object to add to the instance
63
     * @param integer $lifetime The items lifetime
64
     *
65
     * @return null
66
     * @throws \AppserverIo\Collections\InvalidKeyException Is thrown if the passed key is NOT an primitive datatype
67
     * @throws \AppserverIo\Lang\NullPointerException Is thrown if the passed key is null or not a flat datatype like Integer, String, Double or Boolean
68
     */
69
    public function add($key, $object, $lifetime = 0)
70
    {
71
        // check if a key has been passed
72
        if (is_null($key)) {
73
            throw new NullPointerException('Passed key is null');
74
        }
75
        // check if lifetime is of type integer
76
        if (is_integer($lifetime) === false) {
77
            throw new InvalidLifetimeException(sprintf('Passed lifetime must be an integer, but is %s instead', $lifetime));
78
        }
79
        // check if a primitive datatype is passed
80
        if (is_integer($key) || is_string($key) || is_double($key) || is_bool($key)) {
81
            // add the item and lifetime to the array
82
            $this->items[$key] = $object;
83
            // add a lifetime if passed lifetime > 0
84
            if ($lifetime > 0) {
85
                $this->lifetime[$key] = time() + $lifetime;
86
            }
87
            // and return
88
            return;
89
        }
90
        // check if an object is passed
91
        if (is_object($key)) {
92
            if ($key instanceof String) {
93
                $newKey = $key->stringValue();
94
            } elseif ($key instanceof Float) {
95
                $newKey = $key->floatValue();
96
            } elseif ($key instanceof Integer) {
97
                $newKey = $key->intValue();
98
            } elseif ($key instanceof Boolean) {
99
                $newKey = $key->booleanValue();
100
            } elseif (method_exists($key, '__toString')) {
101
                $newKey = $key->__toString();
102
            } else {
103
                throw new InvalidKeyException('Passed key has to be a primitive datatype or has to implement the __toString() method');
104
            }
105
            // add the item and lifetime to the array
106
            $this->items[$newKey] = $object;
107
            // add a lifetime if passed lifetime > 0
108
            if ($lifetime > 0) {
109
                $this->lifetime[$newKey] = time() + $lifetime;
110
            }
111
            // and return
112
            return;
113
        }
114
        throw new InvalidKeyException('Passed key has to be a primitive datatype or has to implement the __toString() method');
115
    }
116
117
    /**
118
     * This method returns the element with the passed key
119
     * from the Collection.
120
     *
121
     * @param mixed $key Holds the key of the element to return
122
     *
123
     * @return mixed The requested element
124
     * @throws \AppserverIo\Collections\InvalidKeyException Is thrown if the passed key is NOT an integer
125
     * @throws \AppserverIo\Lang\NullPointerException Is thrown if the passed key OR value are NULL
126
     * @throws \AppserverIo\Collections\IndexOutOfBoundsException Is thrown if no element with the passed key exists in the Collection
127
     * @see \AppserverIo\Collections\CollectionInterface::get($key)
128
     */
129
    public function get($key)
130
    {
131
        // check if a key has been passed
132
        if (is_null($key)) {
133
            throw new NullPointerException('Passed key is null');
134
        }
135
        // check if a primitive datatype is passed
136
        if (is_integer($key) || is_string($key) || is_double($key) || is_bool($key)) {
137
            // return the value for the passed key, if it exists
138
            if (array_key_exists($key, $this->items) && !$this->isTimedOut($key)) {
0 ignored issues
show
Bug introduced by
$this->items of type AppserverIo\Storage\GenericStackable is incompatible with the type array expected by parameter $search of array_key_exists(). ( Ignorable by Annotation )

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

138
            if (array_key_exists($key, /** @scrutinizer ignore-type */ $this->items) && !$this->isTimedOut($key)) {
Loading history...
139
                // item is available and NOT timed out
140
                return $this->items[$key];
141
            } elseif (array_key_exists($key, $this->items) && $this->isTimedOut($key)) {
142
                // item is available, but timed out
143
                return;
144
            } else {
145
                // item is generally not available
146
                throw new IndexOutOfBoundsException(sprintf('Index %s out of bounds', $key));
147
            }
148
        }
149
        // check if an object is passed
150
        if (is_object($key)) {
151
            if ($key instanceof String) {
152
                $newKey = $key->stringValue();
153
            } elseif ($key instanceof Float) {
154
                $newKey = $key->floatValue();
155
            } elseif ($key instanceof Integer) {
156
                $newKey = $key->intValue();
157
            } elseif ($key instanceof Boolean) {
158
                $newKey = $key->booleanValue();
159
            } elseif (method_exists($key, '__toString')) {
160
                $newKey = $key->__toString();
161
            } else {
162
                throw new InvalidKeyException('Passed key has to be a primitive datatype or has to implement the __toString() method');
163
            }
164
            // return the value for the passed key, if it exists
165
            if (array_key_exists($newKey, $this->items) && !$this->isTimedOut($newKey)) {
166
                // item is available and NOT timed out
167
                return $this->items[$newKey];
168
            } elseif (array_key_exists($newKey, $this->items) && $this->isTimedOut($newKey)) {
169
                // item is available, but timed out
170
                return;
171
            } else {
172
                // item is generally not available
173
                throw new IndexOutOfBoundsException(sprintf('Index %s out of bounds', $newKey));
174
            }
175
        }
176
        throw new InvalidKeyException('Passed key has to be a primitive datatype or has to implement the __toString() method');
177
    }
178
179
    /**
180
     * This method removes the element with the passed
181
     * key, that has to be an integer, from the
182
     * IndexedCollection.
183
     *
184
     * @param mixed    $key          Holds the key of the element to remove
185
     * @param callable $beforeRemove Is called before the item will be removed
186
     *
187
     * @return void
188
     * @throws \AppserverIo\Collections\InvalidKeyException Is thrown if the passed key is NOT an integer
189
     * @throws \AppserverIo\Lang\NullPointerException Is thrown if the passed key is NULL
190
     * @throws \AppserverIo\Collections\IndexOutOfBoundsException Is thrown if no element with the passed key exists in the Collection
191
     */
192
    public function remove($key, callable $beforeRemove = null)
193
    {
194
        // check if a key has been passed
195
        if (is_null($key)) {
196
            throw new NullPointerException('Passed key is null');
197
        }
198
        // check if a primitive datatype is passed
199
        if (is_integer($key) || is_string($key) || is_double($key) || is_bool($key)) {
200
            if (array_key_exists($key, $this->items)) {
0 ignored issues
show
Bug introduced by
$this->items of type AppserverIo\Storage\GenericStackable is incompatible with the type array expected by parameter $search of array_key_exists(). ( Ignorable by Annotation )

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

200
            if (array_key_exists($key, /** @scrutinizer ignore-type */ $this->items)) {
Loading history...
201
                // invoke the callback before
202
                if (is_callable($beforeRemove)) {
203
                    call_user_func($beforeRemove, $this->items[$key]);
204
                }
205
                // remove the item
206
                unset($this->items[$key]);
207
                // remove the lifetime if set
208
                if (isset($this->lifetime[$key])) {
209
                    unset($this->lifetime[$key]);
210
                }
211
                return;
212
            } else {
213
                throw new IndexOutOfBoundsException('Index ' . $key . ' out of bounds');
214
            }
215
        }
216
        // check if an object is passed
217
        if (is_object($key)) {
218
            if ($key instanceof String) {
219
                $newKey = $key->stringValue();
220
            } elseif ($key instanceof Float) {
221
                $newKey = $key->floatValue();
222
            } elseif ($key instanceof Integer) {
223
                $newKey = $key->intValue();
224
            } elseif ($key instanceof Boolean) {
225
                $newKey = $key->booleanValue();
226
            } elseif (method_exists($key, '__toString')) {
227
                $newKey = $key->__toString();
228
            } else {
229
                throw new InvalidKeyException('Passed key has to be a primitive datatype or ' . 'has to implement the __toString() method');
230
            }
231
            if (array_key_exists($newKey, $this->items)) {
232
                // invoke the callback before
233
                if (is_callable($beforeRemove)) {
234
                    call_user_func($beforeRemove, $this->items[$newKey]);
235
                }
236
                // remove the item
237
                unset($this->items[$newKey]);
238
                // remove the lifetime if set
239
                if (isset($this->lifetime[$newKey])) {
240
                    unset($this->lifetime[$newKey]);
241
                }
242
                return;
243
            } else {
244
                throw new IndexOutOfBoundsException('Index ' . $newKey . ' out of bounds');
245
            }
246
        }
247
        throw new InvalidKeyException('Passed key has to be a primitive datatype or ' . 'has to implement the __toString() method');
248
    }
249
250
    /**
251
     * Returns TRUE if an lifetime value for the passed key is available
252
     * and the item has timed out.
253
     *
254
     * @param mixed $key The key of the item the lifetime check is requested
255
     *
256
     * @return boolean TRUE if the item has timed out, else FALSE
257
     */
258
    public function isTimedOut($key)
259
    {
260
        // if the item is available and has timed out, return TRUE
261
        if (array_key_exists($key, $this->lifetime) && $this->lifetime[$key] < time()) {
0 ignored issues
show
Bug introduced by
$this->lifetime of type AppserverIo\Storage\GenericStackable is incompatible with the type array expected by parameter $search of array_key_exists(). ( Ignorable by Annotation )

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

261
        if (array_key_exists($key, /** @scrutinizer ignore-type */ $this->lifetime) && $this->lifetime[$key] < time()) {
Loading history...
262
            return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type AppserverIo\Lang\Boolean.
Loading history...
263
        }
264
        // else return FALSE
265
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type AppserverIo\Lang\Boolean.
Loading history...
266
    }
267
268
    /**
269
     * Returns the lifetime of the items the instance contains.
270
     *
271
     * @return array The array with the items and their lifetime
272
     */
273
    public function getLifetime()
274
    {
275
        return $this->lifetime;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->lifetime returns the type AppserverIo\Storage\GenericStackable which is incompatible with the documented return type array.
Loading history...
276
    }
277
278
    /**
279
     * This method returns the internal array
280
     * with the keys and the related values.
281
     *
282
     * @return array Holds the array with keys and values
283
     * @see \AppserverIo\Collections\MapInterface::toIndexedArray()
284
     */
285
    public function toIndexedArray()
286
    {
287
        $array = array();
288
        foreach ($this->items as $key => $item) {
289
            $array[$key] = $item;
290
        }
291
        return $array;
292
    }
293
294
    /**
295
     * This method returns the number of entries of the Collection.
296
     *
297
     * @return integer The number of entries
298
     */
299
    public function size()
300
    {
301
        return sizeof($this->items);
0 ignored issues
show
Bug Best Practice introduced by
The expression return sizeof($this->items) returns the type integer which is incompatible with the documented return type AppserverIo\Lang\Integer.
Loading history...
302
    }
303
304
    /**
305
     * This method initializes the Collection and removes
306
     * all exsiting entries.
307
     *
308
     * @return void
309
     */
310
    public function clear()
311
    {
312
        $this->items = new GenericStackable();
313
    }
314
315
    /**
316
     * This returns true if the Collection has no
317
     * entries, otherwise false.
318
     *
319
     * @return boolean
320
     */
321
    public function isEmpty()
322
    {
323
        return $this->size() > 0;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->size() > 0 returns the type boolean which is incompatible with the documented return type AppserverIo\Lang\Boolean.
Loading history...
324
    }
325
326
    /**
327
     * This method returns an array with the
328
     * items of the Dictionary.
329
     *
330
     * The keys are lost in the array.
331
     *
332
     * @return array Holds an array with the items of the Dictionary
333
     */
334
    public function toArray()
335
    {
336
        $array = array();
337
        foreach ($this->items as $item) {
338
            $array[] = $item;
339
        }
340
        return $array;
341
    }
342
343
    /**
344
     * This method appends all elements of the
345
     * passed array to the Collection.
346
     *
347
     * @param array $array Holds the array with the values to add
348
     *
349
     * @return \AppserverIo\Collections\CollectionInterface The instance
350
     */
351
    public function addAll($array)
352
    {
353
        $this->items->merge($array);
354
    }
355
356
    /**
357
     * This method checks if the element with the passed
358
     * key exists in the Collection.
359
     *
360
     * @param mixed $key Holds the key to check the elements of the Collection for
361
     *
362
     * @return boolean Returns true if an element with the passed key exists in the Collection
363
     * @throws \AppserverIo\Collections\InvalidKeyException Is thrown if the passed key is invalid
364
     * @throws \AppserverIo\Lang\NullPointerException Is thrown if the passed key is NULL
365
     */
366
    public function exists($key)
367
    {
368
        return isset($this->items[$key]);
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode returns the type boolean which is incompatible with the documented return type AppserverIo\Lang\Boolean.
Loading history...
369
    }
370
}
371