1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* \AppserverIo\Appserver\PersistenceContainer\TimerServiceRegistry |
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 Doctrine\Common\Annotations\AnnotationReader; |
24
|
|
|
use AppserverIo\Storage\StackableStorage; |
25
|
|
|
use AppserverIo\Lang\Reflection\ClassInterface; |
26
|
|
|
use AppserverIo\Psr\Application\ApplicationInterface; |
27
|
|
|
use AppserverIo\Psr\EnterpriseBeans\Annotations\Stateless; |
28
|
|
|
use AppserverIo\Psr\EnterpriseBeans\Annotations\Singleton; |
29
|
|
|
use AppserverIo\Psr\EnterpriseBeans\Annotations\MessageDriven; |
30
|
|
|
use AppserverIo\Psr\EnterpriseBeans\ServiceProviderInterface; |
31
|
|
|
use AppserverIo\Psr\EnterpriseBeans\ServiceExecutorInterface; |
32
|
|
|
use AppserverIo\Psr\EnterpriseBeans\TimerServiceContextInterface; |
33
|
|
|
use AppserverIo\Psr\EnterpriseBeans\ServiceAlreadyRegisteredException; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* The timer service registry handles an application's timer services. |
37
|
|
|
* |
38
|
|
|
* @author Tim Wagner <[email protected]> |
39
|
|
|
* @copyright 2015 TechDivision GmbH <[email protected]> |
40
|
|
|
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
41
|
|
|
* @link https://github.com/appserver-io/appserver |
42
|
|
|
* @link http://www.appserver.io |
43
|
|
|
* |
44
|
|
|
* @property \AppserverIo\Psr\EnterpriseBeans\ServiceExecutorInterface $timerServiceExecutor The timer service executor |
45
|
|
|
* @property \AppserverIo\Appserver\PersistenceContainer\TimerFactoryInterface $timerFactory The timer factory |
46
|
|
|
* @property \AppserverIo\Appserver\PersistenceContainer\CalendarTimerFactoryInterface $calendarTimerFactory The calendar timer factory |
47
|
|
|
*/ |
48
|
|
|
class TimerServiceRegistry extends ServiceRegistry implements TimerServiceContextInterface |
49
|
|
|
{ |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* The annotation reader instance singleton. |
53
|
|
|
* |
54
|
|
|
* @var \Doctrine\Common\Annotations\AnnotationReader |
55
|
|
|
*/ |
56
|
|
|
public static $annotationReaderInstance; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Return's the annotation reader instance. |
60
|
|
|
* |
61
|
|
|
* @return \Doctrine\Common\Annotations\AnnotationReader |
62
|
|
|
*/ |
63
|
|
|
public function getAnnotationReader() |
64
|
|
|
{ |
65
|
|
|
|
66
|
|
|
// query whether or not an instance already exists |
67
|
|
|
if (TimerServiceRegistry::$annotationReaderInstance === null) { |
68
|
|
|
TimerServiceRegistry::$annotationReaderInstance = new AnnotationReader(); |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
// return the instance |
72
|
|
|
return TimerServiceRegistry::$annotationReaderInstance; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Return's the class annotation with the passed name, if available. |
77
|
|
|
* |
78
|
|
|
* @param \AppserverIo\Lang\Reflection\ClassInterface $reflectionClass The reflection class to return the annotation for |
79
|
|
|
* @param string $annotationName The name of the annotation to return |
80
|
|
|
* |
81
|
|
|
* @return object|null The class annotation, or NULL if not available |
82
|
|
|
*/ |
83
|
|
|
public function getClassAnnotation(ClassInterface $reflectionClass, $annotationName) |
84
|
|
|
{ |
85
|
|
|
return $this->getAnnotationReader()->getClassAnnotation($reflectionClass->toPhpReflectionClass(), $annotationName); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Injects the service executor for the timer service registry. |
90
|
|
|
* |
91
|
|
|
* @param \AppserverIo\Psr\EnterpriseBeans\ServiceExecutorInterface $timerServiceExecutor The service executor |
92
|
|
|
* |
93
|
|
|
* @return void |
94
|
|
|
*/ |
95
|
|
|
public function injectTimerServiceExecutor(ServiceExecutorInterface $timerServiceExecutor) |
96
|
|
|
{ |
97
|
|
|
$this->timerServiceExecutor = $timerServiceExecutor; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Injects the timer factory for the timer service registry. |
102
|
|
|
* |
103
|
|
|
* @param \AppserverIo\Appserver\PersistenceContainer\TimerFactoryInterface $timerFactory The timer factory |
104
|
|
|
* |
105
|
|
|
* @return void |
106
|
|
|
*/ |
107
|
|
|
public function injectTimerFactory(TimerFactoryInterface $timerFactory) |
108
|
|
|
{ |
109
|
|
|
$this->timerFactory = $timerFactory; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Injects the calendar timer factory for the timer service registry. |
114
|
|
|
* |
115
|
|
|
* @param \AppserverIo\Appserver\PersistenceContainer\CalendarTimerFactoryInterface $calendarTimerFactory The calendar timer factory |
116
|
|
|
* |
117
|
|
|
* @return void |
118
|
|
|
*/ |
119
|
|
|
public function injectCalendarTimerFactory(CalendarTimerFactoryInterface $calendarTimerFactory) |
120
|
|
|
{ |
121
|
|
|
$this->calendarTimerFactory = $calendarTimerFactory; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* Returns the service executor for the timer service registry. |
126
|
|
|
* |
127
|
|
|
* @return \AppserverIo\Psr\EnterpriseBeans\ServiceExecutorInterface The timer service executor instance |
128
|
|
|
*/ |
129
|
|
|
public function getTimerServiceExecutor() |
130
|
|
|
{ |
131
|
|
|
return $this->timerServiceExecutor; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Returns the timer factory for the timer service registry. |
136
|
|
|
* |
137
|
|
|
* @return \AppserverIo\Appserver\PersistenceContainer\TimerFactoryInterface The timer factory instance |
138
|
|
|
*/ |
139
|
|
|
public function getTimerFactory() |
140
|
|
|
{ |
141
|
|
|
return $this->timerFactory; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Returns the calendar timer factory for the timer service registry. |
146
|
|
|
* |
147
|
|
|
* @return \AppserverIo\Appserver\PersistenceContainer\CalendarTimerFactoryInterface The calendar timer factory instance |
148
|
|
|
*/ |
149
|
|
|
public function getCalendarTimerFactory() |
150
|
|
|
{ |
151
|
|
|
return $this->calendarTimerFactory; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* Has been automatically invoked by the container after the application |
156
|
|
|
* instance has been created. |
157
|
|
|
* |
158
|
|
|
* @param \AppserverIo\Psr\Application\ApplicationInterface $application The application instance |
159
|
|
|
* |
160
|
|
|
* @return void |
161
|
|
|
* @see \AppserverIo\Psr\Application\ManagerInterface::initialize() |
162
|
|
|
*/ |
163
|
|
|
public function initialize(ApplicationInterface $application) |
164
|
|
|
{ |
165
|
|
|
|
166
|
|
|
// build up META-INF directory var |
167
|
|
|
$metaInfDir = $application->getWebappPath() . DIRECTORY_SEPARATOR .'META-INF'; |
168
|
|
|
|
169
|
|
|
// check if we've found a valid directory |
170
|
|
|
if (is_dir($metaInfDir) === false) { |
171
|
|
|
return; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
// load the timer service executor and timer factories |
175
|
|
|
$timerFactory = $this->getTimerFactory(); |
176
|
|
|
$calendarTimerFactory = $this->getCalendarTimerFactory(); |
177
|
|
|
$timerServiceExecutor = $this->getTimerServiceExecutor(); |
178
|
|
|
|
179
|
|
|
// load the service to iterate over application folders |
180
|
|
|
/** @var \AppserverIo\Appserver\Core\Api\DeploymentService $service */ |
181
|
|
|
$service = $application->newService('AppserverIo\Appserver\Core\Api\DeploymentService'); |
182
|
|
|
$phpFiles = $service->globDir($metaInfDir . DIRECTORY_SEPARATOR . '*.php'); |
183
|
|
|
|
184
|
|
|
// iterate all php files |
185
|
|
|
foreach ($phpFiles as $phpFile) { |
186
|
|
|
try { |
187
|
|
|
// cut off the META-INF directory and replace OS specific directory separators |
188
|
|
|
$relativePathToPhpFile = str_replace(DIRECTORY_SEPARATOR, '\\', str_replace($metaInfDir, '', $phpFile)); |
189
|
|
|
|
190
|
|
|
// now cut off the first directory, that will be '/classes' by default |
191
|
|
|
$pregResult = preg_replace('%^(\\\\*)[^\\\\]+%', '', $relativePathToPhpFile); |
192
|
|
|
$className = substr($pregResult, 0, -4); |
193
|
|
|
|
194
|
|
|
// create the reflection class instance |
195
|
|
|
$reflectionClass = new \ReflectionClass($className); |
196
|
|
|
|
197
|
|
|
// initialize the timed object instance with the data from the reflection class |
198
|
|
|
$timedObject = TimedObject::fromPhpReflectionClass($reflectionClass); |
199
|
|
|
|
200
|
|
|
// check if we have a bean with a @Stateless, @Singleton or @MessageDriven annotation |
201
|
|
|
if ($this->getClassAnnotation($timedObject, Stateless::class) || |
202
|
|
|
$this->getClassAnnotation($timedObject, Singleton::class) || |
203
|
|
|
$this->getClassAnnotation($timedObject, MessageDriven::class) |
204
|
|
|
) { |
205
|
|
|
// initialize the stackable for the timeout methods |
206
|
|
|
$timeoutMethods = new StackableStorage(); |
207
|
|
|
|
208
|
|
|
// create the timed object invoker |
209
|
|
|
$timedObjectInvoker = new TimedObjectInvoker(); |
210
|
|
|
$timedObjectInvoker->injectApplication($application); |
211
|
|
|
$timedObjectInvoker->injectTimedObject($timedObject); |
212
|
|
|
$timedObjectInvoker->injectTimeoutMethods($timeoutMethods); |
213
|
|
|
$timedObjectInvoker->start(PTHREADS_INHERIT_NONE|PTHREADS_INHERIT_CONSTANTS); |
|
|
|
|
214
|
|
|
|
215
|
|
|
// initialize the stackable for the timers |
216
|
|
|
$timers = new StackableStorage(); |
217
|
|
|
|
218
|
|
|
// initialize the timer service |
219
|
|
|
$timerService = new TimerService(); |
220
|
|
|
$timerService->injectTimers($timers); |
221
|
|
|
$timerService->injectTimerFactory($timerFactory); |
222
|
|
|
$timerService->injectTimedObjectInvoker($timedObjectInvoker); |
223
|
|
|
$timerService->injectCalendarTimerFactory($calendarTimerFactory); |
224
|
|
|
$timerService->injectTimerServiceExecutor($timerServiceExecutor); |
225
|
|
|
$timerService->start(PTHREADS_INHERIT_NONE|PTHREADS_INHERIT_CONSTANTS); |
|
|
|
|
226
|
|
|
|
227
|
|
|
// register the initialized timer service |
228
|
|
|
$this->register($timerService); |
229
|
|
|
|
230
|
|
|
// log a message that the timer service has been registered |
231
|
|
|
$application->getInitialContext()->getSystemLogger()->debug( |
232
|
|
|
sprintf( |
233
|
|
|
'Successfully registered timer service for bean %s', |
234
|
|
|
$reflectionClass->getName() |
|
|
|
|
235
|
|
|
) |
236
|
|
|
); |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
// if class can not be reflected continue with next class |
240
|
|
|
} catch (\Exception $e) { |
241
|
|
|
// log an error message |
242
|
|
|
$application->getInitialContext()->getSystemLogger()->error($e->__toString()); |
243
|
|
|
|
244
|
|
|
// proceed with the next bean |
245
|
|
|
continue; |
246
|
|
|
} |
247
|
|
|
} |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* Attaches the passed service, to the context. |
252
|
|
|
* |
253
|
|
|
* @param \AppserverIo\Psr\EnterpriseBeans\ServiceProviderInterface $instance The service instance to attach |
254
|
|
|
* |
255
|
|
|
* @return void |
256
|
|
|
* @throws \AppserverIo\Psr\EnterpriseBeans\ServiceAlreadyRegisteredException Is thrown if the passed service has already been registered |
257
|
|
|
*/ |
258
|
|
|
public function register(ServiceProviderInterface $instance) |
259
|
|
|
{ |
260
|
|
|
|
261
|
|
|
// check if the service has already been registered |
262
|
|
|
if ($this->getServices()->has($pk = $instance->getPrimaryKey())) { |
263
|
|
|
throw new ServiceAlreadyRegisteredException( |
264
|
|
|
sprintf( |
265
|
|
|
'It is not allowed to register service %s with primary key %s more than on times', |
266
|
|
|
$instance->getServiceName(), |
267
|
|
|
$pk |
268
|
|
|
) |
269
|
|
|
); |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
// register the service using the primary key |
273
|
|
|
$this->getServices()->set($pk, $instance); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* Initializes the manager instance. |
278
|
|
|
* |
279
|
|
|
* @return string |
280
|
|
|
* @see \AppserverIo\Psr\Application\ManagerInterface::initialize() |
281
|
|
|
*/ |
282
|
|
|
public function getIdentifier() |
283
|
|
|
{ |
284
|
|
|
return TimerServiceContextInterface::IDENTIFIER; |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* Shutdown the session manager instance. |
289
|
|
|
* |
290
|
|
|
* @return void |
291
|
|
|
* \AppserverIo\Psr\Application\ManagerInterface::stop() |
292
|
|
|
*/ |
293
|
|
|
public function stop() |
294
|
|
|
{ |
295
|
|
|
$this->getTimerServiceExecutor()->stop(); |
296
|
|
|
$this->getCalendarTimerFactory()->stop(); |
297
|
|
|
$this->getTimerFactory()->stop(); |
298
|
|
|
} |
299
|
|
|
} |
300
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.