1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* AppserverIo\Appserver\Provisioning\Steps\AbstractStep |
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\Provisioning\Steps; |
22
|
|
|
|
23
|
|
|
use AppserverIo\Appserver\Core\Environment; |
24
|
|
|
use AppserverIo\Appserver\Core\Api\Node\StepNode; |
25
|
|
|
use AppserverIo\Appserver\Core\Utilities\EnvironmentKeys; |
26
|
|
|
use AppserverIo\Appserver\Provisioning\Utilities\ParamKeys; |
27
|
|
|
use AppserverIo\Psr\Servlet\SessionUtils; |
28
|
|
|
use AppserverIo\Psr\Application\ApplicationInterface; |
29
|
|
|
use AppserverIo\Psr\ApplicationServer\ServiceInterface; |
30
|
|
|
use AppserverIo\Psr\ApplicationServer\ContextInterface; |
31
|
|
|
use AppserverIo\Psr\ApplicationServer\Configuration\DatasourceConfigurationInterface; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Abstract base class for a step implementation. |
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
|
|
|
abstract class AbstractStep extends \Thread implements StepInterface |
43
|
|
|
{ |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* The maximum number of retries. |
47
|
|
|
* |
48
|
|
|
* @var integer |
49
|
|
|
*/ |
50
|
|
|
const MAX_RETRIES = 0; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* The provisioning service. |
54
|
|
|
* |
55
|
|
|
* @var \AppserverIo\Appserver\Core\Api\ServiceInterface; |
56
|
|
|
*/ |
57
|
|
|
protected $service; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* The step node with the configuration data for this step. |
61
|
|
|
* |
62
|
|
|
* @var \AppserverIo\Appserver\Core\Api\Node\StepNode |
63
|
|
|
*/ |
64
|
|
|
protected $stepNode; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* The datasource node found in the provisioning configuration. |
68
|
|
|
* |
69
|
|
|
* @var \AppserverIo\Psr\ApplicationServer\Configuration\DatasourceConfigurationInterface |
70
|
|
|
*/ |
71
|
|
|
protected $datasourceNode; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* The initial context. |
75
|
|
|
* |
76
|
|
|
* @var \AppserverIo\Psr\ApplicationServer\ContextInterface |
77
|
|
|
*/ |
78
|
|
|
protected $initialContext; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* The absolute path to the appserver PHP executable. |
82
|
|
|
* |
83
|
|
|
* @var string |
84
|
|
|
*/ |
85
|
|
|
protected $phpExecutable; |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* The absolute path to the applications folder. |
89
|
|
|
* |
90
|
|
|
* @var string |
91
|
|
|
*/ |
92
|
|
|
protected $webappPath; |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* The application instance. |
96
|
|
|
* |
97
|
|
|
* @var \AppserverIo\Psr\Application\ApplicationInterface |
98
|
|
|
*/ |
99
|
|
|
protected $application; |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Injects the provisioning service. |
103
|
|
|
* |
104
|
|
|
* @param \AppserverIo\Psr\ApplicationServer\ServiceInterface $service The provisioning service |
105
|
|
|
* |
106
|
|
|
* @return void |
107
|
|
|
*/ |
108
|
|
|
public function injectService(ServiceInterface $service) |
109
|
|
|
{ |
110
|
|
|
$this->service = $service; |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Injects the step node with the configuration data for this step. |
115
|
|
|
* |
116
|
|
|
* @param \AppserverIo\Appserver\Core\Api\Node\StepNode $stepNode The step node data |
117
|
|
|
* |
118
|
|
|
* @return void |
119
|
|
|
*/ |
120
|
|
|
public function injectStepNode(StepNode $stepNode) |
121
|
|
|
{ |
122
|
|
|
$this->stepNode = $stepNode; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Injects the datasource node found in the provisioning configuration. |
127
|
|
|
* |
128
|
|
|
* @param \AppserverIo\Psr\ApplicationServer\Configuration\DatasourceConfigurationInterface $datasourceNode The datasource node data |
129
|
|
|
* |
130
|
|
|
* @return void |
131
|
|
|
*/ |
132
|
|
|
public function injectDatasourceNode(DatasourceConfigurationInterface $datasourceNode) |
133
|
|
|
{ |
134
|
|
|
$this->datasourceNode = $datasourceNode; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* Injects the absolute path to the appservers PHP executable. |
139
|
|
|
* |
140
|
|
|
* @param string $phpExecutable The absolute path to the appservers PHP executable |
141
|
|
|
* |
142
|
|
|
* @return void |
143
|
|
|
*/ |
144
|
|
|
public function injectPhpExecutable($phpExecutable) |
145
|
|
|
{ |
146
|
|
|
$this->phpExecutable = $phpExecutable; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Injects the absolute path to the applications folder. |
151
|
|
|
* |
152
|
|
|
* @param string $webappPath The absolute path to applications folder |
153
|
|
|
* |
154
|
|
|
* @return void |
155
|
|
|
*/ |
156
|
|
|
public function injectWebappPath($webappPath) |
157
|
|
|
{ |
158
|
|
|
$this->webappPath = $webappPath; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Injects the initial context. |
163
|
|
|
* |
164
|
|
|
* @param \AppserverIo\Appserver\Core\InitialContext $initialContext The initial context instance |
165
|
|
|
* |
166
|
|
|
* @return void |
167
|
|
|
*/ |
168
|
|
|
public function injectInitialContext(ContextInterface $initialContext) |
169
|
|
|
{ |
170
|
|
|
$this->initialContext = $initialContext; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* Injects the application instance. |
175
|
|
|
* |
176
|
|
|
* @param \AppserverIo\Psr\Application\ApplicationInterface $application The application instance |
177
|
|
|
* |
178
|
|
|
* @return void |
179
|
|
|
*/ |
180
|
|
|
public function injectApplication(ApplicationInterface $application) |
181
|
|
|
{ |
182
|
|
|
$this->application = $application; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* Returns the provisioning service. |
187
|
|
|
* |
188
|
|
|
* @return \AppserverIo\Psr\ApplicationServer\ServiceInterface The provisioning service |
189
|
|
|
*/ |
190
|
|
|
protected function getService() |
191
|
|
|
{ |
192
|
|
|
return $this->service; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* Returns the step node data. |
197
|
|
|
* |
198
|
|
|
* @return \AppserverIo\Appserver\Core\Api\Node\StepNode The step node data |
199
|
|
|
*/ |
200
|
|
|
protected function getStepNode() |
201
|
|
|
{ |
202
|
|
|
return $this->stepNode; |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Returns the datasource node found in the provisioning configuration. |
207
|
|
|
* |
208
|
|
|
* @return \AppserverIo\Psr\ApplicationServer\Configuration\DatasourceConfigurationInterface The datasource node data |
209
|
|
|
*/ |
210
|
|
|
protected function getDatasourceNode() |
211
|
|
|
{ |
212
|
|
|
return $this->datasourceNode; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Returns the initial context instance. |
217
|
|
|
* |
218
|
|
|
* @return \AppserverIo\Psr\ApplicationServer\ContextInterface The initial context |
219
|
|
|
*/ |
220
|
|
|
protected function getInitialContext() |
221
|
|
|
{ |
222
|
|
|
return $this->initialContext; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* Returns the absolute path to the appservers PHP executable. |
227
|
|
|
* |
228
|
|
|
* @return string The absolute path to the appservers PHP executable |
229
|
|
|
*/ |
230
|
|
|
protected function getPhpExecutable() |
231
|
|
|
{ |
232
|
|
|
return $this->phpExecutable; |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* Returns the absolute path to the applications folder. |
237
|
|
|
* |
238
|
|
|
* @return string The applications folder |
239
|
|
|
*/ |
240
|
|
|
protected function getWebappPath() |
241
|
|
|
{ |
242
|
|
|
return $this->webappPath; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* Returns the application instance. |
247
|
|
|
* |
248
|
|
|
* @return \AppserverIo\Psr\Application\ApplicationInterface The application instance |
249
|
|
|
*/ |
250
|
|
|
protected function getApplication() |
251
|
|
|
{ |
252
|
|
|
return $this->application; |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* Will return the name of the application |
257
|
|
|
* |
258
|
|
|
* @return string |
259
|
|
|
*/ |
260
|
|
|
protected function getAppName() |
261
|
|
|
{ |
262
|
|
|
return $this->getApplication()->getName(); |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Will return the name of the application environment |
267
|
|
|
* |
268
|
|
|
* @return string |
269
|
|
|
*/ |
270
|
|
|
protected function getAppEnvironment() |
271
|
|
|
{ |
272
|
|
|
return $this->getApplication()->getEnvironmentName(); |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
/** |
276
|
|
|
* Return's the container instance the application is bound to. |
277
|
|
|
* |
278
|
|
|
* @return \AppserverIo\Psr\ApplicationServer\ContainerInterface The container instance |
279
|
|
|
*/ |
280
|
|
|
protected function getContainer() |
281
|
|
|
{ |
282
|
|
|
return $this->getApplication()->getContainer(); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
/** |
286
|
|
|
* Return's the container configuration instance. |
287
|
|
|
* |
288
|
|
|
* @return \AppserverIo\Psr\ApplicationServer\Configuration\ContainerConfigurationInterface The container configuration |
289
|
|
|
*/ |
290
|
|
|
protected function getContainerNode() |
291
|
|
|
{ |
292
|
|
|
return $this->getContainer()->getContainerNode(); |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
/** |
296
|
|
|
* Return's the system properties. |
297
|
|
|
* |
298
|
|
|
* @return \AppserverIo\Properties\PropertiesInterface The system properties |
299
|
|
|
*/ |
300
|
|
|
protected function getSystemProperties() |
301
|
|
|
{ |
302
|
|
|
return $this->getApplication()->getSystemProperties(); |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
/** |
306
|
|
|
* Return's the maximum number of retries. |
307
|
|
|
* |
308
|
|
|
* @return integer The maximum number |
309
|
|
|
*/ |
310
|
|
|
protected function getMaxRetries() |
311
|
|
|
{ |
312
|
|
|
|
313
|
|
|
// try to load the number of maximum retries from the step configuration |
314
|
|
|
$maxRetries = $this->getStepNode()->getParam(ParamKeys::MAX_RETRIES); |
315
|
|
|
|
316
|
|
|
// return the number of maximum retries |
317
|
|
|
return $maxRetries ? $maxRetries : AbstractStep::MAX_RETRIES; |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
/** |
321
|
|
|
* Logs the start of the provisioning. |
322
|
|
|
* |
323
|
|
|
* @return void |
324
|
|
|
*/ |
325
|
|
|
protected function logStart() |
326
|
|
|
{ |
327
|
|
|
\info( |
328
|
|
|
sprintf( |
329
|
|
|
'Now start to execute provisioning step %s for application %s (env %s)', |
330
|
|
|
$this->getStepNode()->getType(), |
331
|
|
|
$this->getAppName(), |
332
|
|
|
$this->getAppEnvironment() |
333
|
|
|
) |
334
|
|
|
); |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
/** |
338
|
|
|
* Logs the retry of the provisioning. |
339
|
|
|
* |
340
|
|
|
* @param integer $retry The retry number |
341
|
|
|
* @param string $failureReason The reason the last try failed |
342
|
|
|
* |
343
|
|
|
* @return void |
344
|
|
|
*/ |
345
|
|
|
protected function logRetry($retry, $failureReason) |
346
|
|
|
{ |
347
|
|
|
\info( |
348
|
|
|
sprintf( |
349
|
|
|
'Provisioning step %s of application %s (env %s) failed %d (of %d) times with message "%s"', |
350
|
|
|
$this->getStepNode()->getType(), |
351
|
|
|
$this->getAppName(), |
352
|
|
|
$this->getAppEnvironment(), |
353
|
|
|
$retry, |
354
|
|
|
AbstractStep::MAX_RETRIES, |
355
|
|
|
$failureReason |
356
|
|
|
) |
357
|
|
|
); |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
/** |
361
|
|
|
* Logs the success of the provisioning. |
362
|
|
|
* |
363
|
|
|
* @return void |
364
|
|
|
*/ |
365
|
|
|
protected function logSuccess() |
366
|
|
|
{ |
367
|
|
|
\info( |
368
|
|
|
sprintf( |
369
|
|
|
'Successfully executed provisioning step %s of application %s (env %s)', |
370
|
|
|
$this->getStepNode()->getType(), |
371
|
|
|
$this->getAppName(), |
372
|
|
|
$this->getAppEnvironment() |
373
|
|
|
) |
374
|
|
|
); |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
/** |
378
|
|
|
* Return's the param with the passed name. |
379
|
|
|
* |
380
|
|
|
* @param string $name The name of the param to return |
381
|
|
|
* |
382
|
|
|
* @return mixed The param value |
383
|
|
|
*/ |
384
|
|
|
protected function getParam($name) |
385
|
|
|
{ |
386
|
|
|
return $this->getStepNode()->getParam($name); |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
/** |
390
|
|
|
* Executes the steps functionality in a separate context. |
391
|
|
|
* |
392
|
|
|
* @return void |
393
|
|
|
*/ |
394
|
|
|
public function run() |
395
|
|
|
{ |
396
|
|
|
|
397
|
|
|
// register the default autoloader |
398
|
|
|
require SERVER_AUTOLOADER; |
399
|
|
|
|
400
|
|
|
// register shutdown handler |
401
|
|
|
register_shutdown_function(array(&$this, "shutdown")); |
402
|
|
|
|
403
|
|
|
// synchronize the application instance and register the class loaders |
404
|
|
|
$application = $this->getApplication(); |
405
|
|
|
$application->registerClassLoaders(); |
406
|
|
|
|
407
|
|
|
// register the applications annotation registries |
408
|
|
|
$application->registerAnnotationRegistries(); |
409
|
|
|
|
410
|
|
|
// add the application instance to the environment |
411
|
|
|
Environment::singleton()->setAttribute(EnvironmentKeys::APPLICATION, $application); |
412
|
|
|
|
413
|
|
|
// create s simulated request/session ID whereas session equals request ID |
414
|
|
|
Environment::singleton()->setAttribute(EnvironmentKeys::SESSION_ID, $sessionId = SessionUtils::generateRandomString()); |
415
|
|
|
Environment::singleton()->setAttribute(EnvironmentKeys::REQUEST_ID, $sessionId); |
416
|
|
|
|
417
|
|
|
// initialize retry flag and counter |
418
|
|
|
$retry = true; |
419
|
|
|
$retryCount = 0; |
420
|
|
|
|
421
|
|
|
// log a message that provisioning starts |
422
|
|
|
$this->logStart(); |
423
|
|
|
|
424
|
|
|
do { |
425
|
|
|
try { |
426
|
|
|
// run the actual provisioning |
427
|
|
|
$this->execute(); |
428
|
|
|
|
429
|
|
|
// log a message that provisioning has been successfull |
430
|
|
|
$this->logSuccess(); |
431
|
|
|
|
432
|
|
|
// don't retry, because step has been successful |
433
|
|
|
$retry = false; |
434
|
|
|
} catch (\Exception $e) { |
435
|
|
|
// raise the retry count |
436
|
|
|
$retryCount++; |
437
|
|
|
// query whether or not we've reached the maximum retry count |
438
|
|
|
if ($retryCount < $this->getMaxRetries()) { |
439
|
|
|
// sleep for an increasing number of seconds |
440
|
|
|
sleep($retryCount + 1); |
441
|
|
|
// debug log the exception |
442
|
|
|
$this->logRetry($retryCount, $e->getMessage()); |
443
|
|
|
} else { |
444
|
|
|
// log a message and stop retrying |
445
|
|
|
\error($e); |
446
|
|
|
$retry = false; |
447
|
|
|
} |
448
|
|
|
} |
449
|
|
|
} while ($retry); |
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
/** |
453
|
|
|
* Shutdown function to log unexpected errors. |
454
|
|
|
* |
455
|
|
|
* @return void |
456
|
|
|
* @see http://php.net/register_shutdown_function |
457
|
|
|
*/ |
458
|
|
View Code Duplication |
public function shutdown() |
|
|
|
|
459
|
|
|
{ |
460
|
|
|
// check if there was a fatal error caused shutdown |
461
|
|
|
if ($lastError = error_get_last()) { |
462
|
|
|
// initialize error type and message |
463
|
|
|
$type = 0; |
464
|
|
|
$message = ''; |
465
|
|
|
// extract the last error values |
466
|
|
|
extract($lastError); |
467
|
|
|
// query whether we've a fatal/user error |
468
|
|
|
if ($type === E_ERROR || $type === E_USER_ERROR) { |
469
|
|
|
$this->getInitialContext()->getSystemLogger()->critical($message); |
470
|
|
|
} |
471
|
|
|
} |
472
|
|
|
} |
473
|
|
|
} |
474
|
|
|
|
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.